tinput.c - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       tinput.c (11631B)
       ---
            1 #include <stdio.h>
            2 #include <stdlib.h>
            3 #include <string.h>
            4 #include <ctype.h>
            5 #include <errno.h>
            6 #include "pic.h"
            7 #include "y.tab.h"
            8 
            9 Infile        infile[10];
           10 Infile        *curfile = infile;
           11 
           12 #define        MAXSRC        50
           13 Src        src[MAXSRC];        /* input source stack */
           14 Src        *srcp        = src;
           15 
           16 void        do_thru(void);
           17 int        nextchar(void);
           18 int        getarg(char *);
           19 void        freedef(char *);
           20 int        baldelim(int, char *);
           21 
           22 void pushsrc(int type, char *ptr)        /* new input source */
           23 {
           24         if (++srcp >= src + MAXSRC)
           25                 ERROR "inputs nested too deep" FATAL;
           26         srcp->type = type;
           27         srcp->sp = ptr;
           28         if (dbg > 1) {
           29                 printf("\n%3d ", (int)(srcp - src));
           30                 switch (srcp->type) {
           31                 case File:
           32                         printf("push file %s\n", ((Infile *)ptr)->fname);
           33                         break;
           34                 case Macro:
           35                         printf("push macro <%s>\n", ptr);
           36                         break;
           37                 case Char:
           38                         printf("push char <%c>\n", *ptr);
           39                         break;
           40                 case Thru:
           41                         printf("push thru\n");
           42                         break;
           43                 case String:
           44                         printf("push string <%s>\n", ptr);
           45                         break;
           46                 case Free:
           47                         printf("push free <%s>\n", ptr);
           48                         break;
           49                 default:
           50                         ERROR "pushed bad type %d", srcp->type FATAL;
           51                 }
           52         }
           53 }
           54 
           55 void popsrc(void)        /* restore an old one */
           56 {
           57         if (srcp <= src)
           58                 ERROR "too many inputs popped" FATAL;
           59         if (dbg > 1) {
           60                 printf("%3d ", (int) (srcp - src));
           61                 switch (srcp->type) {
           62                 case File:
           63                         printf("pop file\n");
           64                         break;
           65                 case Macro:
           66                         printf("pop macro\n");
           67                         break;
           68                 case Char:
           69                         printf("pop char <%c>\n", *srcp->sp);
           70                         break;
           71                 case Thru:
           72                         printf("pop thru\n");
           73                         break;
           74                 case String:
           75                         printf("pop string\n");
           76                         break;
           77                 case Free:
           78                         printf("pop free\n");
           79                         break;
           80                 default:
           81                         ERROR "pop weird input %d", srcp->type FATAL;
           82                 }
           83         }
           84         srcp--;
           85 }
           86 
           87 void definition(char *s)        /* collect definition for s and install */
           88                                 /* definitions picked up lexically */
           89 {
           90         char *p;
           91         struct symtab *stp;
           92 
           93         p = delimstr("definition");
           94         stp = lookup(s);
           95         if (stp != NULL) {        /* it's there before */
           96                 if (stp->s_type != DEFNAME) {
           97                         ERROR "%s used as variable and definition", s WARNING;
           98                         return;
           99                 }
          100                 free(stp->s_val.p);
          101                 stp->s_val.p = p;
          102         } else {
          103                 YYSTYPE u;
          104                 u.p = p;
          105                 makevar(tostring(s), DEFNAME, u);
          106         }
          107         dprintf("installing %s as `%s'\n", s, p);
          108 }
          109 
          110 char *delimstr(char *s)        /* get body of X ... X */
          111                                 /* message if too big */
          112 {
          113         int c, delim, rdelim, n, deep;
          114         static char *buf = NULL;
          115         static int nbuf = 0;
          116         char *p;
          117 
          118         if (buf == NULL)
          119                 buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
          120         while ((delim = input()) == ' ' || delim == '\t' || delim == '\n')
          121                 ;
          122         rdelim = baldelim(delim, "{}");                /* could be "(){}[]`'" */
          123         deep = 1;
          124         for (p = buf; ; ) {
          125                 c = input();
          126                 if (c == rdelim)
          127                         if (--deep == 0)
          128                                 break;
          129                 if (c == delim)
          130                         deep++;
          131                 if (p >= buf + nbuf) {
          132                         n = p - buf;
          133                         buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
          134                         p = buf + n;
          135                 }
          136                 if (c == EOF)
          137                         ERROR "end of file in %s %c %.20s... %c", s, delim, buf, delim FATAL;
          138                 *p++ = c;
          139         }
          140         *p = '\0';
          141         dprintf("delimstr %s %c <%s> %c\n", s, delim, buf, delim);
          142         return tostring(buf);
          143 }
          144 
          145 int
          146 baldelim(int c, char *s)        /* replace c by balancing entry in s */
          147 {
          148         for ( ; *s; s += 2)
          149                 if (*s == c)
          150                         return s[1];
          151         return c;
          152 }
          153 
          154 void undefine(char *s)        /* undefine macro */
          155 {
          156         while (*s != ' ' && *s != '\t')                /* skip "undef..." */
          157                 s++;
          158         while (*s == ' ' || *s == '\t')
          159                 s++;
          160         freedef(s);
          161 }
          162 
          163 
          164 Arg        args[10];        /* argument frames */
          165 Arg        *argfp = args;        /* frame pointer */
          166 int        argcnt;                /* number of arguments seen so far */
          167 
          168 void dodef(struct symtab *stp)        /* collect args and switch input to defn */
          169 {
          170         int i, len;
          171         char *p;
          172         Arg *ap;
          173 
          174         ap = argfp+1;
          175         if (ap >= args+10)
          176                 ERROR "arguments too deep" FATAL;
          177         argcnt = 0;
          178         if (input() != '(')
          179                 ERROR "disaster in dodef" FATAL;
          180         if (ap->argval == 0)
          181                 ap->argval = malloc(1000);
          182         for (p = ap->argval; (len = getarg(p)) != -1; p += len) {
          183                 ap->argstk[argcnt++] = p;
          184                 if (input() == ')')
          185                         break;
          186         }
          187         for (i = argcnt; i < MAXARGS; i++)
          188                 ap->argstk[i] = "";
          189         if (dbg)
          190                 for (i = 0; i < argcnt; i++)
          191                         printf("arg %d.%d = <%s>\n", (int) (ap-args), i+1, ap->argstk[i]);
          192         argfp = ap;
          193         pushsrc(Macro, stp->s_val.p);
          194 }
          195 
          196 int
          197 getarg(char *p)        /* pick up single argument, store in p, return length */
          198 {
          199         int n, c, npar;
          200 
          201         n = npar = 0;
          202         for ( ;; ) {
          203                 c = input();
          204                 if (c == EOF)
          205                         ERROR "end of file in getarg" FATAL;
          206                 if (npar == 0 && (c == ',' || c == ')'))
          207                         break;
          208                 if (c == '"')        /* copy quoted stuff intact */
          209                         do {
          210                                 *p++ = c;
          211                                 n++;
          212                         } while ((c = input()) != '"' && c != EOF);
          213                 else if (c == '(')
          214                         npar++;
          215                 else if (c == ')')
          216                         npar--;
          217                 n++;
          218                 *p++ = c;
          219         }
          220         *p = 0;
          221         unput(c);
          222         return(n + 1);
          223 }
          224 
          225 #define        PBSIZE        2000
          226 char        pbuf[PBSIZE];                /* pushback buffer */
          227 char        *pb        = pbuf-1;        /* next pushed back character */
          228 
          229 char        ebuf[200];                /* collect input here for error reporting */
          230 char        *ep        = ebuf;
          231 
          232 int        begin        = 0;
          233 extern        int        thru;
          234 extern        struct symtab        *thrudef;
          235 extern        char        *untilstr;
          236 
          237 int
          238 input(void)
          239 {
          240         register int c;
          241 
          242         if (thru && begin) {
          243                 do_thru();
          244                 begin = 0;
          245         }
          246         c = nextchar();
          247         if (dbg > 1)
          248                 printf(" <%c>", c);
          249         if (ep >= ebuf + sizeof ebuf)
          250                 ep = ebuf;
          251         return *ep++ = c;
          252 }
          253 
          254 int
          255 nextchar(void)
          256 {
          257         register int c;
          258 
          259         c = 0; /* Botch: gcc */
          260 
          261   loop:
          262         switch (srcp->type) {
          263         case Free:        /* free string */
          264                 free(srcp->sp);
          265                 popsrc();
          266                 goto loop;
          267         case Thru:        /* end of pushed back line */
          268                 begin = 1;
          269                 popsrc();
          270                 c = '\n';
          271                 break;
          272         case Char:
          273                 if (pb >= pbuf) {
          274                         c = *pb--;
          275                         popsrc();
          276                         break;
          277                 } else {        /* can't happen? */
          278                         popsrc();
          279                         goto loop;
          280                 }
          281         case String:
          282                 c = *srcp->sp++;
          283                 if (c == '\0') {
          284                         popsrc();
          285                         goto loop;
          286                 } else {
          287                         if (*srcp->sp == '\0')        /* empty, so pop */
          288                                 popsrc();
          289                         break;
          290                 }
          291         case Macro:
          292                 c = *srcp->sp++;
          293                 if (c == '\0') {
          294                         if (--argfp < args)
          295                                 ERROR "argfp underflow" FATAL;
          296                         popsrc();
          297                         goto loop;
          298                 } else if (c == '$' && isdigit((unsigned char) *srcp->sp)) {
          299                         int n = 0;
          300                         while (isdigit((unsigned char) *srcp->sp))
          301                                 n = 10 * n + *srcp->sp++ - '0';
          302                         if (n > 0 && n <= MAXARGS)
          303                                 pushsrc(String, argfp->argstk[n-1]);
          304                         goto loop;
          305                 }
          306                 break;
          307         case File:
          308                 c = getc(curfile->fin);
          309                 if (c == EOF) {
          310                         if (curfile == infile)
          311                                 ERROR "end of file inside .PS/.PE" FATAL;
          312                         if (curfile->fin != stdin) {
          313                                 fclose(curfile->fin);
          314                                 free(curfile->fname);        /* assumes allocated */
          315                         }
          316                         curfile--;
          317                         printlf(curfile->lineno, curfile->fname);
          318                         popsrc();
          319                         thru = 0;        /* chicken out */
          320                         thrudef = 0;
          321                         if (untilstr) {
          322                                 free(untilstr);
          323                                 untilstr = 0;
          324                         }
          325                         goto loop;
          326                 }
          327                 if (c == '\n')
          328                         curfile->lineno++;
          329                 break;
          330         }
          331         return c;
          332 }
          333 
          334 void do_thru(void)        /* read one line, make into a macro expansion */
          335 {
          336         int c, i;
          337         char *p;
          338         Arg *ap;
          339 
          340         ap = argfp+1;
          341         if (ap >= args+10)
          342                 ERROR "arguments too deep" FATAL;
          343         if (ap->argval == NULL)
          344                 ap->argval = malloc(1000);
          345         p = ap->argval;
          346         argcnt = 0;
          347         c = nextchar();
          348         if (thru == 0) {        /* end of file was seen, so thru is done */
          349                 unput(c);
          350                 return;
          351         }
          352         for ( ; c != '\n' && c != EOF; ) {
          353                 if (c == ' ' || c == '\t') {
          354                         c = nextchar();
          355                         continue;
          356                 }
          357                 ap->argstk[argcnt++] = p;
          358                 if (c == '"') {
          359                         do {
          360                                 *p++ = c;
          361                                 if ((c = nextchar()) == '\\') {
          362                                         *p++ = c;
          363                                         *p++ = nextchar();
          364                                         c = nextchar();
          365                                 }
          366                         } while (c != '"' && c != '\n' && c != EOF);
          367                         *p++ = '"';
          368                         if (c == '"')
          369                                 c = nextchar();
          370                 } else {
          371                         do {
          372                                 *p++ = c;
          373                         } while ((c = nextchar())!=' ' && c!='\t' && c!='\n' && c!=',' && c!=EOF);
          374                         if (c == ',')
          375                                 c = nextchar();
          376                 }
          377                 *p++ = '\0';
          378         }
          379         if (c == EOF)
          380                 ERROR "unexpected end of file in do_thru" FATAL;
          381         if (argcnt == 0) {        /* ignore blank line */
          382                 pushsrc(Thru, (char *) 0);
          383                 return;
          384         }
          385         for (i = argcnt; i < MAXARGS; i++)
          386                 ap->argstk[i] = "";
          387         if (dbg)
          388                 for (i = 0; i < argcnt; i++)
          389                         printf("arg %d.%d = <%s>\n", (int) (ap-args), i+1, ap->argstk[i]);
          390         if (strcmp(ap->argstk[0], ".PE") == 0) {
          391                 thru = 0;
          392                 thrudef = 0;
          393                 pushsrc(String, "\n.PE\n");
          394                 return;
          395         }
          396         if (untilstr && strcmp(ap->argstk[0], untilstr) == 0) {
          397                 thru = 0;
          398                 thrudef = 0;
          399                 free(untilstr);
          400                 untilstr = 0;
          401                 return;
          402         }
          403         pushsrc(Thru, (char *) 0);
          404         dprintf("do_thru pushing back <%s>\n", thrudef->s_val.p);
          405         argfp = ap;
          406         pushsrc(Macro, thrudef->s_val.p);
          407 }
          408 
          409 int
          410 unput(int c)
          411 {
          412         if (++pb >= pbuf + sizeof pbuf)
          413                 ERROR "pushback overflow" FATAL;
          414         if (--ep < ebuf)
          415                 ep = ebuf + sizeof(ebuf) - 1;
          416         *pb = c;
          417         pushsrc(Char, pb);
          418         return c;
          419 }
          420 
          421 void pbstr(char *s)
          422 {
          423         pushsrc(String, s);
          424 }
          425 
          426 double errcheck(double x, char  *s)
          427 {
          428         if (errno == EDOM) {
          429                 errno = 0;
          430                 ERROR "%s argument out of domain", s WARNING;
          431         } else if (errno == ERANGE) {
          432                 errno = 0;
          433                 ERROR "%s result out of range", s WARNING;
          434         }
          435         return x;
          436 }
          437 
          438 char        errbuf[1000];
          439 
          440 void        eprint(void);
          441 
          442 void yyerror(char *s)
          443 {
          444         extern char *cmdname;
          445         int ern = errno;        /* cause some libraries clobber it */
          446 
          447         if (synerr)
          448                 return;
          449         fflush(stdout);
          450         fprintf(stderr, "%s: %s", cmdname, s);
          451         if (ern > 0) {
          452                 errno = ern;
          453                 perror("???");
          454         }
          455         fprintf(stderr, " near %s:%d\n",
          456                 curfile->fname, curfile->lineno+1);
          457         eprint();
          458         synerr = 1;
          459         errno = 0;
          460 }
          461 
          462 void eprint(void)        /* try to print context around error */
          463 {
          464         char *p, *q;
          465 
          466         p = ep - 1;
          467         if (p > ebuf && *p == '\n')
          468                 p--;
          469         for ( ; p >= ebuf && *p != '\n'; p--)
          470                 ;
          471         while (*p == '\n')
          472                 p++;
          473         fprintf(stderr, " context is\n\t");
          474         for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
          475                 ;
          476         while (p < q)
          477                 putc(*p++, stderr);
          478         fprintf(stderr, " >>> ");
          479         while (p < ep)
          480                 putc(*p++, stderr);
          481         fprintf(stderr, " <<< ");
          482         while (pb >= pbuf)
          483                 putc(*pb--, stderr);
          484         fgets(ebuf, sizeof ebuf, curfile->fin);
          485         fprintf(stderr, "%s", ebuf);
          486         pbstr("\n.PE\n");        /* safety first */
          487         ep = ebuf;
          488 }
          489 
          490 void yywrap(void) {}
          491 
          492 char        *newfile = 0;                /* filename for file copy */
          493 char        *untilstr = 0;                /* string that terminates a thru */
          494 int        thru        = 0;                /* 1 if copying thru macro */
          495 struct symtab        *thrudef = 0;                /* macro being used */
          496 
          497 void copyfile(char *s)        /* remember file to start reading from */
          498 {
          499         newfile = s;
          500 }
          501 
          502 void copydef(struct symtab *p)        /* remember macro symtab ptr */
          503 {
          504         thrudef = p;
          505 }
          506 
          507 struct symtab *copythru(char *s)        /* collect the macro name or body for thru */
          508 {
          509         struct symtab *p;
          510         char *q, *addnewline(char *);
          511 
          512         p = lookup(s);
          513         if (p != NULL) {
          514                 if (p->s_type == DEFNAME) {
          515                         p->s_val.p = addnewline(p->s_val.p);
          516                         return p;
          517                 } else
          518                         ERROR "%s used as define and name", s FATAL;
          519         }
          520         /* have to collect the definition */
          521         pbstr(s);        /* first char is the delimiter */
          522         q = delimstr("thru body");
          523         s = "nameless";
          524         p = lookup(s);
          525         if (p != NULL) {
          526                 if (p->s_val.p)
          527                         free(p->s_val.p);
          528                 p->s_val.p = q;
          529         } else {
          530                 YYSTYPE u;
          531                 u.p = q;
          532                 p = makevar(tostring(s), DEFNAME, u);
          533         }
          534         p->s_val.p = addnewline(p->s_val.p);
          535         dprintf("installing %s as `%s'\n", s, p->s_val.p);
          536         return p;
          537 }
          538 
          539 char *addnewline(char *p)        /* add newline to end of p */
          540 {
          541         int n;
          542 
          543         n = strlen(p);
          544         if (p[n-1] != '\n') {
          545                 p = realloc(p, n+2);
          546                 p[n] = '\n';
          547                 p[n+1] = '\0';
          548         }
          549         return p;
          550 }
          551 
          552 void copyuntil(char *s)        /* string that terminates a thru */
          553 {
          554         untilstr = s;
          555 }
          556 
          557 void copy(void)        /* begin input from file, etc. */
          558 {
          559         FILE *fin;
          560 
          561         if (newfile) {
          562                 if ((fin = fopen(newfile, "r")) == NULL)
          563                         ERROR "can't open file %s", newfile FATAL;
          564                 curfile++;
          565                 curfile->fin = fin;
          566                 curfile->fname = newfile;
          567                 curfile->lineno = 0;
          568                 printlf(1, curfile->fname);
          569                 pushsrc(File, curfile->fname);
          570                 newfile = 0;
          571         }
          572         if (thrudef) {
          573                 thru = 1;
          574                 begin = 1;        /* wrong place */
          575         }
          576 }
          577 
          578 char        shellbuf[1000], *shellp;
          579 
          580 void shell_init(void)        /* set up to interpret a shell command */
          581 {
          582         sprintf(shellbuf, "rc -c '");
          583         shellp = shellbuf + strlen(shellbuf);
          584 }
          585 
          586 void shell_text(char *s)        /* add string to command being collected */
          587 {
          588         while ((*shellp++ = *s++))
          589                 ;
          590         shellp--;
          591 }
          592 
          593 void shell_exec(void)        /* do it */
          594 {
          595         *shellp++ = '\'';
          596         *shellp = '\0';
          597         system(shellbuf);
          598 }