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:
|