LCOV - code coverage report
Current view: top level - devices/grohtml - output.cpp (source / functions) Hit Total Coverage
Test: GNU roff Lines: 116 150 77.3 %
Date: 2026-01-16 17:51:41 Functions: 22 27 81.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2000-2025 Free Software Foundation, Inc.
       2             :  *
       3             :  *  Gaius Mulley (gaius@glam.ac.uk) wrote output.cpp
       4             :  *  but it owes a huge amount of ideas and raw code from
       5             :  *  James Clark (jjc@jclark.com) grops/ps.cpp.
       6             :  *
       7             :  *  output.cpp
       8             :  *
       9             :  *  provide the simple low level output routines needed by html.cpp
      10             :  */
      11             : 
      12             : /*
      13             : This file is part of groff, the GNU roff typesetting system.
      14             : 
      15             : groff is free software; you can redistribute it and/or modify it under
      16             : the terms of the GNU General Public License as published by the Free
      17             : Software Foundation, either version 3 of the License, or
      18             : (at your option) any later version.
      19             : 
      20             : groff is distributed in the hope that it will be useful, but WITHOUT ANY
      21             : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      22             : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      23             : for more details.
      24             : 
      25             : You should have received a copy of the GNU General Public License
      26             : along with this program.  If not, see <http://www.gnu.org/licenses/>. */
      27             : 
      28             : #ifdef HAVE_CONFIG_H
      29             : #include <config.h>
      30             : #endif
      31             : 
      32             : #include <stdio.h> // EOF, FILE, fflush(), fputc(), fputs(), fwrite(),
      33             :                    // getc(), putc(), sprintf()
      34             : #include <string.h> // strlen(), strncpy()
      35             : 
      36             : #include "cset.h"
      37             : #include "driver.h"
      38             : #include "lib.h" // INT_DIGITS
      39             : #include "stringclass.h"
      40             : 
      41             : #include "html.h"
      42             : 
      43             : #if !defined(TRUE)
      44             : #   define TRUE  (1==1)
      45             : #endif
      46             : #if !defined(FALSE)
      47             : #   define FALSE (1==0)
      48             : #endif
      49             : 
      50             : 
      51             : #if defined(DEBUGGING)
      52             : #  define FPUTC(X,Y)   do { fputc((X),(Y)); fputc((X), stderr); fflush(stderr); } while (0)
      53             : #  define FPUTS(X,Y)   do { fputs((X),(Y)); fputs((X), stderr); fflush(stderr); } while (0)
      54             : #  define PUTC(X,Y)    do { putc((X),(Y)); putc((X), stderr); fflush(stderr); } while (0)
      55             : #else
      56             : #  define FPUTC(X,Y)   do { fputc((X),(Y)); } while (0)
      57             : #  define FPUTS(X,Y)   do { fputs((X),(Y)); } while (0)
      58             : #  define PUTC(X,Y)    do { putc((X),(Y)); } while (0)
      59             : #endif
      60             : 
      61             : 
      62             : /*
      63             :  *  word - initialise a word and set next to NULL
      64             :  */
      65             : 
      66       35163 : word::word (const char *w, int n)
      67       35163 :   : next(0)
      68             : {
      69       35163 :   s = new char[n+1];
      70       35163 :   strncpy(s, w, n);
      71       35163 :   s[n] = '\0';
      72       35163 : }
      73             : 
      74             : /*
      75             :  *  destroy word and the string copy.
      76             :  */
      77             : 
      78       70326 : word::~word ()
      79             : {
      80       35163 :   delete[] s;
      81       35163 : }
      82             : 
      83             : /*
      84             :  *  word_list - create an empty word list.
      85             :  */
      86             : 
      87          17 : word_list::word_list ()
      88          17 :   : length(0), head(0), tail(0)
      89             : {
      90          17 : }
      91             : 
      92             : /*
      93             :  *  flush - flush a word list to a FILE, f, and return the
      94             :  *          length of the buffered string.
      95             :  */
      96             : 
      97       23989 : int word_list::flush (FILE *f)
      98             : {
      99             :   word *t;
     100       23989 :   int   len=length;
     101             : 
     102       59152 :   while (head != 0) {
     103       35163 :     t = head;
     104       35163 :     head = head->next;
     105       35163 :     FPUTS(t->s, f);
     106       35163 :     delete t;
     107             :   }
     108       23989 :   head   = 0;
     109       23989 :   tail   = 0;
     110       23989 :   length = 0;
     111             : #if defined(DEBUGGING)
     112             :   fflush(f);   // just for testing
     113             : #endif
     114       23989 :   return( len );
     115             : }
     116             : 
     117             : /*
     118             :  *  add_word - adds a word to the outstanding word list.
     119             :  */
     120             : 
     121       35163 : void word_list::add_word (const char *s, int n)
     122             : {
     123       35163 :   if (head == 0) {
     124       21376 :     head = new word(s, n);
     125       21376 :     tail = head;
     126             :   } else {
     127       13787 :     tail->next = new word(s, n);
     128       13787 :     tail       = tail->next;
     129             :   }
     130       35163 :   length += n;
     131       35163 : }
     132             : 
     133             : /*
     134             :  *  get_length - returns the number of characters buffered
     135             :  */
     136             : 
     137       49473 : int word_list::get_length (void)
     138             : {
     139       49473 :   return( length );
     140             : }
     141             : 
     142             : /*
     143             :  *  the classes and methods for simple_output manipulation
     144             :  */
     145             : 
     146          17 : simple_output::simple_output(FILE *f, int n)
     147          17 : : fp(f), max_line_length(n), col(0), fixed_point(0), newlines(0)
     148             : {
     149          17 : }
     150             : 
     151         132 : simple_output &simple_output::set_file(FILE *f)
     152             : {
     153         132 :   if (fp)
     154         115 :     fflush(fp);
     155         132 :   fp = f;
     156         132 :   return *this;
     157             : }
     158             : 
     159      209421 : simple_output &simple_output::copy_file(FILE *infp)
     160             : {
     161             :   int c;
     162      209421 :   while ((c = getc(infp)) != EOF)
     163      209346 :     PUTC(c, fp);
     164          75 :   return *this;
     165             : }
     166             : 
     167         109 : simple_output &simple_output::end_line()
     168             : {
     169         109 :   flush_last_word();
     170         109 :   if (col != 0) {
     171          68 :     PUTC('\n', fp);
     172          68 :     col = 0;
     173             :   }
     174         109 :   return *this;
     175             : }
     176             : 
     177           0 : simple_output &simple_output::special(const char *)
     178             : {
     179           0 :   return *this;
     180             : }
     181             : 
     182           0 : simple_output &simple_output::simple_comment(const char *s)
     183             : {
     184           0 :   flush_last_word();
     185           0 :   if (col != 0)
     186           0 :     PUTC('\n', fp);
     187           0 :   FPUTS("<!-- ", fp);
     188           0 :   FPUTS(s, fp);
     189           0 :   FPUTS(" -->\n", fp);
     190           0 :   col = 0;
     191           0 :   return *this;
     192             : }
     193             : 
     194         110 : simple_output &simple_output::begin_comment(const char *s)
     195             : {
     196         110 :   flush_last_word();
     197         110 :   if (col != 0)
     198           0 :     PUTC('\n', fp);
     199         110 :   col = 0;
     200         110 :   put_string("<!--");
     201         110 :   space_or_newline();
     202         110 :   last_word.add_word(s, strlen(s));
     203         110 :   return *this;
     204             : }
     205             : 
     206         110 : simple_output &simple_output::end_comment()
     207             : {
     208         110 :   flush_last_word();
     209         110 :   space_or_newline();
     210         110 :   put_string("-->").nl();
     211         110 :   return *this;
     212             : }
     213             : 
     214             : /*
     215             :  *  check_newline - checks to see whether we are able to issue
     216             :  *                  a newline and that one is needed.
     217             :  */
     218             : 
     219        4024 : simple_output &simple_output::check_newline(int n)
     220             : {
     221        4024 :   if ((col + n + last_word.get_length() + 1 > max_line_length) && (newlines)) {
     222         326 :     FPUTC('\n', fp);
     223         326 :     col = last_word.flush(fp);
     224             :   }
     225        4024 :   return *this;
     226             : }
     227             : 
     228             : /*
     229             :  *  space_or_newline - will emit a newline or a space later on
     230             :  *                     depending upon the current column.
     231             :  */
     232             : 
     233       22560 : simple_output &simple_output::space_or_newline (void)
     234             : {
     235       22560 :   if ((col + last_word.get_length() + 1 > max_line_length) && (newlines)) {
     236        2379 :     FPUTC('\n', fp);
     237        2379 :     if (last_word.get_length() > 0) {
     238        2379 :       col = last_word.flush(fp);
     239             :     } else {
     240           0 :       col = 0;
     241             :     }
     242             :   } else {
     243       20181 :     if (last_word.get_length() != 0) {
     244       18504 :       if (col > 0) {
     245       16477 :         FPUTC(' ', fp);
     246       16477 :         col++;
     247             :       }
     248       18504 :       col += last_word.flush(fp);
     249             :     }
     250             :   }
     251       22560 :   return *this;
     252             : }
     253             : 
     254             : /*
     255             :  *  force_nl - forces a newline.
     256             :  */
     257             : 
     258           0 : simple_output &simple_output::force_nl (void)
     259             : {
     260           0 :   space_or_newline();
     261           0 :   col += last_word.flush(fp);
     262           0 :   FPUTC('\n', fp);
     263           0 :   col = 0;
     264           0 :   return *this ;
     265             : }
     266             : 
     267             : /*
     268             :  *  nl - writes a newline providing that we
     269             :  *       are not in the first column.
     270             :  */
     271             : 
     272        2613 : simple_output &simple_output::nl (void)
     273             : {
     274        2613 :   space_or_newline();
     275        2613 :   col += last_word.flush(fp);
     276        2613 :   FPUTC('\n', fp);
     277        2613 :   col = 0;
     278        2613 :   return *this ;
     279             : }
     280             : 
     281          17 : simple_output &simple_output::set_fixed_point(int n)
     282             : {
     283          17 :   assert(n >= 0 && n <= 10);
     284          17 :   fixed_point = n;
     285          17 :   return *this;
     286             : }
     287             : 
     288           0 : simple_output &simple_output::put_raw_char(char c)
     289             : {
     290           0 :   col += last_word.flush(fp);
     291           0 :   PUTC(c, fp);
     292           0 :   col++;
     293           0 :   return *this;
     294             : }
     295             : 
     296       20617 : simple_output &simple_output::put_string(const char *s, int n)
     297             : {
     298       20617 :   last_word.add_word(s, n);
     299       20617 :   return *this;
     300             : }
     301             : 
     302       14250 : simple_output &simple_output::put_string(const char *s)
     303             : {
     304       14250 :   last_word.add_word(s, strlen(s));
     305       14250 :   return *this;
     306             : }
     307             : 
     308         186 : simple_output &simple_output::put_string(const string &s)
     309             : {
     310         186 :   last_word.add_word(s.contents(), s.length());
     311         186 :   return *this;
     312             : }
     313             : 
     314         422 : simple_output &simple_output::put_number(int n)
     315             : {
     316             :   char buf[1 + INT_DIGITS + 1];
     317         422 :   sprintf(buf, "%d", n);
     318         422 :   put_string(buf);
     319         422 :   return *this;
     320             : }
     321             : 
     322           0 : simple_output &simple_output::put_float(double d)
     323             : {
     324             :   char buf[128];
     325             : 
     326           0 :   sprintf(buf, "%.4f", d);
     327           0 :   put_string(buf);
     328           0 :   return *this;
     329             : }
     330             : 
     331        2012 : simple_output &simple_output::enable_newlines (int auto_newlines)
     332             : {
     333        2012 :   check_newline(0);
     334        2012 :   newlines = auto_newlines;
     335        2012 :   check_newline(0);
     336        2012 :   return *this;
     337             : }
     338             : 
     339             : /*
     340             :  *  flush_last_word - flushes the last word and adjusts the
     341             :  *                    col position. It will insert a newline
     342             :  *                    before the last word if allowed and if
     343             :  *                    necessary.
     344             :  */
     345             : 
     346         329 : void simple_output::flush_last_word (void)
     347             : {
     348         329 :   int len=last_word.get_length();
     349             : 
     350         329 :   if (len > 0) {
     351         167 :     if (newlines) {
     352           0 :       if (col + len + 1 > max_line_length) {
     353           0 :         FPUTS("\n", fp);
     354           0 :         col = 0;
     355             :       } else {
     356           0 :         FPUTS(" ", fp);
     357           0 :         col++;
     358             :       }
     359           0 :       len += last_word.flush(fp);
     360             :     } else {
     361         167 :       FPUTS(" ", fp);
     362         167 :       col++;
     363         167 :       col += last_word.flush(fp);
     364             :     }
     365             :   }
     366         329 : }
     367             : 
     368             : // Local Variables:
     369             : // fill-column: 72
     370             : // mode: C++
     371             : // End:
     372             : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72:

Generated by: LCOV version 1.14