| #include "mk.h" |
| |
| char *infile; |
| int mkinline; |
| static int rhead(char *, Word **, Word **, int *, char **); |
| static char *rbody(Biobuf*); |
| extern Word *target1; |
| |
| void |
| parse(char *f, int fd, int varoverride) |
| { |
| int hline; |
| char *body; |
| Word *head, *tail; |
| int attr, set, pid; |
| char *prog, *p; |
| int newfd; |
| Biobuf in; |
| Bufblock *buf; |
| char *err; |
| |
| if(fd < 0){ |
| fprint(2, "open %s: %r\n", f); |
| Exit(); |
| } |
| pushshell(); |
| ipush(); |
| infile = strdup(f); |
| mkinline = 1; |
| Binit(&in, fd, OREAD); |
| buf = newbuf(); |
| while(assline(&in, buf)){ |
| hline = mkinline; |
| switch(rhead(buf->start, &head, &tail, &attr, &prog)) |
| { |
| case '<': |
| p = wtos(tail, ' '); |
| if(*p == 0){ |
| SYNERR(-1); |
| fprint(2, "missing include file name\n"); |
| Exit(); |
| } |
| newfd = open(p, OREAD); |
| if(newfd < 0){ |
| fprint(2, "warning: skipping missing include file %s: %r\n", p); |
| } else |
| parse(p, newfd, 0); |
| break; |
| case '|': |
| p = wtos(tail, ' '); |
| if(*p == 0){ |
| SYNERR(-1); |
| fprint(2, "missing include program name\n"); |
| Exit(); |
| } |
| execinit(); |
| pid=pipecmd(p, envy, &newfd, shellt, shellcmd); |
| if(newfd < 0){ |
| fprint(2, "warning: skipping missing program file %s: %r\n", p); |
| } else |
| parse(p, newfd, 0); |
| while(waitup(-3, &pid) >= 0) |
| ; |
| if(pid != 0){ |
| fprint(2, "bad include program status\n"); |
| Exit(); |
| } |
| break; |
| case ':': |
| body = rbody(&in); |
| addrules(head, tail, body, attr, hline, prog); |
| break; |
| case '=': |
| if(head->next){ |
| SYNERR(-1); |
| fprint(2, "multiple vars on left side of assignment\n"); |
| Exit(); |
| } |
| if(symlook(head->s, S_OVERRIDE, 0)){ |
| set = varoverride; |
| } else { |
| set = 1; |
| if(varoverride) |
| symlook(head->s, S_OVERRIDE, (void *)""); |
| } |
| if(set){ |
| /* |
| char *cp; |
| dumpw("tail", tail); |
| cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp); |
| */ |
| setvar(head->s, (void *) tail); |
| symlook(head->s, S_WESET, (void *)""); |
| if(strcmp(head->s, "MKSHELL") == 0){ |
| if((err = setshell(tail)) != nil){ |
| SYNERR(hline); |
| fprint(2, "%s\n", err); |
| Exit(); |
| break; |
| } |
| } |
| } |
| if(attr) |
| symlook(head->s, S_NOEXPORT, (void *)""); |
| break; |
| default: |
| SYNERR(hline); |
| fprint(2, "expected one of :<=\n"); |
| Exit(); |
| break; |
| } |
| } |
| close(fd); |
| freebuf(buf); |
| ipop(); |
| popshell(); |
| } |
| |
| void |
| addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog) |
| { |
| Word *w; |
| |
| assert("addrules args", head && body); |
| /* tuck away first non-meta rule as default target*/ |
| if(target1 == 0 && !(attr®EXP)){ |
| for(w = head; w; w = w->next) |
| if(shellt->charin(w->s, "%&")) |
| break; |
| if(w == 0) |
| target1 = wdup(head); |
| } |
| for(w = head; w; w = w->next) |
| addrule(w->s, tail, body, head, attr, hline, prog); |
| } |
| |
| static int |
| rhead(char *line, Word **h, Word **t, int *attr, char **prog) |
| { |
| char *p; |
| char *pp; |
| int sep; |
| Rune r; |
| int n; |
| Word *w; |
| |
| p = shellt->charin(line,":=<"); |
| if(p == 0) |
| return('?'); |
| sep = *p; |
| *p++ = 0; |
| if(sep == '<' && *p == '|'){ |
| sep = '|'; |
| p++; |
| } |
| *attr = 0; |
| *prog = 0; |
| if(sep == '='){ |
| pp = shellt->charin(p, shellt->termchars); /* termchars is shell-dependent */ |
| if (pp && *pp == '=') { |
| while (p != pp) { |
| n = chartorune(&r, p); |
| switch(r) |
| { |
| default: |
| SYNERR(-1); |
| fprint(2, "unknown attribute '%c'\n",*p); |
| Exit(); |
| case 'U': |
| *attr = 1; |
| break; |
| } |
| p += n; |
| } |
| p++; /* skip trailing '=' */ |
| } |
| } |
| if((sep == ':') && *p && (*p != ' ') && (*p != '\t')){ |
| while (*p) { |
| n = chartorune(&r, p); |
| if (r == ':') |
| break; |
| p += n; |
| switch(r) |
| { |
| default: |
| SYNERR(-1); |
| fprint(2, "unknown attribute '%c'\n", p[-1]); |
| Exit(); |
| case 'D': |
| *attr |= DEL; |
| break; |
| case 'E': |
| *attr |= NOMINUSE; |
| break; |
| case 'n': |
| *attr |= NOVIRT; |
| break; |
| case 'N': |
| *attr |= NOREC; |
| break; |
| case 'P': |
| pp = utfrune(p, ':'); |
| if (pp == 0 || *pp == 0) |
| goto eos; |
| *pp = 0; |
| *prog = strdup(p); |
| *pp = ':'; |
| p = pp; |
| break; |
| case 'Q': |
| *attr |= QUIET; |
| break; |
| case 'R': |
| *attr |= REGEXP; |
| break; |
| case 'U': |
| *attr |= UPD; |
| break; |
| case 'V': |
| *attr |= VIR; |
| break; |
| } |
| } |
| if (*p++ != ':') { |
| eos: |
| SYNERR(-1); |
| fprint(2, "missing trailing :\n"); |
| Exit(); |
| } |
| } |
| *h = w = stow(line); |
| if(*w->s == 0 && sep != '<' && sep != '|' && sep != 'S') { |
| SYNERR(mkinline-1); |
| fprint(2, "no var on left side of assignment/rule\n"); |
| Exit(); |
| } |
| *t = stow(p); |
| return(sep); |
| } |
| |
| static char * |
| rbody(Biobuf *in) |
| { |
| Bufblock *buf; |
| int r, lastr; |
| char *p; |
| |
| lastr = '\n'; |
| buf = newbuf(); |
| for(;;){ |
| r = Bgetrune(in); |
| if (r < 0) |
| break; |
| if (lastr == '\n') { |
| if (r == '#') |
| rinsert(buf, r); |
| else if (r != ' ' && r != '\t') { |
| Bungetrune(in); |
| break; |
| } |
| } else |
| rinsert(buf, r); |
| lastr = r; |
| if (r == '\n') |
| mkinline++; |
| } |
| insert(buf, 0); |
| p = strdup(buf->start); |
| freebuf(buf); |
| return p; |
| } |
| |
| struct input |
| { |
| char *file; |
| int line; |
| struct input *next; |
| }; |
| static struct input *inputs = 0; |
| |
| void |
| ipush(void) |
| { |
| struct input *in, *me; |
| |
| me = (struct input *)Malloc(sizeof(*me)); |
| me->file = infile; |
| me->line = mkinline; |
| me->next = 0; |
| if(inputs == 0) |
| inputs = me; |
| else { |
| for(in = inputs; in->next; ) |
| in = in->next; |
| in->next = me; |
| } |
| } |
| |
| void |
| ipop(void) |
| { |
| struct input *in, *me; |
| |
| assert("pop input list", inputs != 0); |
| if(inputs->next == 0){ |
| me = inputs; |
| inputs = 0; |
| } else { |
| for(in = inputs; in->next->next; ) |
| in = in->next; |
| me = in->next; |
| in->next = 0; |
| } |
| infile = me->file; |
| mkinline = me->line; |
| free((char *)me); |
| } |