i have no idea why the yacc source wasn't included.
here it is.

- erik
%{
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ip.h>

typedef struct T T;
struct T{
        T       *next;
        T       *down;
        char    *s;
        char    *t;
        int     line;
        char    *file;
};
#pragma varargck        type    "T"     T*

Biobuf  in;
char    *file;
char    *ipmask;
int     line;
int     factotum;
T       *dblist;
T       *ll0;
T       **ll;
T       *tab0;
T       **tab;
int     fd;

extern  int     yyparse(void);
extern  void    yyerror(char*, ...);

char*
nonil(char *s)
{
        if(s == nil)
                return "";
        return s;
}

int
Tfmt(Fmt *f)
{
        int sharp;
        T *t, *t0;

        t0 = va_arg(f->args, T*);
        sharp = f->flags & FmtSharp;
        for(; t0 != nil; t0 = t0->down){
                if((t = t0) != nil)
                        fmtprint(f, "%s=%s", t->s, nonil(t->t));
                while(t = t->next)
                        fmtprint(f, " %s=%s", t->s, nonil(t->t));
                if(sharp == 0)
                        break;
                if(t0->down != nil)
                        fmtprint(f, "\n");
        }
        return 0;
}

T*
newt(char *s, char *t)
{
        T *x;
        x = malloc(sizeof *x);
        if(x == nil)
                sysfatal("malloc: %r");
        memset(x, 0, sizeof *x);
        x->s = s;
        x->t = t;
        x->line = line;
        x->file = file;
        return x;
}

static char *nakedtab[] = {
        "database",
        "soa",
        "trampok",
};

int
cknaked(char *s)
{
        int i;

        for(i = 0; i < nelem(nakedtab); i++)
                if(strcmp(nakedtab[i], s) == 0)
                        return 0;
        yyerror("naked token %s", s);
        return -1;
}

%}

%union{
        T       *t;
        char    *s;
}

%type   <s>     rhs
%token  <s>     S
%start  db
%%
db      :
        | db '\n'
        | db tuples '\n'
        ;
tuples: tuple {
                *tab = ll0;
                tab = &ll0->down;

                ll0 = nil;
                ll = &ll0;
        }
        | tuple tuples
        ;
tuple:  S rhs {
                T *x;

                if($2 == nil)
                        cknaked($1);
                x = *ll = newt($1, $2);
                ll = &x->next;
        }
        ;
rhs:            { $$ = nil; }
        | '=' S { $$ = $2; }
        ;
%%
void
freet(T *t)
{
        T *n, *d;

        for(; t != nil; t = d){
                d = t->down;
                for(; t != nil; t = n){
                        n = t->next;
                        free(t->s);
                        free(t->t);
                        free(t);
                }
        }
}

void
yyinit(char *f)
{
        file = f;
        line = 1;
        fd = open(file, OREAD);
        if(fd == -1)
                sysfatal("open: %r");
        if(Binit(&in, fd, OREAD) == -1)
                sysfatal("Binit: %r");

        freet(tab0);
        ll0 = nil;
        tab0 = nil;

        ll = &ll0;
        tab = &tab0;
}

void
yyerror(char *fmt, ...)
{
        char buf[256], *p, *e;
        va_list arg;
        static int nerrors;

        e = buf + sizeof buf;
        va_start(arg, fmt);
        p = seprint(buf, e, "%s:%d ", file, line);
        p = vseprint(p, e, fmt, arg);
        p = seprint(p, e, "\n");
        va_end(arg);
        write(2, buf, p - buf);
        nerrors++;
        if(nerrors > 5)
                sysfatal("too many errors");
}

void
tokerror(T *t, char *fmt, ...)
{
        char buf[256], *p, *e;
        va_list arg;
        static int nerrors;

        e = buf + sizeof buf;
        va_start(arg, fmt);
        p = seprint(buf, e, "%s:%d ", t->file, t->line);
        p = vseprint(p, e, fmt, arg);
        p = seprint(p, e, "\n");
        va_end(arg);
        write(2, buf, p - buf);
}

enum{
        Base,
        Seeneq,
};

