1114402Sru// -*- C++ -*- 2151497Sru/* Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. 3114402Sru Written by Gaius Mulley (gaius@glam.ac.uk). 4114402Sru 5114402SruThis file is part of groff. 6114402Sru 7114402Srugroff is free software; you can redistribute it and/or modify it under 8114402Sruthe terms of the GNU General Public License as published by the Free 9114402SruSoftware Foundation; either version 2, or (at your option) any later 10114402Sruversion. 11114402Sru 12114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY 13114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or 14114402SruFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15114402Srufor more details. 16114402Sru 17114402SruYou should have received a copy of the GNU General Public License along 18114402Sruwith groff; see the file COPYING. If not, write to the Free Software 19151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 20114402Sru 21114402Sru#include "lib.h" 22114402Sru 23114402Sru#include <signal.h> 24114402Sru#include <ctype.h> 25114402Sru#include <assert.h> 26114402Sru#include <stdlib.h> 27114402Sru#include <errno.h> 28114402Sru#include "errarg.h" 29114402Sru#include "error.h" 30114402Sru#include "stringclass.h" 31114402Sru#include "posix.h" 32114402Sru#include "nonposix.h" 33114402Sru 34114402Sru#include <errno.h> 35114402Sru#include <sys/types.h> 36114402Sru#ifdef HAVE_UNISTD_H 37114402Sru#include <unistd.h> 38114402Sru#endif 39114402Sru 40114402Sru#include "pushback.h" 41114402Sru#include "pre-html.h" 42114402Sru 43114402Sru#if !defined(TRUE) 44114402Sru# define TRUE (1==1) 45114402Sru#endif 46114402Sru 47114402Sru#if !defined(FALSE) 48114402Sru# define FALSE (1==0) 49114402Sru#endif 50114402Sru 51114402Sru# define ERROR(X) (void)(fprintf(stderr, "%s:%d error %s\n", __FILE__, __LINE__, X) && \ 52114402Sru (fflush(stderr)) && localexit(1)) 53114402Sru 54114402Sru 55114402Sru#define MAXPUSHBACKSTACK 4096 /* maximum number of character that can be pushed back */ 56114402Sru 57114402Sru 58114402Sru/* 59114402Sru * constructor for pushBackBuffer 60114402Sru */ 61114402Sru 62114402SrupushBackBuffer::pushBackBuffer (char *filename) 63114402Sru{ 64114402Sru charStack = (char *)malloc(MAXPUSHBACKSTACK); 65114402Sru if (charStack == 0) { 66114402Sru sys_fatal("malloc"); 67114402Sru } 68114402Sru stackPtr = 0; /* index to push back stack */ 69114402Sru debug = 0; 70114402Sru verbose = 0; 71114402Sru eofFound = FALSE; 72114402Sru lineNo = 1; 73114402Sru if (strcmp(filename, "") != 0) { 74114402Sru stdIn = dup(0); 75114402Sru close(0); 76114402Sru if (open(filename, O_RDONLY) != 0) { 77114402Sru sys_fatal("when trying to open file"); 78114402Sru } else { 79114402Sru fileName = filename; 80114402Sru } 81114402Sru } 82114402Sru} 83114402Sru 84114402SrupushBackBuffer::~pushBackBuffer () 85114402Sru{ 86114402Sru if (charStack != 0) { 87114402Sru free(charStack); 88114402Sru } 89114402Sru close(0); 90114402Sru /* restore stdin in file descriptor 0 */ 91151497Sru dup(stdIn); 92114402Sru close(stdIn); 93114402Sru} 94114402Sru 95114402Sru/* 96114402Sru * localexit - wraps exit with a return code to aid the ERROR macro. 97114402Sru */ 98114402Sru 99114402Sruint localexit (int i) 100114402Sru{ 101114402Sru exit(i); 102114402Sru return( 1 ); 103114402Sru} 104114402Sru 105114402Sru/* 106114402Sru * getPB - returns a character, possibly a pushed back character. 107114402Sru */ 108114402Sru 109114402Sruchar pushBackBuffer::getPB (void) 110114402Sru{ 111114402Sru if (stackPtr>0) { 112114402Sru stackPtr--; 113114402Sru return( charStack[stackPtr] ); 114114402Sru } else { 115114402Sru char ch; 116114402Sru 117114402Sru if (read(0, &ch, 1) == 1) { 118114402Sru if (verbose) { 119114402Sru printf("%c", ch); 120114402Sru } 121114402Sru if (ch == '\n') { 122114402Sru lineNo++; 123114402Sru } 124114402Sru return( ch ); 125114402Sru } else { 126114402Sru eofFound = TRUE; 127114402Sru return( eof ); 128114402Sru } 129114402Sru } 130114402Sru} 131114402Sru 132114402Sru/* 133114402Sru * putPB - pushes a character onto the push back stack. 134114402Sru * The same character is returned. 135114402Sru */ 136114402Sru 137114402Sruchar pushBackBuffer::putPB (char ch) 138114402Sru{ 139114402Sru if (stackPtr<MAXPUSHBACKSTACK) { 140114402Sru charStack[stackPtr] = ch ; 141114402Sru stackPtr++; 142114402Sru } else { 143114402Sru ERROR("max push back stack exceeded, increase MAXPUSHBACKSTACK constant"); 144114402Sru } 145114402Sru return( ch ); 146114402Sru} 147114402Sru 148114402Sru/* 149114402Sru * isWhite - returns TRUE if a white character is found. This character is NOT consumed. 150114402Sru */ 151114402Sru 152114402Srustatic int isWhite (char ch) 153114402Sru{ 154114402Sru return( (ch==' ') || (ch == '\t') || (ch == '\n') ); 155114402Sru} 156114402Sru 157114402Sru/* 158114402Sru * skipToNewline - skips characters until a newline is seen. 159114402Sru */ 160114402Sru 161114402Sruvoid pushBackBuffer::skipToNewline (void) 162114402Sru{ 163114402Sru while ((putPB(getPB()) != '\n') && (! eofFound)) { 164151497Sru getPB(); 165114402Sru } 166114402Sru} 167114402Sru 168114402Sru/* 169114402Sru * skipUntilToken - skips until a token is seen 170114402Sru */ 171114402Sru 172114402Sruvoid pushBackBuffer::skipUntilToken (void) 173114402Sru{ 174114402Sru char ch; 175114402Sru 176114402Sru while ((isWhite(putPB(getPB())) || (putPB(getPB()) == '#')) && (! eofFound)) { 177114402Sru ch = getPB(); 178114402Sru if (ch == '#') { 179114402Sru skipToNewline(); 180114402Sru } 181114402Sru } 182114402Sru} 183114402Sru 184114402Sru/* 185114402Sru * isString - returns TRUE if the string, s, matches the pushed back string. 186114402Sru * if TRUE is returned then this string is consumed, otherwise it is 187114402Sru * left alone. 188114402Sru */ 189114402Sru 190114402Sruint pushBackBuffer::isString (const char *s) 191114402Sru{ 192114402Sru int length=strlen(s); 193114402Sru int i=0; 194114402Sru 195114402Sru while ((i<length) && (putPB(getPB())==s[i])) { 196114402Sru if (getPB() != s[i]) { 197114402Sru ERROR("assert failed"); 198114402Sru } 199114402Sru i++; 200114402Sru } 201114402Sru if (i==length) { 202114402Sru return( TRUE ); 203114402Sru } else { 204114402Sru i--; 205114402Sru while (i>=0) { 206114402Sru if (putPB(s[i]) != s[i]) { 207114402Sru ERROR("assert failed"); 208114402Sru } 209114402Sru i--; 210114402Sru } 211114402Sru } 212114402Sru return( FALSE ); 213114402Sru} 214114402Sru 215114402Sru/* 216114402Sru * isDigit - returns TRUE if the character, ch, is a digit. 217114402Sru */ 218114402Sru 219114402Srustatic int isDigit (char ch) 220114402Sru{ 221114402Sru return( ((ch>='0') && (ch<='9')) ); 222114402Sru} 223114402Sru 224114402Sru/* 225114402Sru * isHexDigit - returns TRUE if the character, ch, is a hex digit. 226114402Sru */ 227114402Sru 228114402Sru#if 0 229114402Srustatic int isHexDigit (char ch) 230114402Sru{ 231114402Sru return( (isDigit(ch)) || ((ch>='a') && (ch<='f')) ); 232114402Sru} 233114402Sru#endif 234114402Sru 235114402Sru/* 236114402Sru * readInt - returns an integer from the input stream. 237114402Sru */ 238114402Sru 239114402Sruint pushBackBuffer::readInt (void) 240114402Sru{ 241114402Sru int c =0; 242114402Sru int i =0; 243114402Sru int s =1; 244114402Sru char ch=getPB(); 245114402Sru 246114402Sru while (isWhite(ch)) { 247114402Sru ch=getPB(); 248114402Sru } 249114402Sru // now read integer 250114402Sru 251114402Sru if (ch == '-') { 252114402Sru s = -1; 253114402Sru ch = getPB(); 254114402Sru } 255114402Sru while (isDigit(ch)) { 256114402Sru i *= 10; 257114402Sru if ((ch>='0') && (ch<='9')) { 258114402Sru i += (int)(ch-'0'); 259114402Sru } 260114402Sru ch = getPB(); 261114402Sru c++; 262114402Sru } 263114402Sru if (ch != putPB(ch)) { 264114402Sru ERROR("assert failed"); 265114402Sru } 266114402Sru return( i*s ); 267114402Sru} 268114402Sru 269114402Sru/* 270114402Sru * convertToFloat - converts integers, a and b into a.b 271114402Sru */ 272114402Sru 273151497Srustatic double convertToFloat (int a, int b) 274114402Sru{ 275114402Sru int c=10; 276151497Sru double f; 277114402Sru 278114402Sru while (b>c) { 279114402Sru c *= 10; 280114402Sru } 281151497Sru f = ((double)a) + (((double)b)/((double)c)); 282114402Sru return( f ); 283114402Sru} 284114402Sru 285114402Sru/* 286114402Sru * readNumber - returns a float representing the word just read. 287114402Sru */ 288114402Sru 289151497Srudouble pushBackBuffer::readNumber (void) 290114402Sru{ 291114402Sru int i; 292114402Sru char ch; 293114402Sru 294114402Sru i = readInt(); 295114402Sru if ((ch = getPB()) == '.') { 296114402Sru return convertToFloat(i, readInt()); 297114402Sru } 298114402Sru putPB(ch); 299151497Sru return (double)i; 300114402Sru} 301114402Sru 302114402Sru/* 303114402Sru * readString - reads a string terminated by white space 304114402Sru * and returns a malloced area of memory containing 305114402Sru * a copy of the characters. 306114402Sru */ 307114402Sru 308114402Sruchar *pushBackBuffer::readString (void) 309114402Sru{ 310114402Sru char buffer[MAXPUSHBACKSTACK]; 311151497Sru char *str = 0; 312114402Sru int i=0; 313114402Sru char ch=getPB(); 314114402Sru 315114402Sru while (isWhite(ch)) { 316114402Sru ch=getPB(); 317114402Sru } 318114402Sru while ((i < MAXPUSHBACKSTACK) && (! isWhite(ch)) && (! eofFound)) { 319114402Sru buffer[i] = ch; 320114402Sru i++; 321114402Sru ch = getPB(); 322114402Sru } 323114402Sru if (i < MAXPUSHBACKSTACK) { 324114402Sru buffer[i] = (char)0; 325151497Sru str = (char *)malloc(strlen(buffer)+1); 326151497Sru strcpy(str, buffer); 327114402Sru } 328151497Sru return( str ); 329114402Sru} 330