1114402Sru// -*- C++ -*-
2151497Sru/* Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
3114402Sru     Written by Gaius Mulley (gaius@glam.ac.uk).
4114402Sru
5114402SruThis file is part of groff.
6114402Sru
7114402Srugroff is free software; you can redistribute it and/or modify it under
8114402Sruthe terms of the GNU General Public License as published by the Free
9114402SruSoftware Foundation; either version 2, or (at your option) any later
10114402Sruversion.
11114402Sru
12114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY
13114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or
14114402SruFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15114402Srufor more details.
16114402Sru
17114402SruYou should have received a copy of the GNU General Public License along
18114402Sruwith groff; see the file COPYING.  If not, write to the Free Software
19151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
20114402Sru
21114402Sru#include "lib.h"
22114402Sru
23114402Sru#include <signal.h>
24114402Sru#include <ctype.h>
25114402Sru#include <assert.h>
26114402Sru#include <stdlib.h>
27114402Sru#include <errno.h>
28114402Sru#include "errarg.h"
29114402Sru#include "error.h"
30114402Sru#include "stringclass.h"
31114402Sru#include "posix.h"
32114402Sru#include "nonposix.h"
33114402Sru
34114402Sru#include <errno.h>
35114402Sru#include <sys/types.h>
36114402Sru#ifdef HAVE_UNISTD_H
37114402Sru#include <unistd.h>
38114402Sru#endif
39114402Sru
40114402Sru#include "pushback.h"
41114402Sru#include "pre-html.h"
42114402Sru
43114402Sru#if !defined(TRUE)
44114402Sru#   define TRUE  (1==1)
45114402Sru#endif
46114402Sru
47114402Sru#if !defined(FALSE)
48114402Sru#   define FALSE (1==0)
49114402Sru#endif
50114402Sru
51114402Sru#   define ERROR(X)   (void)(fprintf(stderr, "%s:%d error %s\n", __FILE__, __LINE__, X) && \
52114402Sru                            (fflush(stderr)) && localexit(1))
53114402Sru
54114402Sru
55114402Sru#define MAXPUSHBACKSTACK 4096                  /* maximum number of character that can be pushed back */
56114402Sru
57114402Sru
58114402Sru/*
59114402Sru *  constructor for pushBackBuffer
60114402Sru */
61114402Sru
62114402SrupushBackBuffer::pushBackBuffer (char *filename)
63114402Sru{
64114402Sru  charStack = (char *)malloc(MAXPUSHBACKSTACK);
65114402Sru  if (charStack == 0) {
66114402Sru    sys_fatal("malloc");
67114402Sru  }
68114402Sru  stackPtr = 0;   /* index to push back stack        */
69114402Sru  debug    = 0;
70114402Sru  verbose  = 0;
71114402Sru  eofFound = FALSE;
72114402Sru  lineNo   = 1;
73114402Sru  if (strcmp(filename, "") != 0) {
74114402Sru    stdIn = dup(0);
75114402Sru    close(0);
76114402Sru    if (open(filename, O_RDONLY) != 0) {
77114402Sru      sys_fatal("when trying to open file");
78114402Sru    } else {
79114402Sru      fileName = filename;
80114402Sru    }
81114402Sru  }
82114402Sru}
83114402Sru
84114402SrupushBackBuffer::~pushBackBuffer ()
85114402Sru{
86114402Sru  if (charStack != 0) {
87114402Sru    free(charStack);
88114402Sru  }
89114402Sru  close(0);
90114402Sru  /* restore stdin in file descriptor 0 */
91151497Sru  dup(stdIn);
92114402Sru  close(stdIn);
93114402Sru}
94114402Sru
95114402Sru/*
96114402Sru *  localexit - wraps exit with a return code to aid the ERROR macro.
97114402Sru */
98114402Sru
99114402Sruint localexit (int i)
100114402Sru{
101114402Sru  exit(i);
102114402Sru  return( 1 );
103114402Sru}
104114402Sru
105114402Sru/*
106114402Sru *  getPB - returns a character, possibly a pushed back character.
107114402Sru */
108114402Sru
109114402Sruchar pushBackBuffer::getPB (void)
110114402Sru{
111114402Sru  if (stackPtr>0) {
112114402Sru    stackPtr--;
113114402Sru    return( charStack[stackPtr] );
114114402Sru  } else {
115114402Sru    char ch;
116114402Sru
117114402Sru    if (read(0, &ch, 1) == 1) {
118114402Sru      if (verbose) {
119114402Sru	printf("%c", ch);
120114402Sru      }
121114402Sru      if (ch == '\n') {
122114402Sru	lineNo++;
123114402Sru      }
124114402Sru      return( ch );
125114402Sru    } else {
126114402Sru      eofFound = TRUE;
127114402Sru      return( eof );
128114402Sru    }
129114402Sru  }
130114402Sru}
131114402Sru
132114402Sru/*
133114402Sru *  putPB - pushes a character onto the push back stack.
134114402Sru *          The same character is returned.
135114402Sru */
136114402Sru
137114402Sruchar pushBackBuffer::putPB (char ch)
138114402Sru{
139114402Sru  if (stackPtr<MAXPUSHBACKSTACK) {
140114402Sru    charStack[stackPtr] = ch ;
141114402Sru    stackPtr++;
142114402Sru  } else {
143114402Sru    ERROR("max push back stack exceeded, increase MAXPUSHBACKSTACK constant");
144114402Sru  }
145114402Sru  return( ch );
146114402Sru}
147114402Sru
148114402Sru/*
149114402Sru *  isWhite - returns TRUE if a white character is found. This character is NOT consumed.
150114402Sru */
151114402Sru
152114402Srustatic int isWhite (char ch)
153114402Sru{
154114402Sru  return( (ch==' ') || (ch == '\t') || (ch == '\n') );
155114402Sru}
156114402Sru
157114402Sru/*
158114402Sru *  skipToNewline - skips characters until a newline is seen.
159114402Sru */
160114402Sru
161114402Sruvoid pushBackBuffer::skipToNewline (void)
162114402Sru{
163114402Sru  while ((putPB(getPB()) != '\n') && (! eofFound)) {
164151497Sru    getPB();
165114402Sru  }
166114402Sru}
167114402Sru
168114402Sru/*
169114402Sru *  skipUntilToken - skips until a token is seen
170114402Sru */
171114402Sru
172114402Sruvoid pushBackBuffer::skipUntilToken (void)
173114402Sru{
174114402Sru  char ch;
175114402Sru
176114402Sru  while ((isWhite(putPB(getPB())) || (putPB(getPB()) == '#')) && (! eofFound)) {
177114402Sru    ch = getPB();
178114402Sru    if (ch == '#') {
179114402Sru      skipToNewline();
180114402Sru    }
181114402Sru  }
182114402Sru}
183114402Sru
184114402Sru/*
185114402Sru *  isString - returns TRUE if the string, s, matches the pushed back string.
186114402Sru *             if TRUE is returned then this string is consumed, otherwise it is
187114402Sru *             left alone.
188114402Sru */
189114402Sru
190114402Sruint pushBackBuffer::isString (const char *s)
191114402Sru{
192114402Sru  int length=strlen(s);
193114402Sru  int i=0;
194114402Sru
195114402Sru  while ((i<length) && (putPB(getPB())==s[i])) {
196114402Sru    if (getPB() != s[i]) {
197114402Sru      ERROR("assert failed");
198114402Sru    }
199114402Sru    i++;
200114402Sru  }
201114402Sru  if (i==length) {
202114402Sru    return( TRUE );
203114402Sru  } else {
204114402Sru    i--;
205114402Sru    while (i>=0) {
206114402Sru      if (putPB(s[i]) != s[i]) {
207114402Sru	ERROR("assert failed");
208114402Sru      }
209114402Sru      i--;
210114402Sru    }
211114402Sru  }
212114402Sru  return( FALSE );
213114402Sru}
214114402Sru
215114402Sru/*
216114402Sru *  isDigit - returns TRUE if the character, ch, is a digit.
217114402Sru */
218114402Sru
219114402Srustatic int isDigit (char ch)
220114402Sru{
221114402Sru  return( ((ch>='0') && (ch<='9')) );
222114402Sru}
223114402Sru
224114402Sru/*
225114402Sru *  isHexDigit - returns TRUE if the character, ch, is a hex digit.
226114402Sru */
227114402Sru
228114402Sru#if 0
229114402Srustatic int isHexDigit (char ch)
230114402Sru{
231114402Sru  return( (isDigit(ch)) || ((ch>='a') && (ch<='f')) );
232114402Sru}
233114402Sru#endif
234114402Sru
235114402Sru/*
236114402Sru *  readInt - returns an integer from the input stream.
237114402Sru */
238114402Sru
239114402Sruint pushBackBuffer::readInt (void)
240114402Sru{
241114402Sru  int  c =0;
242114402Sru  int  i =0;
243114402Sru  int  s =1;
244114402Sru  char ch=getPB();
245114402Sru
246114402Sru  while (isWhite(ch)) {
247114402Sru    ch=getPB();
248114402Sru  }
249114402Sru  // now read integer
250114402Sru
251114402Sru  if (ch == '-') {
252114402Sru    s = -1;
253114402Sru    ch = getPB();
254114402Sru  }
255114402Sru  while (isDigit(ch)) {
256114402Sru    i *= 10;
257114402Sru    if ((ch>='0') && (ch<='9')) {
258114402Sru      i += (int)(ch-'0');
259114402Sru    }
260114402Sru    ch = getPB();
261114402Sru    c++;
262114402Sru  }
263114402Sru  if (ch != putPB(ch)) {
264114402Sru    ERROR("assert failed");
265114402Sru  }
266114402Sru  return( i*s );
267114402Sru}
268114402Sru
269114402Sru/*
270114402Sru *  convertToFloat - converts integers, a and b into a.b
271114402Sru */
272114402Sru
273151497Srustatic double convertToFloat (int a, int b)
274114402Sru{
275114402Sru  int c=10;
276151497Sru  double f;
277114402Sru
278114402Sru  while (b>c) {
279114402Sru    c *= 10;
280114402Sru  }
281151497Sru  f = ((double)a) + (((double)b)/((double)c));
282114402Sru  return( f );
283114402Sru}
284114402Sru
285114402Sru/*
286114402Sru *  readNumber - returns a float representing the word just read.
287114402Sru */
288114402Sru
289151497Srudouble pushBackBuffer::readNumber (void)
290114402Sru{
291114402Sru  int i;
292114402Sru  char ch;
293114402Sru
294114402Sru  i = readInt();
295114402Sru  if ((ch = getPB()) == '.') {
296114402Sru    return convertToFloat(i, readInt());
297114402Sru  }
298114402Sru  putPB(ch);
299151497Sru  return (double)i;
300114402Sru}
301114402Sru
302114402Sru/*
303114402Sru *  readString - reads a string terminated by white space
304114402Sru *               and returns a malloced area of memory containing
305114402Sru *               a copy of the characters.
306114402Sru */
307114402Sru
308114402Sruchar *pushBackBuffer::readString (void)
309114402Sru{
310114402Sru  char  buffer[MAXPUSHBACKSTACK];
311151497Sru  char *str = 0;
312114402Sru  int   i=0;
313114402Sru  char ch=getPB();
314114402Sru
315114402Sru  while (isWhite(ch)) {
316114402Sru    ch=getPB();
317114402Sru  }
318114402Sru  while ((i < MAXPUSHBACKSTACK) && (! isWhite(ch)) && (! eofFound)) {
319114402Sru    buffer[i] = ch;
320114402Sru    i++;
321114402Sru    ch = getPB();
322114402Sru  }
323114402Sru  if (i < MAXPUSHBACKSTACK) {
324114402Sru    buffer[i] = (char)0;
325151497Sru    str = (char *)malloc(strlen(buffer)+1);
326151497Sru    strcpy(str, buffer);
327114402Sru  }
328151497Sru  return( str );
329114402Sru}
330