r460: no message
[ctsim.git] / libctgraphics / pol.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **   POL - Problem Oriented Language                    
5 **
6 **  This is part of the CTSim program
7 **  Copyright (c) 1983-2001 Kevin Rosenberg
8 **
9 **  $Id: pol.cpp,v 1.10 2001/01/28 19:10:18 kevin Exp $
10 **
11 **  This program is free software; you can redistribute it and/or modify
12 **  it under the terms of the GNU General Public License (version 2) as
13 **  published by the Free Software Foundation.
14 **
15 **  This program is distributed in the hope that it will be useful,
16 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 **  GNU General Public License for more details.
19 **
20 **  You should have received a copy of the GNU General Public License
21 **  along with this program; if not, write to the Free Software
22 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 ******************************************************************************/
24
25 #include "ct.h"
26 #include <math.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include "ctsupport.h"
30 #include "pol.h"
31
32
33 const struct POL::KeywordCodeList POL::cmdlist[] = {
34   {     "eoc",  PC_EOC,},
35   {     "str",  PC_STR,},
36   {     "com",  PC_COM,},
37   {     "cmd",  PC_CMD,},
38   {     "prg",  PC_PRG,},
39   {     "con",  PC_CON,},
40   {     "out",  PC_OUT,},
41   {     "ter",  PC_TER,},
42   {     "inb",  PC_INB,},
43   
44   {     "nl_eoc",PC_NL_EOC,},
45   {     "nl_neoc", PC_NL_NEOC,},
46   {     "tron",  PC_TRON,},
47   {     "troff", PC_TROFF,},
48   {     "file",  PC_FILE,},
49   {     "dump",  PC_DUMP,},
50 };
51
52 const unsigned int POL::NUMCMD = (sizeof(POL::cmdlist) / sizeof (struct POL::KeywordCodeList));
53
54
55 POL::POL()
56 {
57   currentf = -1;
58   m_bTrace = false;
59   init();
60 }
61
62 POL::~POL()
63 {
64 }
65
66 void 
67 POL::init ()
68 {
69   meta.eoc    = SEMICOL;
70   meta.str    = DQUOTE;
71   meta.com    = SHARP;
72   meta.cmd    = EXCLAM;
73   meta.prg    = ATSIGN;
74   meta.con    = AMPERSAND;
75   meta.out    = DOLLAR;
76   meta.ter    = PERCENT;
77   meta.inb    = LBRACK;
78   
79   m_bNewlineIsEOC = true;
80   m_szSkipChars[0] = EOS;
81   
82   
83   for (unsigned int i = 0; i < NUMCMD; i++)
84     cmdtable.installKeywordCode (cmdlist[i].keyword, cmdlist[i].code);
85   
86   token.ready = false;          // no token read yet 
87 }
88
89
90 /* addSkipWord (w)
91 *
92 * char *w - word for pol to ignore and skip over in input
93 *
94 * tok() compares all tokens to words given to this routine. If it finds it,
95 * it will immediately read another token. 
96 */
97
98 void 
99 POL::addSkipWord (const char* const w)
100 {
101   skiptable.installKeywordCode (w, 0);
102 }
103
104 /* skpchar (s)
105 *
106 * skip all characters that appear in string s
107 */
108 void 
109 POL::addSkipChar (int c)
110 {
111   int n = strlen (m_szSkipChars);
112   if (n < MAXSKIPCHAR) {
113     m_szSkipChars[n] = c;
114     m_szSkipChars[n+1] = 0;
115   }
116 }
117
118 // installKeyword (str, code)
119 //
120 // char *str - token string to install
121 // int code  - code to return for token
122 //
123 // tok() looks for these user defined tokens.  If it finds one,
124 // it stores the tokens code in the token structure and returns TT_USERTOK
125 void
126 POL::addKeyword (const char* const str, int code)
127 {
128   usertable.installKeywordCode (str, code);
129 }
130
131 /* get_word - matches tokens on a letter by letter basis
132 *
133 * char *search - string to search for
134 * int  nlet     - maximum number of chars to search for match
135 */
136
137 bool 
138 POL::readWord (char *search, int nlet)
139 {
140   tok (&token);
141   if (m_bTrace)
142     sys_error (ERR_TRACE, "POL matching current token %s against word %s\n", token.tokstr, search);
143   
144   if (strncasecmp (search, token.tokstr, nlet) == 0) {
145     dumptok (&token);
146     return (true);
147   } else
148     return (false);
149 }
150
151 /* usertok (str,code)
152 *       see if current token is a user defined token set with install()
153 *
154 *    char *str - token string as read from input
155 *    int *code - returned code for user defined symbol
156 *    return value - true if current token has been user defined
157 *                    false if current token is not user defined
158 */
159 bool
160 POL::readUserToken (char *str, int *code)
161 {
162   tok (&token);
163   
164   if (m_bTrace)
165     sys_error (ERR_TRACE, "POL checking if current token '%s' is user defined\n", token.tokstr);
166   
167   if (token.type == TT_USERTOK) {
168     *code = token.code;
169     strcpy (str, token.tokstr);
170     dumptok (&token);
171     return (true);
172   } else {
173     *code = 0;
174     return (false);
175   }
176 }
177
178 /* isstring (s) - returns true if current token is a string
179 *
180 * char *s - pointer to place to store token string
181 */
182
183 bool
184 POL::readString (char *str)
185 {
186   tok (&token);
187   
188   if (token.type == TT_STRING) {
189     strcpy (str, token.tokstr);
190     dumptok (&token);
191     return (true);
192   } else
193     return (false);
194 }
195
196 /* integer - test for an integer
197 *
198 * int *n:       returned integer value
199 * int typecode = TT_INT if accept only integer values
200 *               = TT_REAL if accept both real and integer values
201 * int boundcode= true if force to lie between boundries
202 *               = false can take any value it likes
203 * int bb1:      lower bound
204 * int bb2:      upper bound
205 */
206 bool 
207 POL::readInteger (int *n, int typecode, bool boundcode, int bb1, int bb2)
208 {
209   tok (&token);
210   
211   if (m_bTrace)
212     sys_error (ERR_TRACE, "POL checking if current token %s is an integer\n", token.tokstr);
213   
214   if (token.type == TT_INT || token.type == TT_REAL) {
215            if (boundcode) {
216        if (token.inum < bb1)
217          *n = bb1;
218        else if (token.inum > bb2)
219          *n = bb2;
220        else
221          *n = token.inum;
222             } else
223         *n = token.inum;
224       dumptok (&token);
225       return (true);
226   }
227   *n = 0;
228   return (false);
229 }
230
231 bool
232 POL::readFloat (double *n, double typecode, bool boundcode, double bb1, double bb2)
233 {
234   tok (&token);
235   
236   if (m_bTrace)
237     sys_error (ERR_TRACE, "POL checking if current token %s is an floating point number\n", token.tokstr);
238   
239   if (token.type == TT_INT || token.type == TT_REAL) {
240            if (boundcode) {
241        if (token.fnum < bb1)
242          *n = bb1;
243        else if (token.fnum > bb2)
244          *n = bb2;
245        else
246          *n = token.fnum;
247             } else
248         *n = token.fnum;
249       dumptok (&token);
250       return (true);
251   }
252   *n = 0.0;
253   return (false);
254 }
255
256 /*----------------------------------------------------------------------*/
257 /* skip() - skip over any token except for end of command sequence      */
258 /*                                                                      */
259 /*              returns true if succesful skip                          */
260 /*              returns false if already at end of command or EOF       */
261 /*----------------------------------------------------------------------*/
262
263 bool 
264 POL::skipTokens()
265 {
266   char term[5];         /* string of characters not to skip */
267   
268   term[0] = meta.eoc;
269   if (m_bNewlineIsEOC) {
270     term[1] = NEWLINE;
271     term[2] = EOS;
272   } else
273     term[1] = EOS;
274   
275   return (skipSingleToken (term));
276 }
277
278 void 
279 POL::reader()
280 {
281   while (skipTokens())
282     ;
283   
284   dumptok (&token);             /* skip end of command token */
285 }
286
287 /* skiptok (term) - skip a token unless the first character of a token is
288 *                   in the string of terminators, term.
289 * char *term - string of termination characters, don't skip these characters
290 *               skiptok() also does NOT skip TT_EOF
291 * returns (true) if succesful skip of a token
292 * returns (false) if didn't skip, read termination character or TT_EOF
293 */
294
295 bool 
296 POL::skipSingleToken (char term[])
297 {
298   tok (&token);
299   
300   if (token.type == TT_EOF
301     || (token.type == TT_SPECLCHAR && strchr(term, token.tokstr[0]) != NULL))
302     return (false);
303   else {
304     dumptok (&token);
305     return (true);
306   }
307 }
308
309 int 
310 POL::tok (struct token_st *token)
311 {
312   if (token->ready == false)
313     getpol_tok(token);
314   else
315     if (token->type == TT_EOF && lookchar() != EOF)
316       getpol_tok(token);
317     return (token->type);
318 }
319
320 void 
321 POL::dumptok (struct token_st *token)
322 {
323   if (token->ready == false)
324     getpol_tok(token);
325   token->ready = false;
326 }
327
328 int 
329 POL::getpol_tok (struct token_st *token)
330 {
331   KeywordCodeEntry* sym;
332   
333   token->ready = false;
334 nexttok:
335   gettok (token);
336   
337   if (token->type == TT_BLANK)
338     goto nexttok;
339   if (token->type == TT_SPECLCHAR) {
340     if (strchr(m_szSkipChars, token->tokstr[0]) != NULL)
341       goto nexttok;
342     if (token->tokstr[0] == NEWLINE)
343       goto nexttok;
344     if (token->tokstr[0] == meta.cmd) {
345       getcmd();
346       goto nexttok;
347     }
348     if (token->tokstr[0] == meta.com) {         /* skip comment */
349       eatline ();
350       goto nexttok;
351     }
352     if (token->tokstr[0] == meta.out) {
353       getescape(token->tokstr, meta.out, MAXTOK);
354       fputs (token->tokstr, stderr);
355       goto nexttok;
356     }
357     if (token->tokstr[0] == meta.con) {         /* continuation across NEWLINE */
358       while (lookchar() == BLANK || lookchar() == TAB)
359         inchar();
360       if (lookchar() == NEWLINE)
361         inchar();
362     }
363     if (token->tokstr[0] == meta.ter) {         /* get input from terminal */
364       usefile (P_USE_FILE, "");
365       tok (token);
366       closefile();
367       return (token->type);
368     }
369   }
370   
371   /* look for filler words */
372   
373   if (skiptable.lookup (token->tokstr) != NULL) /* ignore words in skip table */
374     goto nexttok;
375   
376   /* look for user defined symbols */
377   
378   if ((sym = usertable.lookup (token->tokstr)) != NULL) {
379     token->type = TT_USERTOK;
380     token->code = sym->getCode();
381   } else
382     token->code = 0;
383   
384   if (m_bTrace)
385     sys_error (ERR_TRACE, "POL read token '%s', type = %d\n", token->tokstr, token->type);
386   
387   return (token->type);
388 }
389
390
391 int 
392 POL::getcmd()
393 {
394   int tt, found;
395   char str[MAXTOK+1];
396   KeywordCodeEntry *cmd;
397   TOKEN tok;
398   
399   tt = getalpha (str, MAXTOK);
400   if (tt == TT_ERROR) {
401     sys_error (ERR_WARNING, "Error in POL parameter command");
402     reader();
403     return(false);
404   }
405   if ((cmd = cmdtable.lookup (str)) == NULL) {
406     sys_error  (ERR_WARNING, "POL: Unrecognized command %s", cmd);
407     reader();
408     return (false);
409   } else {
410     found = false;
411     switch (cmd->getCode()) {
412     case PC_TRON:
413                     m_bTrace = true;
414         found = true;
415         break;
416     case PC_TROFF:
417                     m_bTrace = false;
418         found = true;
419         break;
420     case PC_FILE:
421                     found = true;
422         tt = gettok (&tok);
423         usefile (P_USE_FILE, tok.tokstr);
424         break;
425     case PC_NL_EOC:
426                     found = true;
427         m_bNewlineIsEOC = true;
428         break;
429     case PC_NL_NEOC:
430                     found = true;
431         m_bNewlineIsEOC = false;
432         break;
433     case PC_DUMP:
434                     found = true;
435         printf("eoc = %c  str = %c  com = %c  cmd = %c  prg = %c\n",
436           meta.eoc, meta.str, meta.com, meta.cmd, meta.prg);
437         printf("con = %c  out = %c  ter = %c  inb = %c\n",
438           meta.con, meta.out, meta.ter, meta.inb);
439         break; 
440     }
441     if (found == false) {
442       tt = gettok (&tok);
443       if (tt != TT_SPECLCHAR) {
444         sys_error (ERR_SEVERE, "POL: Illegal command character");
445         return (false);
446       }
447       switch(cmd->getCode()) {
448                     case PC_EOC:
449           meta.eoc = tok.tokstr[0];
450           break;
451         case PC_STR:
452           meta.str = tok.tokstr[0];
453           break;
454         case PC_COM:
455           meta.com = tok.tokstr[0];
456           break;
457         case PC_CMD:
458           meta.cmd = tok.tokstr[0];
459           break;
460         case PC_PRG:
461           meta.prg = tok.tokstr[0];
462           break;
463         case PC_CON:
464           meta.con = tok.tokstr[0];
465           break;
466         case PC_OUT:
467           meta.out = tok.tokstr[0];
468           break;
469         case PC_TER:
470           meta.ter = tok.tokstr[0];
471           break;
472         case PC_INB:
473           meta.inb = tok.tokstr[0];
474           break;
475         default:
476           printf("command not implemented\n");
477           break;
478       }                         /* switch (tok->type) */
479     }                                   /* if (found == false) */
480     reader();                   /* clean up command */
481   }                                     /* if legal command */
482   
483   return (true);
484 }
485
486
487 int 
488 POL::gettok (TOKEN *tok)
489 {
490   int c, toktype;
491   int inum;
492   double fnum;
493   int toksiz = MAXTOK;          /* maximum length of token string */
494   
495   while ((c = inchar()) == BLANK || c == TAB)
496     ;
497   ungetch (c);
498   
499   c = lookchar();
500   toktype = type(c);
501   
502   fnum = 0.0;
503   inum = 0;
504   
505   if (c == BLANK || c == TAB) {                 /* skip white space */
506     getblank(tok->tokstr, toksiz);
507     toktype = TT_BLANK;
508   } else if (toktype == LETTER) {
509     toktype = getalpha (tok->tokstr, toksiz);
510   } else if (c == meta.str) {                   /* quoted string */
511     getquote (tok->tokstr, toksiz);
512     toktype = TT_STRING;
513   } else if (type(c) == DIGIT || c == PLUS || c == HYPHEN || c == PERIOD) {
514     toktype = getnumber (tok->tokstr, toksiz, &fnum, &inum);
515   } else if (c == EOF) {
516     tok->tokstr[0] = EOS;
517     toktype = TT_EOF;
518   } else {
519     c = inchar();
520     tok->tokstr[0] = c;
521     tok->tokstr[1] = EOS;
522     toktype = TT_SPECLCHAR;
523   }
524   
525   tok->type = toktype;
526   tok->ready = true;
527   if (tok->type == TT_REAL || tok->type == TT_INT) {
528     tok->fnum = fnum;
529     tok->inum = inum;
530   } else {
531     tok->fnum = 0.0;
532     tok->inum = 0;
533   }
534   
535   return (toktype);
536 }
537
538
539 void 
540 POL::getblank (char *s, int toksiz)
541 {
542   int c;
543   
544   while ((c = inchar()) == BLANK || c == TAB)
545     ;
546   ungetch(c);
547   
548   s[0] = BLANK;
549   s[1] = EOS;
550 }
551
552
553 int 
554 POL::getalpha (char *s, int toksiz)
555 {
556   int i, chartype, alphatype;
557   
558   if (type(lookchar()) != LETTER) {
559     s[0] = EOS;
560     return (TT_ERROR);
561   }
562   
563   alphatype = TT_ALPHA;
564   for (i = 0; i < toksiz; i++) {                /* get alphanumeric token */
565     s[i] = inchar();
566     chartype = type (s[i]);
567     if (chartype != LETTER && chartype != DIGIT)
568       break;
569     if (chartype == DIGIT)
570       alphatype = TT_ALPNUM;
571   }
572   ungetch(s[i]);
573   
574   if (i >= toksiz)
575     sys_error (ERR_SEVERE, "POL token too long.");
576   
577   s[i] = EOS;                   /* terminate token */
578   return (alphatype);
579 }
580
581
582 /* getquote - get quoted string from file */
583 /* have already gotten delimiter in qs[0] */
584 void 
585 POL::getquote (char *qs, int toksiz)
586 {
587   int delim;
588   
589   delim = inchar();                     /* char = delimiter */
590   getescape(qs, delim, toksiz);
591 }
592
593
594 void 
595 POL::getescape (        /* reads up to delim */
596                 char *s,
597                 int delim,
598                 int toksiz
599                 )
600 {
601   int i, c;
602   
603   for (i = 0; (c = inchar()) != delim; i++) {
604     if (c == NEWLINE) {
605       sys_error (ERR_WARNING, "Missing closing delimiter.");
606       break;
607     }
608     if (i >= toksiz) {
609       sys_error (ERR_SEVERE, "string too long.");
610       break;
611     }
612     if (c == EOF) {
613       ungetch(c);
614       sys_error (ERR_SEVERE, "end of file inside quotation");
615       break;
616     } else if (c == BSLASH) {   /* escape character */
617       s[i++] = c;
618       c = inchar();             /* get escaped character */
619     }
620     s[i] = c;
621   }
622   s[i] = EOS;
623 }
624
625
626 bool 
627 POL::readText (char *str, int lim)
628 {
629   int c;
630   while ((c = inchar()) == BLANK || c == TAB)
631     ;
632   ungetch (c);
633   if (c == EOF) {
634     str[0] = 0;
635     return false;
636   }
637   
638   int i;
639   for (i = 0; i < lim && (c = inchar()) != EOF && c != NEWLINE; i++)
640     str[i] = c;
641   ungetch (c);
642   str[i] = 0;
643   
644   return true;
645 }
646
647 //----------------------------------------------
648 // Get a number for gettok()                    
649 //----------------------------------------------
650
651 int 
652 POL::getnumber 
653 (
654  char str[],                            /* string to return token in */
655  int strsize,                           /* maximum length of token string */
656  double *fnum,                          /* floating point value of number read */
657  int *inum                              /* integer value of number read */
658  )
659 {
660   int sp = 0;
661   double sign = 1.0;
662   bool isSigned = false;                /* true if number prefixed by '+' or '-' */ 
663   *fnum = 0.0;
664   *inum = 0;
665   str[0] = EOS;
666   
667   int c = inchar();
668   if (c == HYPHEN) {
669     str[sp++] = c;
670     isSigned = true;
671     sign = -1.0;
672   } else if (c == PLUS) {
673     str[sp++] = c;
674     isSigned = true;
675     sign = 1.0;
676   } else if (c == PERIOD) {
677     if (type(lookchar()) != DIGIT) {
678       str[0] = PERIOD;
679       str[1] = EOS;
680       return (TT_SPECLCHAR);
681     } else
682       ungetch (PERIOD);
683   } else if (type(c) != DIGIT) {
684     ungetch (c);
685     return (TT_ERROR);
686   } else
687     ungetch (c);
688   
689   if (isSigned) {
690     c = lookchar();
691     if (c == PERIOD) {
692       inchar();         /* get period */
693       c = lookchar();           /* look at character past period */
694       ungetch (PERIOD); /* put back period */
695       if (type(c) != DIGIT) {
696         str[sp] = EOS;
697         return (TT_SPECLCHAR);
698       }
699     } else if (type (c) != DIGIT) {
700       str[sp] = EOS;
701       return (TT_SPECLCHAR);
702     }
703   }
704   
705   double whole = 0.0;
706   while (type(c = inchar()) == DIGIT) {
707     if (sp < strsize)
708       str[sp++] = c;
709     whole = 10.0 * whole + (c - '0');
710   }
711   ungetch (c);          /* put back non-numeric character */
712   
713   if (c != PERIOD && tolower(c) != 'e') {
714     str[sp] = EOS;
715     *fnum = whole * sign;
716     if (*fnum < MIN_INT)
717       *inum = MIN_INT;
718     else if (*fnum > MAX_INT)
719       *inum = MAX_INT;
720     else
721       *inum = (int) *fnum;
722     return (TT_INT);
723   }
724   
725   if (lookchar() == PERIOD) {
726     inchar();
727     if (sp < strsize)
728       str[sp++] = PERIOD;
729   }
730   
731   double frac = 0.0;
732   double powerof10 = 10.0;
733   
734   while (type(c = inchar()) == DIGIT) {
735     if (sp < strsize)
736       str[sp++] = c;
737     frac += (double) (c - '0') / powerof10;
738     powerof10 *= 10.0;
739   }
740   ungetch (c);
741   
742   double exp = 0.0;
743   double expsign = 1.0;
744   c = inchar();
745   if (tolower(c) != 'e')
746     ungetch (c);
747   else {
748     if (sp < strsize)
749       str[sp++] = c;
750     if ((c = inchar()) == PLUS) {
751       if (sp < strsize)
752         str[sp++] = c;
753       expsign = 1.0;
754     } else if (c == HYPHEN) {
755       if (sp < strsize)
756         str[sp++] = c;
757       expsign = -1.0;
758     } else if (type(c) != DIGIT) {
759       --sp;                             /* erase 'e' */
760       ungetch (c);
761       ungetch ('e');
762       goto getnumexit;
763     } else
764       ungetch(c);
765     
766     exp = 0;
767     while (type(c = inchar()) == DIGIT) {
768       if (sp < strsize)
769         str[sp++] = c;
770       exp = 10 * exp + (c - '0');
771     }
772     ungetch (c);
773   }
774   
775 getnumexit:
776   str[sp] = EOS;
777   *fnum = sign * (whole + frac) * pow (10.0, expsign * exp);
778   if (*fnum < MIN_INT)
779     *inum = MIN_INT;
780   else if (*fnum > MAX_INT)
781     *inum = MAX_INT;
782   else
783     *inum = (int) *fnum;
784   return (TT_REAL);
785 }
786
787 void 
788 POL::eatline ()
789 {
790   char term [2];
791   
792   term[0] = NEWLINE;
793   term[1] = EOS;
794   skipSingleToken (term);
795 }
796
797 // return type of ASCII character 
798 int 
799 POL::type (int c)
800 {
801   if (isalpha(c) || c == UNDERLIN)
802     return (LETTER);
803   else if (isdigit(c))
804     return (DIGIT);
805   else
806     return (c);
807 }
808
809
810 //----------------------------------------------------------------------
811 //                              POL INPUT                               
812 //----------------------------------------------------------------------
813
814
815 /* usefile - set source of POL input
816 *
817 *    int source - source of input
818 *                  P_USE_STR  - have POL use strings as input
819 *                  P_USE_FILE - use file.  filename is in str
820 *
821 */
822
823 void 
824 POL::usefile (int source, char *fn)
825 {
826   FILE *fp;
827   
828   ++currentf;
829   if (currentf >= MAXFILE) {
830     --currentf;
831     sys_error (ERR_SEVERE, "files nested too deeply");
832     return;
833   }
834   
835   while (! m_stackPushBackInput.empty())
836     m_stackPushBackInput.pop();
837
838   if (source == P_USE_STR) {
839     filep[currentf] = NULL;
840   } else if (source == P_USE_FILE) {
841     if (fn == NULL || strlen(fn) == 0) {
842       fp = stdin;
843     } else if ((fp = fopen(fn, "r")) == NULL) {
844       --currentf;
845       sys_error (ERR_SEVERE, "can't open file");
846       return;
847     }
848     filep[currentf] = fp;
849     fname[currentf] = strdup (fn);
850   }
851 }
852
853 void 
854 POL::closefile()
855 {
856   if (currentf >= 0) {
857     if (filep[currentf] != NULL)
858       fclose (filep[currentf]);
859     --currentf;
860   }
861 }
862
863 /*-----------------------------*/
864 /* Lowest Level Input Routines */
865 /*-----------------------------*/
866
867
868 int 
869 POL::lookchar()
870 {
871   int c;
872   
873   c = inchar();
874   ungetch (c);
875   return (c);
876 }
877
878 int 
879 POL::inchar()
880 {
881   int c = 0;
882   
883   if (currentf < 0)
884     return (EOF);
885   
886   while (currentf >= 0 && (c = getch(filep[currentf])) == EOF && filep[currentf] != NULL) {
887     closefile ();
888   }
889   
890   return (c);
891 }
892
893 /*--------------------------------------------------------------*/
894 /* getch - get a (possibly pushed back) character               */
895 /*         if fp == NULL, then get character from inputline     */
896 /*--------------------------------------------------------------*/
897
898 int 
899 POL::getch (FILE *fp)
900 {
901   int c;
902   if (m_stackPushBackInput.size() > 0) {
903     c = m_stackPushBackInput.top();
904     m_stackPushBackInput.pop();
905     return c;
906   }
907
908   if (fp == NULL) {
909     if ((c = inputline[lineptr]) == EOS)
910       return (EOF);
911     else {
912       ++lineptr;
913       return (c);
914     }
915   } else
916     c = fgetc(fp);
917   
918   return (c);
919 }
920
921 // push character back on input 
922 void 
923 POL::ungetch (int c)
924 {
925   m_stackPushBackInput.push (c);
926 }
927
928
929 int 
930 POL::get_inputline (FILE *fp)
931 {
932   while (! m_stackPushBackInput.empty())
933     m_stackPushBackInput.pop();
934
935   lineptr = 0;
936   if (fgets (inputline, MAXLINE, fp) == NULL)
937     return (EOF);
938   else
939     return (OK);
940 }
941
942 void 
943 POL::set_inputline (const char* const line)
944 {
945   while (! m_stackPushBackInput.empty())
946     m_stackPushBackInput.pop();
947
948   strncpy (inputline, line, MAXLINE);
949   lineptr = 0;
950 }