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