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