xref: /plan9/sys/src/cmd/mk/varsub.c (revision d3907fe5a68251e8b016f54f72acf8767ba044bb)
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