1/*	$NetBSD: pushback.cpp,v 1.1.1.1 2016/01/13 18:41:49 christos Exp $	*/
2
3// -*- C++ -*-
4/* Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
5     Written by Gaius Mulley (gaius@glam.ac.uk).
6
7This file is part of groff.
8
9groff is free software; you can redistribute it and/or modify it under
10the terms of the GNU General Public License as published by the Free
11Software Foundation; either version 2, or (at your option) any later
12version.
13
14groff is distributed in the hope that it will be useful, but WITHOUT ANY
15WARRANTY; without even the implied warranty of MERCHANTABILITY or
16FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17for more details.
18
19You should have received a copy of the GNU General Public License along
20with groff; see the file COPYING.  If not, write to the Free Software
21Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
22
23#include "lib.h"
24
25#include <signal.h>
26#include <ctype.h>
27#include <assert.h>
28#include <stdlib.h>
29#include <errno.h>
30#include "errarg.h"
31#include "error.h"
32#include "stringclass.h"
33#include "posix.h"
34#include "nonposix.h"
35
36#include <errno.h>
37#include <sys/types.h>
38#ifdef HAVE_UNISTD_H
39#include <unistd.h>
40#endif
41
42#include "pushback.h"
43#include "pre-html.h"
44
45#if !defined(TRUE)
46#   define TRUE  (1==1)
47#endif
48
49#if !defined(FALSE)
50#   define FALSE (1==0)
51#endif
52
53#   define ERROR(X)   (void)(fprintf(stderr, "%s:%d error %s\n", __FILE__, __LINE__, X) && \
54                            (fflush(stderr)) && localexit(1))
55
56
57#define MAXPUSHBACKSTACK 4096                  /* maximum number of character that can be pushed back */
58
59
60/*
61 *  constructor for pushBackBuffer
62 */
63
64pushBackBuffer::pushBackBuffer (char *filename)
65{
66  charStack = (char *)malloc(MAXPUSHBACKSTACK);
67  if (charStack == 0) {
68    sys_fatal("malloc");
69  }
70  stackPtr = 0;   /* index to push back stack        */
71  debug    = 0;
72  verbose  = 0;
73  eofFound = FALSE;
74  lineNo   = 1;
75  if (strcmp(filename, "") != 0) {
76    stdIn = dup(0);
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
86pushBackBuffer::~pushBackBuffer ()
87{
88  if (charStack != 0) {
89    free(charStack);
90  }
91  close(0);
92  /* restore stdin in file descriptor 0 */
93  dup(stdIn);
94  close(stdIn);
95}
96
97/*
98 *  localexit - wraps exit with a return code to aid the ERROR macro.
99 */
100
101int localexit (int i)
102{
103  exit(i);
104  return( 1 );
105}
106
107/*
108 *  getPB - returns a character, possibly a pushed back character.
109 */
110
111char pushBackBuffer::getPB (void)
112{
113  if (stackPtr>0) {
114    stackPtr--;
115    return( charStack[stackPtr] );
116  } else {
117    char ch;
118
119    if (read(0, &ch, 1) == 1) {
120      if (verbose) {
121	printf("%c", ch);
122      }
123      if (ch == '\n') {
124	lineNo++;
125      }
126      return( ch );
127    } else {
128      eofFound = TRUE;
129      return( eof );
130    }
131  }
132}
133
134/*
135 *  putPB - pushes a character onto the push back stack.
136 *          The same character is returned.
137 */
138
139char pushBackBuffer::putPB (char ch)
140{
141  if (stackPtr<MAXPUSHBACKSTACK) {
142    charStack[stackPtr] = ch ;
143    stackPtr++;
144  } else {
145    ERROR("max push back stack exceeded, increase MAXPUSHBACKSTACK constant");
146  }
147  return( ch );
148}
149
150/*
151 *  isWhite - returns TRUE if a white character is found. This character is NOT consumed.
152 */
153
154static int isWhite (char ch)
155{
156  return( (ch==' ') || (ch == '\t') || (ch == '\n') );
157}
158
159/*
160 *  skipToNewline - skips characters until a newline is seen.
161 */
162
163void pushBackBuffer::skipToNewline (void)
164{
165  while ((putPB(getPB()) != '\n') && (! eofFound)) {
166    getPB();
167  }
168}
169
170/*
171 *  skipUntilToken - skips until a token is seen
172 */
173
174void pushBackBuffer::skipUntilToken (void)
175{
176  char ch;
177
178  while ((isWhite(putPB(getPB())) || (putPB(getPB()) == '#')) && (! eofFound)) {
179    ch = getPB();
180    if (ch == '#') {
181      skipToNewline();
182    }
183  }
184}
185
186/*
187 *  isString - returns TRUE if the string, s, matches the pushed back string.
188 *             if TRUE is returned then this string is consumed, otherwise it is
189 *             left alone.
190 */
191
192int pushBackBuffer::isString (const char *s)
193{
194  int length=strlen(s);
195  int i=0;
196
197  while ((i<length) && (putPB(getPB())==s[i])) {
198    if (getPB() != s[i]) {
199      ERROR("assert failed");
200    }
201    i++;
202  }
203  if (i==length) {
204    return( TRUE );
205  } else {
206    i--;
207    while (i>=0) {
208      if (putPB(s[i]) != s[i]) {
209	ERROR("assert failed");
210      }
211      i--;
212    }
213  }
214  return( FALSE );
215}
216
217/*
218 *  isDigit - returns TRUE if the character, ch, is a digit.
219 */
220
221static int isDigit (char ch)
222{
223  return( ((ch>='0') && (ch<='9')) );
224}
225
226/*
227 *  isHexDigit - returns TRUE if the character, ch, is a hex digit.
228 */
229
230#if 0
231static int isHexDigit (char ch)
232{
233  return( (isDigit(ch)) || ((ch>='a') && (ch<='f')) );
234}
235#endif
236
237/*
238 *  readInt - returns an integer from the input stream.
239 */
240
241int pushBackBuffer::readInt (void)
242{
243  int  c =0;
244  int  i =0;
245  int  s =1;
246  char ch=getPB();
247
248  while (isWhite(ch)) {
249    ch=getPB();
250  }
251  // now read integer
252
253  if (ch == '-') {
254    s = -1;
255    ch = getPB();
256  }
257  while (isDigit(ch)) {
258    i *= 10;
259    if ((ch>='0') && (ch<='9')) {
260      i += (int)(ch-'0');
261    }
262    ch = getPB();
263    c++;
264  }
265  if (ch != putPB(ch)) {
266    ERROR("assert failed");
267  }
268  return( i*s );
269}
270
271/*
272 *  convertToFloat - converts integers, a and b into a.b
273 */
274
275static double convertToFloat (int a, int b)
276{
277  int c=10;
278  double f;
279
280  while (b>c) {
281    c *= 10;
282  }
283  f = ((double)a) + (((double)b)/((double)c));
284  return( f );
285}
286
287/*
288 *  readNumber - returns a float representing the word just read.
289 */
290
291double pushBackBuffer::readNumber (void)
292{
293  int i;
294  char ch;
295
296  i = readInt();
297  if ((ch = getPB()) == '.') {
298    return convertToFloat(i, readInt());
299  }
300  putPB(ch);
301  return (double)i;
302}
303
304/*
305 *  readString - reads a string terminated by white space
306 *               and returns a malloced area of memory containing
307 *               a copy of the characters.
308 */
309
310char *pushBackBuffer::readString (void)
311{
312  char  buffer[MAXPUSHBACKSTACK];
313  char *str = 0;
314  int   i=0;
315  char ch=getPB();
316
317  while (isWhite(ch)) {
318    ch=getPB();
319  }
320  while ((i < MAXPUSHBACKSTACK) && (! isWhite(ch)) && (! eofFound)) {
321    buffer[i] = ch;
322    i++;
323    ch = getPB();
324  }
325  if (i < MAXPUSHBACKSTACK) {
326    buffer[i] = (char)0;
327    str = (char *)malloc(strlen(buffer)+1);
328    strcpy(str, buffer);
329  }
330  return( str );
331}
332