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