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