tinput.c - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
tinput.c (11631B)
---
     1 #include 
     2 #include 
     3 #include 
     4 #include 
     5 #include 
     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 }