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