Imported Upstream version 1.22.4
[platform/upstream/groff.git] / src / preproc / html / pushback.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 2000-2018 Free Software Foundation, Inc.
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
9 Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
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
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/>. */
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     if (stdIn < 0) {
75       sys_fatal("dup stdin");
76     }
77     close(0);
78     if (open(filename, O_RDONLY) != 0) {
79       sys_fatal("when trying to open file");
80     } else {
81       fileName = filename;
82     }
83   }
84 }
85
86 pushBackBuffer::~pushBackBuffer ()
87 {
88   if (charStack != 0) {
89     free(charStack);
90   }
91   close(0);
92   /* restore stdin in file descriptor 0 */
93   if (dup(stdIn) < 0) {
94     sys_fatal("restore stdin");
95   }
96   close(stdIn);
97 }
98
99 /*
100  *  localexit - wraps exit with a return code to aid the ERROR macro.
101  */
102
103 int localexit (int i)
104 {
105   exit(i);
106   return( 1 );
107 }
108
109 /*
110  *  getPB - returns a character, possibly a pushed back character.
111  */
112
113 char pushBackBuffer::getPB (void)
114 {
115   if (stackPtr>0) {
116     stackPtr--;
117     return( charStack[stackPtr] );
118   } else {
119     char ch;
120
121     if (read(0, &ch, 1) == 1) {
122       if (verbose) {
123         printf("%c", ch);
124       }
125       if (ch == '\n') {
126         lineNo++;
127       }
128       return( ch );
129     } else {
130       eofFound = TRUE;
131       return( eof );
132     }
133   }
134 }
135
136 /*
137  *  putPB - pushes a character onto the push back stack.
138  *          The same character is returned.
139  */
140
141 char pushBackBuffer::putPB (char ch)
142 {
143   if (stackPtr<MAXPUSHBACKSTACK) {
144     charStack[stackPtr] = ch ;
145     stackPtr++;
146   } else {
147     ERROR("max push back stack exceeded, increase MAXPUSHBACKSTACK constant");
148   }
149   return( ch );
150 }
151
152 /*
153  *  isWhite - returns TRUE if a white character is found. This character is NOT consumed.
154  */
155
156 static int isWhite (char ch)
157 {
158   return( (ch==' ') || (ch == '\t') || (ch == '\n') );
159 }
160
161 /*
162  *  skipToNewline - skips characters until a newline is seen.
163  */
164
165 void pushBackBuffer::skipToNewline (void)
166 {
167   while ((putPB(getPB()) != '\n') && (! eofFound)) {
168     getPB();
169   }
170 }
171
172 /*
173  *  skipUntilToken - skips until a token is seen
174  */
175
176 void pushBackBuffer::skipUntilToken (void)
177 {
178   char ch;
179
180   while ((isWhite(putPB(getPB())) || (putPB(getPB()) == '#')) && (! eofFound)) {
181     ch = getPB();
182     if (ch == '#') {
183       skipToNewline();
184     }
185   }
186 }
187
188 /*
189  *  isString - returns TRUE if the string, s, matches the pushed back string.
190  *             if TRUE is returned then this string is consumed, otherwise it is
191  *             left alone.
192  */
193
194 int pushBackBuffer::isString (const char *s)
195 {
196   int length=strlen(s);
197   int i=0;
198
199   while ((i<length) && (putPB(getPB())==s[i])) {
200     if (getPB() != s[i]) {
201       ERROR("assert failed");
202     }
203     i++;
204   }
205   if (i==length) {
206     return( TRUE );
207   } else {
208     i--;
209     while (i>=0) {
210       if (putPB(s[i]) != s[i]) {
211         ERROR("assert failed");
212       }
213       i--;
214     }
215   }
216   return( FALSE );
217 }
218
219 /*
220  *  isDigit - returns TRUE if the character, ch, is a digit.
221  */
222
223 static int isDigit (char ch)
224 {
225   return( ((ch>='0') && (ch<='9')) );
226 }
227
228 /*
229  *  isHexDigit - returns TRUE if the character, ch, is a hex digit.
230  */
231
232 #if 0
233 static int isHexDigit (char ch)
234 {
235   return( (isDigit(ch)) || ((ch>='a') && (ch<='f')) );
236 }
237 #endif
238
239 /*
240  *  readInt - returns an integer from the input stream.
241  */
242
243 int pushBackBuffer::readInt (void)
244 {
245   int  c =0;
246   int  i =0;
247   int  s =1;
248   char ch=getPB();
249
250   while (isWhite(ch)) {
251     ch=getPB();
252   }
253   // now read integer
254
255   if (ch == '-') {
256     s = -1;
257     ch = getPB();
258   }
259   while (isDigit(ch)) {
260     i *= 10;
261     if ((ch>='0') && (ch<='9')) {
262       i += (int)(ch-'0');
263     }
264     ch = getPB();
265     c++;
266   }
267   if (ch != putPB(ch)) {
268     ERROR("assert failed");
269   }
270   return( i*s );
271 }
272
273 /*
274  *  convertToFloat - converts integers, a and b into a.b
275  */
276
277 static double convertToFloat (int a, int b)
278 {
279   int c=10;
280   double f;
281
282   while (b>c) {
283     c *= 10;
284   }
285   f = ((double)a) + (((double)b)/((double)c));
286   return( f );
287 }
288
289 /*
290  *  readNumber - returns a float representing the word just read.
291  */
292
293 double pushBackBuffer::readNumber (void)
294 {
295   int i;
296   char ch;
297
298   i = readInt();
299   if ((ch = getPB()) == '.') {
300     return convertToFloat(i, readInt());
301   }
302   putPB(ch);
303   return (double)i;
304 }
305
306 /*
307  *  readString - reads a string terminated by white space
308  *               and returns a malloced area of memory containing
309  *               a copy of the characters.
310  */
311
312 char *pushBackBuffer::readString (void)
313 {
314   char  buffer[MAXPUSHBACKSTACK];
315   char *str = 0;
316   int   i=0;
317   char ch=getPB();
318
319   while (isWhite(ch)) {
320     ch=getPB();
321   }
322   while ((i < MAXPUSHBACKSTACK) && (! isWhite(ch)) && (! eofFound)) {
323     buffer[i] = ch;
324     i++;
325     ch = getPB();
326   }
327   if (i < MAXPUSHBACKSTACK) {
328     buffer[i] = (char)0;
329     str = (char *)malloc(strlen(buffer)+1);
330     strcpy(str, buffer);
331   }
332   return( str );
333 }