int
yylex(void)
{
        char buf[128], *s;
        int c, i;
        Rune r;
        static int state = Base;
        static int quoting;

        if(quoting != 0){
                yyerror("bad quote");
                quoting = 0;
        }
        i = 0;
again:
        c = Bgetrune(&in);
        if(c == Beof)
                return 0;
        r = c;
        switch(r){
        case '
':
        case '\0':
                yyerror("bad character %#ux\n", r);
                goto again;
        case '#':
                for(;;){
                        switch(Bgetrune(&in)){
                        case Beof:
                                yyerror("EOF in comment");
                                return 0;
                        case '\n':
                                Bungetrune(&in);
                                goto again;
                        }
                }
        case '\n':
                if(state != Base){
                        Bungetrune(&in);
                        goto tok;
                }
                line++;
                switch(Bgetrune(&in)){
                case Beof:
                        return '\n';
                case ' ':
                case '\t':
                        goto again;
                }
                Bungetrune(&in);
                return '\n';
        case ' ':
        case '\t':
                if(state != Base){
                        Bungetrune(&in);
                        goto tok;
                }
                goto again;
        case '=':
                if(state != Base)
                        break;
                state = Seeneq;
                return '=';
        default:
                break;
        }

        /* token */
        if(r == '"'){
                quoting = 1;
                c = Bgetrune(&in);
                r = c;
        }
        for(;;){
                if(i >= sizeof buf - UTFmax - 1){
                        yyerror("token too long");
                        break;
                }
                i += runetochar(buf + i, &r);
                c = Bgetrune(&in);
                if(c == Beof)
                        break;
                r = c;
                switch(r){
                case '
':
                case '\0':
                        yyerror("bad character %#ux\n", r);
                        goto tok;
                case ' ':
                case '\t':
                        if(quoting)
                                break;
                case '\n':
                        Bungetrune(&in);
                        goto tok;
                case '=':
                        if(state == Base){
                                Bungetrune(&in);
                                goto tok;
                        }
                        break;
                case '\'':
                        if(factotum)
                                goto quote;
                        break;
                case '"':
                        if(!factotum)
                        if(quoting == 1){
                                quoting = 0;
                                goto tok;
                        }
                        break; 
                case '#':
                        yyerror("# in token");
                }
        }
tok:
        if(state == Base && i == 0)
                yyerror("name is nil");
        if(state == Seeneq)
                state = Base;
        buf[i] = 0;
        s = strdup(buf);
        if(s == nil)
                sysfatal("malloc: %r");
        yylval.s = s;
        return S;

quote:
        quoting = 1;
        for(;;){
                /* extra space for ' if quoting fails.  ndb is wierd */
                if(i >= sizeof buf - UTFmax - 1 - 1){
                        yyerror("token too long");
                        break;
                }
                i += runetochar(buf + i, &r);

                c = Bgetrune(&in);
                if(c == Beof)
                        break;
                r = c;
                switch(r){
                case '\n':
                        /* wierd!  this is actually what ndb does */
                        Bungetrune(&in);
                        memmove(buf, buf + 1, i);
                        buf[0] = '\'';
                        goto tok;
                case '\'':
                        if(Bgetrune(&in) == '\'')
                                break;
                        Bungetrune(&in);
                        goto tok;
                }
        }
        goto tok;
}

void
go(char *file)
{
        yyinit(file);
        yyparse();
        close(fd);
}

int
parseipxmask(uchar *ip, uchar *m, char *s0)
{
        uchar tmp[IPaddrlen];
        char *msk, s[4*8+4];

        snprint(s, sizeof s, "%s", s0);
        msk = strchr(s, '/');
        if(msk == nil){
                if(parseipmask(m, "/120") == -1)
                        return -1;
        }else{
                if(parseipmask(m, msk) == -1)
                        return -1;
                *msk = 0;
        }
        if(parseip(tmp, s) == -1)
                return -1;
        maskip(tmp, m, ip);
        return 0;
}

void
checkip(void)
{
        uchar m0[IPaddrlen], mask[IPaddrlen], ip1[IPaddrlen], m1[IPaddrlen];
        int havemsk;
        T *d, *t;

        havemsk = 0;
        if(ipmask != nil)
        if(parseipxmask(m0, mask, ipmask) == 0)
                havemsk = 1;
        for(d = tab0; d != nil; d = d->down)
                for(t = d; t != nil; t = t->next){
                        if(strcmp(t->s, "ip") != 0)
                                continue;
                        if(parseip(ip1, t->t) == -1){
                                tokerror(t, "bad ip %T", d);
                                continue;
                        }
                        if(havemsk == 0)
                                continue;
                        maskip(ip1, mask, m1);
                        if(ipcmp(m0, m1) != 0)
                                tokerror(t, "wrong file: %I", t, ip1);
                }
}

typedef struct {
        uchar   ea[IPaddrlen];
        T       *d[10];
        int     nd;
} B;

static  B       *btab;
static  uint    nbtab;
static  uint    nbtaba;

