17c478bdstevel@tonic-gate%{
27c478bdstevel@tonic-gate/*
37c478bdstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California.
47c478bdstevel@tonic-gate * All rights reserved.
57c478bdstevel@tonic-gate *
67c478bdstevel@tonic-gate * Redistribution and use in source and binary forms are permitted
77c478bdstevel@tonic-gate * provided that the above copyright notice and this paragraph are
87c478bdstevel@tonic-gate * duplicated in all such forms and that any documentation,
97c478bdstevel@tonic-gate * advertising materials, and other materials related to such
107c478bdstevel@tonic-gate * distribution and use acknowledge that the software was developed
117c478bdstevel@tonic-gate * by the University of California, Berkeley.  The name of the
127c478bdstevel@tonic-gate * University may not be used to endorse or promote products derived
137c478bdstevel@tonic-gate * from this software without specific prior written permission.
147c478bdstevel@tonic-gate *
157c478bdstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
167c478bdstevel@tonic-gate * Use is subject to license terms.
177c478bdstevel@tonic-gate */
187c478bdstevel@tonic-gate
197c478bdstevel@tonic-gate#include "defs.h"
207c478bdstevel@tonic-gate
217c478bdstevel@tonic-gatestruct	cmd *cmds = NULL;
227c478bdstevel@tonic-gatestruct	cmd *last_cmd;
237c478bdstevel@tonic-gatestruct	namelist *last_n;
247c478bdstevel@tonic-gatestruct	subcmd *last_sc;
257c478bdstevel@tonic-gate
26740638cbwstatic void append(char *label, struct namelist *files, char *stamp,
27740638cbw    struct subcmd *subcmds);
28740638cbwvoid yyerror(char *s);
29740638cbw
307c478bdstevel@tonic-gate%}
317c478bdstevel@tonic-gate
327c478bdstevel@tonic-gate%term EQUAL	1
337c478bdstevel@tonic-gate%term LP	2
347c478bdstevel@tonic-gate%term RP	3
357c478bdstevel@tonic-gate%term SM	4
367c478bdstevel@tonic-gate%term ARROW	5
377c478bdstevel@tonic-gate%term COLON	6
387c478bdstevel@tonic-gate%term DCOLON	7
397c478bdstevel@tonic-gate%term NAME	8
407c478bdstevel@tonic-gate%term STRING	9
417c478bdstevel@tonic-gate%term INSTALL	10
427c478bdstevel@tonic-gate%term NOTIFY	11
437c478bdstevel@tonic-gate%term EXCEPT	12
447c478bdstevel@tonic-gate%term PATTERN	13
457c478bdstevel@tonic-gate%term SPECIAL	14
467c478bdstevel@tonic-gate%term OPTION	15
477c478bdstevel@tonic-gate
487c478bdstevel@tonic-gate%union {
497c478bdstevel@tonic-gate	int intval;
507c478bdstevel@tonic-gate	char *string;
517c478bdstevel@tonic-gate	struct subcmd *subcmd;
527c478bdstevel@tonic-gate	struct namelist *namel;
537c478bdstevel@tonic-gate}
547c478bdstevel@tonic-gate
557c478bdstevel@tonic-gate%type <intval> OPTION, options
567c478bdstevel@tonic-gate%type <string> NAME, STRING
577c478bdstevel@tonic-gate%type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, cmdlist, cmd
587c478bdstevel@tonic-gate%type <namel> namelist, names, opt_namelist
597c478bdstevel@tonic-gate
607c478bdstevel@tonic-gate%%
617c478bdstevel@tonic-gate
627c478bdstevel@tonic-gatefile:		  /* VOID */
637c478bdstevel@tonic-gate		| file command
647c478bdstevel@tonic-gate		;
657c478bdstevel@tonic-gate
667c478bdstevel@tonic-gatecommand:	  NAME EQUAL namelist = {
677c478bdstevel@tonic-gate			(void) lookup($1, INSERT, $3);
687c478bdstevel@tonic-gate		}
697c478bdstevel@tonic-gate		| namelist ARROW namelist cmdlist = {
707c478bdstevel@tonic-gate			insert(NULL, $1, $3, $4);
717c478bdstevel@tonic-gate		}
727c478bdstevel@tonic-gate		| NAME COLON namelist ARROW namelist cmdlist = {
737c478bdstevel@tonic-gate			insert($1, $3, $5, $6);
747c478bdstevel@tonic-gate		}
757c478bdstevel@tonic-gate		| namelist DCOLON NAME cmdlist = {
767c478bdstevel@tonic-gate			append(NULL, $1, $3, $4);
777c478bdstevel@tonic-gate		}
787c478bdstevel@tonic-gate		| NAME COLON namelist DCOLON NAME cmdlist = {
797c478bdstevel@tonic-gate			append($1, $3, $5, $6);
807c478bdstevel@tonic-gate		}
817c478bdstevel@tonic-gate		| error
827c478bdstevel@tonic-gate		;
837c478bdstevel@tonic-gate
847c478bdstevel@tonic-gatenamelist:	  NAME = {
857c478bdstevel@tonic-gate			$$ = makenl($1);
867c478bdstevel@tonic-gate		}
877c478bdstevel@tonic-gate		| LP names RP = {
887c478bdstevel@tonic-gate			$$ = $2;
897c478bdstevel@tonic-gate		}
907c478bdstevel@tonic-gate		;
917c478bdstevel@tonic-gate
927c478bdstevel@tonic-gatenames:		  /* VOID */ {
937c478bdstevel@tonic-gate			$$ = last_n = NULL;
947c478bdstevel@tonic-gate		}
957c478bdstevel@tonic-gate		| names NAME = {
967c478bdstevel@tonic-gate			if (last_n == NULL)
977c478bdstevel@tonic-gate				$$ = last_n = makenl($2);
987c478bdstevel@tonic-gate			else {
997c478bdstevel@tonic-gate				last_n->n_next = makenl($2);
1007c478bdstevel@tonic-gate				last_n = last_n->n_next;
1017c478bdstevel@tonic-gate				$$ = $1;
1027c478bdstevel@tonic-gate			}
1037c478bdstevel@tonic-gate		}
1047c478bdstevel@tonic-gate		;
1057c478bdstevel@tonic-gate
1067c478bdstevel@tonic-gatecmdlist:	  /* VOID */ {
1077c478bdstevel@tonic-gate			$$ = last_sc = NULL;
1087c478bdstevel@tonic-gate		}
1097c478bdstevel@tonic-gate		| cmdlist cmd = {
1107c478bdstevel@tonic-gate			if (last_sc == NULL)
1117c478bdstevel@tonic-gate				$$ = last_sc = $2;
1127c478bdstevel@tonic-gate			else {
1137c478bdstevel@tonic-gate				last_sc->sc_next = $2;
1147c478bdstevel@tonic-gate				last_sc = $2;
1157c478bdstevel@tonic-gate				$$ = $1;
1167c478bdstevel@tonic-gate			}
1177c478bdstevel@tonic-gate		}
1187c478bdstevel@tonic-gate		;
1197c478bdstevel@tonic-gate
1207c478bdstevel@tonic-gatecmd:		  INSTALL options opt_namelist SM = {
1217c478bdstevel@tonic-gate			register struct namelist *nl;
1227c478bdstevel@tonic-gate
1237c478bdstevel@tonic-gate			$1->sc_options = $2 | options;
1247c478bdstevel@tonic-gate			if ($3 != NULL) {
1257c478bdstevel@tonic-gate				nl = expand($3, E_VARS);
1267c478bdstevel@tonic-gate				if (nl && nl->n_next != NULL)
1277c478bdstevel@tonic-gate					yyerror("only one name allowed\n");
1287c478bdstevel@tonic-gate				$1->sc_name = nl ? nl->n_name: NULL;
1297c478bdstevel@tonic-gate				if (nl)
1307c478bdstevel@tonic-gate					free(nl);
1317c478bdstevel@tonic-gate			}
1327c478bdstevel@tonic-gate			$$ = $1;
1337c478bdstevel@tonic-gate		}
1347c478bdstevel@tonic-gate		| NOTIFY namelist SM = {
1357c478bdstevel@tonic-gate			if ($2 != NULL)
1367c478bdstevel@tonic-gate				$1->sc_args = expand($2, E_VARS);
1377c478bdstevel@tonic-gate			$$ = $1;
1387c478bdstevel@tonic-gate		}
1397c478bdstevel@tonic-gate		| EXCEPT namelist SM = {
1407c478bdstevel@tonic-gate			if ($2 != NULL)
1417c478bdstevel@tonic-gate				$1->sc_args = expand($2, E_ALL);
1427c478bdstevel@tonic-gate			$$ = $1;
1437c478bdstevel@tonic-gate		}
1447c478bdstevel@tonic-gate		| PATTERN namelist SM = {
1457c478bdstevel@tonic-gate			struct namelist *nl;
1467c478bdstevel@tonic-gate			char *cp, *re_comp();
1477c478bdstevel@tonic-gate
1487c478bdstevel@tonic-gate			/*
1497c478bdstevel@tonic-gate			 *	We dup the namelist in $2 because expand()
1507c478bdstevel@tonic-gate			 *	destroys the list referred to in its first
1517c478bdstevel@tonic-gate			 *	argument.
1527c478bdstevel@tonic-gate			 */
1537c478bdstevel@tonic-gate			for (nl = expand(dupnl($2), E_VARS); nl != NULL;
1547c478bdstevel@tonic-gate				nl = nl->n_next)
1557c478bdstevel@tonic-gate				if ((cp = re_comp(nl->n_name)) != NULL)
1567c478bdstevel@tonic-gate					yyerror(cp);
1577c478bdstevel@tonic-gate			$1->sc_args = expand($2, E_VARS);
1587c478bdstevel@tonic-gate			$$ = $1;
1597c478bdstevel@tonic-gate		}
1607c478bdstevel@tonic-gate		| SPECIAL opt_namelist STRING SM = {
1617c478bdstevel@tonic-gate			if ($2 != NULL)
1627c478bdstevel@tonic-gate				$1->sc_args = expand($2, E_ALL);
1637c478bdstevel@tonic-gate			$1->sc_name = $3;
1647c478bdstevel@tonic-gate			$$ = $1;
1657c478bdstevel@tonic-gate		}
1667c478bdstevel@tonic-gate		;
1677c478bdstevel@tonic-gate
1687c478bdstevel@tonic-gateoptions:	  /* VOID */ = {
1697c478bdstevel@tonic-gate			$$ = 0;
1707c478bdstevel@tonic-gate		}
1717c478bdstevel@tonic-gate		| options OPTION = {
1727c478bdstevel@tonic-gate			$$ |= $2;
1737c478bdstevel@tonic-gate		}
1747c478bdstevel@tonic-gate		;
1757c478bdstevel@tonic-gate
1767c478bdstevel@tonic-gateopt_namelist:	  /* VOID */ = {
1777c478bdstevel@tonic-gate			$$ = NULL;
1787c478bdstevel@tonic-gate		}
1797c478bdstevel@tonic-gate		| namelist = {
1807c478bdstevel@tonic-gate			$$ = $1;
1817c478bdstevel@tonic-gate		}
1827c478bdstevel@tonic-gate		;
1837c478bdstevel@tonic-gate
1847c478bdstevel@tonic-gate%%
1857c478bdstevel@tonic-gate
1867c478bdstevel@tonic-gateint	yylineno = 1;
1877c478bdstevel@tonic-gateextern	FILE *fin;
1887c478bdstevel@tonic-gate
189740638cbwint
1907c478bdstevel@tonic-gateyylex()
1917c478bdstevel@tonic-gate{
1927c478bdstevel@tonic-gate	static char yytext[INMAX];
1937c478bdstevel@tonic-gate	register int c;
1947c478bdstevel@tonic-gate	register char *cp1, *cp2;
1957c478bdstevel@tonic-gate	static char quotechars[] = "[]{}*?$";
1967c478bdstevel@tonic-gate
1977c478bdstevel@tonic-gateagain:
1987c478bdstevel@tonic-gate	switch (c = getc(fin)) {
1997c478bdstevel@tonic-gate	case EOF:  /* end of file */
2007c478bdstevel@tonic-gate		return(0);
2017c478bdstevel@tonic-gate
2027c478bdstevel@tonic-gate	case '#':  /* start of comment */
2037c478bdstevel@tonic-gate		while ((c = getc(fin)) != EOF && c != '\n')
2047c478bdstevel@tonic-gate			;
2057c478bdstevel@tonic-gate		if (c == EOF)
2067c478bdstevel@tonic-gate			return(0);
207c15ff06Toomas Soome		/* FALLTHROUGH */
2087c478bdstevel@tonic-gate	case '\n':
2097c478bdstevel@tonic-gate		yylineno++;
2107c478bdstevel@tonic-gate	case ' ':
2117c478bdstevel@tonic-gate	case '\t':  /* skip blanks */
2127c478bdstevel@tonic-gate		goto again;
2137c478bdstevel@tonic-gate
2147c478bdstevel@tonic-gate	case '=':  /* EQUAL */
2157c478bdstevel@tonic-gate		return(EQUAL);
2167c478bdstevel@tonic-gate
2177c478bdstevel@tonic-gate	case '(':  /* LP */
2187c478bdstevel@tonic-gate		return(LP);
2197c478bdstevel@tonic-gate
2207c478bdstevel@tonic-gate	case ')':  /* RP */
2217c478bdstevel@tonic-gate		return(RP);
2227c478bdstevel@tonic-gate
2237c478bdstevel@tonic-gate	case ';':  /* SM */
2247c478bdstevel@tonic-gate		return(SM);
2257c478bdstevel@tonic-gate
2267c478bdstevel@tonic-gate	case '-':  /* -> */
2277c478bdstevel@tonic-gate		if ((c = getc(fin)) == '>')
2287c478bdstevel@tonic-gate			return(ARROW);
2297c478bdstevel@tonic-gate		ungetc(c, fin);
2307c478bdstevel@tonic-gate		c = '-';
2317c478bdstevel@tonic-gate		break;
2327c478bdstevel@tonic-gate
2337c478bdstevel@tonic-gate	case '"':  /* STRING */
2347c478bdstevel@tonic-gate		cp1 = yytext;
2357c478bdstevel@tonic-gate		cp2 = &yytext[INMAX - 1];
2367c478bdstevel@tonic-gate		for (;;) {
2377c478bdstevel@tonic-gate			if (cp1 >= cp2) {
2387c478bdstevel@tonic-gate				yyerror("command string too long\n");
2397c478bdstevel@tonic-gate				break;
2407c478bdstevel@tonic-gate			}
2417c478bdstevel@tonic-gate			c = getc(fin);
2427c478bdstevel@tonic-gate			if (c == EOF || c == '"')
2437c478bdstevel@tonic-gate				break;
2447c478bdstevel@tonic-gate			if (c == '\\') {
2457c478bdstevel@tonic-gate				if ((c = getc(fin)) == EOF) {
2467c478bdstevel@tonic-gate					*cp1++ = '\\';
2477c478bdstevel@tonic-gate					break;
2487c478bdstevel@tonic-gate				}
2497c478bdstevel@tonic-gate			}
2507c478bdstevel@tonic-gate			if (c == '\n') {
2517c478bdstevel@tonic-gate				yylineno++;
2527c478bdstevel@tonic-gate				c = ' '; /* can't send '\n' */
2537c478bdstevel@tonic-gate			}
2547c478bdstevel@tonic-gate			*cp1++ = c;
2557c478bdstevel@tonic-gate		}
2567c478bdstevel@tonic-gate		if (c != '"')
2577c478bdstevel@tonic-gate			yyerror("missing closing '\"'\n");
2587c478bdstevel@tonic-gate		*cp1 = '\0';
2597c478bdstevel@tonic-gate		yylval.string = makestr(yytext);
2607c478bdstevel@tonic-gate		return(STRING);
2617c478bdstevel@tonic-gate
2627c478bdstevel@tonic-gate	case ':':  /* : or :: */
2637c478bdstevel@tonic-gate		if ((c = getc(fin)) == ':')
2647c478bdstevel@tonic-gate			return(DCOLON);
2657c478bdstevel@tonic-gate		ungetc(c, fin);
2667c478bdstevel@tonic-gate		return(COLON);
2677c478bdstevel@tonic-gate	}
2687c478bdstevel@tonic-gate	cp1 = yytext;
2697c478bdstevel@tonic-gate	cp2 = &yytext[INMAX - 1];
2707c478bdstevel@tonic-gate	for (;;) {
2717c478bdstevel@tonic-gate		if (cp1 >= cp2) {
2727c478bdstevel@tonic-gate			yyerror("input line too long\n");
2737c478bdstevel@tonic-gate			break;
2747c478bdstevel@tonic-gate		}
2757c478bdstevel@tonic-gate		if (c == '\\') {
2767c478bdstevel@tonic-gate			if ((c = getc(fin)) != EOF) {
2777c478bdstevel@tonic-gate				if (any(c, quotechars))
2787c478bdstevel@tonic-gate					c |= QUOTE;
2797c478bdstevel@tonic-gate			} else {
2807c478bdstevel@tonic-gate				*cp1++ = '\\';
2817c478bdstevel@tonic-gate				break;
2827c478bdstevel@tonic-gate			}
2837c478bdstevel@tonic-gate		}
2847c478bdstevel@tonic-gate		*cp1++ = c;
2857c478bdstevel@tonic-gate		c = getc(fin);
2867c478bdstevel@tonic-gate		if (c == EOF || any(c, " \"'\t()=;:\n")) {
2877c478bdstevel@tonic-gate			ungetc(c, fin);
2887c478bdstevel@tonic-gate			break;
2897c478bdstevel@tonic-gate		}
2907c478bdstevel@tonic-gate	}
2917c478bdstevel@tonic-gate	*cp1 = '\0';
2927c478bdstevel@tonic-gate	if (yytext[0] == '-' && yytext[2] == '\0') {
2937c478bdstevel@tonic-gate		switch (yytext[1]) {
2947c478bdstevel@tonic-gate		case 'b':
2957c478bdstevel@tonic-gate			yylval.intval = COMPARE;
2967c478bdstevel@tonic-gate			return(OPTION);
2977c478bdstevel@tonic-gate
2987c478bdstevel@tonic-gate		case 'R':
2997c478bdstevel@tonic-gate			yylval.intval = REMOVE;
3007c478bdstevel@tonic-gate			return(OPTION);
3017c478bdstevel@tonic-gate
3027c478bdstevel@tonic-gate		case 'v':
3037c478bdstevel@tonic-gate			yylval.intval = VERIFY;
3047c478bdstevel@tonic-gate			return(OPTION);
3057c478bdstevel@tonic-gate
3067c478bdstevel@tonic-gate		case 'w':
3077c478bdstevel@tonic-gate			yylval.intval = WHOLE;
3087c478bdstevel@tonic-gate			return(OPTION);
3097c478bdstevel@tonic-gate
3107c478bdstevel@tonic-gate		case 'y':
3117c478bdstevel@tonic-gate			yylval.intval = YOUNGER;
3127c478bdstevel@tonic-gate			return(OPTION);
3137c478bdstevel@tonic-gate
3147c478bdstevel@tonic-gate		case 'h':
3157c478bdstevel@tonic-gate			yylval.intval = FOLLOW;
3167c478bdstevel@tonic-gate			return(OPTION);
3177c478bdstevel@tonic-gate
3187c478bdstevel@tonic-gate		case 'i':
3197c478bdstevel@tonic-gate			yylval.intval = IGNLNKS;
3207c478bdstevel@tonic-gate			return(OPTION);
3217c478bdstevel@tonic-gate		}
3227c478bdstevel@tonic-gate	}
3237c478bdstevel@tonic-gate	if (!strcmp(yytext, "install"))
3247c478bdstevel@tonic-gate		c = INSTALL;
3257c478bdstevel@tonic-gate	else if (!strcmp(yytext, "notify"))
3267c478bdstevel@tonic-gate		c = NOTIFY;
3277c478bdstevel@tonic-gate	else if (!strcmp(yytext, "except"))
3287c478bdstevel@tonic-gate		c = EXCEPT;
3297c478bdstevel@tonic-gate	else if (!strcmp(yytext, "except_pat"))
3307c478bdstevel@tonic-gate		c = PATTERN;
3317c478bdstevel@tonic-gate	else if (!strcmp(yytext, "special"))
3327c478bdstevel@tonic-gate		c = SPECIAL;
3337c478bdstevel@tonic-gate	else {
3347c478bdstevel@tonic-gate		yylval.string = makestr(yytext);
3357c478bdstevel@tonic-gate		return(NAME);
3367c478bdstevel@tonic-gate	}
3377c478bdstevel@tonic-gate	yylval.subcmd = makesubcmd(c);
3387c478bdstevel@tonic-gate	return(c);
3397c478bdstevel@tonic-gate}
3407c478bdstevel@tonic-gate
341740638cbwint
3427c478bdstevel@tonic-gateany(c, str)
3437c478bdstevel@tonic-gate	register int c;
3447c478bdstevel@tonic-gate	register char *str;
3457c478bdstevel@tonic-gate{
3467c478bdstevel@tonic-gate	while (*str)
3477c478bdstevel@tonic-gate		if (c == *str++)
3487c478bdstevel@tonic-gate			return(1);
3497c478bdstevel@tonic-gate	return(0);
3507c478bdstevel@tonic-gate}
3517c478bdstevel@tonic-gate
3527c478bdstevel@tonic-gate/*
3537c478bdstevel@tonic-gate * Insert or append ARROW command to list of hosts to be updated.
3547c478bdstevel@tonic-gate */
355740638cbwvoid
3567c478bdstevel@tonic-gateinsert(label, files, hosts, subcmds)
3577c478bdstevel@tonic-gate	char *label;
3587c478bdstevel@tonic-gate	struct namelist *files, *hosts;
3597c478bdstevel@tonic-gate	struct subcmd *subcmds;
3607c478bdstevel@tonic-gate{
3617c478bdstevel@tonic-gate	register struct cmd *c, *prev, *nc;
3627c478bdstevel@tonic-gate	register struct namelist *h, *oldh;
3637c478bdstevel@tonic-gate
3647c478bdstevel@tonic-gate	files = expand(files, E_VARS|E_SHELL);
3657c478bdstevel@tonic-gate	hosts = expand(hosts, E_ALL);
3667c478bdstevel@tonic-gateif (debug) {
3677c478bdstevel@tonic-gate	printf("insert:  files = ");
3687c478bdstevel@tonic-gate	prnames(files);
3697c478bdstevel@tonic-gate	printf("insert:  hosts = ");
3707c478bdstevel@tonic-gate	prnames(hosts);
3717c478bdstevel@tonic-gate	if (cmds)
3727c478bdstevel@tonic-gate		prcmd(cmds);
3737c478bdstevel@tonic-gate	else
3747c478bdstevel@tonic-gate		printf("insert:  cmds NULL\n");
3757c478bdstevel@tonic-gate}
3767c478bdstevel@tonic-gate	for (h = hosts; h != NULL; oldh = h, h = h->n_next, free(oldh)) {
3777c478bdstevel@tonic-gate		/*
3787c478bdstevel@tonic-gate		 * Search command list for an update to the same host.
3797c478bdstevel@tonic-gate		 */
3807c478bdstevel@tonic-gate		for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) {
3817c478bdstevel@tonic-gate			if (strcmp(c->c_name, h->n_name) == 0) {
3827c478bdstevel@tonic-gate				do {
3837c478bdstevel@tonic-gate					prev = c;
3847c478bdstevel@tonic-gate					c = c->c_next;
3857c478bdstevel@tonic-gate				} while (c != NULL &&
3867c478bdstevel@tonic-gate					strcmp(c->c_name, h->n_name) == 0);
3877c478bdstevel@tonic-gate				break;
3887c478bdstevel@tonic-gate			}
3897c478bdstevel@tonic-gate		}
3907c478bdstevel@tonic-gate		/*
3917c478bdstevel@tonic-gate		 * Insert new command to update host.
3927c478bdstevel@tonic-gate		 */
3937c478bdstevel@tonic-gate		nc = ALLOC(cmd);
3947c478bdstevel@tonic-gate		if (nc == NULL)
3957c478bdstevel@tonic-gate			fatal("ran out of memory\n");
3967c478bdstevel@tonic-gate		nc->c_type = ARROW;
3977c478bdstevel@tonic-gate		nc->c_name = h->n_name;
3987c478bdstevel@tonic-gate		nc->c_label = label;
3997c478bdstevel@tonic-gate		nc->c_files = files;
4007c478bdstevel@tonic-gate		nc->c_cmds = subcmds;
4017c478bdstevel@tonic-gate		nc->c_next = c;
4027c478bdstevel@tonic-gate		if (prev == NULL)
4037c478bdstevel@tonic-gate			cmds = nc;
4047c478bdstevel@tonic-gate		else
4057c478bdstevel@tonic-gate			prev->c_next = nc;
4067c478bdstevel@tonic-gate		/* update last_cmd if appending nc to cmds */
4077c478bdstevel@tonic-gate		if (c == NULL)
4087c478bdstevel@tonic-gate			last_cmd = nc;
4097c478bdstevel@tonic-gate	}
4107c478bdstevel@tonic-gate}
4117c478bdstevel@tonic-gate
4127c478bdstevel@tonic-gate/*
4137c478bdstevel@tonic-gate * Append DCOLON command to the end of the command list since these are always
4147c478bdstevel@tonic-gate * executed in the order they appear in the distfile.
4157c478bdstevel@tonic-gate */
416740638cbwstatic void
4177c478bdstevel@tonic-gateappend(label, files, stamp, subcmds)
4187c478bdstevel@tonic-gate	char *label;
4197c478bdstevel@tonic-gate	struct namelist *files;
4207c478bdstevel@tonic-gate	char *stamp;
4217c478bdstevel@tonic-gate	struct subcmd *subcmds;
4227c478bdstevel@tonic-gate{
4237c478bdstevel@tonic-gate	register struct cmd *c;
4247c478bdstevel@tonic-gate
4257c478bdstevel@tonic-gate	c = ALLOC(cmd);
4267c478bdstevel@tonic-gate	if (c == NULL)
4277c478bdstevel@tonic-gate		fatal("ran out of memory\n");
4287c478bdstevel@tonic-gate	c->c_type = DCOLON;
4297c478bdstevel@tonic-gate	c->c_name = stamp;
4307c478bdstevel@tonic-gate	c->c_label = label;
4317c478bdstevel@tonic-gate	c->c_files = expand(files, E_ALL);
4327c478bdstevel@tonic-gate	c->c_cmds = subcmds;
4337c478bdstevel@tonic-gate	c->c_next = NULL;
4347c478bdstevel@tonic-gate	if (cmds == NULL)
4357c478bdstevel@tonic-gate		cmds = last_cmd = c;
4367c478bdstevel@tonic-gate	else {
4377c478bdstevel@tonic-gate		last_cmd->c_next = c;
4387c478bdstevel@tonic-gate		last_cmd = c;
4397c478bdstevel@tonic-gate	}
4407c478bdstevel@tonic-gate}
4417c478bdstevel@tonic-gate
4427c478bdstevel@tonic-gate/*
4437c478bdstevel@tonic-gate * Error printing routine in parser.
4447c478bdstevel@tonic-gate */
445740638cbwvoid
4467c478bdstevel@tonic-gateyyerror(s)
4477c478bdstevel@tonic-gate	char *s;
4487c478bdstevel@tonic-gate{
4497c478bdstevel@tonic-gate	extern int yychar;
4507c478bdstevel@tonic-gate
4517c478bdstevel@tonic-gate	nerrs++;
4527c478bdstevel@tonic-gate	fflush(stdout);
4537c478bdstevel@tonic-gate	fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
4547c478bdstevel@tonic-gate}
4557c478bdstevel@tonic-gate
4567c478bdstevel@tonic-gate/*
4577c478bdstevel@tonic-gate * Return a copy of the string.
4587c478bdstevel@tonic-gate */
4597c478bdstevel@tonic-gatechar *
4607c478bdstevel@tonic-gatemakestr(str)
4617c478bdstevel@tonic-gate	char *str;
4627c478bdstevel@tonic-gate{
4637c478bdstevel@tonic-gate	register char *cp, *s;
4647c478bdstevel@tonic-gate
4657c478bdstevel@tonic-gate	str = cp = malloc(strlen(s = str) + 1);
4667c478bdstevel@tonic-gate	if (cp == NULL)
4677c478bdstevel@tonic-gate		fatal("ran out of memory\n");
4687c478bdstevel@tonic-gate	while (*cp++ = *s++)
4697c478bdstevel@tonic-gate		;
4707c478bdstevel@tonic-gate	return(str);
4717c478bdstevel@tonic-gate}
4727c478bdstevel@tonic-gate
4737c478bdstevel@tonic-gate/*
4747c478bdstevel@tonic-gate * Allocate a namelist structure.
4757c478bdstevel@tonic-gate */
4767c478bdstevel@tonic-gatestruct namelist *
4777c478bdstevel@tonic-gatemakenl(name)
4787c478bdstevel@tonic-gate	char *name;
4797c478bdstevel@tonic-gate{
4807c478bdstevel@tonic-gate	register struct namelist *nl;
4817c478bdstevel@tonic-gate
4827c478bdstevel@tonic-gate	nl = ALLOC(namelist);
4837c478bdstevel@tonic-gate	if (nl == NULL)
4847c478bdstevel@tonic-gate		fatal("ran out of memory\n");
4857c478bdstevel@tonic-gate	nl->n_name = name;
4867c478bdstevel@tonic-gate	nl->n_next = NULL;
4877c478bdstevel@tonic-gate	return(nl);
4887c478bdstevel@tonic-gate}
4897c478bdstevel@tonic-gate
4907c478bdstevel@tonic-gate/*
4917c478bdstevel@tonic-gate * Duplicate an existing namelist structure.  Only used by the PATTERN
4927c478bdstevel@tonic-gate * code, and then only because expand() is destructive.
4937c478bdstevel@tonic-gate */
4947c478bdstevel@tonic-gatestruct namelist *
4957c478bdstevel@tonic-gatedupnl(old)
4967c478bdstevel@tonic-gate	struct namelist *old;
4977c478bdstevel@tonic-gate{
4987c478bdstevel@tonic-gate	struct namelist *n;
4997c478bdstevel@tonic-gate	struct namelist *new, *newhead = (struct namelist *) NULL;
5007c478bdstevel@tonic-gate	struct namelist *prev = (struct namelist *) NULL;
5017c478bdstevel@tonic-gate
5027c478bdstevel@tonic-gate	for (n = old; n; n = n->n_next) {
5037c478bdstevel@tonic-gate		new = ALLOC(namelist);
5047c478bdstevel@tonic-gate		if (new == (struct namelist *) NULL)
5057c478bdstevel@tonic-gate			fatal("ran out of memory\n");
5067c478bdstevel@tonic-gate		if (newhead == (struct namelist *) NULL)
5077c478bdstevel@tonic-gate			newhead = new;
5087c478bdstevel@tonic-gate		if (n->n_name) {
5097c478bdstevel@tonic-gate			if ((new->n_name = strdup(n->n_name)) == (char *) NULL)
5107c478bdstevel@tonic-gate				fatal("ran out of memory\n");
5117c478bdstevel@tonic-gate		} else
5127c478bdstevel@tonic-gate			new->n_name = (char *) NULL;
5137c478bdstevel@tonic-gate		if (prev)
5147c478bdstevel@tonic-gate			prev->n_next = new;
5157c478bdstevel@tonic-gate		prev = new;
5167c478bdstevel@tonic-gate	}
5177c478bdstevel@tonic-gate	if (prev)
5187c478bdstevel@tonic-gate		prev->n_next = (struct namelist *) NULL;
5197c478bdstevel@tonic-gate
5207c478bdstevel@tonic-gate	return (newhead);
5217c478bdstevel@tonic-gate}
5227c478bdstevel@tonic-gate
5237c478bdstevel@tonic-gate/*
5247c478bdstevel@tonic-gate * Make a sub command for lists of variables, commands, etc.
5257c478bdstevel@tonic-gate */
5267c478bdstevel@tonic-gatestruct subcmd *
5277c478bdstevel@tonic-gatemakesubcmd(type, name)
5287c478bdstevel@tonic-gate	int type;
5297c478bdstevel@tonic-gate	register char *name;
5307c478bdstevel@tonic-gate{
5317c478bdstevel@tonic-gate	register char *cp;
5327c478bdstevel@tonic-gate	register struct subcmd *sc;
5337c478bdstevel@tonic-gate
5347c478bdstevel@tonic-gate	sc = ALLOC(subcmd);
5357c478bdstevel@tonic-gate	if (sc == NULL)
5367c478bdstevel@tonic-gate		fatal("ran out of memory\n");
5377c478bdstevel@tonic-gate	sc->sc_type = type;
5387c478bdstevel@tonic-gate	sc->sc_args = NULL;
5397c478bdstevel@tonic-gate	sc->sc_next = NULL;
5407c478bdstevel@tonic-gate	sc->sc_name = NULL;
5417c478bdstevel@tonic-gate	return(sc);
5427c478bdstevel@tonic-gate}
543