groff: update vendor branch to v1.20.1
[dragonfly.git] / contrib / groff / src / preproc / html / pushback.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 2000, 2001, 2003, 2004, 2005, 2009 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     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 {
85   if (charStack != 0) {
86     free(charStack);
87   }
88   close(0);
89   /* restore stdin in file descriptor 0 */
90   dup(stdIn);
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 {
162   while ((putPB(getPB()) != '\n') && (! eofFound)) {
163     getPB();
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 }