|  | #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); | 
|  | } |