Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include        "mk.h"

char *infile;
int mkinline;
static int rhead(char *, Word **, Word **, int *, char **);
static char *rbody(Biobuf*);
extern Word *target1;

void
parse(char *f, int fd, int varoverride)
{
        int hline;
        char *body;
        Word *head, *tail;
        int attr, set, pid;
        char *prog, *p;
        int newfd;
        Biobuf in;
        Bufblock *buf;

        if(fd < 0){
                perror(f);
                Exit();
        }
        ipush();
        infile = strdup(f);
        mkinline = 1;
        Binit(&in, fd, OREAD);
        buf = newbuf();
        while(assline(&in, buf)){
                hline = mkinline;
                switch(rhead(buf->start, &head, &tail, &attr, &prog))
                {
                case '<':
                        p = wtos(tail, ' ');
                        if(*p == 0){
                                SYNERR(-1);
                                fprint(2, "missing include file name\n");
                                Exit();
                        }
                        newfd = open(p, OREAD);
                        if(newfd < 0){
                                fprint(2, "warning: skipping missing include file: ");
                                perror(p);
                        } else
                                parse(p, newfd, 0);
                        break;
                case '|':
                        p = wtos(tail, ' ');
                        if(*p == 0){
                                SYNERR(-1);
                                fprint(2, "missing include program name\n");
                                Exit();
                        }
                        execinit();
                        pid=pipecmd(p, envy, &newfd);
                        if(newfd < 0){
                                fprint(2, "warning: skipping missing program file: ");
                                perror(p);
                        } else
                                parse(p, newfd, 0);
                        while(waitup(-3, &pid) >= 0)
                                ;
                        if(pid != 0){
                                fprint(2, "bad include program status\n");
                                Exit();
                        }
                        break;
                case ':':
                        body = rbody(&in);
                        addrules(head, tail, body, attr, hline, prog);
                        break;
                case '=':
                        if(head->next){
                                SYNERR(-1);
                                fprint(2, "multiple vars on left side of assignment\n");
                                Exit();
                        }
                        if(symlook(head->s, S_OVERRIDE, 0)){
                                set = varoverride;
                        } else {
                                set = 1;
                                if(varoverride)
                                        symlook(head->s, S_OVERRIDE, (void *)"");
                        }
                        if(set){
/*
char *cp;
dumpw("tail", tail);
cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp);
*/
                                setvar(head->s, (void *) tail);
                                symlook(head->s, S_WESET, (void *)"");
                        }
                        if(attr)
                                symlook(head->s, S_NOEXPORT, (void *)"");
                        break;
                default:
                        SYNERR(hline);
                        fprint(2, "expected one of :<=\n");
                        Exit();
                        break;
                }
        }
        close(fd);
        freebuf(buf);
        ipop();
}

void
addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog)
{
        Word *w;

        assert(/*addrules args*/ head && body);
                /* tuck away first non-meta rule as default target*/
        if(target1 == 0 && !(attr&REGEXP)){
                for(w = head; w; w = w->next)
                        if(charin(w->s, "%&"))
                                break;
                if(w == 0)
                        target1 = wdup(head);
        }
        for(w = head; w; w = w->next)
                addrule(w->s, tail, body, head, attr, hline, prog);
}

static int
rhead(char *line, Word **h, Word **t, int *attr, char **prog)
{
        char *p;
        char *pp;
        int sep;
        Rune r;
        int n;
        Word *w;

        p = charin(line,":=<");
        if(p == 0)
                return('?');
        sep = *p;
        *p++ = 0;
        if(sep == '<' && *p == '|'){
                sep = '|';
                p++;
        }
        *attr = 0;
        *prog = 0;
        if(sep == '='){
                pp = charin(p, termchars);      /* termchars is shell-dependent */
                if (pp && *pp == '=') {
                        while (p != pp) {
                                n = chartorune(&r, p);
                                switch(r)
                                {
                                default:
                                        SYNERR(-1);
                                        fprint(2, "unknown attribute '%c'\n",*p);
                                        Exit();
                                case 'U':
                                        *attr = 1;
                                        break;
                                }
                                p += n;
                        }
                        p++;            /* skip trailing '=' */
                }
        }
        if((sep == ':') && *p && (*p != ' ') && (*p != '\t')){
                while (*p) {
                        n = chartorune(&r, p);
                        if (r == ':')
                                break;
                        p += n;
                        switch(r)
                        {
                        default:
                                SYNERR(-1);
                                fprint(2, "unknown attribute '%c'\n", p[-1]);
                                Exit();
                        case 'D':
                                *attr |= DEL;
                                break;
                        case 'E':
                                *attr |= NOMINUSE;
                                break;
                        case 'n':
                                *attr |= NOVIRT;
                                break;
                        case 'N':
                                *attr |= NOREC;
                                break;
                        case 'P':
                                pp = utfrune(p, ':');
                                if (pp == 0 || *pp == 0)
                                        goto eos;
                                *pp = 0;
                                *prog = strdup(p);
                                *pp = ':';
                                p = pp;
                                break;
                        case 'Q':
                                *attr |= QUIET;
                                break;
                        case 'R':
                                *attr |= REGEXP;
                                break;
                        case 'U':
                                *attr |= UPD;
                                break;
                        case 'V':
                                *attr |= VIR;
                                break;
                        }
                }
                if (*p++ != ':') {
        eos:
                        SYNERR(-1);
                        fprint(2, "missing trailing :\n");
                        Exit();
                }
        }
        *h = w = stow(line);
        if(*w->s == 0 && sep != '<' && sep != '|') {
                SYNERR(mkinline-1);
                fprint(2, "no var on left side of assignment/rule\n");
                Exit();
        }
        *t = stow(p);
        return(sep);
}

static char *
rbody(Biobuf *in)
{
        Bufblock *buf;
        int r, lastr;
        char *p;

        lastr = '\n';
        buf = newbuf();
        for(;;){
                r = Bgetrune(in);
                if (r < 0)
                        break;
                if (lastr == '\n') {
                        if (r == '#')
                                rinsert(buf, r);
                        else if (r != ' ' && r != '\t') {
                                Bungetrune(in);
                                break;
                        }
                } else
                        rinsert(buf, r);
                lastr = r;
                if (r == '\n')
                        mkinline++;
        }
        insert(buf, 0);
        p = strdup(buf->start);
        freebuf(buf);
        return p;
}

struct input
{
        char *file;
        int line;
        struct input *next;
};
static struct input *inputs = 0;

void
ipush(void)
{
        struct input *in, *me;

        me = (struct input *)Malloc(sizeof(*me));
        me->file = infile;
        me->line = mkinline;
        me->next = 0;
        if(inputs == 0)
                inputs = me;
        else {
                for(in = inputs; in->next; )
                        in = in->next;
                in->next = me;
        }
}

void
ipop(void)
{
        struct input *in, *me;

        assert(/*pop input list*/ inputs != 0);
        if(inputs->next == 0){
                me = inputs;
                inputs = 0;
        } else {
                for(in = inputs; in->next->next; )
                        in = in->next;
                me = in->next;
                in->next = 0;
        }
        infile = me->file;
        mkinline = me->line;
        free((char *)me);
}