Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include        "mk.h"

static  Word            *subsub(Word*, char*, char*);
static  Word            *expandvar(char**);
static  Bufblock        *varname(char**);
static  Word            *extractpat(char*, char**, char*, char*);
static  int             submatch(char*, Word*, Word*, int*, char**);
static  Word            *varmatch(char *);

Word *
varsub(char **s)
{
        Bufblock *b;
        Word *w;

        if(**s == '{')          /* either ${name} or ${name: A%B==C%D}*/
                return expandvar(s);

        b = varname(s);
        if(b == 0)
                return 0;

        w = varmatch(b->start);
        freebuf(b);
        return w;
}

/*
 *      extract a variable name
 */
static Bufblock*
varname(char **s)
{
        Bufblock *b;
        char *cp;
        Rune r;
        int n;

        b = newbuf();
        cp = *s;
        for(;;){
                n = chartorune(&r, cp);
                if (!WORDCHR(r))
                        break;
                rinsert(b, r);
                cp += n;
        }
        if (b->current == b->start){
                SYNERR(-1);
                fprint(2, "missing variable name <%s>\n", *s);
                freebuf(b);
                return 0;
        }
        *s = cp;
        insert(b, 0);
        return b;
}

static Word*
varmatch(char *name)
{
        Word *w;
        Symtab *sym;
        
        sym = symlook(name, S_VAR, 0);
        if(sym){
                        /* check for at least one non-NULL value */
                for (w = sym->u.ptr; w; w = w->next)
                        if(w->s && *w->s)
                                return wdup(w);
        }
        return 0;
}

static Word*
expandvar(char **s)
{
        Word *w;
        Bufblock *buf;
        Symtab *sym;
        char *cp, *begin, *end;

        begin = *s;
        (*s)++;                                         /* skip the '{' */
        buf = varname(s);
        if (buf == 0)
                return 0;
        cp = *s;
        if (*cp == '}') {                               /* ${name} variant*/
                (*s)++;                                 /* skip the '}' */
                w = varmatch(buf->start);
                freebuf(buf);
                return w;
        }
        if (*cp != ':') {
                SYNERR(-1);
                fprint(2, "bad variable name <%s>\n", buf->start);
                freebuf(buf);
                return 0;
        }
        cp++;
        end = charin(cp , "}");
        if(end == 0){
                SYNERR(-1);
                fprint(2, "missing '}': %s\n", begin);
                Exit();
        }
        *end = 0;
        *s = end+1;
        
        sym = symlook(buf->start, S_VAR, 0);
        if(sym == 0 || sym->u.value == 0)
                w = newword(buf->start);
        else
                w = subsub(sym->u.ptr, cp, end);
        freebuf(buf);
        return w;
}

static Word*
extractpat(char *s, char **r, char *term, char *end)
{
        int save;
        char *cp;
        Word *w;

        cp = charin(s, term);
        if(cp){
                *r = cp;
                if(cp == s)
                        return 0;
                save = *cp;
                *cp = 0;
                w = stow(s);
                *cp = save;
        } else {
                *r = end;
                w = stow(s);
        }
        return w;
}

static Word*
subsub(Word *v, char *s, char *end)
{
        int nmid;
        Word *head, *tail, *w, *h;
        Word *a, *b, *c, *d;
        Bufblock *buf;
        char *cp, *enda;

        a = extractpat(s, &cp, "=%&", end);
        b = c = d = 0;
        if(PERCENT(*cp))
                b = extractpat(cp+1, &cp, "=", end);
        if(*cp == '=')
                c = extractpat(cp+1, &cp, "&%", end);
        if(PERCENT(*cp))
                d = stow(cp+1);
        else if(*cp)
                d = stow(cp);

        head = tail = 0;
        buf = newbuf();
        for(; v; v = v->next){
                h = w = 0;
                if(submatch(v->s, a, b, &nmid, &enda)){
                        /* enda points to end of A match in source;
                         * nmid = number of chars between end of A and start of B
                         */
                        if(c){
                                h = w = wdup(c);
                                while(w->next)
                                        w = w->next;
                        }
                        if(PERCENT(*cp) && nmid > 0){   
                                if(w){
                                        bufcpy(buf, w->s, strlen(w->s));
                                        bufcpy(buf, enda, nmid);
                                        insert(buf, 0);
                                        free(w->s);
                                        w->s = strdup(buf->start);
                                } else {
                                        bufcpy(buf, enda, nmid);
                                        insert(buf, 0);
                                        h = w = newword(buf->start);
                                }
                                buf->current = buf->start;
                        }
                        if(d && *d->s){
                                if(w){

                                        bufcpy(buf, w->s, strlen(w->s));
                                        bufcpy(buf, d->s, strlen(d->s));
                                        insert(buf, 0);
                                        free(w->s);
                                        w->s = strdup(buf->start);
                                        w->next = wdup(d->next);
                                        while(w->next)
                                                w = w->next;
                                        buf->current = buf->start;
                                } else
                                        h = w = wdup(d);
                        }
                }
                if(w == 0)
                        h = w = newword(v->s);
        
                if(head == 0)
                        head = h;
                else
                        tail->next = h;
                tail = w;
        }
        freebuf(buf);
        delword(a);
        delword(b);
        delword(c);
        delword(d);
        return head;
}

static int
submatch(char *s, Word *a, Word *b, int *nmid, char **enda)
{
        Word *w;
        int n;
        char *end;

        n = 0;
        for(w = a; w; w = w->next){
                n = strlen(w->s);
                if(strncmp(s, w->s, n) == 0)
                        break;
        }
        if(a && w == 0)         /*  a == NULL matches everything*/
                return 0;

        *enda = s+n;            /* pointer to end a A part match */
        *nmid = strlen(s)-n;    /* size of remainder of source */
        end = *enda+*nmid;
        for(w = b; w; w = w->next){
                n = strlen(w->s);
                if(strcmp(w->s, end-n) == 0){
                        *nmid -= n;
                        break;
                }
        }
        if(b && w == 0)         /* b == NULL matches everything */
                return 0;
        return 1;
}