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