Annotation of src/usr.bin/oldrdist/gram.y, Revision 1.4
1.1 dm 1: %{
2: /*
3: * Copyright (c) 1983, 1993
4: * The Regents of the University of California. All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: * 3. All advertising materials mentioning features or use of this software
15: * must display the following acknowledgement:
16: * This product includes software developed by the University of
17: * California, Berkeley and its contributors.
18: * 4. Neither the name of the University nor the names of its contributors
19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: */
34:
35: #ifndef lint
36: /* from: static char sccsid[] = "@(#)gram.y 8.1 (Berkeley) 6/9/93"; */
1.4 ! millert 37: static char *rcsid = "$Id: gram.y,v 1.3 1996/09/10 23:20:21 millert Exp $";
1.1 dm 38: #endif /* not lint */
39:
40: #include "defs.h"
41:
42: struct cmd *cmds = NULL;
43: struct cmd *last_cmd;
44: struct namelist *last_n;
45: struct subcmd *last_sc;
46:
1.4 ! millert 47: static char *makestr(char *);
1.1 dm 48:
49: %}
50:
51: %term EQUAL 1
52: %term LP 2
53: %term RP 3
54: %term SM 4
55: %term ARROW 5
56: %term COLON 6
57: %term DCOLON 7
58: %term NAME 8
59: %term STRING 9
60: %term INSTALL 10
61: %term NOTIFY 11
62: %term EXCEPT 12
63: %term PATTERN 13
64: %term SPECIAL 14
65: %term OPTION 15
66:
67: %union {
68: int intval;
69: char *string;
70: struct subcmd *subcmd;
71: struct namelist *namel;
72: }
73:
74: %type <intval> OPTION, options
75: %type <string> NAME, STRING
76: %type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, cmdlist, cmd
77: %type <namel> namelist, names, opt_namelist
78:
79: %%
80:
81: file: /* VOID */
82: | file command
83: ;
84:
85: command: NAME EQUAL namelist = {
86: (void) lookup($1, INSERT, $3);
87: }
88: | namelist ARROW namelist cmdlist = {
89: insert(NULL, $1, $3, $4);
90: }
91: | NAME COLON namelist ARROW namelist cmdlist = {
92: insert($1, $3, $5, $6);
93: }
94: | namelist DCOLON NAME cmdlist = {
95: append(NULL, $1, $3, $4);
96: }
97: | NAME COLON namelist DCOLON NAME cmdlist = {
98: append($1, $3, $5, $6);
99: }
100: | error
101: ;
102:
103: namelist: NAME = {
104: $$ = makenl($1);
105: }
106: | LP names RP = {
107: $$ = $2;
108: }
109: ;
110:
111: names: /* VOID */ {
112: $$ = last_n = NULL;
113: }
114: | names NAME = {
115: if (last_n == NULL)
116: $$ = last_n = makenl($2);
117: else {
118: last_n->n_next = makenl($2);
119: last_n = last_n->n_next;
120: $$ = $1;
121: }
122: }
123: ;
124:
125: cmdlist: /* VOID */ {
126: $$ = last_sc = NULL;
127: }
128: | cmdlist cmd = {
129: if (last_sc == NULL)
130: $$ = last_sc = $2;
131: else {
132: last_sc->sc_next = $2;
133: last_sc = $2;
134: $$ = $1;
135: }
136: }
137: ;
138:
139: cmd: INSTALL options opt_namelist SM = {
140: register struct namelist *nl;
141:
142: $1->sc_options = $2 | options;
143: if ($3 != NULL) {
144: nl = expand($3, E_VARS);
145: if (nl) {
146: if (nl->n_next != NULL)
147: yyerror("only one name allowed\n");
148: $1->sc_name = nl->n_name;
149: free(nl);
150: } else
151: $1->sc_name = NULL;
152: }
153: $$ = $1;
154: }
155: | NOTIFY namelist SM = {
156: if ($2 != NULL)
157: $1->sc_args = expand($2, E_VARS);
158: $$ = $1;
159: }
160: | EXCEPT namelist SM = {
161: if ($2 != NULL)
162: $1->sc_args = expand($2, E_ALL);
163: $$ = $1;
164: }
165: | PATTERN namelist SM = {
1.2 millert 166: if ($2 != NULL)
167: $1->sc_args = expand($2, E_VARS);
1.1 dm 168: $$ = $1;
169: }
170: | SPECIAL opt_namelist STRING SM = {
171: if ($2 != NULL)
172: $1->sc_args = expand($2, E_ALL);
173: $1->sc_name = $3;
174: $$ = $1;
175: }
176: ;
177:
178: options: /* VOID */ = {
179: $$ = 0;
180: }
181: | options OPTION = {
182: $$ |= $2;
183: }
184: ;
185:
186: opt_namelist: /* VOID */ = {
187: $$ = NULL;
188: }
189: | namelist = {
190: $$ = $1;
191: }
192: ;
193:
194: %%
195:
196: int yylineno = 1;
197: extern FILE *fin;
198:
199: int
200: yylex()
201: {
202: static char yytext[INMAX];
203: register int c;
204: register char *cp1, *cp2;
205: static char quotechars[] = "[]{}*?$";
206:
207: again:
208: switch (c = getc(fin)) {
209: case EOF: /* end of file */
210: return(0);
211:
212: case '#': /* start of comment */
213: while ((c = getc(fin)) != EOF && c != '\n')
214: ;
215: if (c == EOF)
216: return(0);
217: case '\n':
218: yylineno++;
219: case ' ':
220: case '\t': /* skip blanks */
221: goto again;
222:
223: case '=': /* EQUAL */
224: return(EQUAL);
225:
226: case '(': /* LP */
227: return(LP);
228:
229: case ')': /* RP */
230: return(RP);
231:
232: case ';': /* SM */
233: return(SM);
234:
235: case '-': /* -> */
236: if ((c = getc(fin)) == '>')
237: return(ARROW);
238: ungetc(c, fin);
239: c = '-';
240: break;
241:
242: case '"': /* STRING */
243: cp1 = yytext;
244: cp2 = &yytext[INMAX - 1];
245: for (;;) {
246: if (cp1 >= cp2) {
247: yyerror("command string too long\n");
248: break;
249: }
250: c = getc(fin);
251: if (c == EOF || c == '"')
252: break;
253: if (c == '\\') {
254: if ((c = getc(fin)) == EOF) {
255: *cp1++ = '\\';
256: break;
257: }
258: }
259: if (c == '\n') {
260: yylineno++;
261: c = ' '; /* can't send '\n' */
262: }
263: *cp1++ = c;
264: }
265: if (c != '"')
266: yyerror("missing closing '\"'\n");
267: *cp1 = '\0';
268: yylval.string = makestr(yytext);
269: return(STRING);
270:
271: case ':': /* : or :: */
272: if ((c = getc(fin)) == ':')
273: return(DCOLON);
274: ungetc(c, fin);
275: return(COLON);
276: }
277: cp1 = yytext;
278: cp2 = &yytext[INMAX - 1];
279: for (;;) {
280: if (cp1 >= cp2) {
281: yyerror("input line too long\n");
282: break;
283: }
284: if (c == '\\') {
285: if ((c = getc(fin)) != EOF) {
286: if (any(c, quotechars))
287: c |= QUOTE;
288: } else {
289: *cp1++ = '\\';
290: break;
291: }
292: }
293: *cp1++ = c;
294: c = getc(fin);
295: if (c == EOF || any(c, " \"'\t()=;:\n")) {
296: ungetc(c, fin);
297: break;
298: }
299: }
300: *cp1 = '\0';
301: if (yytext[0] == '-' && yytext[2] == '\0') {
302: switch (yytext[1]) {
303: case 'b':
304: yylval.intval = COMPARE;
305: return(OPTION);
306:
307: case 'R':
308: yylval.intval = REMOVE;
309: return(OPTION);
310:
311: case 'v':
312: yylval.intval = VERIFY;
313: return(OPTION);
314:
315: case 'w':
316: yylval.intval = WHOLE;
317: return(OPTION);
318:
319: case 'y':
320: yylval.intval = YOUNGER;
321: return(OPTION);
322:
323: case 'h':
324: yylval.intval = FOLLOW;
325: return(OPTION);
326:
327: case 'i':
328: yylval.intval = IGNLNKS;
329: return(OPTION);
330: }
331: }
332: if (!strcmp(yytext, "install"))
333: c = INSTALL;
334: else if (!strcmp(yytext, "notify"))
335: c = NOTIFY;
336: else if (!strcmp(yytext, "except"))
337: c = EXCEPT;
338: else if (!strcmp(yytext, "except_pat"))
339: c = PATTERN;
340: else if (!strcmp(yytext, "special"))
341: c = SPECIAL;
342: else {
343: yylval.string = makestr(yytext);
344: return(NAME);
345: }
346: yylval.subcmd = makesubcmd(c);
347: return(c);
348: }
349:
350: int
351: any(c, str)
352: register int c;
353: register char *str;
354: {
355: while (*str)
356: if (c == *str++)
357: return(1);
358: return(0);
359: }
360:
361: /*
362: * Insert or append ARROW command to list of hosts to be updated.
363: */
364: void
365: insert(label, files, hosts, subcmds)
366: char *label;
367: struct namelist *files, *hosts;
368: struct subcmd *subcmds;
369: {
370: register struct cmd *c, *prev, *nc;
1.3 millert 371: register struct namelist *h, *nexth;
1.1 dm 372:
373: files = expand(files, E_VARS|E_SHELL);
374: hosts = expand(hosts, E_ALL);
1.3 millert 375: for (h = hosts; h != NULL; nexth = h->n_next, free(h), h = nexth) {
1.1 dm 376: /*
377: * Search command list for an update to the same host.
378: */
379: for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) {
380: if (strcmp(c->c_name, h->n_name) == 0) {
381: do {
382: prev = c;
383: c = c->c_next;
384: } while (c != NULL &&
385: strcmp(c->c_name, h->n_name) == 0);
386: break;
387: }
388: }
389: /*
390: * Insert new command to update host.
391: */
392: nc = ALLOC(cmd);
393: if (nc == NULL)
394: fatal("ran out of memory\n");
395: nc->c_type = ARROW;
396: nc->c_name = h->n_name;
397: nc->c_label = label;
398: nc->c_files = files;
399: nc->c_cmds = subcmds;
400: nc->c_next = c;
401: if (prev == NULL)
402: cmds = nc;
403: else
404: prev->c_next = nc;
405: /* update last_cmd if appending nc to cmds */
406: if (c == NULL)
407: last_cmd = nc;
408: }
409: }
410:
411: /*
412: * Append DCOLON command to the end of the command list since these are always
413: * executed in the order they appear in the distfile.
414: */
415: void
416: append(label, files, stamp, subcmds)
417: char *label;
418: struct namelist *files;
419: char *stamp;
420: struct subcmd *subcmds;
421: {
422: register struct cmd *c;
423:
424: c = ALLOC(cmd);
425: if (c == NULL)
426: fatal("ran out of memory\n");
427: c->c_type = DCOLON;
428: c->c_name = stamp;
429: c->c_label = label;
430: c->c_files = expand(files, E_ALL);
431: c->c_cmds = subcmds;
432: c->c_next = NULL;
433: if (cmds == NULL)
434: cmds = last_cmd = c;
435: else {
436: last_cmd->c_next = c;
437: last_cmd = c;
438: }
439: }
440:
441: /*
442: * Error printing routine in parser.
443: */
444: void
445: yyerror(s)
446: char *s;
447: {
448: ++nerrs;
449: fflush(stdout);
450: fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
451: }
452:
453: /*
454: * Return a copy of the string.
455: */
456: static char *
457: makestr(str)
458: char *str;
459: {
460: register char *cp, *s;
461:
462: str = cp = malloc(strlen(s = str) + 1);
463: if (cp == NULL)
464: fatal("ran out of memory\n");
465: while (*cp++ = *s++)
466: ;
467: return(str);
468: }
469:
470: /*
471: * Allocate a namelist structure.
472: */
473: struct namelist *
474: makenl(name)
475: char *name;
476: {
477: register struct namelist *nl;
478:
479: nl = ALLOC(namelist);
480: if (nl == NULL)
481: fatal("ran out of memory\n");
482: nl->n_name = name;
483: nl->n_next = NULL;
484: return(nl);
485: }
486:
487: /*
488: * Make a sub command for lists of variables, commands, etc.
489: */
490: struct subcmd *
491: makesubcmd(type)
492: int type;
493: {
494: register struct subcmd *sc;
495:
496: sc = ALLOC(subcmd);
497: if (sc == NULL)
498: fatal("ran out of memory\n");
499: sc->sc_type = type;
500: sc->sc_args = NULL;
501: sc->sc_next = NULL;
502: sc->sc_name = NULL;
503: return(sc);
504: }