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