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