1230557Sjimharris// -*- C++ -*- 2230557Sjimharris/* Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. 3230557Sjimharris Written by Gaius Mulley (gaius@glam.ac.uk). 4230557Sjimharris 5230557SjimharrisThis file is part of groff. 6230557Sjimharris 7230557Sjimharrisgroff is free software; you can redistribute it and/or modify it under 8230557Sjimharristhe terms of the GNU General Public License as published by the Free 9230557SjimharrisSoftware Foundation; either version 2, or (at your option) any later 10230557Sjimharrisversion. 11230557Sjimharris 12230557Sjimharrisgroff is distributed in the hope that it will be useful, but WITHOUT ANY 13230557SjimharrisWARRANTY; without even the implied warranty of MERCHANTABILITY or 14230557SjimharrisFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15230557Sjimharrisfor more details. 16230557Sjimharris 17230557SjimharrisYou should have received a copy of the GNU General Public License along 18230557Sjimharriswith groff; see the file COPYING. If not, write to the Free Software 19230557SjimharrisFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 20230557Sjimharris 21230557Sjimharris#include "lib.h" 22230557Sjimharris 23230557Sjimharris#include <signal.h> 24230557Sjimharris#include <ctype.h> 25230557Sjimharris#include <assert.h> 26230557Sjimharris#include <stdlib.h> 27230557Sjimharris#include <errno.h> 28230557Sjimharris#include "errarg.h" 29230557Sjimharris#include "error.h" 30230557Sjimharris#include "stringclass.h" 31230557Sjimharris#include "posix.h" 32230557Sjimharris#include "nonposix.h" 33230557Sjimharris 34230557Sjimharris#include <errno.h> 35230557Sjimharris#include <sys/types.h> 36230557Sjimharris#ifdef HAVE_UNISTD_H 37230557Sjimharris#include <unistd.h> 38230557Sjimharris#endif 39230557Sjimharris 40230557Sjimharris#include "pushback.h" 41230557Sjimharris#include "pre-html.h" 42230557Sjimharris 43230557Sjimharris#if !defined(TRUE) 44230557Sjimharris# define TRUE (1==1) 45230557Sjimharris#endif 46230557Sjimharris 47230557Sjimharris#if !defined(FALSE) 48230557Sjimharris# define FALSE (1==0) 49230557Sjimharris#endif 50230557Sjimharris 51230557Sjimharris# define ERROR(X) (void)(fprintf(stderr, "%s:%d error %s\n", __FILE__, __LINE__, X) && \ 52230557Sjimharris (fflush(stderr)) && localexit(1)) 53230557Sjimharris 54230557Sjimharris 55230557Sjimharris#define MAXPUSHBACKSTACK 4096 /* maximum number of character that can be pushed back */ 56230557Sjimharris 57230557Sjimharris 58230557Sjimharris/* 59230557Sjimharris * constructor for pushBackBuffer 60230557Sjimharris */ 61230557Sjimharris 62230557SjimharrispushBackBuffer::pushBackBuffer (char *filename) 63230557Sjimharris{ 64230557Sjimharris charStack = (char *)malloc(MAXPUSHBACKSTACK); 65230557Sjimharris if (charStack == 0) { 66230557Sjimharris sys_fatal("malloc"); 67230557Sjimharris } 68230557Sjimharris stackPtr = 0; /* index to push back stack */ 69230557Sjimharris debug = 0; 70230557Sjimharris verbose = 0; 71230557Sjimharris eofFound = FALSE; 72230557Sjimharris lineNo = 1; 73230557Sjimharris if (strcmp(filename, "") != 0) { 74230557Sjimharris stdIn = dup(0); 75230557Sjimharris close(0); 76230557Sjimharris if (open(filename, O_RDONLY) != 0) { 77230557Sjimharris sys_fatal("when trying to open file"); 78230557Sjimharris } else { 79230557Sjimharris fileName = filename; 80230557Sjimharris } 81230557Sjimharris } 82230557Sjimharris} 83230557Sjimharris 84230557SjimharrispushBackBuffer::~pushBackBuffer () 85230557Sjimharris{ 86230557Sjimharris if (charStack != 0) { 87230557Sjimharris free(charStack); 88230557Sjimharris } 89230557Sjimharris close(0); 90230557Sjimharris /* restore stdin in file descriptor 0 */ 91230557Sjimharris dup(stdIn); 92230557Sjimharris close(stdIn); 93230557Sjimharris} 94230557Sjimharris 95230557Sjimharris/* 96230557Sjimharris * localexit - wraps exit with a return code to aid the ERROR macro. 97230557Sjimharris */ 98230557Sjimharris 99230557Sjimharrisint localexit (int i) 100230557Sjimharris{ 101230557Sjimharris exit(i); 102230557Sjimharris return( 1 ); 103230557Sjimharris} 104230557Sjimharris 105230557Sjimharris/* 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