/* * extract a variable name */ static Bufblock* varname(char **s) { Bufblock *b; char *cp; Rune r; int n; b = newbuf(); cp = *s; for(;;){ n = chartorune(&r, cp); if (!WORDCHR(r)) break; rinsert(b, r); cp += n; } if (b->current == b->start){ SYNERR(-1); fprint(2, "missing variable name <%s>\n", *s); freebuf(b); return 0; } *s = cp; insert(b, 0); return b; }
/* * Input an escaped token. Possible escape chars are single-quote, * double-quote and backslash. Only the first is a valid escape for * rc; the others are just inserted into the receiving buffer. */ int escapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc) { int c, line; if(esc != '\'') return 1; line = mkinline; while((c = nextrune(bp, 0)) > 0){ if(c == '\''){ if(preserve) rinsert(buf, c); c = Bgetrune(bp); if (c < 0) break; if(c != '\''){ Bungetrune(bp); return 1; } } rinsert(buf, c); } SYNERR(line); fprint(2, "missing closing %c\n", esc); return 0; }
static Word* expandvar(char **s) { Word *w; Bufblock *buf; Symtab *sym; char *cp, *begin, *end; begin = *s; (*s)++; /* skip the '{' */ buf = varname(s); if (buf == 0) return 0; cp = *s; if (*cp == '}') { /* ${name} variant*/ (*s)++; /* skip the '}' */ w = varmatch(buf->start, s); freebuf(buf); return w; } if (*cp != ':') { SYNERR(-1); fprint(2, "bad variable name <%s>\n", buf->start); freebuf(buf); return 0; } cp++; end = charin(cp , "}"); if(end == 0){ SYNERR(-1); fprint(2, "missing '}': %s\n", begin); Exit(); } *end = 0; *s = end+1; sym = symlook(buf->start, S_VAR, 0); if(sym == 0 || sym->value == 0) w = newword(buf->start); else w = subsub((Word*) sym->value, cp, end); freebuf(buf); return w; }
/* * skip a token in quotes. */ static char * squote(char *cp, int c) { Rune r; int n; while(*cp){ n = chartorune(&r, cp); if(r == c) return cp; if(r == '\\') n += chartorune(&r, cp+n); cp += n; } SYNERR(-1); /* should never occur */ fprint(2, "missing closing '\n"); return 0; }
/* * search a string for unescaped characters in a pattern set */ static char * shcharin(char *cp, char *pat) { Rune r; int n, vargen; vargen = 0; while(*cp){ n = chartorune(&r, cp); switch(r){ case '\\': /* skip escaped char */ cp += n; n = chartorune(&r, cp); break; case '\'': /* skip quoted string */ case '"': cp = squote(cp+1, r); /* n must = 1 */ if(!cp) return 0; break; case '$': if(*(cp+1) == '{') vargen = 1; break; case '}': if(vargen) vargen = 0; else if(utfrune(pat, r)) return cp; break; default: if(vargen == 0 && utfrune(pat, r)) return cp; break; } cp += n; } if(vargen){ SYNERR(-1); fprint(2, "missing closing } in pattern generator\n"); } return 0; }
/* * assemble a back-quoted shell command into a buffer */ static int bquote(Biobuf *bp, Bufblock *buf) { int c, line, term, depth; int start; line = mkinline; while((c = Bgetrune(bp)) == ' ' || c == '\t') ; if(c == '{'){ term = '}'; /* rc style */ while((c = Bgetrune(bp)) == ' ' || c == '\t') ; } else term = '`'; /* sh style */ depth = 1; start = buf->current-buf->start; for(;c > 0; c = nextrune(bp, 0)){ if(c == '{' && term == '}') depth++; if(c == term && --depth == 0){ insert(buf, '\n'); insert(buf,0); buf->current = buf->start+start; execinit(); execsh(0, buf->current, buf, envy); return 1; } if(c == '\n') break; if(c == '\'' || c == '"' || c == '\\'){ insert(buf, c); if(!escapetoken(bp, buf, 1, c)) return 0; continue; } rinsert(buf, c); } SYNERR(line); fprint(2, "missing closing %c after `\n", term); return 0; }
/* * Input an escaped token. Possible escape chars are single-quote, * double-quote and backslash. */ static int shescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc) { int c, line; if(esc == '\\') { c = Bgetrune(bp); if(c == '\r') c = Bgetrune(bp); if (c == '\n') mkinline++; rinsert(buf, c); return 1; } line = mkinline; while((c = nextrune(bp, 0)) >= 0){ if(c == esc){ if(preserve) rinsert(buf, c); return 1; } if(c == '\\') { rinsert(buf, c); c = Bgetrune(bp); if(c == '\r') c = Bgetrune(bp); if (c < 0) break; if (c == '\n') mkinline++; } rinsert(buf, c); } SYNERR(line); fprint(2, "missing closing %c\n", esc); return 0; }
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; if(fd < 0) { perror(f); Exit(); } 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: "); perror(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); if(newfd < 0) { fprint(2, "warning: skipping missing program file: "); perror(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(attr) symlook(head->s, S_NOEXPORT, (void *)""); break; default: SYNERR(hline); fprint(2, "expected one of :<=\n"); Exit(); break; } } close(fd); freebuf(buf); ipop(); }
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 = charin(line,":=<"); if(p == 0) return('?'); sep = *p; *p++ = 0; if(sep == '<' && *p == '|') { sep = '|'; p++; } *attr = 0; *prog = 0; if(sep == '=') { pp = charin(p, 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 != '|') { SYNERR(mkinline-1); fprint(2, "no var on left side of assignment/rule\n"); Exit(); } *t = stow(p); return(sep); }