b3149018331f659ca8af68ef2577be68fbbb65d2
[platform/upstream/groff.git] / src / devices / grohtml / output.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 2000-2014  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 3 of the License, or
19 (at your option) any later 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
27 along with this program. If not, see <http://www.gnu.org/licenses/>. */
28
29 #include "driver.h"
30 #include "stringclass.h"
31 #include "cset.h"
32
33 #include <time.h>
34 #include "html.h"
35
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39
40 #undef DEBUGGING
41 // #define DEBUGGING
42
43 #if !defined(TRUE)
44 #   define TRUE  (1==1)
45 #endif
46 #if !defined(FALSE)
47 #   define FALSE (1==0)
48 #endif
49
50
51 #if defined(DEBUGGING)
52 #  define FPUTC(X,Y)   do { fputc((X),(Y)); fputc((X), stderr); fflush(stderr); } while (0)
53 #  define FPUTS(X,Y)   do { fputs((X),(Y)); fputs((X), stderr); fflush(stderr); } while (0)
54 #  define PUTC(X,Y)    do { putc((X),(Y)); putc((X), stderr); fflush(stderr); } while (0)
55 #else
56 #  define FPUTC(X,Y)   do { fputc((X),(Y)); } while (0)
57 #  define FPUTS(X,Y)   do { fputs((X),(Y)); } while (0)
58 #  define PUTC(X,Y)    do { putc((X),(Y)); } while (0)
59 #endif
60
61
62 /*
63  *  word - initialise a word and set next to NULL
64  */
65
66 word::word (const char *w, int n)
67   : next(0)
68 {
69   s = new char[n+1];
70   strncpy(s, w, n);
71   s[n] = (char)0;
72 }
73
74 /*
75  *  destroy word and the string copy.
76  */
77
78 word::~word ()
79 {
80   a_delete s;
81 }
82
83 /*
84  *  word_list - create an empty word list.
85  */
86
87 word_list::word_list ()
88   : length(0), head(0), tail(0)
89 {
90 }
91
92 /*
93  *  flush - flush a word list to a FILE, f, and return the
94  *          length of the buffered string.
95  */
96
97 int word_list::flush (FILE *f)
98 {
99   word *t;
100   int   len=length;
101
102   while (head != 0) {
103     t = head;
104     head = head->next;
105     FPUTS(t->s, f);
106     delete t;
107   }
108   head   = 0;
109   tail   = 0;
110   length = 0;
111 #if defined(DEBUGGING)
112   fflush(f);   // just for testing
113 #endif
114   return( len );
115 }
116
117 /*
118  *  add_word - adds a word to the outstanding word list.
119  */
120
121 void word_list::add_word (const char *s, int n)
122 {
123   if (head == 0) {
124     head = new word(s, n);
125     tail = head;
126   } else {
127     tail->next = new word(s, n);
128     tail       = tail->next;
129   }
130   length += n;
131 }
132
133 /*
134  *  get_length - returns the number of characters buffered
135  */
136
137 int word_list::get_length (void)
138 {
139   return( length );
140 }
141
142 /*
143  *  the classes and methods for simple_output manipulation
144  */
145
146 simple_output::simple_output(FILE *f, int n)
147 : fp(f), max_line_length(n), col(0), fixed_point(0), newlines(0)
148 {
149 }
150
151 simple_output &simple_output::set_file(FILE *f)
152 {
153   if (fp)
154     fflush(fp);
155   fp = f;
156   return *this;
157 }
158
159 simple_output &simple_output::copy_file(FILE *infp)
160 {
161   int c;
162   while ((c = getc(infp)) != EOF)
163     PUTC(c, fp);
164   return *this;
165 }
166
167 simple_output &simple_output::end_line()
168 {
169   flush_last_word();
170   if (col != 0) {
171     PUTC('\n', fp);
172     col = 0;
173   }
174   return *this;
175 }
176
177 simple_output &simple_output::special(const char *)
178 {
179   return *this;
180 }
181
182 simple_output &simple_output::simple_comment(const char *s)
183 {
184   flush_last_word();
185   if (col != 0)
186     PUTC('\n', fp);
187   FPUTS("<!-- ", fp);
188   FPUTS(s, fp);
189   FPUTS(" -->\n", fp);
190   col = 0;
191   return *this;
192 }
193
194 simple_output &simple_output::begin_comment(const char *s)
195 {
196   flush_last_word();
197   if (col != 0)
198     PUTC('\n', fp);
199   col = 0;
200   put_string("<!--");
201   space_or_newline();
202   last_word.add_word(s, strlen(s));
203   return *this;
204 }
205
206 simple_output &simple_output::end_comment()
207 {
208   flush_last_word();
209   space_or_newline();
210   put_string("-->").nl();
211   return *this;
212 }
213
214 /*
215  *  check_newline - checks to see whether we are able to issue
216  *                  a newline and that one is needed.
217  */
218
219 simple_output &simple_output::check_newline(int n)
220 {
221   if ((col + n + last_word.get_length() + 1 > max_line_length) && (newlines)) {
222     FPUTC('\n', fp);
223     col = last_word.flush(fp);
224   }
225   return *this;
226 }
227
228 /*
229  *  space_or_newline - will emit a newline or a space later on
230  *                     depending upon the current column.
231  */
232
233 simple_output &simple_output::space_or_newline (void)
234 {
235   if ((col + last_word.get_length() + 1 > max_line_length) && (newlines)) {
236     FPUTC('\n', fp);
237     if (last_word.get_length() > 0) {
238       col = last_word.flush(fp);
239     } else {
240       col = 0;
241     }
242   } else {
243     if (last_word.get_length() != 0) {
244       if (col > 0) {
245         FPUTC(' ', fp);
246         col++;
247       }
248       col += last_word.flush(fp);
249     }
250   }
251   return *this;
252 }
253
254 /*
255  *  force_nl - forces a newline.
256  */
257
258 simple_output &simple_output::force_nl (void)
259 {
260   space_or_newline();
261   col += last_word.flush(fp);
262   FPUTC('\n', fp);
263   col = 0;
264   return *this ;
265 }
266
267 /*
268  *  nl - writes a newline providing that we
269  *       are not in the first column.
270  */
271
272 simple_output &simple_output::nl (void)
273 {
274   space_or_newline();
275   col += last_word.flush(fp);
276   FPUTC('\n', fp);
277   col = 0;
278   return *this ;
279 }
280
281 simple_output &simple_output::set_fixed_point(int n)
282 {
283   assert(n >= 0 && n <= 10);
284   fixed_point = n;
285   return *this;
286 }
287
288 simple_output &simple_output::put_raw_char(char c)
289 {
290   col += last_word.flush(fp);
291   PUTC(c, fp);
292   col++;
293   return *this;
294 }
295
296 simple_output &simple_output::put_string(const char *s, int n)
297 {
298   last_word.add_word(s, n);
299   return *this;
300 }
301
302 simple_output &simple_output::put_string(const char *s)
303 {
304   last_word.add_word(s, strlen(s));
305   return *this;
306 }
307
308 simple_output &simple_output::put_string(const string &s)
309 {
310   last_word.add_word(s.contents(), s.length());
311   return *this;
312 }
313
314 simple_output &simple_output::put_number(int n)
315 {
316   char buf[1 + INT_DIGITS + 1];
317   sprintf(buf, "%d", n);
318   put_string(buf);
319   return *this;
320 }
321
322 simple_output &simple_output::put_float(double d)
323 {
324   char buf[128];
325
326   sprintf(buf, "%.4f", d);
327   put_string(buf);
328   return *this;
329 }
330
331 simple_output &simple_output::enable_newlines (int auto_newlines)
332 {
333   check_newline(0);
334   newlines = auto_newlines;
335   check_newline(0);
336   return *this;
337 }
338
339 /*
340  *  flush_last_word - flushes the last word and adjusts the
341  *                    col position. It will insert a newline
342  *                    before the last word if allowed and if
343  *                    necessary.
344  */
345
346 void simple_output::flush_last_word (void)
347 {
348   int len=last_word.get_length();
349
350   if (len > 0) {
351     if (newlines) {
352       if (col + len + 1 > max_line_length) {
353         FPUTS("\n", fp);
354         col = 0;
355       } else {
356         FPUTS(" ", fp);
357         col++;
358       }
359       len += last_word.flush(fp);
360     } else {
361       FPUTS(" ", fp);
362       col++;
363       col += last_word.flush(fp);
364     }
365   }
366 }