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