Annotation of src/usr.bin/rdist/gram.y, Revision 1.4
1.1 deraadt 1: %{
1.4 ! millert 2: /* $OpenBSD$ */
! 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.4 ! millert 44: "$OpenBSD$";
! 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)) {
354: (void) sprintf(ebuf,
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:
379: (void) sprintf(ebuf, "Unknown option \"%s\".", yytext);
380: yyerror(ebuf);
1.1 deraadt 381: }
1.2 dm 382:
383: yylval.optval = opt;
384: return(OPTION);
1.1 deraadt 385: }
386: if (!strcmp(yytext, "install"))
387: c = INSTALL;
388: else if (!strcmp(yytext, "notify"))
389: c = NOTIFY;
390: else if (!strcmp(yytext, "except"))
391: c = EXCEPT;
392: else if (!strcmp(yytext, "except_pat"))
393: c = PATTERN;
394: else if (!strcmp(yytext, "special"))
395: c = SPECIAL;
1.2 dm 396: else if (!strcmp(yytext, "cmdspecial"))
397: c = CMDSPECIAL;
1.1 deraadt 398: else {
399: yylval.string = makestr(yytext);
400: return(NAME);
401: }
402: yylval.subcmd = makesubcmd(c);
403: return(c);
404: }
405:
1.2 dm 406: /*
407: * XXX We should use strchr(), but most versions can't handle
408: * some of the characters we use.
409: */
410: extern int any(c, str)
1.1 deraadt 411: register int c;
412: register char *str;
413: {
414: while (*str)
415: if (c == *str++)
416: return(1);
417: return(0);
418: }
419:
420: /*
421: * Insert or append ARROW command to list of hosts to be updated.
422: */
1.4 ! millert 423: void
1.1 deraadt 424: insert(label, files, hosts, subcmds)
425: char *label;
426: struct namelist *files, *hosts;
427: struct subcmd *subcmds;
428: {
429: register struct cmd *c, *prev, *nc;
1.2 dm 430: register struct namelist *h, *lasth;
431:
432: debugmsg(DM_CALL, "insert(%s, %x, %x, %x) start, files = %s",
433: label == NULL ? "(null)" : label,
434: files, hosts, subcmds, getnlstr(files));
1.1 deraadt 435:
436: files = expand(files, E_VARS|E_SHELL);
437: hosts = expand(hosts, E_ALL);
1.2 dm 438: for (h = hosts; h != NULL; lasth = h, h = h->n_next,
439: free((char *)lasth)) {
1.1 deraadt 440: /*
441: * Search command list for an update to the same host.
442: */
443: for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) {
444: if (strcmp(c->c_name, h->n_name) == 0) {
445: do {
446: prev = c;
447: c = c->c_next;
448: } while (c != NULL &&
449: strcmp(c->c_name, h->n_name) == 0);
450: break;
451: }
452: }
453: /*
454: * Insert new command to update host.
455: */
456: nc = ALLOC(cmd);
457: nc->c_type = ARROW;
458: nc->c_name = h->n_name;
459: nc->c_label = label;
460: nc->c_files = files;
461: nc->c_cmds = subcmds;
1.2 dm 462: nc->c_flags = 0;
1.1 deraadt 463: nc->c_next = c;
464: if (prev == NULL)
465: cmds = nc;
466: else
467: prev->c_next = nc;
468: /* update last_cmd if appending nc to cmds */
469: if (c == NULL)
470: last_cmd = nc;
471: }
472: }
473:
474: /*
475: * Append DCOLON command to the end of the command list since these are always
476: * executed in the order they appear in the distfile.
477: */
1.4 ! millert 478: void
1.1 deraadt 479: append(label, files, stamp, subcmds)
480: char *label;
481: struct namelist *files;
482: char *stamp;
483: struct subcmd *subcmds;
484: {
485: register struct cmd *c;
486:
487: c = ALLOC(cmd);
488: c->c_type = DCOLON;
489: c->c_name = stamp;
490: c->c_label = label;
491: c->c_files = expand(files, E_ALL);
492: c->c_cmds = subcmds;
493: c->c_next = NULL;
494: if (cmds == NULL)
495: cmds = last_cmd = c;
496: else {
497: last_cmd->c_next = c;
498: last_cmd = c;
499: }
500: }
501:
502: /*
503: * Error printing routine in parser.
504: */
1.4 ! millert 505: void
1.1 deraadt 506: yyerror(s)
507: char *s;
508: {
1.2 dm 509: error("Error in distfile: line %d: %s", yylineno, s);
1.1 deraadt 510: }
511:
512: /*
513: * Return a copy of the string.
514: */
1.2 dm 515: char *
1.1 deraadt 516: makestr(str)
517: char *str;
518: {
1.2 dm 519: char *cp;
1.1 deraadt 520:
1.2 dm 521: cp = strdup(str);
1.1 deraadt 522: if (cp == NULL)
1.2 dm 523: fatalerr("ran out of memory");
524:
525: return(cp);
1.1 deraadt 526: }
527:
528: /*
529: * Allocate a namelist structure.
530: */
531: struct namelist *
532: makenl(name)
533: char *name;
534: {
535: register struct namelist *nl;
536:
1.2 dm 537: debugmsg(DM_CALL, "makenl(%s)", name == NULL ? "null" : name);
538:
1.1 deraadt 539: nl = ALLOC(namelist);
540: nl->n_name = name;
541: nl->n_next = NULL;
1.2 dm 542:
1.1 deraadt 543: return(nl);
544: }
545:
1.2 dm 546:
547: /*
548: * Is the name p in the namelist nl?
549: */
550: static int
551: innl(nl, p)
552: struct namelist *nl;
553: char *p;
554: {
555: for ( ; nl; nl = nl->n_next)
556: if (!strcmp(p, nl->n_name))
557: return(1);
558: return(0);
559: }
560:
561: /*
562: * Join two namelists.
563: */
564: static struct namelist *
565: addnl(n1, n2)
566: struct namelist *n1, *n2;
567: {
568: struct namelist *nl, *prev;
569:
570: n1 = expand(n1, E_VARS);
571: n2 = expand(n2, E_VARS);
572: for (prev = NULL, nl = NULL; n1; n1 = n1->n_next, prev = nl) {
573: nl = makenl(n1->n_name);
574: nl->n_next = prev;
575: }
576: for (; n2; n2 = n2->n_next)
577: if (!innl(nl, n2->n_name)) {
578: nl = makenl(n2->n_name);
579: nl->n_next = prev;
580: prev = nl;
581: }
582: return(prev);
583: }
584:
585: /*
586: * Copy n1 except for elements that are in n2.
587: */
588: static struct namelist *
589: subnl(n1, n2)
590: struct namelist *n1, *n2;
591: {
592: struct namelist *nl, *prev;
593:
594: n1 = expand(n1, E_VARS);
595: n2 = expand(n2, E_VARS);
596: for (prev = NULL; n1; n1 = n1->n_next)
597: if (!innl(n2, n1->n_name)) {
598: nl = makenl(n1->n_name);
599: nl->n_next = prev;
600: prev = nl;
601: }
602: return(prev);
603: }
604:
605: /*
606: * Copy all items of n1 that are also in n2.
607: */
608: static struct namelist *
609: andnl(n1, n2)
610: struct namelist *n1, *n2;
611: {
612: struct namelist *nl, *prev;
613:
614: n1 = expand(n1, E_VARS);
615: n2 = expand(n2, E_VARS);
616: for (prev = NULL; n1; n1 = n1->n_next)
617: if (innl(n2, n1->n_name)) {
618: nl = makenl(n1->n_name);
619: nl->n_next = prev;
620: prev = nl;
621: }
622: return(prev);
623: }
624:
1.1 deraadt 625: /*
626: * Make a sub command for lists of variables, commands, etc.
627: */
1.2 dm 628: extern struct subcmd *
1.1 deraadt 629: makesubcmd(type)
630: int type;
631: {
632: register struct subcmd *sc;
633:
634: sc = ALLOC(subcmd);
635: sc->sc_type = type;
636: sc->sc_args = NULL;
637: sc->sc_next = NULL;
638: sc->sc_name = NULL;
1.2 dm 639:
1.1 deraadt 640: return(sc);
641: }