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