Line data Source code
1 : /* Copyright (C) 2000-2025 Free Software Foundation, Inc.
2 : *
3 : * Gaius Mulley (gaius@glam.ac.uk) wrote output.cpp
4 : * but it owes a huge amount of ideas and raw code from
5 : * James Clark (jjc@jclark.com) grops/ps.cpp.
6 : *
7 : * output.cpp
8 : *
9 : * provide the simple low level output routines needed by html.cpp
10 : */
11 :
12 : /*
13 : This file is part of groff, the GNU roff typesetting system.
14 :
15 : groff is free software; you can redistribute it and/or modify it under
16 : the terms of the GNU General Public License as published by the Free
17 : Software Foundation, either version 3 of the License, or
18 : (at your option) any later version.
19 :
20 : groff is distributed in the hope that it will be useful, but WITHOUT ANY
21 : WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 : for more details.
24 :
25 : You should have received a copy of the GNU General Public License
26 : along with this program. If not, see <http://www.gnu.org/licenses/>. */
27 :
28 : #ifdef HAVE_CONFIG_H
29 : #include <config.h>
30 : #endif
31 :
32 : #include <stdio.h> // EOF, FILE, fflush(), fputc(), fputs(), fwrite(),
33 : // getc(), putc(), sprintf()
34 : #include <string.h> // strlen(), strncpy()
35 :
36 : #include "cset.h"
37 : #include "driver.h"
38 : #include "lib.h" // INT_DIGITS
39 : #include "stringclass.h"
40 :
41 : #include "html.h"
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 35163 : word::word (const char *w, int n)
67 35163 : : next(0)
68 : {
69 35163 : s = new char[n+1];
70 35163 : strncpy(s, w, n);
71 35163 : s[n] = '\0';
72 35163 : }
73 :
74 : /*
75 : * destroy word and the string copy.
76 : */
77 :
78 70326 : word::~word ()
79 : {
80 35163 : delete[] s;
81 35163 : }
82 :
83 : /*
84 : * word_list - create an empty word list.
85 : */
86 :
87 17 : word_list::word_list ()
88 17 : : length(0), head(0), tail(0)
89 : {
90 17 : }
91 :
92 : /*
93 : * flush - flush a word list to a FILE, f, and return the
94 : * length of the buffered string.
95 : */
96 :
97 23989 : int word_list::flush (FILE *f)
98 : {
99 : word *t;
100 23989 : int len=length;
101 :
102 59152 : while (head != 0) {
103 35163 : t = head;
104 35163 : head = head->next;
105 35163 : FPUTS(t->s, f);
106 35163 : delete t;
107 : }
108 23989 : head = 0;
109 23989 : tail = 0;
110 23989 : length = 0;
111 : #if defined(DEBUGGING)
112 : fflush(f); // just for testing
113 : #endif
114 23989 : return( len );
115 : }
116 :
117 : /*
118 : * add_word - adds a word to the outstanding word list.
119 : */
120 :
121 35163 : void word_list::add_word (const char *s, int n)
122 : {
123 35163 : if (head == 0) {
124 21376 : head = new word(s, n);
125 21376 : tail = head;
126 : } else {
127 13787 : tail->next = new word(s, n);
128 13787 : tail = tail->next;
129 : }
130 35163 : length += n;
131 35163 : }
132 :
133 : /*
134 : * get_length - returns the number of characters buffered
135 : */
136 :
137 49473 : int word_list::get_length (void)
138 : {
139 49473 : return( length );
140 : }
141 :
142 : /*
143 : * the classes and methods for simple_output manipulation
144 : */
145 :
146 17 : simple_output::simple_output(FILE *f, int n)
147 17 : : fp(f), max_line_length(n), col(0), fixed_point(0), newlines(0)
148 : {
149 17 : }
150 :
151 132 : simple_output &simple_output::set_file(FILE *f)
152 : {
153 132 : if (fp)
154 115 : fflush(fp);
155 132 : fp = f;
156 132 : return *this;
157 : }
158 :
159 209421 : simple_output &simple_output::copy_file(FILE *infp)
160 : {
161 : int c;
162 209421 : while ((c = getc(infp)) != EOF)
163 209346 : PUTC(c, fp);
164 75 : return *this;
165 : }
166 :
167 109 : simple_output &simple_output::end_line()
168 : {
169 109 : flush_last_word();
170 109 : if (col != 0) {
171 68 : PUTC('\n', fp);
172 68 : col = 0;
173 : }
174 109 : return *this;
175 : }
176 :
177 0 : simple_output &simple_output::special(const char *)
178 : {
179 0 : return *this;
180 : }
181 :
182 0 : simple_output &simple_output::simple_comment(const char *s)
183 : {
184 0 : flush_last_word();
185 0 : if (col != 0)
186 0 : PUTC('\n', fp);
187 0 : FPUTS("<!-- ", fp);
188 0 : FPUTS(s, fp);
189 0 : FPUTS(" -->\n", fp);
190 0 : col = 0;
191 0 : return *this;
192 : }
193 :
194 110 : simple_output &simple_output::begin_comment(const char *s)
195 : {
196 110 : flush_last_word();
197 110 : if (col != 0)
198 0 : PUTC('\n', fp);
199 110 : col = 0;
200 110 : put_string("<!--");
201 110 : space_or_newline();
202 110 : last_word.add_word(s, strlen(s));
203 110 : return *this;
204 : }
205 :
206 110 : simple_output &simple_output::end_comment()
207 : {
208 110 : flush_last_word();
209 110 : space_or_newline();
210 110 : put_string("-->").nl();
211 110 : 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 4024 : simple_output &simple_output::check_newline(int n)
220 : {
221 4024 : if ((col + n + last_word.get_length() + 1 > max_line_length) && (newlines)) {
222 326 : FPUTC('\n', fp);
223 326 : col = last_word.flush(fp);
224 : }
225 4024 : 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 22560 : simple_output &simple_output::space_or_newline (void)
234 : {
235 22560 : if ((col + last_word.get_length() + 1 > max_line_length) && (newlines)) {
236 2379 : FPUTC('\n', fp);
237 2379 : if (last_word.get_length() > 0) {
238 2379 : col = last_word.flush(fp);
239 : } else {
240 0 : col = 0;
241 : }
242 : } else {
243 20181 : if (last_word.get_length() != 0) {
244 18504 : if (col > 0) {
245 16477 : FPUTC(' ', fp);
246 16477 : col++;
247 : }
248 18504 : col += last_word.flush(fp);
249 : }
250 : }
251 22560 : return *this;
252 : }
253 :
254 : /*
255 : * force_nl - forces a newline.
256 : */
257 :
258 0 : simple_output &simple_output::force_nl (void)
259 : {
260 0 : space_or_newline();
261 0 : col += last_word.flush(fp);
262 0 : FPUTC('\n', fp);
263 0 : col = 0;
264 0 : return *this ;
265 : }
266 :
267 : /*
268 : * nl - writes a newline providing that we
269 : * are not in the first column.
270 : */
271 :
272 2613 : simple_output &simple_output::nl (void)
273 : {
274 2613 : space_or_newline();
275 2613 : col += last_word.flush(fp);
276 2613 : FPUTC('\n', fp);
277 2613 : col = 0;
278 2613 : return *this ;
279 : }
280 :
281 17 : simple_output &simple_output::set_fixed_point(int n)
282 : {
283 17 : assert(n >= 0 && n <= 10);
284 17 : fixed_point = n;
285 17 : return *this;
286 : }
287 :
288 0 : simple_output &simple_output::put_raw_char(char c)
289 : {
290 0 : col += last_word.flush(fp);
291 0 : PUTC(c, fp);
292 0 : col++;
293 0 : return *this;
294 : }
295 :
296 20617 : simple_output &simple_output::put_string(const char *s, int n)
297 : {
298 20617 : last_word.add_word(s, n);
299 20617 : return *this;
300 : }
301 :
302 14250 : simple_output &simple_output::put_string(const char *s)
303 : {
304 14250 : last_word.add_word(s, strlen(s));
305 14250 : return *this;
306 : }
307 :
308 186 : simple_output &simple_output::put_string(const string &s)
309 : {
310 186 : last_word.add_word(s.contents(), s.length());
311 186 : return *this;
312 : }
313 :
314 422 : simple_output &simple_output::put_number(int n)
315 : {
316 : char buf[1 + INT_DIGITS + 1];
317 422 : sprintf(buf, "%d", n);
318 422 : put_string(buf);
319 422 : return *this;
320 : }
321 :
322 0 : simple_output &simple_output::put_float(double d)
323 : {
324 : char buf[128];
325 :
326 0 : sprintf(buf, "%.4f", d);
327 0 : put_string(buf);
328 0 : return *this;
329 : }
330 :
331 2012 : simple_output &simple_output::enable_newlines (int auto_newlines)
332 : {
333 2012 : check_newline(0);
334 2012 : newlines = auto_newlines;
335 2012 : check_newline(0);
336 2012 : 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 329 : void simple_output::flush_last_word (void)
347 : {
348 329 : int len=last_word.get_length();
349 :
350 329 : if (len > 0) {
351 167 : if (newlines) {
352 0 : if (col + len + 1 > max_line_length) {
353 0 : FPUTS("\n", fp);
354 0 : col = 0;
355 : } else {
356 0 : FPUTS(" ", fp);
357 0 : col++;
358 : }
359 0 : len += last_word.flush(fp);
360 : } else {
361 167 : FPUTS(" ", fp);
362 167 : col++;
363 167 : col += last_word.flush(fp);
364 : }
365 : }
366 329 : }
367 :
368 : // Local Variables:
369 : // fill-column: 72
370 : // mode: C++
371 : // End:
372 : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72:
|