Annotation of src/usr.bin/rdist/gram.y, Revision 1.5
1.1 deraadt 1: %{
1.5 ! deraadt 2: /* $OpenBSD: gram.y,v 1.4 1998/06/26 21:21:11 millert Exp $ */
1.4 millert 3:
1.1 deraadt 4: /*
1.2 dm 5: * Copyright (c) 1993 Michael A. Cooper
6: * Copyright (c) 1993 Regents of the University of California.
7: * All rights reserved.
1.1 deraadt 8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by the University of
20: * California, Berkeley and its contributors.
21: * 4. Neither the name of the University nor the names of its contributors
22: * may be used to endorse or promote products derived from this software
23: * without specific prior written permission.
24: *
25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35: * SUCH DAMAGE.
36: */
37:
38: #ifndef lint
1.4 millert 39: #if 0
40: static char RCSid[] =
41: "$From: gram.y,v 6.29 1994/04/11 23:59:15 mcooper Exp mcooper $";
42: #else
1.2 dm 43: static char RCSid[] =
1.5 ! deraadt 44: "$OpenBSD: gram.y,v 1.4 1998/06/26 21:21:11 millert Exp $";
1.4 millert 45: #endif
1.2 dm 46:
47: static char *sccsid = "@(#)gram.y 5.2 (Berkeley) 85/06/21";
48:
49: static char copyright[] =
50: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
51: All rights reserved.\n";
1.1 deraadt 52: #endif /* not lint */
53:
1.2 dm 54: /*
55: * Tell defs.h not to include y.tab.h
56: */
57: #ifndef yacc
58: #define yacc
59: #endif
60:
1.1 deraadt 61: #include "defs.h"
62:
1.2 dm 63: static struct namelist *addnl(), *subnl(), *andnl();
1.1 deraadt 64: struct cmd *cmds = NULL;
65: struct cmd *last_cmd;
66: struct namelist *last_n;
67: struct subcmd *last_sc;
1.2 dm 68: int parendepth = 0;
1.1 deraadt 69:
70: %}
71:
1.2 dm 72: %term ARROW 1
73: %term COLON 2
74: %term DCOLON 3
75: %term NAME 4
76: %term STRING 5
77: %term INSTALL 6
78: %term NOTIFY 7
79: %term EXCEPT 8
80: %term PATTERN 9
81: %term SPECIAL 10
82: %term CMDSPECIAL 11
83: %term OPTION 12
1.1 deraadt 84:
85: %union {
1.2 dm 86: opt_t optval;
87: char *string;
88: struct subcmd *subcmd;
89: struct namelist *namel;
1.1 deraadt 90: }
91:
1.2 dm 92: %type <optval> OPTION, options
1.1 deraadt 93: %type <string> NAME, STRING
1.2 dm 94: %type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, CMDSPECIAL, cmdlist, cmd
95: %type <namel> namelist, names, opt_namelist nlist
1.1 deraadt 96:
97: %%
98:
99: file: /* VOID */
100: | file command
101: ;
102:
1.2 dm 103: command: NAME '=' namelist = {
1.1 deraadt 104: (void) lookup($1, INSERT, $3);
105: }
106: | namelist ARROW namelist cmdlist = {
1.2 dm 107: insert((char *)NULL, $1, $3, $4);
1.1 deraadt 108: }
109: | NAME COLON namelist ARROW namelist cmdlist = {
110: insert($1, $3, $5, $6);
111: }
112: | namelist DCOLON NAME cmdlist = {
1.2 dm 113: append((char *)NULL, $1, $3, $4);
1.1 deraadt 114: }
115: | NAME COLON namelist DCOLON NAME cmdlist = {
116: append($1, $3, $5, $6);
117: }
118: | error
119: ;
120:
1.2 dm 121: namelist: nlist {
122: $$ = $1;
123: }
124: | nlist '-' nlist {
125: $$ = subnl($1, $3);
126: }
127: | nlist '+' nlist {
128: $$ = addnl($1, $3);
129: }
130: | nlist '&' nlist {
131: $$ = andnl($1, $3);
132: }
133: ;
134:
135: nlist: NAME = {
1.1 deraadt 136: $$ = makenl($1);
137: }
1.2 dm 138: | '(' names ')' = {
1.1 deraadt 139: $$ = $2;
140: }
141: ;
142:
143: names: /* VOID */ {
144: $$ = last_n = NULL;
145: }
146: | names NAME = {
147: if (last_n == NULL)
148: $$ = last_n = makenl($2);
149: else {
150: last_n->n_next = makenl($2);
151: last_n = last_n->n_next;
152: $$ = $1;
153: }
154: }
155: ;
156:
157: cmdlist: /* VOID */ {
158: $$ = last_sc = NULL;
159: }
160: | cmdlist cmd = {
161: if (last_sc == NULL)
162: $$ = last_sc = $2;
163: else {
164: last_sc->sc_next = $2;
165: last_sc = $2;
166: $$ = $1;
167: }
168: }
169: ;
170:
1.2 dm 171: cmd: INSTALL options opt_namelist ';' = {
1.1 deraadt 172: register struct namelist *nl;
173:
174: $1->sc_options = $2 | options;
175: if ($3 != NULL) {
176: nl = expand($3, E_VARS);
177: if (nl) {
178: if (nl->n_next != NULL)
179: yyerror("only one name allowed\n");
180: $1->sc_name = nl->n_name;
181: free(nl);
182: } else
183: $1->sc_name = NULL;
184: }
185: $$ = $1;
186: }
1.2 dm 187: | NOTIFY namelist ';' = {
1.1 deraadt 188: if ($2 != NULL)
189: $1->sc_args = expand($2, E_VARS);
190: $$ = $1;
191: }
1.2 dm 192: | EXCEPT namelist ';' = {
1.1 deraadt 193: if ($2 != NULL)
194: $1->sc_args = expand($2, E_ALL);
195: $$ = $1;
196: }
1.2 dm 197: | PATTERN namelist ';' = {
1.1 deraadt 198: struct namelist *nl;
199: char *cp, *re_comp();
200:
201: for (nl = $2; nl != NULL; nl = nl->n_next)
202: if ((cp = re_comp(nl->n_name)) != NULL)
203: yyerror(cp);
204: $1->sc_args = expand($2, E_VARS);
205: $$ = $1;
206: }
1.2 dm 207: | SPECIAL opt_namelist STRING ';' = {
208: if ($2 != NULL)
209: $1->sc_args = expand($2, E_ALL);
210: $1->sc_name = $3;
211: $$ = $1;
212: }
213: | CMDSPECIAL opt_namelist STRING ';' = {
1.1 deraadt 214: if ($2 != NULL)
215: $1->sc_args = expand($2, E_ALL);
216: $1->sc_name = $3;
217: $$ = $1;
218: }
219: ;
220:
221: options: /* VOID */ = {
222: $$ = 0;
223: }
224: | options OPTION = {
225: $$ |= $2;
226: }
227: ;
228:
229: opt_namelist: /* VOID */ = {
230: $$ = NULL;
231: }
232: | namelist = {
233: $$ = $1;
234: }
235: ;
236:
237: %%
238:
239: int yylineno = 1;
240: extern FILE *fin;
241:
242: yylex()
243: {
244: static char yytext[INMAX];
245: register int c;
246: register char *cp1, *cp2;
247: static char quotechars[] = "[]{}*?$";
248:
249: again:
250: switch (c = getc(fin)) {
251: case EOF: /* end of file */
252: return(0);
253:
254: case '#': /* start of comment */
255: while ((c = getc(fin)) != EOF && c != '\n')
256: ;
257: if (c == EOF)
258: return(0);
259: case '\n':
260: yylineno++;
261: case ' ':
262: case '\t': /* skip blanks */
263: goto again;
264:
265: case '=': /* EQUAL */
1.2 dm 266: case ';': /* SM */
267: case '+':
268: case '&':
269: return(c);
1.1 deraadt 270:
271: case '(': /* LP */
1.2 dm 272: ++parendepth;
273: return(c);
1.1 deraadt 274:
275: case ')': /* RP */
1.2 dm 276: --parendepth;
277: return(c);
1.1 deraadt 278:
279: case '-': /* -> */
280: if ((c = getc(fin)) == '>')
281: return(ARROW);
1.2 dm 282: (void) ungetc(c, fin);
1.1 deraadt 283: c = '-';
284: break;
285:
286: case '"': /* STRING */
287: cp1 = yytext;
288: cp2 = &yytext[INMAX - 1];
289: for (;;) {
290: if (cp1 >= cp2) {
291: yyerror("command string too long\n");
292: break;
293: }
294: c = getc(fin);
295: if (c == EOF || c == '"')
296: break;
297: if (c == '\\') {
298: if ((c = getc(fin)) == EOF) {
299: *cp1++ = '\\';
300: break;
301: }
302: }
303: if (c == '\n') {
304: yylineno++;
305: c = ' '; /* can't send '\n' */
306: }
307: *cp1++ = c;
308: }
309: if (c != '"')
310: yyerror("missing closing '\"'\n");
311: *cp1 = '\0';
312: yylval.string = makestr(yytext);
313: return(STRING);
314:
315: case ':': /* : or :: */
316: if ((c = getc(fin)) == ':')
317: return(DCOLON);
1.2 dm 318: (void) ungetc(c, fin);
1.1 deraadt 319: return(COLON);
320: }
321: cp1 = yytext;
322: cp2 = &yytext[INMAX - 1];
323: for (;;) {
324: if (cp1 >= cp2) {
325: yyerror("input line too long\n");
326: break;
327: }
328: if (c == '\\') {
329: if ((c = getc(fin)) != EOF) {
330: if (any(c, quotechars))
1.2 dm 331: *cp1++ = QUOTECHAR;
1.1 deraadt 332: } else {
333: *cp1++ = '\\';
334: break;
335: }
336: }
337: *cp1++ = c;
338: c = getc(fin);
339: if (c == EOF || any(c, " \"'\t()=;:\n")) {
1.2 dm 340: (void) ungetc(c, fin);
1.1 deraadt 341: break;
342: }
343: }
344: *cp1 = '\0';
1.2 dm 345: if (yytext[0] == '-' && yytext[1] == CNULL)
346: return '-';
347: if (yytext[0] == '-' && parendepth <= 0) {
348: opt_t opt = 0;
349: static char ebuf[BUFSIZ];
350:
1.1 deraadt 351: switch (yytext[1]) {
1.2 dm 352: case 'o':
353: if (parsedistopts(&yytext[2], &opt, TRUE)) {
1.5 ! deraadt 354: (void) snprintf(ebuf, sizeof ebuf,
1.2 dm 355: "Bad distfile options \"%s\".",
356: &yytext[2]);
357: yyerror(ebuf);
358: }
359: break;
360:
361: /*
362: * These options are obsoleted by -o.
363: */
364: case 'b': opt = DO_COMPARE; break;
365: case 'R': opt = DO_REMOVE; break;
366: case 'v': opt = DO_VERIFY; break;
367: case 'w': opt = DO_WHOLE; break;
368: case 'y': opt = DO_YOUNGER; break;
369: case 'h': opt = DO_FOLLOW; break;
370: case 'i': opt = DO_IGNLNKS; break;
371: case 'q': opt = DO_QUIET; break;
372: case 'x': opt = DO_NOEXEC; break;
373: case 'N': opt = DO_CHKNFS; break;
374: case 'O': opt = DO_CHKREADONLY; break;
375: case 's': opt = DO_SAVETARGETS; break;
376: case 'r': opt = DO_NODESCEND; break;
377:
378: default:
1.5 ! deraadt 379: (void) snprintf(ebuf, sizeof ebuf,
! 380: "Unknown option \"%s\".", yytext);
1.2 dm 381: yyerror(ebuf);
1.1 deraadt 382: }
1.2 dm 383:
384: yylval.optval = opt;
385: return(OPTION);
1.1 deraadt 386: }
387: if (!strcmp(yytext, "install"))
388: c = INSTALL;
389: else if (!strcmp(yytext, "notify"))
390: c = NOTIFY;
391: else if (!strcmp(yytext, "except"))
392: c = EXCEPT;
393: else if (!strcmp(yytext, "except_pat"))
394: c = PATTERN;
395: else if (!strcmp(yytext, "special"))
396: c = SPECIAL;
1.2 dm 397: else if (!strcmp(yytext, "cmdspecial"))
398: c = CMDSPECIAL;
1.1 deraadt 399: else {
400: yylval.string = makestr(yytext);
401: return(NAME);
402: }
403: yylval.subcmd = makesubcmd(c);
404: return(c);
405: }
406:
1.2 dm 407: /*
408: * XXX We should use strchr(), but most versions can't handle
409: * some of the characters we use.
410: */
411: extern int any(c, str)
1.1 deraadt 412: register int c;
413: register char *str;
414: {
415: while (*str)
416: if (c == *str++)
417: return(1);
418: return(0);
419: }
420:
421: /*
422: * Insert or append ARROW command to list of hosts to be updated.
423: */
1.4 millert 424: void
1.1 deraadt 425: insert(label, files, hosts, subcmds)
426: char *label;
427: struct namelist *files, *hosts;
428: struct subcmd *subcmds;
429: {
430: register struct cmd *c, *prev, *nc;
1.2 dm 431: register struct namelist *h, *lasth;
432:
433: debugmsg(DM_CALL, "insert(%s, %x, %x, %x) start, files = %s",
434: label == NULL ? "(null)" : label,
435: files, hosts, subcmds, getnlstr(files));
1.1 deraadt 436:
437: files = expand(files, E_VARS|E_SHELL);
438: hosts = expand(hosts, E_ALL);
1.2 dm 439: for (h = hosts; h != NULL; lasth = h, h = h->n_next,
440: free((char *)lasth)) {
1.1 deraadt 441: /*
442: * Search command list for an update to the same host.
443: */
444: for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) {
445: if (strcmp(c->c_name, h->n_name) == 0) {
446: do {
447: prev = c;
448: c = c->c_next;
449: } while (c != NULL &&
450: strcmp(c->c_name, h->n_name) == 0);
451: break;
452: }
453: }
454: /*
455: * Insert new command to update host.
456: */
457: nc = ALLOC(cmd);
458: nc->c_type = ARROW;
459: nc->c_name = h->n_name;
460: nc->c_label = label;
461: nc->c_files = files;
462: nc->c_cmds = subcmds;
1.2 dm 463: nc->c_flags = 0;
1.1 deraadt 464: nc->c_next = c;
465: if (prev == NULL)
466: cmds = nc;
467: else
468: prev->c_next = nc;
469: /* update last_cmd if appending nc to cmds */
470: if (c == NULL)
471: last_cmd = nc;
472: }
473: }
474:
475: /*
476: * Append DCOLON command to the end of the command list since these are always
477: * executed in the order they appear in the distfile.
478: */
1.4 millert 479: void
1.1 deraadt 480: append(label, files, stamp, subcmds)
481: char *label;
482: struct namelist *files;
483: char *stamp;
484: struct subcmd *subcmds;
485: {
486: register struct cmd *c;
487:
488: c = ALLOC(cmd);
489: c->c_type = DCOLON;
490: c->c_name = stamp;
491: c->c_label = label;
492: c->c_files = expand(files, E_ALL);
493: c->c_cmds = subcmds;
494: c->c_next = NULL;
495: if (cmds == NULL)
496: cmds = last_cmd = c;
497: else {
498: last_cmd->c_next = c;
499: last_cmd = c;
500: }
501: }
502:
503: /*
504: * Error printing routine in parser.
505: */
1.4 millert 506: void
1.1 deraadt 507: yyerror(s)
508: char *s;
509: {
1.2 dm 510: error("Error in distfile: line %d: %s", yylineno, s);
1.1 deraadt 511: }
512:
513: /*
514: * Return a copy of the string.
515: */
1.2 dm 516: char *
1.1 deraadt 517: makestr(str)
518: char *str;
519: {
1.2 dm 520: char *cp;
1.1 deraadt 521:
1.2 dm 522: cp = strdup(str);
1.1 deraadt 523: if (cp == NULL)
1.2 dm 524: fatalerr("ran out of memory");
525:
526: return(cp);
1.1 deraadt 527: }
528:
529: /*
530: * Allocate a namelist structure.
531: */
532: struct namelist *
533: makenl(name)
534: char *name;
535: {
536: register struct namelist *nl;
537:
1.2 dm 538: debugmsg(DM_CALL, "makenl(%s)", name == NULL ? "null" : name);
539:
1.1 deraadt 540: nl = ALLOC(namelist);
541: nl->n_name = name;
542: nl->n_next = NULL;
1.2 dm 543:
1.1 deraadt 544: return(nl);
545: }
546:
1.2 dm 547:
548: /*
549: * Is the name p in the namelist nl?
550: */
551: static int
552: innl(nl, p)
553: struct namelist *nl;
554: char *p;
555: {
556: for ( ; nl; nl = nl->n_next)
557: if (!strcmp(p, nl->n_name))
558: return(1);
559: return(0);
560: }
561:
562: /*
563: * Join two namelists.
564: */
565: static struct namelist *
566: addnl(n1, n2)
567: struct namelist *n1, *n2;
568: {
569: struct namelist *nl, *prev;
570:
571: n1 = expand(n1, E_VARS);
572: n2 = expand(n2, E_VARS);
573: for (prev = NULL, nl = NULL; n1; n1 = n1->n_next, prev = nl) {
574: nl = makenl(n1->n_name);
575: nl->n_next = prev;
576: }
577: for (; n2; n2 = n2->n_next)
578: if (!innl(nl, n2->n_name)) {
579: nl = makenl(n2->n_name);
580: nl->n_next = prev;
581: prev = nl;
582: }
583: return(prev);
584: }
585:
586: /*
587: * Copy n1 except for elements that are in n2.
588: */
589: static struct namelist *
590: subnl(n1, n2)
591: struct namelist *n1, *n2;
592: {
593: struct namelist *nl, *prev;
594:
595: n1 = expand(n1, E_VARS);
596: n2 = expand(n2, E_VARS);
597: for (prev = NULL; n1; n1 = n1->n_next)
598: if (!innl(n2, n1->n_name)) {
599: nl = makenl(n1->n_name);
600: nl->n_next = prev;
601: prev = nl;
602: }
603: return(prev);
604: }
605:
606: /*
607: * Copy all items of n1 that are also in n2.
608: */
609: static struct namelist *
610: andnl(n1, n2)
611: struct namelist *n1, *n2;
612: {
613: struct namelist *nl, *prev;
614:
615: n1 = expand(n1, E_VARS);
616: n2 = expand(n2, E_VARS);
617: for (prev = NULL; n1; n1 = n1->n_next)
618: if (innl(n2, n1->n_name)) {
619: nl = makenl(n1->n_name);
620: nl->n_next = prev;
621: prev = nl;
622: }
623: return(prev);
624: }
625:
1.1 deraadt 626: /*
627: * Make a sub command for lists of variables, commands, etc.
628: */
1.2 dm 629: extern struct subcmd *
1.1 deraadt 630: makesubcmd(type)
631: int type;
632: {
633: register struct subcmd *sc;
634:
635: sc = ALLOC(subcmd);
636: sc->sc_type = type;
637: sc->sc_args = NULL;
638: sc->sc_next = NULL;
639: sc->sc_name = NULL;
1.2 dm 640:
1.1 deraadt 641: return(sc);
642: }