output.cpp revision 114402
1// -*- C++ -*- 2/* Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc. 3 * 4 * Gaius Mulley (gaius@glam.ac.uk) wrote output.cpp 5 * but it owes a huge amount of ideas and raw code from 6 * James Clark (jjc@jclark.com) grops/ps.cpp. 7 * 8 * output.cpp 9 * 10 * provide the simple low level output routines needed by html.cpp 11 */ 12 13/* 14This file is part of groff. 15 16groff is free software; you can redistribute it and/or modify it under 17the terms of the GNU General Public License as published by the Free 18Software Foundation; either version 2, or (at your option) any later 19version. 20 21groff is distributed in the hope that it will be useful, but WITHOUT ANY 22WARRANTY; without even the implied warranty of MERCHANTABILITY or 23FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 24for more details. 25 26You should have received a copy of the GNU General Public License along 27with groff; see the file COPYING. If not, write to the Free Software 28Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 29 30#include "driver.h" 31#include "stringclass.h" 32#include "cset.h" 33 34#include <time.h> 35#include "html.h" 36 37#ifdef HAVE_UNISTD_H 38#include <unistd.h> 39#endif 40 41#undef DEBUGGING 42// #define DEBUGGING 43 44#if !defined(TRUE) 45# define TRUE (1==1) 46#endif 47#if !defined(FALSE) 48# define FALSE (1==0) 49#endif 50 51 52#if defined(DEBUGGING) 53# define FPUTC(X,Y) do { fputc((X),(Y)); fputc((X), stderr); fflush(stderr); } while (0) 54# define FPUTS(X,Y) do { fputs((X),(Y)); fputs((X), stderr); fflush(stderr); } while (0) 55# define PUTC(X,Y) do { putc((X),(Y)); putc((X), stderr); fflush(stderr); } while (0) 56#else 57# define FPUTC(X,Y) do { fputc((X),(Y)); } while (0) 58# define FPUTS(X,Y) do { fputs((X),(Y)); } while (0) 59# define PUTC(X,Y) do { putc((X),(Y)); } while (0) 60#endif 61 62 63/* 64 * word - initialise a word and set next to NULL 65 */ 66 67word::word (const char *w, int n) 68 : next(0) 69{ 70 s = (char *)malloc(n+1); 71 strncpy(s, w, n); 72 s[n] = (char)0; 73} 74 75/* 76 * destroy word and the string copy. 77 */ 78 79word::~word () 80{ 81 free(s); 82} 83 84/* 85 * word_list - create an empty word list. 86 */ 87 88word_list::word_list () 89 : length(0), head(0), tail(0) 90{ 91} 92 93/* 94 * flush - flush a word list to a FILE, f, and return the 95 * length of the buffered string. 96 */ 97 98int word_list::flush (FILE *f) 99{ 100 word *t; 101 int len=length; 102 103 while (head != 0) { 104 t = head; 105 head = head->next; 106 FPUTS(t->s, f); 107 delete t; 108 } 109 head = 0; 110 tail = 0; 111 length = 0; 112#if defined(DEBUGGING) 113 fflush(f); // just for testing 114#endif 115 return( len ); 116} 117 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