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