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 /* 16 This file is part of groff. 17 18 groff is free software; you can redistribute it and/or modify it under 19 the terms of the GNU General Public License as published by the Free 20 Software Foundation; either version 2, or (at your option) any later 21 version. 22 23 groff is distributed in the hope that it will be useful, but WITHOUT ANY 24 WARRANTY; without even the implied warranty of MERCHANTABILITY or 25 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 26 for more details. 27 28 You should have received a copy of the GNU General Public License along 29 with groff; see the file COPYING. If not, write to the Free Software 30 Foundation, 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 69 word::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 81 word::~word () 82 { 83 a_delete s; 84 } 85 86 /* 87 * word_list - create an empty word list. 88 */ 89 90 word_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 100 int 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 124 void 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 140 int word_list::get_length (void) 141 { 142 return( length ); 143 } 144 145 /* 146 * the classes and methods for simple_output manipulation 147 */ 148 149 simple_output::simple_output(FILE *f, int n) 150 : fp(f), max_line_length(n), col(0), fixed_point(0), newlines(0) 151 { 152 } 153 154 simple_output &simple_output::set_file(FILE *f) 155 { 156 if (fp) 157 fflush(fp); 158 fp = f; 159 return *this; 160 } 161 162 simple_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 170 simple_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 180 simple_output &simple_output::special(const char *) 181 { 182 return *this; 183 } 184 185 simple_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 197 simple_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 209 simple_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 222 simple_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 236 simple_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 261 simple_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 275 simple_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 284 simple_output &simple_output::set_fixed_point(int n) 285 { 286 assert(n >= 0 && n <= 10); 287 fixed_point = n; 288 return *this; 289 } 290 291 simple_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 299 simple_output &simple_output::put_string(const char *s, int n) 300 { 301 last_word.add_word(s, n); 302 return *this; 303 } 304 305 simple_output &simple_output::put_string(const char *s) 306 { 307 last_word.add_word(s, strlen(s)); 308 return *this; 309 } 310 311 simple_output &simple_output::put_string(const string &s) 312 { 313 last_word.add_word(s.contents(), s.length()); 314 return *this; 315 } 316 317 simple_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 325 simple_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 334 simple_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 349 void 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