| ---
varsub.c (4311B)
---
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 *
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*
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*
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*
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 = shellt->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.ptr == 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*
121 extractpat(char *s, char **r, char *term, char *end)
122 {
123 int save;
124 char *cp;
125 Word *w;
126
127 cp = shellt->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*
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
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 } |