varsub.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       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 }