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 }