]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/mk/varsub.c
ip/ipconfig: format ipmask with %M instead of %I
[plan9front.git] / sys / src / cmd / mk / varsub.c
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 = 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*
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*
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 }