xref: /original-bsd/usr.bin/rdist/gram.y (revision 7cab520e)
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.4 (Berkeley) 06/29/88";
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->n_next != NULL)
127 					yyerror("only one name allowed\n");
128 				$1->sc_name = nl->n_name;
129 				free(nl);
130 			}
131 			$$ = $1;
132 		}
133 		| NOTIFY namelist SM = {
134 			if ($2 != NULL)
135 				$1->sc_args = expand($2, E_VARS);
136 			$$ = $1;
137 		}
138 		| EXCEPT namelist SM = {
139 			if ($2 != NULL)
140 				$1->sc_args = expand($2, E_ALL);
141 			$$ = $1;
142 		}
143 		| PATTERN namelist SM = {
144 			struct namelist *nl;
145 			char *cp, *re_comp();
146 
147 			for (nl = $2; nl != NULL; nl = nl->n_next)
148 				if ((cp = re_comp(nl->n_name)) != NULL)
149 					yyerror(cp);
150 			$1->sc_args = expand($2, E_VARS);
151 			$$ = $1;
152 		}
153 		| SPECIAL opt_namelist STRING SM = {
154 			if ($2 != NULL)
155 				$1->sc_args = expand($2, E_ALL);
156 			$1->sc_name = $3;
157 			$$ = $1;
158 		}
159 		;
160 
161 options:	  /* VOID */ = {
162 			$$ = 0;
163 		}
164 		| options OPTION = {
165 			$$ |= $2;
166 		}
167 		;
168 
169 opt_namelist:	  /* VOID */ = {
170 			$$ = NULL;
171 		}
172 		| namelist = {
173 			$$ = $1;
174 		}
175 		;
176 
177 %%
178 
179 int	yylineno = 1;
180 extern	FILE *fin;
181 
182 yylex()
183 {
184 	static char yytext[INMAX];
185 	register int c;
186 	register char *cp1, *cp2;
187 	static char quotechars[] = "[]{}*?$";
188 
189 again:
190 	switch (c = getc(fin)) {
191 	case EOF:  /* end of file */
192 		return(0);
193 
194 	case '#':  /* start of comment */
195 		while ((c = getc(fin)) != EOF && c != '\n')
196 			;
197 		if (c == EOF)
198 			return(0);
199 	case '\n':
200 		yylineno++;
201 	case ' ':
202 	case '\t':  /* skip blanks */
203 		goto again;
204 
205 	case '=':  /* EQUAL */
206 		return(EQUAL);
207 
208 	case '(':  /* LP */
209 		return(LP);
210 
211 	case ')':  /* RP */
212 		return(RP);
213 
214 	case ';':  /* SM */
215 		return(SM);
216 
217 	case '-':  /* -> */
218 		if ((c = getc(fin)) == '>')
219 			return(ARROW);
220 		ungetc(c, fin);
221 		c = '-';
222 		break;
223 
224 	case '"':  /* STRING */
225 		cp1 = yytext;
226 		cp2 = &yytext[INMAX - 1];
227 		for (;;) {
228 			if (cp1 >= cp2) {
229 				yyerror("command string too long\n");
230 				break;
231 			}
232 			c = getc(fin);
233 			if (c == EOF || c == '"')
234 				break;
235 			if (c == '\\') {
236 				if ((c = getc(fin)) == EOF) {
237 					*cp1++ = '\\';
238 					break;
239 				}
240 			}
241 			if (c == '\n') {
242 				yylineno++;
243 				c = ' '; /* can't send '\n' */
244 			}
245 			*cp1++ = c;
246 		}
247 		if (c != '"')
248 			yyerror("missing closing '\"'\n");
249 		*cp1 = '\0';
250 		yylval.string = makestr(yytext);
251 		return(STRING);
252 
253 	case ':':  /* : or :: */
254 		if ((c = getc(fin)) == ':')
255 			return(DCOLON);
256 		ungetc(c, fin);
257 		return(COLON);
258 	}
259 	cp1 = yytext;
260 	cp2 = &yytext[INMAX - 1];
261 	for (;;) {
262 		if (cp1 >= cp2) {
263 			yyerror("input line too long\n");
264 			break;
265 		}
266 		if (c == '\\') {
267 			if ((c = getc(fin)) != EOF) {
268 				if (any(c, quotechars))
269 					c |= QUOTE;
270 			} else {
271 				*cp1++ = '\\';
272 				break;
273 			}
274 		}
275 		*cp1++ = c;
276 		c = getc(fin);
277 		if (c == EOF || any(c, " \"'\t()=;:\n")) {
278 			ungetc(c, fin);
279 			break;
280 		}
281 	}
282 	*cp1 = '\0';
283 	if (yytext[0] == '-' && yytext[2] == '\0') {
284 		switch (yytext[1]) {
285 		case 'b':
286 			yylval.intval = COMPARE;
287 			return(OPTION);
288 
289 		case 'R':
290 			yylval.intval = REMOVE;
291 			return(OPTION);
292 
293 		case 'v':
294 			yylval.intval = VERIFY;
295 			return(OPTION);
296 
297 		case 'w':
298 			yylval.intval = WHOLE;
299 			return(OPTION);
300 
301 		case 'y':
302 			yylval.intval = YOUNGER;
303 			return(OPTION);
304 
305 		case 'h':
306 			yylval.intval = FOLLOW;
307 			return(OPTION);
308 
309 		case 'i':
310 			yylval.intval = IGNLNKS;
311 			return(OPTION);
312 		}
313 	}
314 	if (!strcmp(yytext, "install"))
315 		c = INSTALL;
316 	else if (!strcmp(yytext, "notify"))
317 		c = NOTIFY;
318 	else if (!strcmp(yytext, "except"))
319 		c = EXCEPT;
320 	else if (!strcmp(yytext, "except_pat"))
321 		c = PATTERN;
322 	else if (!strcmp(yytext, "special"))
323 		c = SPECIAL;
324 	else {
325 		yylval.string = makestr(yytext);
326 		return(NAME);
327 	}
328 	yylval.subcmd = makesubcmd(c);
329 	return(c);
330 }
331 
332 any(c, str)
333 	register int c;
334 	register char *str;
335 {
336 	while (*str)
337 		if (c == *str++)
338 			return(1);
339 	return(0);
340 }
341 
342 /*
343  * Insert or append ARROW command to list of hosts to be updated.
344  */
345 insert(label, files, hosts, subcmds)
346 	char *label;
347 	struct namelist *files, *hosts;
348 	struct subcmd *subcmds;
349 {
350 	register struct cmd *c, *prev, *nc;
351 	register struct namelist *h;
352 
353 	files = expand(files, E_VARS|E_SHELL);
354 	hosts = expand(hosts, E_ALL);
355 	for (h = hosts; h != NULL; free(h), h = h->n_next) {
356 		/*
357 		 * Search command list for an update to the same host.
358 		 */
359 		for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) {
360 			if (strcmp(c->c_name, h->n_name) == 0) {
361 				do {
362 					prev = c;
363 					c = c->c_next;
364 				} while (c != NULL &&
365 					strcmp(c->c_name, h->n_name) == 0);
366 				break;
367 			}
368 		}
369 		/*
370 		 * Insert new command to update host.
371 		 */
372 		nc = ALLOC(cmd);
373 		if (nc == NULL)
374 			fatal("ran out of memory\n");
375 		nc->c_type = ARROW;
376 		nc->c_name = h->n_name;
377 		nc->c_label = label;
378 		nc->c_files = files;
379 		nc->c_cmds = subcmds;
380 		nc->c_next = c;
381 		if (prev == NULL)
382 			cmds = nc;
383 		else
384 			prev->c_next = nc;
385 		/* update last_cmd if appending nc to cmds */
386 		if (c == NULL)
387 			last_cmd = nc;
388 	}
389 }
390 
391 /*
392  * Append DCOLON command to the end of the command list since these are always
393  * executed in the order they appear in the distfile.
394  */
395 append(label, files, stamp, subcmds)
396 	char *label;
397 	struct namelist *files;
398 	char *stamp;
399 	struct subcmd *subcmds;
400 {
401 	register struct cmd *c;
402 
403 	c = ALLOC(cmd);
404 	if (c == NULL)
405 		fatal("ran out of memory\n");
406 	c->c_type = DCOLON;
407 	c->c_name = stamp;
408 	c->c_label = label;
409 	c->c_files = expand(files, E_ALL);
410 	c->c_cmds = subcmds;
411 	c->c_next = NULL;
412 	if (cmds == NULL)
413 		cmds = last_cmd = c;
414 	else {
415 		last_cmd->c_next = c;
416 		last_cmd = c;
417 	}
418 }
419 
420 /*
421  * Error printing routine in parser.
422  */
423 yyerror(s)
424 	char *s;
425 {
426 	extern int yychar;
427 
428 	nerrs++;
429 	fflush(stdout);
430 	fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
431 }
432 
433 /*
434  * Return a copy of the string.
435  */
436 char *
437 makestr(str)
438 	char *str;
439 {
440 	register char *cp, *s;
441 
442 	str = cp = malloc(strlen(s = str) + 1);
443 	if (cp == NULL)
444 		fatal("ran out of memory\n");
445 	while (*cp++ = *s++)
446 		;
447 	return(str);
448 }
449 
450 /*
451  * Allocate a namelist structure.
452  */
453 struct namelist *
454 makenl(name)
455 	char *name;
456 {
457 	register struct namelist *nl;
458 
459 	nl = ALLOC(namelist);
460 	if (nl == NULL)
461 		fatal("ran out of memory\n");
462 	nl->n_name = name;
463 	nl->n_next = NULL;
464 	return(nl);
465 }
466 
467 /*
468  * Make a sub command for lists of variables, commands, etc.
469  */
470 struct subcmd *
471 makesubcmd(type, name)
472 	int type;
473 	register char *name;
474 {
475 	register char *cp;
476 	register struct subcmd *sc;
477 
478 	sc = ALLOC(subcmd);
479 	if (sc == NULL)
480 		fatal("ran out of memory\n");
481 	sc->sc_type = type;
482 	sc->sc_args = NULL;
483 	sc->sc_next = NULL;
484 	sc->sc_name = NULL;
485 	return(sc);
486 }
487