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/*
16This file is part of groff.
17
18groff is free software; you can redistribute it and/or modify it under
19the terms of the GNU General Public License as published by the Free
20Software Foundation; either version 2, or (at your option) any later
21version.
22
23groff is distributed in the hope that it will be useful, but WITHOUT ANY
24WARRANTY; without even the implied warranty of MERCHANTABILITY or
25FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
26for more details.
27
28You should have received a copy of the GNU General Public License along
29with groff; see the file COPYING.  If not, write to the Free Software
30Foundation, 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
69word::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
81word::~word ()
82{
83  a_delete s;
84}
85
86/*
87 *  word_list - create an empty word list.
88 */
89
90word_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
100int 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
124void 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
140int word_list::get_length (void)
141{
142  return( length );
143}
144
145/*
146 *  the classes and methods for simple_output manipulation
147 */
148
149simple_output::simple_output(FILE *f, int n)
150: fp(f), max_line_length(n), col(0), fixed_point(0), newlines(0)
151{
152}
153
154simple_output &simple_output::set_file(FILE *f)
155{
156  if (fp)
157    fflush(fp);
158  fp = f;
159  return *this;
160}
161
162simple_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
170simple_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
180simple_output &simple_output::special(const char *)
181{
182  return *this;
183}
184
185simple_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
197simple_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
209simple_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
222simple_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
236simple_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
261simple_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
275simple_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
284simple_output &simple_output::set_fixed_point(int n)
285{
286  assert(n >= 0 && n <= 10);
287  fixed_point = n;
288  return *this;
289}
290
291simple_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
299simple_output &simple_output::put_string(const char *s, int n)
300{
301  last_word.add_word(s, n);
302  return *this;
303}
304
305simple_output &simple_output::put_string(const char *s)
306{
307  last_word.add_word(s, strlen(s));
308  return *this;
309}
310
311simple_output &simple_output::put_string(const string &s)
312{
313  last_word.add_word(s.contents(), s.length());
314  return *this;
315}
316
317simple_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
325simple_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
334simple_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
349void 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