Home | History | Annotate | Line # | Download | only in rdist
gram.y revision 1.9
      1 %{
      2 /*	$NetBSD: gram.y,v 1.9 2002/06/14 01:18:55 wiz Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 1983, 1993
      6  *	The Regents of the University of California.  All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by the University of
     19  *	California, Berkeley and its contributors.
     20  * 4. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  */
     36 
     37 #include <sys/cdefs.h>
     38 #ifndef lint
     39 #if 0
     40 static char sccsid[] = "@(#)gram.y	8.1 (Berkeley) 6/9/93";
     41 #else
     42 __RCSID("$NetBSD: gram.y,v 1.9 2002/06/14 01:18:55 wiz Exp $");
     43 #endif
     44 #endif /* not lint */
     45 
     46 #include "defs.h"
     47 
     48 struct	cmd *cmds = NULL;
     49 struct	cmd *last_cmd;
     50 struct	namelist *last_n;
     51 struct	subcmd *last_sc;
     52 
     53 static char   *makestr(char *);
     54 void	append(char *, struct namelist *, char *, struct subcmd *);
     55 
     56 %}
     57 
     58 %term EQUAL	1
     59 %term LP	2
     60 %term RP	3
     61 %term SM	4
     62 %term ARROW	5
     63 %term COLON	6
     64 %term DCOLON	7
     65 %term NAME	8
     66 %term STRING	9
     67 %term INSTALL	10
     68 %term NOTIFY	11
     69 %term EXCEPT	12
     70 %term PATTERN	13
     71 %term SPECIAL	14
     72 %term OPTION	15
     73 
     74 %union {
     75 	int intval;
     76 	char *string;
     77 	struct subcmd *subcmd;
     78 	struct namelist *namel;
     79 }
     80 
     81 %type <intval> OPTION, options
     82 %type <string> NAME, STRING
     83 %type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, cmdlist, cmd
     84 %type <namel> namelist, names, opt_namelist
     85 
     86 %%
     87 
     88 file:		  /* VOID */
     89 		| file command
     90 		;
     91 
     92 command:	  NAME EQUAL namelist = {
     93 			(void) lookup($1, INSERT, $3);
     94 		}
     95 		| namelist ARROW namelist cmdlist = {
     96 			insert(NULL, $1, $3, $4);
     97 		}
     98 		| NAME COLON namelist ARROW namelist cmdlist = {
     99 			insert($1, $3, $5, $6);
    100 		}
    101 		| namelist DCOLON NAME cmdlist = {
    102 			append(NULL, $1, $3, $4);
    103 		}
    104 		| NAME COLON namelist DCOLON NAME cmdlist = {
    105 			append($1, $3, $5, $6);
    106 		}
    107 		| error
    108 		;
    109 
    110 namelist:	  NAME = {
    111 			$$ = makenl($1);
    112 		}
    113 		| LP names RP = {
    114 			$$ = $2;
    115 		}
    116 		;
    117 
    118 names:		  /* VOID */ {
    119 			$$ = last_n = NULL;
    120 		}
    121 		| names NAME = {
    122 			if (last_n == NULL)
    123 				$$ = last_n = makenl($2);
    124 			else {
    125 				last_n->n_next = makenl($2);
    126 				last_n = last_n->n_next;
    127 				$$ = $1;
    128 			}
    129 		}
    130 		;
    131 
    132 cmdlist:	  /* VOID */ {
    133 			$$ = last_sc = NULL;
    134 		}
    135 		| cmdlist cmd = {
    136 			if (last_sc == NULL)
    137 				$$ = last_sc = $2;
    138 			else {
    139 				last_sc->sc_next = $2;
    140 				last_sc = $2;
    141 				$$ = $1;
    142 			}
    143 		}
    144 		;
    145 
    146 cmd:		  INSTALL options opt_namelist SM = {
    147 			struct namelist *nl;
    148 
    149 			$1->sc_options = $2 | options;
    150 			if ($3 != NULL) {
    151 				nl = expand($3, E_VARS);
    152 				if (nl) {
    153 					if (nl->n_next != NULL)
    154 					    yyerror("only one name allowed\n");
    155 					$1->sc_name = nl->n_name;
    156 					free(nl);
    157 				} else
    158 					$1->sc_name = NULL;
    159 			}
    160 			$$ = $1;
    161 		}
    162 		| NOTIFY namelist SM = {
    163 			if ($2 != NULL)
    164 				$1->sc_args = expand($2, E_VARS);
    165 			$$ = $1;
    166 		}
    167 		| EXCEPT namelist SM = {
    168 			if ($2 != NULL)
    169 				$1->sc_args = expand($2, E_ALL);
    170 			$$ = $1;
    171 		}
    172 		| PATTERN namelist SM = {
    173 			if ($2 != NULL)
    174 				$1->sc_args = expand($2, E_VARS);
    175 			$$ = $1;
    176 		}
    177 		| SPECIAL opt_namelist STRING SM = {
    178 			if ($2 != NULL)
    179 				$1->sc_args = expand($2, E_ALL);
    180 			$1->sc_name = $3;
    181 			$$ = $1;
    182 		}
    183 		;
    184 
    185 options:	  /* VOID */ = {
    186 			$$ = 0;
    187 		}
    188 		| options OPTION = {
    189 			$$ |= $2;
    190 		}
    191 		;
    192 
    193 opt_namelist:	  /* VOID */ = {
    194 			$$ = NULL;
    195 		}
    196 		| namelist = {
    197 			$$ = $1;
    198 		}
    199 		;
    200 
    201 %%
    202 
    203 int	yylineno = 1;
    204 extern	FILE *fin;
    205 
    206 int	yylex(void);
    207 
    208 int
    209 yylex(void)
    210 {
    211 	static char yytext[INMAX];
    212 	int c;
    213 	char *cp1, *cp2;
    214 	static char quotechars[] = "[]{}*?$";
    215 
    216 again:
    217 	switch (c = getc(fin)) {
    218 	case EOF:  /* end of file */
    219 		return(0);
    220 
    221 	case '#':  /* start of comment */
    222 		while ((c = getc(fin)) != EOF && c != '\n')
    223 			;
    224 		if (c == EOF)
    225 			return(0);
    226 	case '\n':
    227 		yylineno++;
    228 	case ' ':
    229 	case '\t':  /* skip blanks */
    230 		goto again;
    231 
    232 	case '=':  /* EQUAL */
    233 		return(EQUAL);
    234 
    235 	case '(':  /* LP */
    236 		return(LP);
    237 
    238 	case ')':  /* RP */
    239 		return(RP);
    240 
    241 	case ';':  /* SM */
    242 		return(SM);
    243 
    244 	case '-':  /* -> */
    245 		if ((c = getc(fin)) == '>')
    246 			return(ARROW);
    247 		ungetc(c, fin);
    248 		c = '-';
    249 		break;
    250 
    251 	case '"':  /* STRING */
    252 		cp1 = yytext;
    253 		cp2 = &yytext[INMAX - 1];
    254 		for (;;) {
    255 			if (cp1 >= cp2) {
    256 				yyerror("command string too long\n");
    257 				break;
    258 			}
    259 			c = getc(fin);
    260 			if (c == EOF || c == '"')
    261 				break;
    262 			if (c == '\\') {
    263 				if ((c = getc(fin)) == EOF) {
    264 					*cp1++ = '\\';
    265 					break;
    266 				}
    267 			}
    268 			if (c == '\n') {
    269 				yylineno++;
    270 				c = ' '; /* can't send '\n' */
    271 			}
    272 			*cp1++ = c;
    273 		}
    274 		if (c != '"')
    275 			yyerror("missing closing '\"'\n");
    276 		*cp1 = '\0';
    277 		yylval.string = makestr(yytext);
    278 		return(STRING);
    279 
    280 	case ':':  /* : or :: */
    281 		if ((c = getc(fin)) == ':')
    282 			return(DCOLON);
    283 		ungetc(c, fin);
    284 		return(COLON);
    285 	}
    286 	cp1 = yytext;
    287 	cp2 = &yytext[INMAX - 1];
    288 	for (;;) {
    289 		if (cp1 >= cp2) {
    290 			yyerror("input line too long\n");
    291 			break;
    292 		}
    293 		if (c == '\\') {
    294 			if ((c = getc(fin)) != EOF) {
    295 				if (any(c, quotechars))
    296 					c |= QUOTE;
    297 			} else {
    298 				*cp1++ = '\\';
    299 				break;
    300 			}
    301 		}
    302 		*cp1++ = c;
    303 		c = getc(fin);
    304 		if (c == EOF || any(c, " \"'\t()=;:\n")) {
    305 			ungetc(c, fin);
    306 			break;
    307 		}
    308 	}
    309 	*cp1 = '\0';
    310 	if (yytext[0] == '-' && yytext[2] == '\0') {
    311 		switch (yytext[1]) {
    312 		case 'b':
    313 			yylval.intval = COMPARE;
    314 			return(OPTION);
    315 
    316 		case 'R':
    317 			yylval.intval = REMOVE;
    318 			return(OPTION);
    319 
    320 		case 'v':
    321 			yylval.intval = VERIFY;
    322 			return(OPTION);
    323 
    324 		case 'w':
    325 			yylval.intval = WHOLE;
    326 			return(OPTION);
    327 
    328 		case 'y':
    329 			yylval.intval = YOUNGER;
    330 			return(OPTION);
    331 
    332 		case 'h':
    333 			yylval.intval = FOLLOW;
    334 			return(OPTION);
    335 
    336 		case 'i':
    337 			yylval.intval = IGNLNKS;
    338 			return(OPTION);
    339 		}
    340 	}
    341 	if (!strcmp(yytext, "install"))
    342 		c = INSTALL;
    343 	else if (!strcmp(yytext, "notify"))
    344 		c = NOTIFY;
    345 	else if (!strcmp(yytext, "except"))
    346 		c = EXCEPT;
    347 	else if (!strcmp(yytext, "except_pat"))
    348 		c = PATTERN;
    349 	else if (!strcmp(yytext, "special"))
    350 		c = SPECIAL;
    351 	else {
    352 		yylval.string = makestr(yytext);
    353 		return(NAME);
    354 	}
    355 	yylval.subcmd = makesubcmd(c);
    356 	return(c);
    357 }
    358 
    359 int
    360 any(int c, char *str)
    361 {
    362 	while (*str)
    363 		if (c == *str++)
    364 			return(1);
    365 	return(0);
    366 }
    367 
    368 /*
    369  * Insert or append ARROW command to list of hosts to be updated.
    370  */
    371 void
    372 insert(char *label, struct namelist *files, struct namelist *hosts,
    373        struct subcmd *subcmds)
    374 {
    375 	struct cmd *c, *prev, *nc;
    376 	struct namelist *h, *nexth;
    377 
    378 	files = expand(files, E_VARS|E_SHELL);
    379 	hosts = expand(hosts, E_ALL);
    380 	for (h = hosts; h != NULL; nexth = h->n_next, free(h), h = nexth) {
    381 		/*
    382 		 * Search command list for an update to the same host.
    383 		 */
    384 		for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) {
    385 			if (strcmp(c->c_name, h->n_name) == 0) {
    386 				do {
    387 					prev = c;
    388 					c = c->c_next;
    389 				} while (c != NULL &&
    390 					strcmp(c->c_name, h->n_name) == 0);
    391 				break;
    392 			}
    393 		}
    394 		/*
    395 		 * Insert new command to update host.
    396 		 */
    397 		nc = ALLOC(cmd);
    398 		if (nc == NULL)
    399 			fatal("ran out of memory\n");
    400 		nc->c_type = ARROW;
    401 		nc->c_name = h->n_name;
    402 		nc->c_label = label;
    403 		nc->c_files = files;
    404 		nc->c_cmds = subcmds;
    405 		nc->c_next = c;
    406 		if (prev == NULL)
    407 			cmds = nc;
    408 		else
    409 			prev->c_next = nc;
    410 		/* update last_cmd if appending nc to cmds */
    411 		if (c == NULL)
    412 			last_cmd = nc;
    413 	}
    414 }
    415 
    416 /*
    417  * Append DCOLON command to the end of the command list since these are always
    418  * executed in the order they appear in the distfile.
    419  */
    420 void
    421 append(char *label, struct namelist *files, char *stamp,
    422        struct subcmd *subcmds)
    423 {
    424 	struct cmd *c;
    425 
    426 	c = ALLOC(cmd);
    427 	if (c == NULL)
    428 		fatal("ran out of memory\n");
    429 	c->c_type = DCOLON;
    430 	c->c_name = stamp;
    431 	c->c_label = label;
    432 	c->c_files = expand(files, E_ALL);
    433 	c->c_cmds = subcmds;
    434 	c->c_next = NULL;
    435 	if (cmds == NULL)
    436 		cmds = last_cmd = c;
    437 	else {
    438 		last_cmd->c_next = c;
    439 		last_cmd = c;
    440 	}
    441 }
    442 
    443 /*
    444  * Error printing routine in parser.
    445  */
    446 void
    447 yyerror(char *s)
    448 {
    449 
    450 	++nerrs;
    451 	fflush(stdout);
    452 	fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
    453 }
    454 
    455 /*
    456  * Return a copy of the string.
    457  */
    458 static char *
    459 makestr(char *str)
    460 {
    461 	char *cp, *s;
    462 
    463 	str = cp = malloc(strlen(s = str) + 1);
    464 	if (cp == NULL)
    465 		fatal("ran out of memory\n");
    466 	while ((*cp++ = *s++) != NULL)
    467 		;
    468 	return(str);
    469 }
    470 
    471 /*
    472  * Allocate a namelist structure.
    473  */
    474 struct namelist *
    475 makenl(char *name)
    476 {
    477 	struct namelist *nl;
    478 
    479 	nl = ALLOC(namelist);
    480 	if (nl == NULL)
    481 		fatal("ran out of memory\n");
    482 	nl->n_name = name;
    483 	nl->n_next = NULL;
    484 	return(nl);
    485 }
    486 
    487 /*
    488  * Make a sub command for lists of variables, commands, etc.
    489  */
    490 struct subcmd *
    491 makesubcmd(int type)
    492 {
    493 	struct subcmd *sc;
    494 
    495 	sc = ALLOC(subcmd);
    496 	if (sc == NULL)
    497 		fatal("ran out of memory\n");
    498 	sc->sc_type = type;
    499 	sc->sc_args = NULL;
    500 	sc->sc_next = NULL;
    501 	sc->sc_name = NULL;
    502 	return(sc);
    503 }
    504