int
addrcmp(uchar *a, uchar *b)
{
        int d;

        d = memcmp(a, b, IPaddrlen);
        if(d > 0)
                return 1;
        if(d < 0)
                return -1;
        return 0;
}

static B*
bsearch(uchar *ea)
{
        B *tab, *m;
        int n, i, d;

        tab = btab;
        for(n = nbtab; n > 0;){
                i = n/2;
                m = tab+i;
                d = addrcmp(m->ea, ea);
                if(d == 0)
                        return m;
                if(d < 0){
                        tab += i+1;
                        n -= i+1;
                }else
                        n = i;
        }
        return nil;
}

void
binsert(B *m, T *d, uchar *ea)
{
        char buf[256], *p, *e;
        int i;
        T **x;

        if(m == nil){
                if(nbtab + 1 >= nbtaba){
                        nbtaba = nbtab + 1 << 1;
                        btab = realloc(btab, sizeof btab[0]*nbtaba);
                        if(btab == nil)
                                sysfatal("realloc: %r");
                }
                for(m=btab+nbtab; m > btab && addrcmp(m[-1].ea, ea) > 0; m--)
                        m[0] = m[-1];
                m->nd = 0;
                memcpy(m->ea, ea, IPaddrlen);
                nbtab++;
        }
        m->d[m->nd++] = d;
        if(m->nd > 1){
                x = m->d;
                p = buf;
                e = buf + sizeof buf;
                for(i = 0; i < m->nd - 1; i++)
                        p = seprint(p, e, "%s:%d ", x[i]->file, x[i]->line);
                tokerror(d, "duplicate ea %E %s", m->ea, buf);
        }
}

void
prdb(void)
{
        int i;

        for(i = 0; i < nbtab; i++)
                print("%E\n", btab[i].ea);
}

void
checkether(void)
{
        uchar ea[IPaddrlen];
        T *d, *t;

        for(d = tab0; d != nil; d = d->down)
                for(t = d; t != nil; t = t->next){
                        if(strcmp(t->s, "ether") != 0)
                                continue;
                        if(strspn(t->t, "0123456789abcdef") != 12)
                                tokerror(t, "bad ea %s", t->t);
                        parseether(ea, t->t);
                        binsert(bsearch(ea), d, ea);
                }
}

static char *soaattr[] = {
        "refresh",
        "ttl",
        "ns",
        "mx",
        "pref",
        "mbox",
};

static char *cattrtab[] = {
        "clog",                 /* only in consoledb */
        "console",
        "dev",
        "gid",
        "group",
        "speed",
        "uid",
        "openondemand",
};

static char *xattrtab[] = {
        "auth",
        "authdom",
        "bootf",
        "cname",
        "console",
        "database",
        "dns",
        "dnsdomain",
        "dom",
        "el",
        "ether",
        "file",
        "fs",
        "gw",
        "imap",
        "ip",
        "ipgw",
        "ipmask",
        "ipnet",
        "mb",
        "mbox",
        "mx",
        "ns",
        "pref",
        "proto",
        "refresh",
        "smtp",
        "soa",
        "sys",
        "trampok",
        "ttl",
        "txtrr",

        "pri",
        "srv",
        "weight",

        "gre",
        "il",
        "ipv4proto",
        "port",
        "protocol",
        "restricted",
        "tcp",
        "udp",

        "uid",
        "hostid"
};

char    **attrtab       = xattrtab;
int     nattrtab        = nelem(xattrtab);

void
checkattrs(void)
{
        int i;
        T *d, *t;

        for(d = tab0; d != nil; d = d->down)
                for(t = d; t != nil; t = t->next){
                        for(i = 0; i < nattrtab; i++)
                                if(strcmp(t->s, attrtab[i]) == 0)
                                        break;
                        if(i == nattrtab)
                                tokerror(t, "unknown attr %s", t->s);
                }
}

void
usage(void)
{
        fprint(2, "usage: ndb/vrfy [-m ip/mask]  [file ...]\n");
        exits("usage");
}

void
main(int argc, char **argv)
{
        int i;

        fmtinstall('T', Tfmt);
        fmtinstall('I', eipfmt);
        fmtinstall('M', eipfmt);
        fmtinstall('E', eipfmt);
        ARGBEGIN{
        case 'c':
                attrtab = cattrtab;
                nattrtab = nelem(cattrtab);
                break;
        case 'm':
                ipmask = EARGF(usage());
                break;
        default:
                usage();
        }ARGEND
        for(i = 0; i < argc; i++){
                go(argv[i]);
                checkip();
                checkether();
                checkattrs();
        }

        exits("");
}

Reply via email to