parse.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       parse.c (5593B)
       ---
            1 #include        "mk.h"
            2 
            3 char *infile;
            4 int mkinline;
            5 static int rhead(char *, Word **, Word **, int *, char **);
            6 static char *rbody(Biobuf*);
            7 extern Word *target1;
            8 
            9 void
           10 parse(char *f, int fd, int varoverride)
           11 {
           12         int hline;
           13         char *body;
           14         Word *head, *tail;
           15         int attr, set, pid;
           16         char *prog, *p;
           17         int newfd;
           18         Biobuf in;
           19         Bufblock *buf;
           20         char *err;
           21 
           22         if(fd < 0){
           23                 fprint(2, "open %s: %r\n", f);
           24                 Exit();
           25         }
           26         pushshell();
           27         ipush();
           28         infile = strdup(f);
           29         mkinline = 1;
           30         Binit(&in, fd, OREAD);
           31         buf = newbuf();
           32         while(assline(&in, buf)){
           33                 hline = mkinline;
           34                 switch(rhead(buf->start, &head, &tail, &attr, &prog))
           35                 {
           36                 case '<':
           37                         p = wtos(tail, ' ');
           38                         if(*p == 0){
           39                                 SYNERR(-1);
           40                                 fprint(2, "missing include file name\n");
           41                                 Exit();
           42                         }
           43                         newfd = open(p, OREAD);
           44                         if(newfd < 0){
           45                                 fprint(2, "warning: skipping missing include file %s: %r\n", p);
           46                         } else
           47                                 parse(p, newfd, 0);
           48                         break;
           49                 case '|':
           50                         p = wtos(tail, ' ');
           51                         if(*p == 0){
           52                                 SYNERR(-1);
           53                                 fprint(2, "missing include program name\n");
           54                                 Exit();
           55                         }
           56                         execinit();
           57                         pid=pipecmd(p, envy, &newfd, shellt, shellcmd);
           58                         if(newfd < 0){
           59                                 fprint(2, "warning: skipping missing program file %s: %r\n", p);
           60                         } else
           61                                 parse(p, newfd, 0);
           62                         while(waitup(-3, &pid) >= 0)
           63                                 ;
           64                         if(pid != 0){
           65                                 fprint(2, "bad include program status\n");
           66                                 Exit();
           67                         }
           68                         break;
           69                 case ':':
           70                         body = rbody(&in);
           71                         addrules(head, tail, body, attr, hline, prog);
           72                         break;
           73                 case '=':
           74                         if(head->next){
           75                                 SYNERR(-1);
           76                                 fprint(2, "multiple vars on left side of assignment\n");
           77                                 Exit();
           78                         }
           79                         if(symlook(head->s, S_OVERRIDE, 0)){
           80                                 set = varoverride;
           81                         } else {
           82                                 set = 1;
           83                                 if(varoverride)
           84                                         symlook(head->s, S_OVERRIDE, (void *)"");
           85                         }
           86                         if(set){
           87 /*
           88 char *cp;
           89 dumpw("tail", tail);
           90 cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp);
           91 */
           92                                 setvar(head->s, (void *) tail);
           93                                 symlook(head->s, S_WESET, (void *)"");
           94                                 if(strcmp(head->s, "MKSHELL") == 0){
           95                                         if((err = setshell(tail)) != nil){
           96                                                 SYNERR(hline);
           97                                                 fprint(2, "%s\n", err);
           98                                                 Exit();
           99                                                 break;
          100                                         }
          101                                 }
          102                         }
          103                         if(attr)
          104                                 symlook(head->s, S_NOEXPORT, (void *)"");
          105                         break;
          106                 default:
          107                         SYNERR(hline);
          108                         fprint(2, "expected one of :<=\n");
          109                         Exit();
          110                         break;
          111                 }
          112         }
          113         close(fd);
          114         freebuf(buf);
          115         ipop();
          116         popshell();
          117 }
          118 
          119 void
          120 addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog)
          121 {
          122         Word *w;
          123 
          124         assert("addrules args", head && body);
          125                 /* tuck away first non-meta rule as default target*/
          126         if(target1 == 0 && !(attr&REGEXP)){
          127                 for(w = head; w; w = w->next)
          128                         if(shellt->charin(w->s, "%&"))
          129                                 break;
          130                 if(w == 0)
          131                         target1 = wdup(head);
          132         }
          133         for(w = head; w; w = w->next)
          134                 addrule(w->s, tail, body, head, attr, hline, prog);
          135 }
          136 
          137 static int
          138 rhead(char *line, Word **h, Word **t, int *attr, char **prog)
          139 {
          140         char *p;
          141         char *pp;
          142         int sep;
          143         Rune r;
          144         int n;
          145         Word *w;
          146 
          147         p = shellt->charin(line,":=<");
          148         if(p == 0)
          149                 return('?');
          150         sep = *p;
          151         *p++ = 0;
          152         if(sep == '<' && *p == '|'){
          153                 sep = '|';
          154                 p++;
          155         }
          156         *attr = 0;
          157         *prog = 0;
          158         if(sep == '='){
          159                 pp = shellt->charin(p, shellt->termchars);        /* termchars is shell-dependent */
          160                 if (pp && *pp == '=') {
          161                         while (p != pp) {
          162                                 n = chartorune(&r, p);
          163                                 switch(r)
          164                                 {
          165                                 default:
          166                                         SYNERR(-1);
          167                                         fprint(2, "unknown attribute '%c'\n",*p);
          168                                         Exit();
          169                                 case 'U':
          170                                         *attr = 1;
          171                                         break;
          172                                 }
          173                                 p += n;
          174                         }
          175                         p++;                /* skip trailing '=' */
          176                 }
          177         }
          178         if((sep == ':') && *p && (*p != ' ') && (*p != '\t')){
          179                 while (*p) {
          180                         n = chartorune(&r, p);
          181                         if (r == ':')
          182                                 break;
          183                         p += n;
          184                         switch(r)
          185                         {
          186                         default:
          187                                 SYNERR(-1);
          188                                 fprint(2, "unknown attribute '%c'\n", p[-1]);
          189                                 Exit();
          190                         case 'D':
          191                                 *attr |= DEL;
          192                                 break;
          193                         case 'E':
          194                                 *attr |= NOMINUSE;
          195                                 break;
          196                         case 'n':
          197                                 *attr |= NOVIRT;
          198                                 break;
          199                         case 'N':
          200                                 *attr |= NOREC;
          201                                 break;
          202                         case 'P':
          203                                 pp = utfrune(p, ':');
          204                                 if (pp == 0 || *pp == 0)
          205                                         goto eos;
          206                                 *pp = 0;
          207                                 *prog = strdup(p);
          208                                 *pp = ':';
          209                                 p = pp;
          210                                 break;
          211                         case 'Q':
          212                                 *attr |= QUIET;
          213                                 break;
          214                         case 'R':
          215                                 *attr |= REGEXP;
          216                                 break;
          217                         case 'U':
          218                                 *attr |= UPD;
          219                                 break;
          220                         case 'V':
          221                                 *attr |= VIR;
          222                                 break;
          223                         }
          224                 }
          225                 if (*p++ != ':') {
          226         eos:
          227                         SYNERR(-1);
          228                         fprint(2, "missing trailing :\n");
          229                         Exit();
          230                 }
          231         }
          232         *h = w = stow(line);
          233         if(*w->s == 0 && sep != '<' && sep != '|' && sep != 'S') {
          234                 SYNERR(mkinline-1);
          235                 fprint(2, "no var on left side of assignment/rule\n");
          236                 Exit();
          237         }
          238         *t = stow(p);
          239         return(sep);
          240 }
          241 
          242 static char *
          243 rbody(Biobuf *in)
          244 {
          245         Bufblock *buf;
          246         int r, lastr;
          247         char *p;
          248 
          249         lastr = '\n';
          250         buf = newbuf();
          251         for(;;){
          252                 r = Bgetrune(in);
          253                 if (r < 0)
          254                         break;
          255                 if (lastr == '\n') {
          256                         if (r == '#')
          257                                 rinsert(buf, r);
          258                         else if (r != ' ' && r != '\t') {
          259                                 Bungetrune(in);
          260                                 break;
          261                         }
          262                 } else
          263                         rinsert(buf, r);
          264                 lastr = r;
          265                 if (r == '\n')
          266                         mkinline++;
          267         }
          268         insert(buf, 0);
          269         p = strdup(buf->start);
          270         freebuf(buf);
          271         return p;
          272 }
          273 
          274 struct input
          275 {
          276         char *file;
          277         int line;
          278         struct input *next;
          279 };
          280 static struct input *inputs = 0;
          281 
          282 void
          283 ipush(void)
          284 {
          285         struct input *in, *me;
          286 
          287         me = (struct input *)Malloc(sizeof(*me));
          288         me->file = infile;
          289         me->line = mkinline;
          290         me->next = 0;
          291         if(inputs == 0)
          292                 inputs = me;
          293         else {
          294                 for(in = inputs; in->next; )
          295                         in = in->next;
          296                 in->next = me;
          297         }
          298 }
          299 
          300 void
          301 ipop(void)
          302 {
          303         struct input *in, *me;
          304 
          305         assert("pop input list", inputs != 0);
          306         if(inputs->next == 0){
          307                 me = inputs;
          308                 inputs = 0;
          309         } else {
          310                 for(in = inputs; in->next->next; )
          311                         in = in->next;
          312                 me = in->next;
          313                 in->next = 0;
          314         }
          315         infile = me->file;
          316         mkinline = me->line;
          317         free((char *)me);
          318 }