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