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