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