output.cpp revision 256281
1// -*- C++ -*- 2/* Copyright (C) 2000, 2001, 2003, 2004, 2005 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, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, 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 = new char[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 a_delete 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 * force_nl - forces a newline. 257 */ 258 259simple_output &simple_output::force_nl (void) 260{ 261 space_or_newline(); 262 col += last_word.flush(fp); 263 FPUTC('\n', fp); 264 col = 0; 265 return *this ; 266} 267 268/* 269 * nl - writes a newline providing that we 270 * are not in the first column. 271 */ 272 273simple_output &simple_output::nl (void) 274{ 275 space_or_newline(); 276 col += last_word.flush(fp); 277 FPUTC('\n', fp); 278 col = 0; 279 return *this ; 280} 281 282simple_output &simple_output::set_fixed_point(int n) 283{ 284 assert(n >= 0 && n <= 10); 285 fixed_point = n; 286 return *this; 287} 288 289simple_output &simple_output::put_raw_char(char c) 290{ 291 col += last_word.flush(fp); 292 PUTC(c, fp); 293 col++; 294 return *this; 295} 296 297simple_output &simple_output::put_string(const char *s, int n) 298{ 299 last_word.add_word(s, n); 300 return *this; 301} 302 303simple_output &simple_output::put_string(const char *s) 304{ 305 last_word.add_word(s, strlen(s)); 306 return *this; 307} 308 309simple_output &simple_output::put_string(const string &s) 310{ 311 last_word.add_word(s.contents(), s.length()); 312 return *this; 313} 314 315simple_output &simple_output::put_number(int n) 316{ 317 char buf[1 + INT_DIGITS + 1]; 318 sprintf(buf, "%d", n); 319 put_string(buf); 320 return *this; 321} 322 323simple_output &simple_output::put_float(double d) 324{ 325 char buf[128]; 326 327 sprintf(buf, "%.4f", d); 328 put_string(buf); 329 return *this; 330} 331 332simple_output &simple_output::enable_newlines (int auto_newlines) 333{ 334 check_newline(0); 335 newlines = auto_newlines; 336 check_newline(0); 337 return *this; 338} 339 340/* 341 * flush_last_word - flushes the last word and adjusts the 342 * col position. It will insert a newline 343 * before the last word if allowed and if 344 * necessary. 345 */ 346 347void simple_output::flush_last_word (void) 348{ 349 int len=last_word.get_length(); 350 351 if (len > 0) { 352 if (newlines) { 353 if (col + len + 1 > max_line_length) { 354 FPUTS("\n", fp); 355 col = 0; 356 } else { 357 FPUTS(" ", fp); 358 col++; 359 } 360 len += last_word.flush(fp); 361 } else { 362 FPUTS(" ", fp); 363 col++; 364 col += last_word.flush(fp); 365 } 366 } 367} 368