%{ /* $NetBSD: gram.y,v 1.12 2006/03/18 09:46:35 christos Exp $ */ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #ifndef lint #if 0 static char sccsid[] = "@(#)gram.y 8.1 (Berkeley) 6/9/93"; #else __RCSID("$NetBSD: gram.y,v 1.12 2006/03/18 09:46:35 christos Exp $"); #endif #endif /* not lint */ #include "defs.h" struct cmd *cmds = NULL; struct cmd *last_cmd; struct namelist *last_n; struct subcmd *last_sc; static char *makestr(char *); void append(char *, struct namelist *, char *, struct subcmd *); %} %term EQUAL 1 %term LP 2 %term RP 3 %term SM 4 %term ARROW 5 %term COLON 6 %term DCOLON 7 %term NAME 8 %term STRING 9 %term INSTALL 10 %term NOTIFY 11 %term EXCEPT 12 %term PATTERN 13 %term SPECIAL 14 %term OPTION 15 %union { int intval; char *string; struct subcmd *subcmd; struct namelist *namel; } %type OPTION, options %type NAME, STRING %type INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, cmdlist, cmd %type namelist, names, opt_namelist %% file: /* VOID */ | file command ; command: NAME EQUAL namelist = { (void) lookup($1, INSERT, $3); } | namelist ARROW namelist cmdlist = { insert(NULL, $1, $3, $4); } | NAME COLON namelist ARROW namelist cmdlist = { insert($1, $3, $5, $6); } | namelist DCOLON NAME cmdlist = { append(NULL, $1, $3, $4); } | NAME COLON namelist DCOLON NAME cmdlist = { append($1, $3, $5, $6); } | error ; namelist: NAME = { $$ = makenl($1); } | LP names RP = { $$ = $2; } ; names: /* VOID */ { $$ = last_n = NULL; } | names NAME = { if (last_n == NULL) $$ = last_n = makenl($2); else { last_n->n_next = makenl($2); last_n = last_n->n_next; $$ = $1; } } ; cmdlist: /* VOID */ { $$ = last_sc = NULL; } | cmdlist cmd = { if (last_sc == NULL) $$ = last_sc = $2; else { last_sc->sc_next = $2; last_sc = $2; $$ = $1; } } ; cmd: INSTALL options opt_namelist SM = { struct namelist *nl; $1->sc_options = $2 | options; if ($3 != NULL) { nl = expand($3, E_VARS); if (nl) { if (nl->n_next != NULL) yyerror("only one name allowed\n"); $1->sc_name = nl->n_name; free(nl); } else $1->sc_name = NULL; } $$ = $1; } | NOTIFY namelist SM = { if ($2 != NULL) $1->sc_args = expand($2, E_VARS); $$ = $1; } | EXCEPT namelist SM = { if ($2 != NULL) $1->sc_args = expand($2, E_ALL); $$ = $1; } | PATTERN namelist SM = { if ($2 != NULL) $1->sc_args = expand($2, E_VARS); $$ = $1; } | SPECIAL opt_namelist STRING SM = { if ($2 != NULL) $1->sc_args = expand($2, E_ALL); $1->sc_name = $3; $$ = $1; } ; options: /* VOID */ = { $$ = 0; } | options OPTION = { $$ |= $2; } ; opt_namelist: /* VOID */ = { $$ = NULL; } | namelist = { $$ = $1; } ; %% int yylineno = 1; extern FILE *fin; int yylex(void); int yylex(void) { static char yytext[INMAX]; int c; char *cp1, *cp2; static char quotechars[] = "[]{}*?$"; again: switch (c = getc(fin)) { case EOF: /* end of file */ return(0); case '#': /* start of comment */ while ((c = getc(fin)) != EOF && c != '\n') ; if (c == EOF) return(0); case '\n': yylineno++; case ' ': case '\t': /* skip blanks */ goto again; case '=': /* EQUAL */ return(EQUAL); case '(': /* LP */ return(LP); case ')': /* RP */ return(RP); case ';': /* SM */ return(SM); case '-': /* -> */ if ((c = getc(fin)) == '>') return(ARROW); ungetc(c, fin); c = '-'; break; case '"': /* STRING */ cp1 = yytext; cp2 = &yytext[INMAX - 1]; for (;;) { if (cp1 >= cp2) { yyerror("command string too long\n"); break; } c = getc(fin); if (c == EOF || c == '"') break; if (c == '\\') { if ((c = getc(fin)) == EOF) { *cp1++ = '\\'; break; } } if (c == '\n') { yylineno++; c = ' '; /* can't send '\n' */ } *cp1++ = c; } if (c != '"') yyerror("missing closing '\"'\n"); *cp1 = '\0'; yylval.string = makestr(yytext); return(STRING); case ':': /* : or :: */ if ((c = getc(fin)) == ':') return(DCOLON); ungetc(c, fin); return(COLON); } cp1 = yytext; cp2 = &yytext[INMAX - 1]; for (;;) { if (cp1 >= cp2) { yyerror("input line too long\n"); break; } if (c == '\\') { if ((c = getc(fin)) != EOF) { if (any(c, quotechars)) c |= QUOTE; } else { *cp1++ = '\\'; break; } } *cp1++ = c; c = getc(fin); if (c == EOF || any(c, " \"'\t()=;:\n")) { ungetc(c, fin); break; } } *cp1 = '\0'; if (yytext[0] == '-' && yytext[2] == '\0') { switch (yytext[1]) { case 'b': yylval.intval = COMPARE; return(OPTION); case 'R': yylval.intval = REMOVE; return(OPTION); case 'v': yylval.intval = VERIFY; return(OPTION); case 'w': yylval.intval = WHOLE; return(OPTION); case 'y': yylval.intval = YOUNGER; return(OPTION); case 'h': yylval.intval = FOLLOW; return(OPTION); case 'i': yylval.intval = IGNLNKS; return(OPTION); } } if (!strcmp(yytext, "install")) c = INSTALL; else if (!strcmp(yytext, "notify")) c = NOTIFY; else if (!strcmp(yytext, "except")) c = EXCEPT; else if (!strcmp(yytext, "except_pat")) c = PATTERN; else if (!strcmp(yytext, "special")) c = SPECIAL; else { yylval.string = makestr(yytext); return(NAME); } yylval.subcmd = makesubcmd(c); return(c); } int any(int c, char *str) { while (*str) if (c == *str++) return(1); return(0); } /* * Insert or append ARROW command to list of hosts to be updated. */ void insert(char *label, struct namelist *files, struct namelist *hosts, struct subcmd *subcmds) { struct cmd *c, *prev, *nc; struct namelist *h, *nexth; files = expand(files, E_VARS|E_SHELL); hosts = expand(hosts, E_ALL); for (h = hosts; h != NULL; nexth = h->n_next, free(h), h = nexth) { /* * Search command list for an update to the same host. */ for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) { if (strcmp(c->c_name, h->n_name) == 0) { do { prev = c; c = c->c_next; } while (c != NULL && strcmp(c->c_name, h->n_name) == 0); break; } } /* * Insert new command to update host. */ nc = ALLOC(cmd); if (nc == NULL) fatal("ran out of memory\n"); nc->c_type = ARROW; nc->c_name = h->n_name; nc->c_label = label; nc->c_files = files; nc->c_cmds = subcmds; nc->c_next = c; if (prev == NULL) cmds = nc; else prev->c_next = nc; /* update last_cmd if appending nc to cmds */ if (c == NULL) last_cmd = nc; } } /* * Append DCOLON command to the end of the command list since these are always * executed in the order they appear in the distfile. */ void append(char *label, struct namelist *files, char *stamp, struct subcmd *subcmds) { struct cmd *c; c = ALLOC(cmd); if (c == NULL) fatal("ran out of memory\n"); c->c_type = DCOLON; c->c_name = stamp; c->c_label = label; c->c_files = expand(files, E_ALL); c->c_cmds = subcmds; c->c_next = NULL; if (cmds == NULL) cmds = last_cmd = c; else { last_cmd->c_next = c; last_cmd = c; } } /* * Error printing routine in parser. */ void yyerror(char *s) { ++nerrs; fflush(stdout); fprintf(stderr, "rdist: line %d: %s\n", yylineno, s); } /* * Return a copy of the string. */ static char * makestr(char *str) { char *cp, *s; str = cp = malloc(strlen(s = str) + 1); if (cp == NULL) fatal("ran out of memory\n"); while ((*cp++ = *s++) != 0) ; return(str); } /* * Allocate a namelist structure. */ struct namelist * makenl(char *name) { struct namelist *nl; nl = ALLOC(namelist); if (nl == NULL) fatal("ran out of memory\n"); nl->n_name = name; nl->n_next = NULL; return(nl); } void freenl(struct namelist *nl) { if (nl == NULL) return; freenl(nl->n_next); free(nl); } void freesubcmd(struct subcmd *cmd) { if (cmd == NULL) return; freesubcmd(cmd->sc_next); free(cmd); } /* * Make a sub command for lists of variables, commands, etc. */ struct subcmd * makesubcmd(int type) { struct subcmd *sc; sc = ALLOC(subcmd); if (sc == NULL) fatal("ran out of memory\n"); sc->sc_type = type; sc->sc_args = NULL; sc->sc_next = NULL; sc->sc_name = NULL; return(sc); }