Blob


1 #include "mk.h"
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 *, char**);
10 Word *
11 varsub(char **s)
12 {
13 Bufblock *b;
14 Word *w;
16 if(**s == '{') /* either ${name} or ${name: A%B==C%D}*/
17 return expandvar(s);
19 b = varname(s);
20 if(b == 0)
21 return 0;
23 w = varmatch(b->start, s);
24 freebuf(b);
25 return w;
26 }
28 /*
29 * extract a variable name
30 */
31 static Bufblock*
32 varname(char **s)
33 {
34 Bufblock *b;
35 char *cp;
36 Rune r;
37 int n;
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 }
59 static Word*
60 varmatch(char *name, char **s)
61 {
62 Word *w;
63 Symtab *sym;
64 char *cp;
66 sym = symlook(name, S_VAR, 0);
67 if(sym){
68 /* check for at least one non-NULL value */
69 for (w = (Word*)sym->value; w; w = w->next)
70 if(w->s && *w->s)
71 return wdup(w);
72 }
73 for(cp = *s; *cp == ' ' || *cp == '\t'; cp++) /* skip trailing whitespace */
74 ;
75 *s = cp;
76 return 0;
77 }
79 static Word*
80 expandvar(char **s)
81 {
82 Word *w;
83 Bufblock *buf;
84 Symtab *sym;
85 char *cp, *begin, *end;
87 begin = *s;
88 (*s)++; /* skip the '{' */
89 buf = varname(s);
90 if (buf == 0)
91 return 0;
92 cp = *s;
93 if (*cp == '}') { /* ${name} variant*/
94 (*s)++; /* skip the '}' */
95 w = varmatch(buf->start, s);
96 freebuf(buf);
97 return w;
98 }
99 if (*cp != ':') {
100 SYNERR(-1);
101 fprint(2, "bad variable name <%s>\n", buf->start);
102 freebuf(buf);
103 return 0;
105 cp++;
106 end = shellt->charin(cp , "}");
107 if(end == 0){
108 SYNERR(-1);
109 fprint(2, "missing '}': %s\n", begin);
110 Exit();
112 *end = 0;
113 *s = end+1;
115 sym = symlook(buf->start, S_VAR, 0);
116 if(sym == 0 || sym->value == 0)
117 w = newword(buf->start);
118 else
119 w = subsub((Word*) sym->value, cp, end);
120 freebuf(buf);
121 return w;
124 static Word*
125 extractpat(char *s, char **r, char *term, char *end)
127 int save;
128 char *cp;
129 Word *w;
131 cp = shellt->charin(s, term);
132 if(cp){
133 *r = cp;
134 if(cp == s)
135 return 0;
136 save = *cp;
137 *cp = 0;
138 w = stow(s);
139 *cp = save;
140 } else {
141 *r = end;
142 w = stow(s);
144 return w;
147 static Word*
148 subsub(Word *v, char *s, char *end)
150 int nmid;
151 Word *head, *tail, *w, *h;
152 Word *a, *b, *c, *d;
153 Bufblock *buf;
154 char *cp, *enda;
156 a = extractpat(s, &cp, "=%&", end);
157 b = c = d = 0;
158 if(PERCENT(*cp))
159 b = extractpat(cp+1, &cp, "=", end);
160 if(*cp == '=')
161 c = extractpat(cp+1, &cp, "&%", end);
162 if(PERCENT(*cp))
163 d = stow(cp+1);
164 else if(*cp)
165 d = stow(cp);
167 head = tail = 0;
168 buf = newbuf();
169 for(; v; v = v->next){
170 h = w = 0;
171 if(submatch(v->s, a, b, &nmid, &enda)){
172 /* enda points to end of A match in source;
173 * nmid = number of chars between end of A and start of B
174 */
175 if(c){
176 h = w = wdup(c);
177 while(w->next)
178 w = w->next;
180 if(PERCENT(*cp) && nmid > 0){
181 if(w){
182 bufcpy(buf, w->s, strlen(w->s));
183 bufcpy(buf, enda, nmid);
184 insert(buf, 0);
185 free(w->s);
186 w->s = strdup(buf->start);
187 } else {
188 bufcpy(buf, enda, nmid);
189 insert(buf, 0);
190 h = w = newword(buf->start);
192 buf->current = buf->start;
194 if(d && *d->s){
195 if(w){
197 bufcpy(buf, w->s, strlen(w->s));
198 bufcpy(buf, d->s, strlen(d->s));
199 insert(buf, 0);
200 free(w->s);
201 w->s = strdup(buf->start);
202 w->next = wdup(d->next);
203 while(w->next)
204 w = w->next;
205 buf->current = buf->start;
206 } else
207 h = w = wdup(d);
210 if(w == 0)
211 h = w = newword(v->s);
213 if(head == 0)
214 head = h;
215 else
216 tail->next = h;
217 tail = w;
219 freebuf(buf);
220 delword(a);
221 delword(b);
222 delword(c);
223 delword(d);
224 return head;
227 static int
228 submatch(char *s, Word *a, Word *b, int *nmid, char **enda)
230 Word *w;
231 int n;
232 char *end;
234 n = 0;
235 for(w = a; w; w = w->next){
236 n = strlen(w->s);
237 if(strncmp(s, w->s, n) == 0)
238 break;
240 if(a && w == 0) /* a == NULL matches everything*/
241 return 0;
243 *enda = s+n; /* pointer to end a A part match */
244 *nmid = strlen(s)-n; /* size of remainder of source */
245 end = *enda+*nmid;
246 for(w = b; w; w = w->next){
247 n = strlen(w->s);
248 if(strcmp(w->s, end-n) == 0){
249 *nmid -= n;
250 break;
253 if(b && w == 0) /* b == NULL matches everything */
254 return 0;
255 return 1;