123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- #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 *, 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, s);
- 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, char **s)
- {
- Word *w;
- Symtab *sym;
- char *cp;
-
- sym = symlook(name, S_VAR, 0);
- if(sym){
- /* check for at least one non-NULL value */
- for (w = (Word*)sym->value; w; w = w->next)
- if(w->s && *w->s)
- return wdup(w);
- }
- for(cp = *s; *cp == ' ' || *cp == '\t'; cp++) /* skip trailing whitespace */
- ;
- *s = cp;
- 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;
- }
- static Word*
- extractpat(char *s, char **r, char *term, char *end)
- {
- int save;
- char *cp;
- Word *w;
- cp = 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;
- }
|