xref: /netbsd-src/external/gpl2/groff/dist/src/devices/grohtml/output.cpp (revision 89a07cf815a29524268025a1139fac4c5190f765)
1 /*	$NetBSD: output.cpp,v 1.1.1.1 2016/01/13 18:41:49 christos Exp $	*/
2 
3 // -*- C++ -*-
4 /* Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
5  *
6  *  Gaius Mulley (gaius@glam.ac.uk) wrote output.cpp
7  *  but it owes a huge amount of ideas and raw code from
8  *  James Clark (jjc@jclark.com) grops/ps.cpp.
9  *
10  *  output.cpp
11  *
12  *  provide the simple low level output routines needed by html.cpp
13  */
14 
15 /*
16 This file is part of groff.
17 
18 groff is free software; you can redistribute it and/or modify it under
19 the terms of the GNU General Public License as published by the Free
20 Software Foundation; either version 2, or (at your option) any later
21 version.
22 
23 groff is distributed in the hope that it will be useful, but WITHOUT ANY
24 WARRANTY; without even the implied warranty of MERCHANTABILITY or
25 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
26 for more details.
27 
28 You should have received a copy of the GNU General Public License along
29 with groff; see the file COPYING.  If not, write to the Free Software
30 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
31 
32 #include "driver.h"
33 #include "stringclass.h"
34 #include "cset.h"
35 
36 #include <time.h>
37 #include "html.h"
38 
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42 
43 #undef DEBUGGING
44 // #define DEBUGGING
45 
46 #if !defined(TRUE)
47 #   define TRUE  (1==1)
48 #endif
49 #if !defined(FALSE)
50 #   define FALSE (1==0)
51 #endif
52 
53 
54 #if defined(DEBUGGING)
55 #  define FPUTC(X,Y)   do { fputc((X),(Y)); fputc((X), stderr); fflush(stderr); } while (0)
56 #  define FPUTS(X,Y)   do { fputs((X),(Y)); fputs((X), stderr); fflush(stderr); } while (0)
57 #  define PUTC(X,Y)    do { putc((X),(Y)); putc((X), stderr); fflush(stderr); } while (0)
58 #else
59 #  define FPUTC(X,Y)   do { fputc((X),(Y)); } while (0)
60 #  define FPUTS(X,Y)   do { fputs((X),(Y)); } while (0)
61 #  define PUTC(X,Y)    do { putc((X),(Y)); } while (0)
62 #endif
63 
64 
65 /*
66  *  word - initialise a word and set next to NULL
67  */
68 
word(const char * w,int n)69 word::word (const char *w, int n)
70   : next(0)
71 {
72   s = new char[n+1];
73   strncpy(s, w, n);
74   s[n] = (char)0;
75 }
76 
77 /*
78  *  destroy word and the string copy.
79  */
80 
~word()81 word::~word ()
82 {
83   a_delete s;
84 }
85 
86 /*
87  *  word_list - create an empty word list.
88  */
89 
word_list()90 word_list::word_list ()
91   : length(0), head(0), tail(0)
92 {
93 }
94 
95 /*
96  *  flush - flush a word list to a FILE, f, and return the
97  *          length of the buffered string.
98  */
99 
flush(FILE * f)100 int word_list::flush (FILE *f)
101 {
102   word *t;
103   int   len=length;
104 
105   while (head != 0) {
106     t = head;
107     head = head->next;
108     FPUTS(t->s, f);
109     delete t;
110   }
111   head   = 0;
112   tail   = 0;
113   length = 0;
114 #if defined(DEBUGGING)
115   fflush(f);   // just for testing
116 #endif
117   return( len );
118 }
119 
120 /*
121  *  add_word - adds a word to the outstanding word list.
122  */
123 
add_word(const char * s,int n)124 void word_list::add_word (const char *s, int n)
125 {
126   if (head == 0) {
127     head = new word(s, n);
128     tail = head;
129   } else {
130     tail->next = new word(s, n);
131     tail       = tail->next;
132   }
133   length += n;
134 }
135 
136 /*
137  *  get_length - returns the number of characters buffered
138  */
139 
get_length(void)140 int word_list::get_length (void)
141 {
142   return( length );
143 }
144 
145 /*
146  *  the classes and methods for simple_output manipulation
147  */
148 
simple_output(FILE * f,int n)149 simple_output::simple_output(FILE *f, int n)
150 : fp(f), max_line_length(n), col(0), fixed_point(0), newlines(0)
151 {
152 }
153 
set_file(FILE * f)154 simple_output &simple_output::set_file(FILE *f)
155 {
156   if (fp)
157     fflush(fp);
158   fp = f;
159   return *this;
160 }
161 
copy_file(FILE * infp)162 simple_output &simple_output::copy_file(FILE *infp)
163 {
164   int c;
165   while ((c = getc(infp)) != EOF)
166     PUTC(c, fp);
167   return *this;
168 }
169 
end_line()170 simple_output &simple_output::end_line()
171 {
172   flush_last_word();
173   if (col != 0) {
174     PUTC('\n', fp);
175     col = 0;
176   }
177   return *this;
178 }
179 
special(const char *)180 simple_output &simple_output::special(const char *)
181 {
182   return *this;
183 }
184 
simple_comment(const char * s)185 simple_output &simple_output::simple_comment(const char *s)
186 {
187   flush_last_word();
188   if (col != 0)
189     PUTC('\n', fp);
190   FPUTS("<!-- ", fp);
191   FPUTS(s, fp);
192   FPUTS(" -->\n", fp);
193   col = 0;
194   return *this;
195 }
196 
begin_comment(const char * s)197 simple_output &simple_output::begin_comment(const char *s)
198 {
199   flush_last_word();
200   if (col != 0)
201     PUTC('\n', fp);
202   col = 0;
203   put_string("<!--");
204   space_or_newline();
205   last_word.add_word(s, strlen(s));
206   return *this;
207 }
208 
end_comment()209 simple_output &simple_output::end_comment()
210 {
211   flush_last_word();
212   space_or_newline();
213   put_string("-->").nl();
214   return *this;
215 }
216 
217 /*
218  *  check_newline - checks to see whether we are able to issue
219  *                  a newline and that one is needed.
220  */
221 
check_newline(int n)222 simple_output &simple_output::check_newline(int n)
223 {
224   if ((col + n + last_word.get_length() + 1 > max_line_length) && (newlines)) {
225     FPUTC('\n', fp);
226     col = last_word.flush(fp);
227   }
228   return *this;
229 }
230 
231 /*
232  *  space_or_newline - will emit a newline or a space later on
233  *                     depending upon the current column.
234  */
235 
space_or_newline(void)236 simple_output &simple_output::space_or_newline (void)
237 {
238   if ((col + last_word.get_length() + 1 > max_line_length) && (newlines)) {
239     FPUTC('\n', fp);
240     if (last_word.get_length() > 0) {
241       col = last_word.flush(fp);
242     } else {
243       col = 0;
244     }
245   } else {
246     if (last_word.get_length() != 0) {
247       if (col > 0) {
248 	FPUTC(' ', fp);
249 	col++;
250       }
251       col += last_word.flush(fp);
252     }
253   }
254   return *this;
255 }
256 
257 /*
258  *  force_nl - forces a newline.
259  */
260 
force_nl(void)261 simple_output &simple_output::force_nl (void)
262 {
263   space_or_newline();
264   col += last_word.flush(fp);
265   FPUTC('\n', fp);
266   col = 0;
267   return *this ;
268 }
269 
270 /*
271  *  nl - writes a newline providing that we
272  *       are not in the first column.
273  */
274 
nl(void)275 simple_output &simple_output::nl (void)
276 {
277   space_or_newline();
278   col += last_word.flush(fp);
279   FPUTC('\n', fp);
280   col = 0;
281   return *this ;
282 }
283 
set_fixed_point(int n)284 simple_output &simple_output::set_fixed_point(int n)
285 {
286   assert(n >= 0 && n <= 10);
287   fixed_point = n;
288   return *this;
289 }
290 
put_raw_char(char c)291 simple_output &simple_output::put_raw_char(char c)
292 {
293   col += last_word.flush(fp);
294   PUTC(c, fp);
295   col++;
296   return *this;
297 }
298 
put_string(const char * s,int n)299 simple_output &simple_output::put_string(const char *s, int n)
300 {
301   last_word.add_word(s, n);
302   return *this;
303 }
304 
put_string(const char * s)305 simple_output &simple_output::put_string(const char *s)
306 {
307   last_word.add_word(s, strlen(s));
308   return *this;
309 }
310 
put_string(const string & s)311 simple_output &simple_output::put_string(const string &s)
312 {
313   last_word.add_word(s.contents(), s.length());
314   return *this;
315 }
316 
put_number(int n)317 simple_output &simple_output::put_number(int n)
318 {
319   char buf[1 + INT_DIGITS + 1];
320   sprintf(buf, "%d", n);
321   put_string(buf);
322   return *this;
323 }
324 
put_float(double d)325 simple_output &simple_output::put_float(double d)
326 {
327   char buf[128];
328 
329   sprintf(buf, "%.4f", d);
330   put_string(buf);
331   return *this;
332 }
333 
enable_newlines(int auto_newlines)334 simple_output &simple_output::enable_newlines (int auto_newlines)
335 {
336   check_newline(0);
337   newlines = auto_newlines;
338   check_newline(0);
339   return *this;
340 }
341 
342 /*
343  *  flush_last_word - flushes the last word and adjusts the
344  *                    col position. It will insert a newline
345  *                    before the last word if allowed and if
346  *                    necessary.
347  */
348 
flush_last_word(void)349 void simple_output::flush_last_word (void)
350 {
351   int len=last_word.get_length();
352 
353   if (len > 0) {
354     if (newlines) {
355       if (col + len + 1 > max_line_length) {
356 	FPUTS("\n", fp);
357 	col = 0;
358       } else {
359 	FPUTS(" ", fp);
360 	col++;
361       }
362       len += last_word.flush(fp);
363     } else {
364       FPUTS(" ", fp);
365       col++;
366       col += last_word.flush(fp);
367     }
368   }
369 }
370