LCOV - code coverage report
Current view: top level - preproc/html - pushback.cpp (source / functions) Hit Total Coverage
Test: GNU roff Lines: 87 120 72.5 %
Date: 2026-01-16 17:51:41 Functions: 9 14 64.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2000-2025 Free Software Foundation, Inc.
       2             :      Written by Gaius Mulley (gaius@glam.ac.uk).
       3             : 
       4             : This file is part of groff, the GNU roff typesetting system.
       5             : 
       6             : groff is free software; you can redistribute it and/or modify it under
       7             : the terms of the GNU General Public License as published by the Free
       8             : Software Foundation, either version 3 of the License, or
       9             : (at your option) any later version.
      10             : 
      11             : groff is distributed in the hope that it will be useful, but WITHOUT ANY
      12             : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13             : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14             : for more details.
      15             : 
      16             : You should have received a copy of the GNU General Public License
      17             : along with this program.  If not, see <http://www.gnu.org/licenses/>. */
      18             : 
      19             : #ifdef HAVE_CONFIG_H
      20             : #include <config.h>
      21             : #endif
      22             : 
      23             : #include <stdio.h> // fflush(), fprintf(), printf(), putchar(), stderr
      24             : #include <stdlib.h> // exit(), free(), malloc()
      25             : #include <string.h> // strcpy(), strlen()
      26             : 
      27             : // needed for close(), dup(), open(), read()
      28             : #include "posix.h"
      29             : #include "nonposix.h"
      30             : 
      31             : #include "lib.h"
      32             : 
      33             : #include "errarg.h"
      34             : #include "error.h"
      35             : #include "stringclass.h"
      36             : 
      37             : #include "pushback.h"
      38             : #include "pre-html.h"
      39             : 
      40             : #if !defined(TRUE)
      41             : #   define TRUE  (1==1)
      42             : #endif
      43             : 
      44             : #if !defined(FALSE)
      45             : #   define FALSE (1==0)
      46             : #endif
      47             : 
      48             : #   define ERROR(X)   (void)(fprintf(stderr, "%s:%d error %s\n", __FILE__, __LINE__, X) && \
      49             :                             (fflush(stderr)) && localexit(1))
      50             : 
      51             : 
      52             : #define MAXPUSHBACKSTACK 4096                  /* maximum number of character that can be pushed back */
      53             : 
      54             : 
      55             : /*
      56             :  *  constructor for pushBackBuffer
      57             :  */
      58             : 
      59          17 : pushBackBuffer::pushBackBuffer (const char *filename)
      60             : {
      61          17 :   charStack = (char *)malloc(MAXPUSHBACKSTACK);
      62          17 :   if (charStack == 0) {
      63           0 :     sys_fatal("malloc");
      64             :   }
      65          17 :   stackPtr = 0;   /* index to push back stack        */
      66          17 :   verbose  = 0;
      67          17 :   eofFound = FALSE;
      68          17 :   lineNo   = 1;
      69          17 :   if (strcmp(filename, "") != 0) {
      70          17 :     stdIn = dup(0);
      71          17 :     if (stdIn < 0) {
      72           0 :       sys_fatal("dup stdin");
      73             :     }
      74          17 :     close(0);
      75          17 :     if (open(filename, O_RDONLY) != 0) {
      76           0 :       sys_fatal("when trying to open file");
      77             :     } else {
      78          17 :       fileName = filename;
      79             :     }
      80             :   }
      81          17 : }
      82             : 
      83          34 : pushBackBuffer::~pushBackBuffer ()
      84             : {
      85          17 :   if (charStack != 0) {
      86          17 :     free(charStack);
      87             :   }
      88          17 :   close(0);
      89             :   /* restore stdin in file descriptor 0 */
      90          17 :   if (dup(stdIn) < 0) {
      91           0 :     sys_fatal("restore stdin");
      92             :   }
      93          17 :   close(stdIn);
      94          17 : }
      95             : 
      96             : /*
      97             :  *  localexit - wraps exit with a return code to aid the ERROR macro.
      98             :  */
      99             : 
     100           0 : int localexit (int i)
     101             : {
     102           0 :   exit(i);
     103             :   return( 1 );
     104             : }
     105             : 
     106             : /*
     107             :  *  getPB - returns a character, possibly a pushed back character.
     108             :  */
     109             : 
     110       16214 : char pushBackBuffer::getPB (void)
     111             : {
     112       16214 :   if (stackPtr>0) {
     113        8290 :     stackPtr--;
     114        8290 :     return( charStack[stackPtr] );
     115             :   } else {
     116             :     char ch;
     117             : 
     118        7924 :     if (read(0, &ch, 1) == 1) {
     119        7907 :       if (verbose) {
     120           0 :         printf("%c", ch);
     121             :       }
     122        7907 :       if (ch == '\n') {
     123          60 :         lineNo++;
     124             :       }
     125        7907 :       return( ch );
     126             :     } else {
     127          17 :       eofFound = TRUE;
     128          17 :       return( eof );
     129             :     }
     130             :   }
     131             : }
     132             : 
     133             : /*
     134             :  *  putPB - pushes a character onto the push back stack.
     135             :  *          The same character is returned.
     136             :  */
     137             : 
     138        8307 : char pushBackBuffer::putPB (char ch)
     139             : {
     140        8307 :   if (stackPtr<MAXPUSHBACKSTACK) {
     141        8307 :     charStack[stackPtr] = ch ;
     142        8307 :     stackPtr++;
     143             :   } else {
     144           0 :     ERROR("max push back stack exceeded, increase MAXPUSHBACKSTACK constant");
     145             :   }
     146        8307 :   return( ch );
     147             : }
     148             : 
     149             : /*
     150             :  *  isWhite - returns TRUE if a white character is found. This character is NOT consumed.
     151             :  */
     152             : 
     153        2082 : static int isWhite (char ch)
     154             : {
     155        2082 :   return( (ch==' ') || (ch == '\t') || (ch == '\n') );
     156             : }
     157             : 
     158             : /*
     159             :  *  skipToNewline - skips characters until a newline is seen.
     160             :  */
     161             : 
     162           0 : void pushBackBuffer::skipToNewline (void)
     163             : {
     164           0 :   while ((putPB(getPB()) != '\n') && (! eofFound)) {
     165           0 :     getPB();
     166             :   }
     167           0 : }
     168             : 
     169             : /*
     170             :  *  skipUntilToken - skips until a token is seen
     171             :  */
     172             : 
     173           0 : void pushBackBuffer::skipUntilToken (void)
     174             : {
     175             :   char ch;
     176             : 
     177           0 :   while ((isWhite(putPB(getPB())) || (putPB(getPB()) == '#')) && (! eofFound)) {
     178           0 :     ch = getPB();
     179           0 :     if (ch == '#') {
     180           0 :       skipToNewline();
     181             :     }
     182             :   }
     183           0 : }
     184             : 
     185             : /*
     186             :  *  isString - returns TRUE if the string, s, matches the pushed back string.
     187             :  *             if TRUE is returned then this string is consumed, otherwise it is
     188             :  *             left alone.
     189             :  */
     190             : 
     191         111 : int pushBackBuffer::isString (const char *s)
     192             : {
     193         111 :   ptrdiff_t length=ptrdiff_t(strlen(s));
     194         111 :   ptrdiff_t i=0;
     195             : 
     196        1117 :   while ((i<length) && (putPB(getPB())==s[i])) {
     197        1006 :     if (getPB() != s[i]) {
     198           0 :       ERROR("assert failed");
     199             :     }
     200        1006 :     i++;
     201             :   }
     202         111 :   if (i==length) {
     203          59 :     return( TRUE );
     204             :   } else {
     205          52 :     i--;
     206          55 :     while (i>=0) {
     207           3 :       if (putPB(s[i]) != s[i]) {
     208           0 :         ERROR("assert failed");
     209             :       }
     210           3 :       i--;
     211             :     }
     212             :   }
     213          52 :   return( FALSE );
     214             : }
     215             : 
     216             : /*
     217             :  *  isDigit - returns TRUE if the character, ch, is a digit.
     218             :  */
     219             : 
     220        2146 : static int isDigit (char ch)
     221             : {
     222        2146 :   return( ((ch>='0') && (ch<='9')) );
     223             : }
     224             : 
     225             : /*
     226             :  *  isHexDigit - returns TRUE if the character, ch, is a hex digit.
     227             :  */
     228             : 
     229             : #if 0
     230             : static int isHexDigit (char ch)
     231             : {
     232             :   return( (isDigit(ch)) || ((ch>='a') && (ch<='f')) );
     233             : }
     234             : #endif
     235             : 
     236             : /*
     237             :  *  readInt - returns an integer from the input stream.
     238             :  */
     239             : 
     240         354 : int pushBackBuffer::readInt (void)
     241             : {
     242         354 :   int  c =0;
     243         354 :   int  i =0;
     244         354 :   int  s =1;
     245         354 :   char ch=getPB();
     246             : 
     247        1003 :   while (isWhite(ch)) {
     248         649 :     ch=getPB();
     249             :   }
     250             :   // now read integer
     251             : 
     252         354 :   if (ch == '-') {
     253           9 :     s = -1;
     254           9 :     ch = getPB();
     255             :   }
     256        2146 :   while (isDigit(ch)) {
     257        1792 :     i *= 10;
     258        1792 :     if ((ch>='0') && (ch<='9')) {
     259        1792 :       i += (int)(ch-'0');
     260             :     }
     261        1792 :     ch = getPB();
     262        1792 :     c++;
     263             :   }
     264         354 :   if (ch != putPB(ch)) {
     265           0 :     ERROR("assert failed");
     266             :   }
     267         354 :   return( i*s );
     268             : }
     269             : 
     270             : /*
     271             :  *  convertToFloat - converts integers, a and b into a.b
     272             :  */
     273             : 
     274           0 : static double convertToFloat (int a, int b)
     275             : {
     276           0 :   int c=10;
     277             :   double f;
     278             : 
     279           0 :   while (b>c) {
     280           0 :     c *= 10;
     281             :   }
     282           0 :   f = ((double)a) + (((double)b)/((double)c));
     283           0 :   return( f );
     284             : }
     285             : 
     286             : /*
     287             :  *  readNumber - returns a float representing the word just read.
     288             :  */
     289             : 
     290           0 : double pushBackBuffer::readNumber (void)
     291             : {
     292             :   int i;
     293             :   char ch;
     294             : 
     295           0 :   i = readInt();
     296           0 :   if ((ch = getPB()) == '.') {
     297           0 :     return convertToFloat(i, readInt());
     298             :   }
     299           0 :   putPB(ch);
     300           0 :   return (double)i;
     301             : }
     302             : 
     303             : /*
     304             :  *  readString - reads a string terminated by whitespace
     305             :  *               and returns a malloced area of memory containing
     306             :  *               a copy of the characters.
     307             :  */
     308             : 
     309          59 : char *pushBackBuffer::readString (void)
     310             : {
     311             :   char  buffer[MAXPUSHBACKSTACK];
     312          59 :   char *str = 0;
     313          59 :   int   i=0;
     314          59 :   char ch=getPB();
     315             : 
     316         177 :   while (isWhite(ch)) {
     317         118 :     ch=getPB();
     318             :   }
     319         902 :   while ((i < MAXPUSHBACKSTACK) && (! isWhite(ch)) && (! eofFound)) {
     320         843 :     buffer[i] = ch;
     321         843 :     i++;
     322         843 :     ch = getPB();
     323             :   }
     324          59 :   if (i < MAXPUSHBACKSTACK) {
     325          59 :     buffer[i] = (char)0;
     326          59 :     str = (char *)malloc(strlen(buffer)+1);
     327          59 :     strcpy(str, buffer);
     328             :   }
     329          59 :   return( str );
     330             : }
     331             : 
     332             : // Local Variables:
     333             : // fill-column: 72
     334             : // mode: C++
     335             : // End:
     336             : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72:

Generated by: LCOV version 1.14