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