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