1 // -*- C++ -*-
2 /* Copyright (C) 2000, 2001, 2003, 2004, 2005 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, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, 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
word(const char * w,int n)67 word::word (const char *w, int n)
68 : next(0)
69 {
70 s = new char[n+1];
71 strncpy(s, w, n);
72 s[n] = (char)0;
73 }
74
75 /*
76 * destroy word and the string copy.
77 */
78
~word()79 word::~word ()
80 {
81 a_delete s;
82 }
83
84 /*
85 * word_list - create an empty word list.
86 */
87
word_list()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
flush(FILE * f)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
add_word(const char * s,int n)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
get_length(void)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
simple_output(FILE * f,int n)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
set_file(FILE * f)152 simple_output &simple_output::set_file(FILE *f)
153 {
154 if (fp)
155 fflush(fp);
156 fp = f;
157 return *this;
158 }
159
copy_file(FILE * infp)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
end_line()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
special(const char *)178 simple_output &simple_output::special(const char *)
179 {
180 return *this;
181 }
182
simple_comment(const char * s)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
begin_comment(const char * s)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
end_comment()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
check_newline(int n)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
space_or_newline(void)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 * force_nl - forces a newline.
257 */
258
force_nl(void)259 simple_output &simple_output::force_nl (void)
260 {
261 space_or_newline();
262 col += last_word.flush(fp);
263 FPUTC('\n', fp);
264 col = 0;
265 return *this ;
266 }
267
268 /*
269 * nl - writes a newline providing that we
270 * are not in the first column.
271 */
272
nl(void)273 simple_output &simple_output::nl (void)
274 {
275 space_or_newline();
276 col += last_word.flush(fp);
277 FPUTC('\n', fp);
278 col = 0;
279 return *this ;
280 }
281
set_fixed_point(int n)282 simple_output &simple_output::set_fixed_point(int n)
283 {
284 assert(n >= 0 && n <= 10);
285 fixed_point = n;
286 return *this;
287 }
288
put_raw_char(char c)289 simple_output &simple_output::put_raw_char(char c)
290 {
291 col += last_word.flush(fp);
292 PUTC(c, fp);
293 col++;
294 return *this;
295 }
296
put_string(const char * s,int n)297 simple_output &simple_output::put_string(const char *s, int n)
298 {
299 last_word.add_word(s, n);
300 return *this;
301 }
302
put_string(const char * s)303 simple_output &simple_output::put_string(const char *s)
304 {
305 last_word.add_word(s, strlen(s));
306 return *this;
307 }
308
put_string(const string & s)309 simple_output &simple_output::put_string(const string &s)
310 {
311 last_word.add_word(s.contents(), s.length());
312 return *this;
313 }
314
put_number(int n)315 simple_output &simple_output::put_number(int n)
316 {
317 char buf[1 + INT_DIGITS + 1];
318 sprintf(buf, "%d", n);
319 put_string(buf);
320 return *this;
321 }
322
put_float(double d)323 simple_output &simple_output::put_float(double d)
324 {
325 char buf[128];
326
327 sprintf(buf, "%.4f", d);
328 put_string(buf);
329 return *this;
330 }
331
enable_newlines(int auto_newlines)332 simple_output &simple_output::enable_newlines (int auto_newlines)
333 {
334 check_newline(0);
335 newlines = auto_newlines;
336 check_newline(0);
337 return *this;
338 }
339
340 /*
341 * flush_last_word - flushes the last word and adjusts the
342 * col position. It will insert a newline
343 * before the last word if allowed and if
344 * necessary.
345 */
346
flush_last_word(void)347 void simple_output::flush_last_word (void)
348 {
349 int len=last_word.get_length();
350
351 if (len > 0) {
352 if (newlines) {
353 if (col + len + 1 > max_line_length) {
354 FPUTS("\n", fp);
355 col = 0;
356 } else {
357 FPUTS(" ", fp);
358 col++;
359 }
360 len += last_word.flush(fp);
361 } else {
362 FPUTS(" ", fp);
363 col++;
364 col += last_word.flush(fp);
365 }
366 }
367 }
368