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 *);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);24 freebuf(b);25 return w;26 }28 /*29 * extract a variable name30 */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)61 {62 Word *w;63 Symtab *sym;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 }75 static Word*76 expandvar(char **s)77 {78 Word *w;79 Bufblock *buf;80 Symtab *sym;81 char *cp, *begin, *end;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;111 sym = symlook(buf->start, S_VAR, 0);112 if(sym == 0 || sym->u.ptr == 0)113 w = newword(buf->start);114 else115 w = subsub(sym->u.ptr, cp, end);116 freebuf(buf);117 return w;118 }120 static Word*121 extractpat(char *s, char **r, char *term, char *end)122 {123 int save;124 char *cp;125 Word *w;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 }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;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);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 B170 */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){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 } else203 h = w = wdup(d);204 }205 }206 if(w == 0)207 h = w = newword(v->s);209 if(head == 0)210 head = h;211 else212 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 }223 static int224 submatch(char *s, Word *a, Word *b, int *nmid, char **enda)225 {226 Word *w;227 int n;228 char *end;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;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 }