| #include "mk.h" |
| |
| static Word *subsub(Word*, char*, char*); |
| static Word *expandvar(char**); |
| static Bufblock *varname(char**); |
| static Word *extractpat(char*, char**, char*, char*); |
| static int submatch(char*, Word*, Word*, int*, char**); |
| static Word *varmatch(char *); |
| |
| Word * |
| varsub(char **s) |
| { |
| Bufblock *b; |
| Word *w; |
| |
| if(**s == '{') /* either ${name} or ${name: A%B==C%D}*/ |
| return expandvar(s); |
| |
| b = varname(s); |
| if(b == 0) |
| return 0; |
| |
| w = varmatch(b->start); |
| freebuf(b); |
| return w; |
| } |
| |
| /* |
| * 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; |
| } |
| |
| static Word* |
| varmatch(char *name) |
| { |
| Word *w; |
| Symtab *sym; |
| |
| sym = symlook(name, S_VAR, 0); |
| if(sym){ |
| /* check for at least one non-NULL value */ |
| for (w = sym->u.ptr; w; w = w->next) |
| if(w->s && *w->s) |
| return wdup(w); |
| } |
| 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); |
| freebuf(buf); |
| return w; |
| } |
| if (*cp != ':') { |
| SYNERR(-1); |
| fprint(2, "bad variable name <%s>\n", buf->start); |
| freebuf(buf); |
| return 0; |
| } |
| cp++; |
| end = shellt->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->u.ptr == 0) |
| w = newword(buf->start); |
| else |
| w = subsub(sym->u.ptr, cp, end); |
| freebuf(buf); |
| return w; |
| } |
| |
| static Word* |
| extractpat(char *s, char **r, char *term, char *end) |
| { |
| int save; |
| char *cp; |
| Word *w; |
| |
| cp = shellt->charin(s, term); |
| if(cp){ |
| *r = cp; |
| if(cp == s) |
| return 0; |
| save = *cp; |
| *cp = 0; |
| w = stow(s); |
| *cp = save; |
| } else { |
| *r = end; |
| w = stow(s); |
| } |
| return w; |
| } |
| |
| static Word* |
| subsub(Word *v, char *s, char *end) |
| { |
| int nmid; |
| Word *head, *tail, *w, *h; |
| Word *a, *b, *c, *d; |
| Bufblock *buf; |
| char *cp, *enda; |
| |
| a = extractpat(s, &cp, "=%&", end); |
| b = c = d = 0; |
| if(PERCENT(*cp)) |
| b = extractpat(cp+1, &cp, "=", end); |
| if(*cp == '=') |
| c = extractpat(cp+1, &cp, "&%", end); |
| if(PERCENT(*cp)) |
| d = stow(cp+1); |
| else if(*cp) |
| d = stow(cp); |
| |
| head = tail = 0; |
| buf = newbuf(); |
| for(; v; v = v->next){ |
| h = w = 0; |
| if(submatch(v->s, a, b, &nmid, &enda)){ |
| /* enda points to end of A match in source; |
| * nmid = number of chars between end of A and start of B |
| */ |
| if(c){ |
| h = w = wdup(c); |
| while(w->next) |
| w = w->next; |
| } |
| if(PERCENT(*cp) && nmid > 0){ |
| if(w){ |
| bufcpy(buf, w->s, strlen(w->s)); |
| bufcpy(buf, enda, nmid); |
| insert(buf, 0); |
| free(w->s); |
| w->s = strdup(buf->start); |
| } else { |
| bufcpy(buf, enda, nmid); |
| insert(buf, 0); |
| h = w = newword(buf->start); |
| } |
| buf->current = buf->start; |
| } |
| if(d && *d->s){ |
| if(w){ |
| |
| bufcpy(buf, w->s, strlen(w->s)); |
| bufcpy(buf, d->s, strlen(d->s)); |
| insert(buf, 0); |
| free(w->s); |
| w->s = strdup(buf->start); |
| w->next = wdup(d->next); |
| while(w->next) |
| w = w->next; |
| buf->current = buf->start; |
| } else |
| h = w = wdup(d); |
| } |
| } |
| if(w == 0) |
| h = w = newword(v->s); |
| |
| if(head == 0) |
| head = h; |
| else |
| tail->next = h; |
| tail = w; |
| } |
| freebuf(buf); |
| delword(a); |
| delword(b); |
| delword(c); |
| delword(d); |
| return head; |
| } |
| |
| static int |
| submatch(char *s, Word *a, Word *b, int *nmid, char **enda) |
| { |
| Word *w; |
| int n; |
| char *end; |
| |
| n = 0; |
| for(w = a; w; w = w->next){ |
| n = strlen(w->s); |
| if(strncmp(s, w->s, n) == 0) |
| break; |
| } |
| if(a && w == 0) /* a == NULL matches everything*/ |
| return 0; |
| |
| *enda = s+n; /* pointer to end a A part match */ |
| *nmid = strlen(s)-n; /* size of remainder of source */ |
| end = *enda+*nmid; |
| for(w = b; w; w = w->next){ |
| n = strlen(w->s); |
| if(strcmp(w->s, end-n) == 0){ |
| *nmid -= n; |
| break; |
| } |
| } |
| if(b && w == 0) /* b == NULL matches everything */ |
| return 0; |
| return 1; |
| } |