1114402Sru// -*- C++ -*-
2151497Sru/* Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
3114402Sru *
4114402Sru *  Gaius Mulley (gaius@glam.ac.uk) wrote output.cpp
5114402Sru *  but it owes a huge amount of ideas and raw code from
6114402Sru *  James Clark (jjc@jclark.com) grops/ps.cpp.
7114402Sru *
8114402Sru *  output.cpp
9114402Sru *
10114402Sru *  provide the simple low level output routines needed by html.cpp
11114402Sru */
12114402Sru
13114402Sru/*
14114402SruThis file is part of groff.
15114402Sru
16114402Srugroff is free software; you can redistribute it and/or modify it under
17114402Sruthe terms of the GNU General Public License as published by the Free
18114402SruSoftware Foundation; either version 2, or (at your option) any later
19114402Sruversion.
20114402Sru
21114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY
22114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or
23114402SruFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24114402Srufor more details.
25114402Sru
26114402SruYou should have received a copy of the GNU General Public License along
27114402Sruwith groff; see the file COPYING.  If not, write to the Free Software
28151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
29114402Sru
30114402Sru#include "driver.h"
31114402Sru#include "stringclass.h"
32114402Sru#include "cset.h"
33114402Sru
34114402Sru#include <time.h>
35114402Sru#include "html.h"
36114402Sru
37114402Sru#ifdef HAVE_UNISTD_H
38114402Sru#include <unistd.h>
39114402Sru#endif
40114402Sru
41114402Sru#undef DEBUGGING
42114402Sru// #define DEBUGGING
43114402Sru
44114402Sru#if !defined(TRUE)
45114402Sru#   define TRUE  (1==1)
46114402Sru#endif
47114402Sru#if !defined(FALSE)
48114402Sru#   define FALSE (1==0)
49114402Sru#endif
50114402Sru
51114402Sru
52114402Sru#if defined(DEBUGGING)
53114402Sru#  define FPUTC(X,Y)   do { fputc((X),(Y)); fputc((X), stderr); fflush(stderr); } while (0)
54114402Sru#  define FPUTS(X,Y)   do { fputs((X),(Y)); fputs((X), stderr); fflush(stderr); } while (0)
55114402Sru#  define PUTC(X,Y)    do { putc((X),(Y)); putc((X), stderr); fflush(stderr); } while (0)
56114402Sru#else
57114402Sru#  define FPUTC(X,Y)   do { fputc((X),(Y)); } while (0)
58114402Sru#  define FPUTS(X,Y)   do { fputs((X),(Y)); } while (0)
59114402Sru#  define PUTC(X,Y)    do { putc((X),(Y)); } while (0)
60114402Sru#endif
61114402Sru
62114402Sru
63114402Sru/*
64114402Sru *  word - initialise a word and set next to NULL
65114402Sru */
66114402Sru
67114402Sruword::word (const char *w, int n)
68114402Sru  : next(0)
69114402Sru{
70151497Sru  s = new char[n+1];
71114402Sru  strncpy(s, w, n);
72114402Sru  s[n] = (char)0;
73114402Sru}
74114402Sru
75114402Sru/*
76114402Sru *  destroy word and the string copy.
77114402Sru */
78114402Sru
79114402Sruword::~word ()
80114402Sru{
81151497Sru  a_delete s;
82114402Sru}
83114402Sru
84114402Sru/*
85114402Sru *  word_list - create an empty word list.
86114402Sru */
87114402Sru
88114402Sruword_list::word_list ()
89114402Sru  : length(0), head(0), tail(0)
90114402Sru{
91114402Sru}
92114402Sru
93114402Sru/*
94114402Sru *  flush - flush a word list to a FILE, f, and return the
95114402Sru *          length of the buffered string.
96114402Sru */
97114402Sru
98114402Sruint word_list::flush (FILE *f)
99114402Sru{
100114402Sru  word *t;
101114402Sru  int   len=length;
102114402Sru
103114402Sru  while (head != 0) {
104114402Sru    t = head;
105114402Sru    head = head->next;
106114402Sru    FPUTS(t->s, f);
107114402Sru    delete t;
108114402Sru  }
109114402Sru  head   = 0;
110114402Sru  tail   = 0;
111114402Sru  length = 0;
112114402Sru#if defined(DEBUGGING)
113114402Sru  fflush(f);   // just for testing
114114402Sru#endif
115114402Sru  return( len );
116114402Sru}
117114402Sru
118114402Sru/*
119114402Sru *  add_word - adds a word to the outstanding word list.
120114402Sru */
121114402Sru
122114402Sruvoid word_list::add_word (const char *s, int n)
123114402Sru{
124114402Sru  if (head == 0) {
125114402Sru    head = new word(s, n);
126114402Sru    tail = head;
127114402Sru  } else {
128114402Sru    tail->next = new word(s, n);
129114402Sru    tail       = tail->next;
130114402Sru  }
131114402Sru  length += n;
132114402Sru}
133114402Sru
134114402Sru/*
135114402Sru *  get_length - returns the number of characters buffered
136114402Sru */
137114402Sru
138114402Sruint word_list::get_length (void)
139114402Sru{
140114402Sru  return( length );
141114402Sru}
142114402Sru
143114402Sru/*
144114402Sru *  the classes and methods for simple_output manipulation
145114402Sru */
146114402Sru
147114402Srusimple_output::simple_output(FILE *f, int n)
148114402Sru: fp(f), max_line_length(n), col(0), fixed_point(0), newlines(0)
149114402Sru{
150114402Sru}
151114402Sru
152114402Srusimple_output &simple_output::set_file(FILE *f)
153114402Sru{
154114402Sru  if (fp)
155114402Sru    fflush(fp);
156114402Sru  fp = f;
157114402Sru  return *this;
158114402Sru}
159114402Sru
160114402Srusimple_output &simple_output::copy_file(FILE *infp)
161114402Sru{
162114402Sru  int c;
163114402Sru  while ((c = getc(infp)) != EOF)
164114402Sru    PUTC(c, fp);
165114402Sru  return *this;
166114402Sru}
167114402Sru
168114402Srusimple_output &simple_output::end_line()
169114402Sru{
170114402Sru  flush_last_word();
171114402Sru  if (col != 0) {
172114402Sru    PUTC('\n', fp);
173114402Sru    col = 0;
174114402Sru  }
175114402Sru  return *this;
176114402Sru}
177114402Sru
178114402Srusimple_output &simple_output::special(const char *)
179114402Sru{
180114402Sru  return *this;
181114402Sru}
182114402Sru
183114402Srusimple_output &simple_output::simple_comment(const char *s)
184114402Sru{
185114402Sru  flush_last_word();
186114402Sru  if (col != 0)
187114402Sru    PUTC('\n', fp);
188114402Sru  FPUTS("<!-- ", fp);
189114402Sru  FPUTS(s, fp);
190114402Sru  FPUTS(" -->\n", fp);
191114402Sru  col = 0;
192114402Sru  return *this;
193114402Sru}
194114402Sru
195114402Srusimple_output &simple_output::begin_comment(const char *s)
196114402Sru{
197114402Sru  flush_last_word();
198114402Sru  if (col != 0)
199114402Sru    PUTC('\n', fp);
200114402Sru  col = 0;
201114402Sru  put_string("<!--");
202114402Sru  space_or_newline();
203114402Sru  last_word.add_word(s, strlen(s));
204114402Sru  return *this;
205114402Sru}
206114402Sru
207114402Srusimple_output &simple_output::end_comment()
208114402Sru{
209114402Sru  flush_last_word();
210114402Sru  space_or_newline();
211114402Sru  put_string("-->").nl();
212114402Sru  return *this;
213114402Sru}
214114402Sru
215114402Sru/*
216114402Sru *  check_newline - checks to see whether we are able to issue
217114402Sru *                  a newline and that one is needed.
218114402Sru */
219114402Sru
220114402Srusimple_output &simple_output::check_newline(int n)
221114402Sru{
222114402Sru  if ((col + n + last_word.get_length() + 1 > max_line_length) && (newlines)) {
223114402Sru    FPUTC('\n', fp);
224114402Sru    col = last_word.flush(fp);
225114402Sru  }
226114402Sru  return *this;
227114402Sru}
228114402Sru
229114402Sru/*
230114402Sru *  space_or_newline - will emit a newline or a space later on
231114402Sru *                     depending upon the current column.
232114402Sru */
233114402Sru
234114402Srusimple_output &simple_output::space_or_newline (void)
235114402Sru{
236114402Sru  if ((col + last_word.get_length() + 1 > max_line_length) && (newlines)) {
237114402Sru    FPUTC('\n', fp);
238114402Sru    if (last_word.get_length() > 0) {
239114402Sru      col = last_word.flush(fp);
240114402Sru    } else {
241114402Sru      col = 0;
242114402Sru    }
243114402Sru  } else {
244114402Sru    if (last_word.get_length() != 0) {
245114402Sru      if (col > 0) {
246114402Sru	FPUTC(' ', fp);
247114402Sru	col++;
248114402Sru      }
249114402Sru      col += last_word.flush(fp);
250114402Sru    }
251114402Sru  }
252114402Sru  return *this;
253114402Sru}
254114402Sru
255114402Sru/*
256151497Sru *  force_nl - forces a newline.
257151497Sru */
258151497Sru
259151497Srusimple_output &simple_output::force_nl (void)
260151497Sru{
261151497Sru  space_or_newline();
262151497Sru  col += last_word.flush(fp);
263151497Sru  FPUTC('\n', fp);
264151497Sru  col = 0;
265151497Sru  return *this ;
266151497Sru}
267151497Sru
268151497Sru/*
269114402Sru *  nl - writes a newline providing that we
270114402Sru *       are not in the first column.
271114402Sru */
272114402Sru
273114402Srusimple_output &simple_output::nl (void)
274114402Sru{
275114402Sru  space_or_newline();
276114402Sru  col += last_word.flush(fp);
277151497Sru  FPUTC('\n', fp);
278151497Sru  col = 0;
279114402Sru  return *this ;
280114402Sru}
281114402Sru
282114402Srusimple_output &simple_output::set_fixed_point(int n)
283114402Sru{
284114402Sru  assert(n >= 0 && n <= 10);
285114402Sru  fixed_point = n;
286114402Sru  return *this;
287114402Sru}
288114402Sru
289114402Srusimple_output &simple_output::put_raw_char(char c)
290114402Sru{
291114402Sru  col += last_word.flush(fp);
292114402Sru  PUTC(c, fp);
293114402Sru  col++;
294114402Sru  return *this;
295114402Sru}
296114402Sru
297114402Srusimple_output &simple_output::put_string(const char *s, int n)
298114402Sru{
299114402Sru  last_word.add_word(s, n);
300114402Sru  return *this;
301114402Sru}
302114402Sru
303114402Srusimple_output &simple_output::put_string(const char *s)
304114402Sru{
305114402Sru  last_word.add_word(s, strlen(s));
306114402Sru  return *this;
307114402Sru}
308114402Sru
309114402Srusimple_output &simple_output::put_string(const string &s)
310114402Sru{
311114402Sru  last_word.add_word(s.contents(), s.length());
312114402Sru  return *this;
313114402Sru}
314114402Sru
315114402Srusimple_output &simple_output::put_number(int n)
316114402Sru{
317114402Sru  char buf[1 + INT_DIGITS + 1];
318114402Sru  sprintf(buf, "%d", n);
319114402Sru  put_string(buf);
320114402Sru  return *this;
321114402Sru}
322114402Sru
323114402Srusimple_output &simple_output::put_float(double d)
324114402Sru{
325114402Sru  char buf[128];
326114402Sru
327114402Sru  sprintf(buf, "%.4f", d);
328114402Sru  put_string(buf);
329114402Sru  return *this;
330114402Sru}
331114402Sru
332114402Srusimple_output &simple_output::enable_newlines (int auto_newlines)
333114402Sru{
334114402Sru  check_newline(0);
335114402Sru  newlines = auto_newlines;
336114402Sru  check_newline(0);
337114402Sru  return *this;
338114402Sru}
339114402Sru
340114402Sru/*
341114402Sru *  flush_last_word - flushes the last word and adjusts the
342114402Sru *                    col position. It will insert a newline
343114402Sru *                    before the last word if allowed and if
344114402Sru *                    necessary.
345114402Sru */
346114402Sru
347114402Sruvoid simple_output::flush_last_word (void)
348114402Sru{
349114402Sru  int len=last_word.get_length();
350114402Sru
351114402Sru  if (len > 0) {
352114402Sru    if (newlines) {
353114402Sru      if (col + len + 1 > max_line_length) {
354114402Sru	FPUTS("\n", fp);
355114402Sru	col = 0;
356114402Sru      } else {
357114402Sru	FPUTS(" ", fp);
358114402Sru	col++;
359114402Sru      }
360114402Sru      len += last_word.flush(fp);
361114402Sru    } else {
362114402Sru      FPUTS(" ", fp);
363114402Sru      col++;
364114402Sru      col += last_word.flush(fp);
365114402Sru    }
366114402Sru  }
367114402Sru}
368