gram.y revision 740638c8fa5a1c03618a9c75c3161dba57259a17
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#pragma ident	"%Z%%M%	%I%	%E% SMI"
19
20#include "defs.h"
21
22struct	cmd *cmds = NULL;
23struct	cmd *last_cmd;
24struct	namelist *last_n;
25struct	subcmd *last_sc;
26
27static void append(char *label, struct namelist *files, char *stamp,
28    struct subcmd *subcmds);
29void yyerror(char *s);
30
31%}
32
33%term EQUAL	1
34%term LP	2
35%term RP	3
36%term SM	4
37%term ARROW	5
38%term COLON	6
39%term DCOLON	7
40%term NAME	8
41%term STRING	9
42%term INSTALL	10
43%term NOTIFY	11
44%term EXCEPT	12
45%term PATTERN	13
46%term SPECIAL	14
47%term OPTION	15
48
49%union {
50	int intval;
51	char *string;
52	struct subcmd *subcmd;
53	struct namelist *namel;
54}
55
56%type <intval> OPTION, options
57%type <string> NAME, STRING
58%type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, cmdlist, cmd
59%type <namel> namelist, names, opt_namelist
60
61%%
62
63file:		  /* VOID */
64		| file command
65		;
66
67command:	  NAME EQUAL namelist = {
68			(void) lookup($1, INSERT, $3);
69		}
70		| namelist ARROW namelist cmdlist = {
71			insert(NULL, $1, $3, $4);
72		}
73		| NAME COLON namelist ARROW namelist cmdlist = {
74			insert($1, $3, $5, $6);
75		}
76		| namelist DCOLON NAME cmdlist = {
77			append(NULL, $1, $3, $4);
78		}
79		| NAME COLON namelist DCOLON NAME cmdlist = {
80			append($1, $3, $5, $6);
81		}
82		| error
83		;
84
85namelist:	  NAME = {
86			$$ = makenl($1);
87		}
88		| LP names RP = {
89			$$ = $2;
90		}
91		;
92
93names:		  /* VOID */ {
94			$$ = last_n = NULL;
95		}
96		| names NAME = {
97			if (last_n == NULL)
98				$$ = last_n = makenl($2);
99			else {
100				last_n->n_next = makenl($2);
101				last_n = last_n->n_next;
102				$$ = $1;
103			}
104		}
105		;
106
107cmdlist:	  /* VOID */ {
108			$$ = last_sc = NULL;
109		}
110		| cmdlist cmd = {
111			if (last_sc == NULL)
112				$$ = last_sc = $2;
113			else {
114				last_sc->sc_next = $2;
115				last_sc = $2;
116				$$ = $1;
117			}
118		}
119		;
120
121cmd:		  INSTALL options opt_namelist SM = {
122			register struct namelist *nl;
123
124			$1->sc_options = $2 | options;
125			if ($3 != NULL) {
126				nl = expand($3, E_VARS);
127				if (nl && nl->n_next != NULL)
128					yyerror("only one name allowed\n");
129				$1->sc_name = nl ? nl->n_name: NULL;
130				if (nl)
131					free(nl);
132			}
133			$$ = $1;
134		}
135		| NOTIFY namelist SM = {
136			if ($2 != NULL)
137				$1->sc_args = expand($2, E_VARS);
138			$$ = $1;
139		}
140		| EXCEPT namelist SM = {
141			if ($2 != NULL)
142				$1->sc_args = expand($2, E_ALL);
143			$$ = $1;
144		}
145		| PATTERN namelist SM = {
146			struct namelist *nl;
147			char *cp, *re_comp();
148
149			/*
150			 *	We dup the namelist in $2 because expand()
151			 *	destroys the list referred to in its first
152			 *	argument.
153			 */
154			for (nl = expand(dupnl($2), E_VARS); nl != NULL;
155				nl = nl->n_next)
156				if ((cp = re_comp(nl->n_name)) != NULL)
157					yyerror(cp);
158			$1->sc_args = expand($2, E_VARS);
159			$$ = $1;
160		}
161		| SPECIAL opt_namelist STRING SM = {
162			if ($2 != NULL)
163				$1->sc_args = expand($2, E_ALL);
164			$1->sc_name = $3;
165			$$ = $1;
166		}
167		;
168
169options:	  /* VOID */ = {
170			$$ = 0;
171		}
172		| options OPTION = {
173			$$ |= $2;
174		}
175		;
176
177opt_namelist:	  /* VOID */ = {
178			$$ = NULL;
179		}
180		| namelist = {
181			$$ = $1;
182		}
183		;
184
185%%
186
187int	yylineno = 1;
188extern	FILE *fin;
189
190int
191yylex()
192{
193	static char yytext[INMAX];
194	register int c;
195	register char *cp1, *cp2;
196	static char quotechars[] = "[]{}*?$";
197
198again:
199	switch (c = getc(fin)) {
200	case EOF:  /* end of file */
201		return(0);
202
203	case '#':  /* start of comment */
204		while ((c = getc(fin)) != EOF && c != '\n')
205			;
206		if (c == EOF)
207			return(0);
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