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