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