gram.y revision c15ff06a5cef5880e0afc02c7a87c6b22455f848
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 *
15 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
16 * Use is subject to license terms.
17 */
18
19#include "defs.h"
20
21struct	cmd *cmds = NULL;
22struct	cmd *last_cmd;
23struct	namelist *last_n;
24struct	subcmd *last_sc;
25
26static void append(char *label, struct namelist *files, char *stamp,
27    struct subcmd *subcmds);
28void yyerror(char *s);
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
62file:		  /* VOID */
63		| file command
64		;
65
66command:	  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
84namelist:	  NAME = {
85			$$ = makenl($1);
86		}
87		| LP names RP = {
88			$$ = $2;
89		}
90		;
91
92names:		  /* 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
106cmdlist:	  /* 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
120cmd:		  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 && nl->n_next != NULL)
127					yyerror("only one name allowed\n");
128				$1->sc_name = nl ? nl->n_name: NULL;
129				if (nl)
130					free(nl);
131			}
132			$$ = $1;
133		}
134		| NOTIFY namelist SM = {
135			if ($2 != NULL)
136				$1->sc_args = expand($2, E_VARS);
137			$$ = $1;
138		}
139		| EXCEPT namelist SM = {
140			if ($2 != NULL)
141				$1->sc_args = expand($2, E_ALL);
142			$$ = $1;
143		}
144		| PATTERN namelist SM = {
145			struct namelist *nl;
146			char *cp, *re_comp();
147
148			/*
149			 *	We dup the namelist in $2 because expand()
150			 *	destroys the list referred to in its first
151			 *	argument.
152			 */
153			for (nl = expand(dupnl($2), E_VARS); nl != NULL;
154				nl = nl->n_next)
155				if ((cp = re_comp(nl->n_name)) != NULL)
156					yyerror(cp);
157			$1->sc_args = expand($2, E_VARS);
158			$$ = $1;
159		}
160		| SPECIAL opt_namelist STRING SM = {
161			if ($2 != NULL)
162				$1->sc_args = expand($2, E_ALL);
163			$1->sc_name = $3;
164			$$ = $1;
165		}
166		;
167
168options:	  /* VOID */ = {
169			$$ = 0;
170		}
171		| options OPTION = {
172			$$ |= $2;
173		}
174		;
175
176opt_namelist:	  /* VOID */ = {
177			$$ = NULL;
178		}
179		| namelist = {
180			$$ = $1;
181		}
182		;
183
184%%
185
186int	yylineno = 1;
187extern	FILE *fin;
188
189int
190yylex()
191{
192	static char yytext[INMAX];
193	register int c;
194	register char *cp1, *cp2;
195	static char quotechars[] = "[]{}*?$";
196
197again:
198	switch (c = getc(fin)) {
199	case EOF:  /* end of file */
200		return(0);
201
202	case '#':  /* start of comment */
203		while ((c = getc(fin)) != EOF && c != '\n')
204			;
205		if (c == EOF)
206			return(0);
207		/* FALLTHROUGH */
208	case '\n':
209		yylineno++;
210	case ' ':
211	case '\t':  /* skip blanks */
212		goto again;
213
214	case '=':  /* EQUAL */
215		return(EQUAL);
216
217	case '(':  /* LP */
218		return(LP);
219
220	case ')':  /* RP */
221		return(RP);
222
223	case ';':  /* SM */
224		return(SM);
225
226	case '-':  /* -> */
227		if ((c = getc(fin)) == '>')
228			return(ARROW);
229		ungetc(c, fin);
230		c = '-';
231		break;
232
233	case '"':  /* STRING */
234		cp1 = yytext;
235		cp2 = &yytext[INMAX - 1];
236		for (;;) {
237			if (cp1 >= cp2) {
238				yyerror("command string too long\n");
239				break;
240			}
241			c = getc(fin);
242			if (c == EOF || c == '"')
243				break;
244			if (c == '\\') {
245				if ((c = getc(fin)) == EOF) {
246					*cp1++ = '\\';
247					break;
248				}
249			}
250			if (c == '\n') {
251				yylineno++;
252				c = ' '; /* can't send '\n' */
253			}
254			*cp1++ = c;
255		}
256		if (c != '"')
257			yyerror("missing closing '\"'\n");
258		*cp1 = '\0';
259		yylval.string = makestr(yytext);
260		return(STRING);
261
262	case ':':  /* : or :: */
263		if ((c = getc(fin)) == ':')
264			return(DCOLON);
265		ungetc(c, fin);
266		return(COLON);
267	}
268	cp1 = yytext;
269	cp2 = &yytext[INMAX - 1];
270	for (;;) {
271		if (cp1 >= cp2) {
272			yyerror("input line too long\n");
273			break;
274		}
275		if (c == '\\') {
276			if ((c = getc(fin)) != EOF) {
277				if (any(c, quotechars))
278					c |= QUOTE;
279			} else {
280				*cp1++ = '\\';
281				break;
282			}
283		}
284		*cp1++ = c;
285		c = getc(fin);
286		if (c == EOF || any(c, " \"'\t()=;:\n")) {
287			ungetc(c, fin);
288			break;
289		}
290	}
291	*cp1 = '\0';
292	if (yytext[0] == '-' && yytext[2] == '\0') {
293		switch (yytext[1]) {
294		case 'b':
295			yylval.intval = COMPARE;
296			return(OPTION);
297
298		case 'R':
299			yylval.intval = REMOVE;
300			return(OPTION);
301
302		case 'v':
303			yylval.intval = VERIFY;
304			return(OPTION);
305
306		case 'w':
307			yylval.intval = WHOLE;
308			return(OPTION);
309
310		case 'y':
311			yylval.intval = YOUNGER;
312			return(OPTION);
313
314		case 'h':
315			yylval.intval = FOLLOW;
316			return(OPTION);
317
318		case 'i':
319			yylval.intval = IGNLNKS;
320			return(OPTION);
321		}
322	}
323	if (!strcmp(yytext, "install"))
324		c = INSTALL;
325	else if (!strcmp(yytext, "notify"))
326		c = NOTIFY;
327	else if (!strcmp(yytext, "except"))
328		c = EXCEPT;
329	else if (!strcmp(yytext, "except_pat"))
330		c = PATTERN;
331	else if (!strcmp(yytext, "special"))
332		c = SPECIAL;
333	else {
334		yylval.string = makestr(yytext);
335		return(NAME);
336	}
337	yylval.subcmd = makesubcmd(c);
338	return(c);
339}
340
341int
342any(c, str)
343	register int c;
344	register char *str;
345{
346	while (*str)
347		if (c == *str++)
348			return(1);
349	return(0);
350}
351
352/*
353 * Insert or append ARROW command to list of hosts to be updated.
354 */
355void
356insert(label, files, hosts, subcmds)
357	char *label;
358	struct namelist *files, *hosts;
359	struct subcmd *subcmds;
360{
361	register struct cmd *c, *prev, *nc;
362	register struct namelist *h, *oldh;
363
364	files = expand(files, E_VARS|E_SHELL);
365	hosts = expand(hosts, E_ALL);
366if (debug) {
367	printf("insert:  files = ");
368	prnames(files);
369	printf("insert:  hosts = ");
370	prnames(hosts);
371	if (cmds)
372		prcmd(cmds);
373	else
374		printf("insert:  cmds NULL\n");
375}
376	for (h = hosts; h != NULL; oldh = h, h = h->n_next, free(oldh)) {
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 */
416static void
417append(label, files, stamp, subcmds)
418	char *label;
419	struct namelist *files;
420	char *stamp;
421	struct subcmd *subcmds;
422{
423	register struct cmd *c;
424
425	c = ALLOC(cmd);
426	if (c == NULL)
427		fatal("ran out of memory\n");
428	c->c_type = DCOLON;
429	c->c_name = stamp;
430	c->c_label = label;
431	c->c_files = expand(files, E_ALL);
432	c->c_cmds = subcmds;
433	c->c_next = NULL;
434	if (cmds == NULL)
435		cmds = last_cmd = c;
436	else {
437		last_cmd->c_next = c;
438		last_cmd = c;
439	}
440}
441
442/*
443 * Error printing routine in parser.
444 */
445void
446yyerror(s)
447	char *s;
448{
449	extern int yychar;
450
451	nerrs++;
452	fflush(stdout);
453	fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
454}
455
456/*
457 * Return a copy of the string.
458 */
459char *
460makestr(str)
461	char *str;
462{
463	register char *cp, *s;
464
465	str = cp = malloc(strlen(s = str) + 1);
466	if (cp == NULL)
467		fatal("ran out of memory\n");
468	while (*cp++ = *s++)
469		;
470	return(str);
471}
472
473/*
474 * Allocate a namelist structure.
475 */
476struct namelist *
477makenl(name)
478	char *name;
479{
480	register struct namelist *nl;
481
482	nl = ALLOC(namelist);
483	if (nl == NULL)
484		fatal("ran out of memory\n");
485	nl->n_name = name;
486	nl->n_next = NULL;
487	return(nl);
488}
489
490/*
491 * Duplicate an existing namelist structure.  Only used by the PATTERN
492 * code, and then only because expand() is destructive.
493 */
494struct namelist *
495dupnl(old)
496	struct namelist *old;
497{
498	struct namelist *n;
499	struct namelist *new, *newhead = (struct namelist *) NULL;
500	struct namelist *prev = (struct namelist *) NULL;
501
502	for (n = old; n; n = n->n_next) {
503		new = ALLOC(namelist);
504		if (new == (struct namelist *) NULL)
505			fatal("ran out of memory\n");
506		if (newhead == (struct namelist *) NULL)
507			newhead = new;
508		if (n->n_name) {
509			if ((new->n_name = strdup(n->n_name)) == (char *) NULL)
510				fatal("ran out of memory\n");
511		} else
512			new->n_name = (char *) NULL;
513		if (prev)
514			prev->n_next = new;
515		prev = new;
516	}
517	if (prev)
518		prev->n_next = (struct namelist *) NULL;
519
520	return (newhead);
521}
522
523/*
524 * Make a sub command for lists of variables, commands, etc.
525 */
526struct subcmd *
527makesubcmd(type, name)
528	int type;
529	register char *name;
530{
531	register char *cp;
532	register struct subcmd *sc;
533
534	sc = ALLOC(subcmd);
535	if (sc == NULL)
536		fatal("ran out of memory\n");
537	sc->sc_type = type;
538	sc->sc_args = NULL;
539	sc->sc_next = NULL;
540	sc->sc_name = NULL;
541	return(sc);
542}
543