output.cpp revision 114402
1247834Skib// -*- C++ -*-
2247834Skib/* Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc.
3247834Skib *
4247834Skib *  Gaius Mulley (gaius@glam.ac.uk) wrote output.cpp
5247834Skib *  but it owes a huge amount of ideas and raw code from
6247834Skib *  James Clark (jjc@jclark.com) grops/ps.cpp.
7247834Skib *
8247834Skib *  output.cpp
9247834Skib *
10247834Skib *  provide the simple low level output routines needed by html.cpp
11247834Skib */
12247834Skib
13247834Skib/*
14247834SkibThis file is part of groff.
15247834Skib
16247834Skibgroff is free software; you can redistribute it and/or modify it under
17247834Skibthe terms of the GNU General Public License as published by the Free
18247834SkibSoftware Foundation; either version 2, or (at your option) any later
19247834Skibversion.
20247834Skib
21247834Skibgroff is distributed in the hope that it will be useful, but WITHOUT ANY
22247834SkibWARRANTY; without even the implied warranty of MERCHANTABILITY or
23247834SkibFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24247834Skibfor more details.
25247834Skib
26247834SkibYou should have received a copy of the GNU General Public License along
27247834Skibwith groff; see the file COPYING.  If not, write to the Free Software
28247834SkibFoundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
29247834Skib
30247834Skib#include "driver.h"
31247834Skib#include "stringclass.h"
32247834Skib#include "cset.h"
33247834Skib
34247834Skib#include <time.h>
35247834Skib#include "html.h"
36247834Skib
37247834Skib#ifdef HAVE_UNISTD_H
38247834Skib#include <unistd.h>
39247834Skib#endif
40247834Skib
41247834Skib#undef DEBUGGING
42247834Skib// #define DEBUGGING
43247834Skib
44247834Skib#if !defined(TRUE)
45247834Skib#   define TRUE  (1==1)
46247834Skib#endif
47247834Skib#if !defined(FALSE)
48247834Skib#   define FALSE (1==0)
49247834Skib#endif
50247834Skib
51247834Skib
52247834Skib#if defined(DEBUGGING)
53247834Skib#  define FPUTC(X,Y)   do { fputc((X),(Y)); fputc((X), stderr); fflush(stderr); } while (0)
54247834Skib#  define FPUTS(X,Y)   do { fputs((X),(Y)); fputs((X), stderr); fflush(stderr); } while (0)
55247834Skib#  define PUTC(X,Y)    do { putc((X),(Y)); putc((X), stderr); fflush(stderr); } while (0)
56247834Skib#else
57247834Skib#  define FPUTC(X,Y)   do { fputc((X),(Y)); } while (0)
58247834Skib#  define FPUTS(X,Y)   do { fputs((X),(Y)); } while (0)
59247834Skib#  define PUTC(X,Y)    do { putc((X),(Y)); } while (0)
60247834Skib#endif
61247834Skib
62247834Skib
63247834Skib/*
64247834Skib *  word - initialise a word and set next to NULL
65247834Skib */
66247839Sdumbbell
67247834Skibword::word (const char *w, int n)
68247834Skib  : next(0)
69247834Skib{
70247834Skib  s = (char *)malloc(n+1);
71247834Skib  strncpy(s, w, n);
72247834Skib  s[n] = (char)0;
73247834Skib}
74247834Skib
75247834Skib/*
76247834Skib *  destroy word and the string copy.
77247834Skib */
78247834Skib
79282199Sdumbbellword::~word ()
80282199Sdumbbell{
81282199Sdumbbell  free(s);
82282199Sdumbbell}
83282199Sdumbbell
84247834Skib/*
85247834Skib *  word_list - create an empty word list.
86247834Skib */
87247834Skib
88247834Skibword_list::word_list ()
89247834Skib  : length(0), head(0), tail(0)
90247834Skib{
91247834Skib}
92247834Skib
93247834Skib/*
94247834Skib *  flush - flush a word list to a FILE, f, and return the
95247834Skib *          length of the buffered string.
96247834Skib */
97247834Skib
98247834Skibint word_list::flush (FILE *f)
99247834Skib{
100247834Skib  word *t;
101282199Sdumbbell  int   len=length;
102247834Skib
103247834Skib  while (head != 0) {
104247834Skib    t = head;
105247834Skib    head = head->next;
106247834Skib    FPUTS(t->s, f);
107247834Skib    delete t;
108247834Skib  }
109247834Skib  head   = 0;
110247834Skib  tail   = 0;
111247834Skib  length = 0;
112248060Sdumbbell#if defined(DEBUGGING)
113247834Skib  fflush(f);   // just for testing
114247834Skib#endif
115247834Skib  return( len );
116247834Skib}
117282199Sdumbbell
118/*
119 *  add_word - adds a word to the outstanding word list.
120 */
121
122void 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
138int word_list::get_length (void)
139{
140  return( length );
141}
142
143/*
144 *  the classes and methods for simple_output manipulation
145 */
146
147simple_output::simple_output(FILE *f, int n)
148: fp(f), max_line_length(n), col(0), fixed_point(0), newlines(0)
149{
150}
151
152simple_output &simple_output::set_file(FILE *f)
153{
154  if (fp)
155    fflush(fp);
156  fp = f;
157  return *this;
158}
159
160simple_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
168simple_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
178simple_output &simple_output::special(const char *)
179{
180  return *this;
181}
182
183simple_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
195simple_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
207simple_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
220simple_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
234simple_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 *  nl - writes a newline providing that we
257 *       are not in the first column.
258 */
259
260simple_output &simple_output::nl (void)
261{
262  space_or_newline();
263  col += last_word.flush(fp);
264  if (col != 0) {
265    FPUTC('\n', fp);
266    col = 0;
267  }
268  return *this ;
269}
270
271simple_output &simple_output::set_fixed_point(int n)
272{
273  assert(n >= 0 && n <= 10);
274  fixed_point = n;
275  return *this;
276}
277
278simple_output &simple_output::put_raw_char(char c)
279{
280  col += last_word.flush(fp);
281  PUTC(c, fp);
282  col++;
283  return *this;
284}
285
286simple_output &simple_output::put_string(const char *s, int n)
287{
288  last_word.add_word(s, n);
289  return *this;
290}
291
292simple_output &simple_output::put_string(const char *s)
293{
294  last_word.add_word(s, strlen(s));
295  return *this;
296}
297
298simple_output &simple_output::put_string(const string &s)
299{
300  last_word.add_word(s.contents(), s.length());
301  return *this;
302}
303
304simple_output &simple_output::put_number(int n)
305{
306  char buf[1 + INT_DIGITS + 1];
307  sprintf(buf, "%d", n);
308  put_string(buf);
309  return *this;
310}
311
312simple_output &simple_output::put_float(double d)
313{
314  char buf[128];
315
316  sprintf(buf, "%.4f", d);
317  put_string(buf);
318  return *this;
319}
320
321simple_output &simple_output::enable_newlines (int auto_newlines)
322{
323  check_newline(0);
324  newlines = auto_newlines;
325  check_newline(0);
326  return *this;
327}
328
329/*
330 *  flush_last_word - flushes the last word and adjusts the
331 *                    col position. It will insert a newline
332 *                    before the last word if allowed and if
333 *                    necessary.
334 */
335
336void simple_output::flush_last_word (void)
337{
338  int len=last_word.get_length();
339
340  if (len > 0) {
341    if (newlines) {
342      if (col + len + 1 > max_line_length) {
343	FPUTS("\n", fp);
344	col = 0;
345      } else {
346	FPUTS(" ", fp);
347	col++;
348      }
349      len += last_word.flush(fp);
350    } else {
351      FPUTS(" ", fp);
352      col++;
353      col += last_word.flush(fp);
354    }
355  }
356}
357