13e12c5d1SDavid du Colombier #include "mk.h"
23e12c5d1SDavid du Colombier
37dd7cddfSDavid du Colombier static Word *subsub(Word*, char*, char*);
47dd7cddfSDavid du Colombier static Word *expandvar(char**);
57dd7cddfSDavid du Colombier static Bufblock *varname(char**);
67dd7cddfSDavid du Colombier static Word *extractpat(char*, char**, char*, char*);
77dd7cddfSDavid du Colombier static int submatch(char*, Word*, Word*, int*, char**);
8*d3907fe5SDavid du Colombier static Word *varmatch(char *);
93e12c5d1SDavid du Colombier
107dd7cddfSDavid du Colombier Word *
varsub(char ** s)117dd7cddfSDavid du Colombier varsub(char **s)
123e12c5d1SDavid du Colombier {
137dd7cddfSDavid du Colombier Bufblock *b;
143e12c5d1SDavid du Colombier Word *w;
153e12c5d1SDavid du Colombier
167dd7cddfSDavid du Colombier if(**s == '{') /* either ${name} or ${name: A%B==C%D}*/
177dd7cddfSDavid du Colombier return expandvar(s);
187dd7cddfSDavid du Colombier
197dd7cddfSDavid du Colombier b = varname(s);
207dd7cddfSDavid du Colombier if(b == 0)
217dd7cddfSDavid du Colombier return 0;
227dd7cddfSDavid du Colombier
23*d3907fe5SDavid du Colombier w = varmatch(b->start);
247dd7cddfSDavid du Colombier freebuf(b);
257dd7cddfSDavid du Colombier return w;
263e12c5d1SDavid du Colombier }
273e12c5d1SDavid du Colombier
287dd7cddfSDavid du Colombier /*
297dd7cddfSDavid du Colombier * extract a variable name
307dd7cddfSDavid du Colombier */
317dd7cddfSDavid du Colombier static Bufblock*
varname(char ** s)327dd7cddfSDavid du Colombier varname(char **s)
333e12c5d1SDavid du Colombier {
347dd7cddfSDavid du Colombier Bufblock *b;
357dd7cddfSDavid du Colombier char *cp;
363e12c5d1SDavid du Colombier Rune r;
377dd7cddfSDavid du Colombier int n;
383e12c5d1SDavid du Colombier
397dd7cddfSDavid du Colombier b = newbuf();
407dd7cddfSDavid du Colombier cp = *s;
417dd7cddfSDavid du Colombier for(;;){
427dd7cddfSDavid du Colombier n = chartorune(&r, cp);
437dd7cddfSDavid du Colombier if (!WORDCHR(r))
447dd7cddfSDavid du Colombier break;
457dd7cddfSDavid du Colombier rinsert(b, r);
467dd7cddfSDavid du Colombier cp += n;
473e12c5d1SDavid du Colombier }
487dd7cddfSDavid du Colombier if (b->current == b->start){
497dd7cddfSDavid du Colombier SYNERR(-1);
507dd7cddfSDavid du Colombier fprint(2, "missing variable name <%s>\n", *s);
517dd7cddfSDavid du Colombier freebuf(b);
527dd7cddfSDavid du Colombier return 0;
537dd7cddfSDavid du Colombier }
547dd7cddfSDavid du Colombier *s = cp;
557dd7cddfSDavid du Colombier insert(b, 0);
567dd7cddfSDavid du Colombier return b;
577dd7cddfSDavid du Colombier }
587dd7cddfSDavid du Colombier
597dd7cddfSDavid du Colombier static Word*
varmatch(char * name)60*d3907fe5SDavid du Colombier varmatch(char *name)
617dd7cddfSDavid du Colombier {
627dd7cddfSDavid du Colombier Word *w;
637dd7cddfSDavid du Colombier Symtab *sym;
647dd7cddfSDavid du Colombier
657dd7cddfSDavid du Colombier sym = symlook(name, S_VAR, 0);
667dd7cddfSDavid du Colombier if(sym){
677dd7cddfSDavid du Colombier /* check for at least one non-NULL value */
684de34a7eSDavid du Colombier for (w = sym->u.ptr; w; w = w->next)
697dd7cddfSDavid du Colombier if(w->s && *w->s)
707dd7cddfSDavid du Colombier return wdup(w);
717dd7cddfSDavid du Colombier }
727dd7cddfSDavid du Colombier return 0;
737dd7cddfSDavid du Colombier }
747dd7cddfSDavid du Colombier
757dd7cddfSDavid du Colombier static Word*
expandvar(char ** s)767dd7cddfSDavid du Colombier expandvar(char **s)
777dd7cddfSDavid du Colombier {
787dd7cddfSDavid du Colombier Word *w;
797dd7cddfSDavid du Colombier Bufblock *buf;
807dd7cddfSDavid du Colombier Symtab *sym;
817dd7cddfSDavid du Colombier char *cp, *begin, *end;
827dd7cddfSDavid du Colombier
837dd7cddfSDavid du Colombier begin = *s;
847dd7cddfSDavid du Colombier (*s)++; /* skip the '{' */
857dd7cddfSDavid du Colombier buf = varname(s);
867dd7cddfSDavid du Colombier if (buf == 0)
877dd7cddfSDavid du Colombier return 0;
887dd7cddfSDavid du Colombier cp = *s;
897dd7cddfSDavid du Colombier if (*cp == '}') { /* ${name} variant*/
907dd7cddfSDavid du Colombier (*s)++; /* skip the '}' */
91*d3907fe5SDavid du Colombier w = varmatch(buf->start);
927dd7cddfSDavid du Colombier freebuf(buf);
937dd7cddfSDavid du Colombier return w;
947dd7cddfSDavid du Colombier }
957dd7cddfSDavid du Colombier if (*cp != ':') {
967dd7cddfSDavid du Colombier SYNERR(-1);
977dd7cddfSDavid du Colombier fprint(2, "bad variable name <%s>\n", buf->start);
987dd7cddfSDavid du Colombier freebuf(buf);
997dd7cddfSDavid du Colombier return 0;
1007dd7cddfSDavid du Colombier }
1017dd7cddfSDavid du Colombier cp++;
1027dd7cddfSDavid du Colombier end = charin(cp , "}");
1037dd7cddfSDavid du Colombier if(end == 0){
1047dd7cddfSDavid du Colombier SYNERR(-1);
1057dd7cddfSDavid du Colombier fprint(2, "missing '}': %s\n", begin);
1067dd7cddfSDavid du Colombier Exit();
1077dd7cddfSDavid du Colombier }
1087dd7cddfSDavid du Colombier *end = 0;
1097dd7cddfSDavid du Colombier *s = end+1;
1107dd7cddfSDavid du Colombier
1117dd7cddfSDavid du Colombier sym = symlook(buf->start, S_VAR, 0);
1124de34a7eSDavid du Colombier if(sym == 0 || sym->u.value == 0)
1137dd7cddfSDavid du Colombier w = newword(buf->start);
1147dd7cddfSDavid du Colombier else
1154de34a7eSDavid du Colombier w = subsub(sym->u.ptr, cp, end);
1167dd7cddfSDavid du Colombier freebuf(buf);
1177dd7cddfSDavid du Colombier return w;
1187dd7cddfSDavid du Colombier }
1197dd7cddfSDavid du Colombier
1207dd7cddfSDavid du Colombier static Word*
extractpat(char * s,char ** r,char * term,char * end)1217dd7cddfSDavid du Colombier extractpat(char *s, char **r, char *term, char *end)
1227dd7cddfSDavid du Colombier {
1237dd7cddfSDavid du Colombier int save;
1247dd7cddfSDavid du Colombier char *cp;
1257dd7cddfSDavid du Colombier Word *w;
1267dd7cddfSDavid du Colombier
1277dd7cddfSDavid du Colombier cp = charin(s, term);
1287dd7cddfSDavid du Colombier if(cp){
1297dd7cddfSDavid du Colombier *r = cp;
1307dd7cddfSDavid du Colombier if(cp == s)
1317dd7cddfSDavid du Colombier return 0;
1327dd7cddfSDavid du Colombier save = *cp;
1337dd7cddfSDavid du Colombier *cp = 0;
1347dd7cddfSDavid du Colombier w = stow(s);
1357dd7cddfSDavid du Colombier *cp = save;
1367dd7cddfSDavid du Colombier } else {
1377dd7cddfSDavid du Colombier *r = end;
1387dd7cddfSDavid du Colombier w = stow(s);
1397dd7cddfSDavid du Colombier }
1407dd7cddfSDavid du Colombier return w;
1417dd7cddfSDavid du Colombier }
1427dd7cddfSDavid du Colombier
1437dd7cddfSDavid du Colombier static Word*
subsub(Word * v,char * s,char * end)1447dd7cddfSDavid du Colombier subsub(Word *v, char *s, char *end)
1457dd7cddfSDavid du Colombier {
1467dd7cddfSDavid du Colombier int nmid;
1477dd7cddfSDavid du Colombier Word *head, *tail, *w, *h;
1487dd7cddfSDavid du Colombier Word *a, *b, *c, *d;
1497dd7cddfSDavid du Colombier Bufblock *buf;
1507dd7cddfSDavid du Colombier char *cp, *enda;
1517dd7cddfSDavid du Colombier
1527dd7cddfSDavid du Colombier a = extractpat(s, &cp, "=%&", end);
1537dd7cddfSDavid du Colombier b = c = d = 0;
1547dd7cddfSDavid du Colombier if(PERCENT(*cp))
1557dd7cddfSDavid du Colombier b = extractpat(cp+1, &cp, "=", end);
1567dd7cddfSDavid du Colombier if(*cp == '=')
1577dd7cddfSDavid du Colombier c = extractpat(cp+1, &cp, "&%", end);
1587dd7cddfSDavid du Colombier if(PERCENT(*cp))
1597dd7cddfSDavid du Colombier d = stow(cp+1);
1607dd7cddfSDavid du Colombier else if(*cp)
1617dd7cddfSDavid du Colombier d = stow(cp);
1627dd7cddfSDavid du Colombier
1637dd7cddfSDavid du Colombier head = tail = 0;
1647dd7cddfSDavid du Colombier buf = newbuf();
1657dd7cddfSDavid du Colombier for(; v; v = v->next){
1667dd7cddfSDavid du Colombier h = w = 0;
1677dd7cddfSDavid du Colombier if(submatch(v->s, a, b, &nmid, &enda)){
1687dd7cddfSDavid du Colombier /* enda points to end of A match in source;
1697dd7cddfSDavid du Colombier * nmid = number of chars between end of A and start of B
1707dd7cddfSDavid du Colombier */
1717dd7cddfSDavid du Colombier if(c){
1727dd7cddfSDavid du Colombier h = w = wdup(c);
1737dd7cddfSDavid du Colombier while(w->next)
1747dd7cddfSDavid du Colombier w = w->next;
1757dd7cddfSDavid du Colombier }
1767dd7cddfSDavid du Colombier if(PERCENT(*cp) && nmid > 0){
1777dd7cddfSDavid du Colombier if(w){
1787dd7cddfSDavid du Colombier bufcpy(buf, w->s, strlen(w->s));
1797dd7cddfSDavid du Colombier bufcpy(buf, enda, nmid);
1807dd7cddfSDavid du Colombier insert(buf, 0);
1817dd7cddfSDavid du Colombier free(w->s);
1827dd7cddfSDavid du Colombier w->s = strdup(buf->start);
1837dd7cddfSDavid du Colombier } else {
1847dd7cddfSDavid du Colombier bufcpy(buf, enda, nmid);
1857dd7cddfSDavid du Colombier insert(buf, 0);
1867dd7cddfSDavid du Colombier h = w = newword(buf->start);
1877dd7cddfSDavid du Colombier }
1887dd7cddfSDavid du Colombier buf->current = buf->start;
1897dd7cddfSDavid du Colombier }
1907dd7cddfSDavid du Colombier if(d && *d->s){
1917dd7cddfSDavid du Colombier if(w){
1927dd7cddfSDavid du Colombier
1937dd7cddfSDavid du Colombier bufcpy(buf, w->s, strlen(w->s));
1947dd7cddfSDavid du Colombier bufcpy(buf, d->s, strlen(d->s));
1957dd7cddfSDavid du Colombier insert(buf, 0);
1967dd7cddfSDavid du Colombier free(w->s);
1977dd7cddfSDavid du Colombier w->s = strdup(buf->start);
1987dd7cddfSDavid du Colombier w->next = wdup(d->next);
1997dd7cddfSDavid du Colombier while(w->next)
2007dd7cddfSDavid du Colombier w = w->next;
2017dd7cddfSDavid du Colombier buf->current = buf->start;
2027dd7cddfSDavid du Colombier } else
2037dd7cddfSDavid du Colombier h = w = wdup(d);
2047dd7cddfSDavid du Colombier }
2057dd7cddfSDavid du Colombier }
2067dd7cddfSDavid du Colombier if(w == 0)
2077dd7cddfSDavid du Colombier h = w = newword(v->s);
2087dd7cddfSDavid du Colombier
2097dd7cddfSDavid du Colombier if(head == 0)
2107dd7cddfSDavid du Colombier head = h;
2117dd7cddfSDavid du Colombier else
2127dd7cddfSDavid du Colombier tail->next = h;
2137dd7cddfSDavid du Colombier tail = w;
2147dd7cddfSDavid du Colombier }
2157dd7cddfSDavid du Colombier freebuf(buf);
2167dd7cddfSDavid du Colombier delword(a);
2177dd7cddfSDavid du Colombier delword(b);
2187dd7cddfSDavid du Colombier delword(c);
2197dd7cddfSDavid du Colombier delword(d);
2207dd7cddfSDavid du Colombier return head;
2217dd7cddfSDavid du Colombier }
2227dd7cddfSDavid du Colombier
2237dd7cddfSDavid du Colombier static int
submatch(char * s,Word * a,Word * b,int * nmid,char ** enda)2247dd7cddfSDavid du Colombier submatch(char *s, Word *a, Word *b, int *nmid, char **enda)
2257dd7cddfSDavid du Colombier {
2267dd7cddfSDavid du Colombier Word *w;
2277dd7cddfSDavid du Colombier int n;
2287dd7cddfSDavid du Colombier char *end;
2297dd7cddfSDavid du Colombier
2307dd7cddfSDavid du Colombier n = 0;
2317dd7cddfSDavid du Colombier for(w = a; w; w = w->next){
2327dd7cddfSDavid du Colombier n = strlen(w->s);
2337dd7cddfSDavid du Colombier if(strncmp(s, w->s, n) == 0)
2347dd7cddfSDavid du Colombier break;
2357dd7cddfSDavid du Colombier }
2367dd7cddfSDavid du Colombier if(a && w == 0) /* a == NULL matches everything*/
2377dd7cddfSDavid du Colombier return 0;
2387dd7cddfSDavid du Colombier
2397dd7cddfSDavid du Colombier *enda = s+n; /* pointer to end a A part match */
2407dd7cddfSDavid du Colombier *nmid = strlen(s)-n; /* size of remainder of source */
2417dd7cddfSDavid du Colombier end = *enda+*nmid;
2427dd7cddfSDavid du Colombier for(w = b; w; w = w->next){
2437dd7cddfSDavid du Colombier n = strlen(w->s);
2447dd7cddfSDavid du Colombier if(strcmp(w->s, end-n) == 0){
2457dd7cddfSDavid du Colombier *nmid -= n;
2467dd7cddfSDavid du Colombier break;
2477dd7cddfSDavid du Colombier }
2487dd7cddfSDavid du Colombier }
2497dd7cddfSDavid du Colombier if(b && w == 0) /* b == NULL matches everything */
2507dd7cddfSDavid du Colombier return 0;
2517dd7cddfSDavid du Colombier return 1;
2523e12c5d1SDavid du Colombier }
253