xref: /plan9/sys/src/cmd/mk/varsub.c (revision d3907fe5a68251e8b016f54f72acf8767ba044bb)
1 #include	"mk.h"
2 
3 static	Word		*subsub(Word*, char*, char*);
4 static	Word		*expandvar(char**);
5 static	Bufblock	*varname(char**);
6 static	Word		*extractpat(char*, char**, char*, char*);
7 static	int		submatch(char*, Word*, Word*, int*, char**);
8 static	Word		*varmatch(char *);
9 
10 Word *
varsub(char ** s)11 varsub(char **s)
12 {
13 	Bufblock *b;
14 	Word *w;
15 
16 	if(**s == '{')		/* either ${name} or ${name: A%B==C%D}*/
17 		return expandvar(s);
18 
19 	b = varname(s);
20 	if(b == 0)
21 		return 0;
22 
23 	w = varmatch(b->start);
24 	freebuf(b);
25 	return w;
26 }
27 
28 /*
29  *	extract a variable name
30  */
31 static Bufblock*
varname(char ** s)32 varname(char **s)
33 {
34 	Bufblock *b;
35 	char *cp;
36 	Rune r;
37 	int n;
38 
39 	b = newbuf();
40 	cp = *s;
41 	for(;;){
42 		n = chartorune(&r, cp);
43 		if (!WORDCHR(r))
44 			break;
45 		rinsert(b, r);
46 		cp += n;
47 	}
48 	if (b->current == b->start){
49 		SYNERR(-1);
50 		fprint(2, "missing variable name <%s>\n", *s);
51 		freebuf(b);
52 		return 0;
53 	}
54 	*s = cp;
55 	insert(b, 0);
56 	return b;
57 }
58 
59 static Word*
varmatch(char * name)60 varmatch(char *name)
61 {
62 	Word *w;
63 	Symtab *sym;
64 
65 	sym = symlook(name, S_VAR, 0);
66 	if(sym){
67 			/* check for at least one non-NULL value */
68 		for (w = sym->u.ptr; w; w = w->next)
69 			if(w->s && *w->s)
70 				return wdup(w);
71 	}
72 	return 0;
73 }
74 
75 static Word*
expandvar(char ** s)76 expandvar(char **s)
77 {
78 	Word *w;
79 	Bufblock *buf;
80 	Symtab *sym;
81 	char *cp, *begin, *end;
82 
83 	begin = *s;
84 	(*s)++;						/* skip the '{' */
85 	buf = varname(s);
86 	if (buf == 0)
87 		return 0;
88 	cp = *s;
89 	if (*cp == '}') {				/* ${name} variant*/
90 		(*s)++;					/* skip the '}' */
91 		w = varmatch(buf->start);
92 		freebuf(buf);
93 		return w;
94 	}
95 	if (*cp != ':') {
96 		SYNERR(-1);
97 		fprint(2, "bad variable name <%s>\n", buf->start);
98 		freebuf(buf);
99 		return 0;
100 	}
101 	cp++;
102 	end = charin(cp , "}");
103 	if(end == 0){
104 		SYNERR(-1);
105 		fprint(2, "missing '}': %s\n", begin);
106 		Exit();
107 	}
108 	*end = 0;
109 	*s = end+1;
110 
111 	sym = symlook(buf->start, S_VAR, 0);
112 	if(sym == 0 || sym->u.value == 0)
113 		w = newword(buf->start);
114 	else
115 		w = subsub(sym->u.ptr, cp, end);
116 	freebuf(buf);
117 	return w;
118 }
119 
120 static Word*
extractpat(char * s,char ** r,char * term,char * end)121 extractpat(char *s, char **r, char *term, char *end)
122 {
123 	int save;
124 	char *cp;
125 	Word *w;
126 
127 	cp = charin(s, term);
128 	if(cp){
129 		*r = cp;
130 		if(cp == s)
131 			return 0;
132 		save = *cp;
133 		*cp = 0;
134 		w = stow(s);
135 		*cp = save;
136 	} else {
137 		*r = end;
138 		w = stow(s);
139 	}
140 	return w;
141 }
142 
143 static Word*
subsub(Word * v,char * s,char * end)144 subsub(Word *v, char *s, char *end)
145 {
146 	int nmid;
147 	Word *head, *tail, *w, *h;
148 	Word *a, *b, *c, *d;
149 	Bufblock *buf;
150 	char *cp, *enda;
151 
152 	a = extractpat(s, &cp, "=%&", end);
153 	b = c = d = 0;
154 	if(PERCENT(*cp))
155 		b = extractpat(cp+1, &cp, "=", end);
156 	if(*cp == '=')
157 		c = extractpat(cp+1, &cp, "&%", end);
158 	if(PERCENT(*cp))
159 		d = stow(cp+1);
160 	else if(*cp)
161 		d = stow(cp);
162 
163 	head = tail = 0;
164 	buf = newbuf();
165 	for(; v; v = v->next){
166 		h = w = 0;
167 		if(submatch(v->s, a, b, &nmid, &enda)){
168 			/* enda points to end of A match in source;
169 			 * nmid = number of chars between end of A and start of B
170 			 */
171 			if(c){
172 				h = w = wdup(c);
173 				while(w->next)
174 					w = w->next;
175 			}
176 			if(PERCENT(*cp) && nmid > 0){
177 				if(w){
178 					bufcpy(buf, w->s, strlen(w->s));
179 					bufcpy(buf, enda, nmid);
180 					insert(buf, 0);
181 					free(w->s);
182 					w->s = strdup(buf->start);
183 				} else {
184 					bufcpy(buf, enda, nmid);
185 					insert(buf, 0);
186 					h = w = newword(buf->start);
187 				}
188 				buf->current = buf->start;
189 			}
190 			if(d && *d->s){
191 				if(w){
192 
193 					bufcpy(buf, w->s, strlen(w->s));
194 					bufcpy(buf, d->s, strlen(d->s));
195 					insert(buf, 0);
196 					free(w->s);
197 					w->s = strdup(buf->start);
198 					w->next = wdup(d->next);
199 					while(w->next)
200 						w = w->next;
201 					buf->current = buf->start;
202 				} else
203 					h = w = wdup(d);
204 			}
205 		}
206 		if(w == 0)
207 			h = w = newword(v->s);
208 
209 		if(head == 0)
210 			head = h;
211 		else
212 			tail->next = h;
213 		tail = w;
214 	}
215 	freebuf(buf);
216 	delword(a);
217 	delword(b);
218 	delword(c);
219 	delword(d);
220 	return head;
221 }
222 
223 static int
submatch(char * s,Word * a,Word * b,int * nmid,char ** enda)224 submatch(char *s, Word *a, Word *b, int *nmid, char **enda)
225 {
226 	Word *w;
227 	int n;
228 	char *end;
229 
230 	n = 0;
231 	for(w = a; w; w = w->next){
232 		n = strlen(w->s);
233 		if(strncmp(s, w->s, n) == 0)
234 			break;
235 	}
236 	if(a && w == 0)		/*  a == NULL matches everything*/
237 		return 0;
238 
239 	*enda = s+n;		/* pointer to end a A part match */
240 	*nmid = strlen(s)-n;	/* size of remainder of source */
241 	end = *enda+*nmid;
242 	for(w = b; w; w = w->next){
243 		n = strlen(w->s);
244 		if(strcmp(w->s, end-n) == 0){
245 			*nmid -= n;
246 			break;
247 		}
248 	}
249 	if(b && w == 0)		/* b == NULL matches everything */
250 		return 0;
251 	return 1;
252 }
253