Home | History | Annotate | Line # | Download | only in rdist
gram.y revision 1.8
      1 %{
      2 /*	$NetBSD: gram.y,v 1.8 1997/10/19 13:59:00 lukem 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.8 1997/10/19 13:59:00 lukem 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 __P((char *));
     54 void	append __P((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 __P((void));
    207 
    208 int
    209 yylex()
    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(c, str)
    361 	int c;
    362 	char *str;
    363 {
    364 	while (*str)
    365 		if (c == *str++)
    366 			return(1);
    367 	return(0);
    368 }
    369 
    370 /*
    371  * Insert or append ARROW command to list of hosts to be updated.
    372  */
    373 void
    374 insert(label, files, hosts, subcmds)
    375 	char *label;
    376 	struct namelist *files, *hosts;
    377 	struct subcmd *subcmds;
    378 {
    379 	struct cmd *c, *prev, *nc;
    380 	struct namelist *h, *nexth;
    381 
    382 	files = expand(files, E_VARS|E_SHELL);
    383 	hosts = expand(hosts, E_ALL);
    384 	for (h = hosts; h != NULL; nexth = h->n_next, free(h), h = nexth) {
    385 		/*
    386 		 * Search command list for an update to the same host.
    387 		 */
    388 		for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) {
    389 			if (strcmp(c->c_name, h->n_name) == 0) {
    390 				do {
    391 					prev = c;
    392 					c = c->c_next;
    393 				} while (c != NULL &&
    394 					strcmp(c->c_name, h->n_name) == 0);
    395 				break;
    396 			}
    397 		}
    398 		/*
    399 		 * Insert new command to update host.
    400 		 */
    401 		nc = ALLOC(cmd);
    402 		if (nc == NULL)
    403 			fatal("ran out of memory\n");
    404 		nc->c_type = ARROW;
    405 		nc->c_name = h->n_name;
    406 		nc->c_label = label;
    407 		nc->c_files = files;
    408 		nc->c_cmds = subcmds;
    409 		nc->c_next = c;
    410 		if (prev == NULL)
    411 			cmds = nc;
    412 		else
    413 			prev->c_next = nc;
    414 		/* update last_cmd if appending nc to cmds */
    415 		if (c == NULL)
    416 			last_cmd = nc;
    417 	}
    418 }
    419 
    420 /*
    421  * Append DCOLON command to the end of the command list since these are always
    422  * executed in the order they appear in the distfile.
    423  */
    424 void
    425 append(label, files, stamp, subcmds)
    426 	char *label;
    427 	struct namelist *files;
    428 	char *stamp;
    429 	struct subcmd *subcmds;
    430 {
    431 	struct cmd *c;
    432 
    433 	c = ALLOC(cmd);
    434 	if (c == NULL)
    435 		fatal("ran out of memory\n");
    436 	c->c_type = DCOLON;
    437 	c->c_name = stamp;
    438 	c->c_label = label;
    439 	c->c_files = expand(files, E_ALL);
    440 	c->c_cmds = subcmds;
    441 	c->c_next = NULL;
    442 	if (cmds == NULL)
    443 		cmds = last_cmd = c;
    444 	else {
    445 		last_cmd->c_next = c;
    446 		last_cmd = c;
    447 	}
    448 }
    449 
    450 /*
    451  * Error printing routine in parser.
    452  */
    453 void
    454 yyerror(s)
    455 	char *s;
    456 {
    457 
    458 	++nerrs;
    459 	fflush(stdout);
    460 	fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
    461 }
    462 
    463 /*
    464  * Return a copy of the string.
    465  */
    466 static char *
    467 makestr(str)
    468 	char *str;
    469 {
    470 	char *cp, *s;
    471 
    472 	str = cp = malloc(strlen(s = str) + 1);
    473 	if (cp == NULL)
    474 		fatal("ran out of memory\n");
    475 	while ((*cp++ = *s++) != NULL)
    476 		;
    477 	return(str);
    478 }
    479 
    480 /*
    481  * Allocate a namelist structure.
    482  */
    483 struct namelist *
    484 makenl(name)
    485 	char *name;
    486 {
    487 	struct namelist *nl;
    488 
    489 	nl = ALLOC(namelist);
    490 	if (nl == NULL)
    491 		fatal("ran out of memory\n");
    492 	nl->n_name = name;
    493 	nl->n_next = NULL;
    494 	return(nl);
    495 }
    496 
    497 /*
    498  * Make a sub command for lists of variables, commands, etc.
    499  */
    500 struct subcmd *
    501 makesubcmd(type)
    502 	int	type;
    503 {
    504 	struct subcmd *sc;
    505 
    506 	sc = ALLOC(subcmd);
    507 	if (sc == NULL)
    508 		fatal("ran out of memory\n");
    509 	sc->sc_type = type;
    510 	sc->sc_args = NULL;
    511 	sc->sc_next = NULL;
    512 	sc->sc_name = NULL;
    513 	return(sc);
    514 }
    515