gram.y revision 1.9 1 %{
2 /* $NetBSD: gram.y,v 1.9 2002/06/14 01:18:55 wiz 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.9 2002/06/14 01:18:55 wiz 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(char *);
54 void append(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(void);
207
208 int
209 yylex(void)
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(int c, char *str)
361 {
362 while (*str)
363 if (c == *str++)
364 return(1);
365 return(0);
366 }
367
368 /*
369 * Insert or append ARROW command to list of hosts to be updated.
370 */
371 void
372 insert(char *label, struct namelist *files, struct namelist *hosts,
373 struct subcmd *subcmds)
374 {
375 struct cmd *c, *prev, *nc;
376 struct namelist *h, *nexth;
377
378 files = expand(files, E_VARS|E_SHELL);
379 hosts = expand(hosts, E_ALL);
380 for (h = hosts; h != NULL; nexth = h->n_next, free(h), h = nexth) {
381 /*
382 * Search command list for an update to the same host.
383 */
384 for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) {
385 if (strcmp(c->c_name, h->n_name) == 0) {
386 do {
387 prev = c;
388 c = c->c_next;
389 } while (c != NULL &&
390 strcmp(c->c_name, h->n_name) == 0);
391 break;
392 }
393 }
394 /*
395 * Insert new command to update host.
396 */
397 nc = ALLOC(cmd);
398 if (nc == NULL)
399 fatal("ran out of memory\n");
400 nc->c_type = ARROW;
401 nc->c_name = h->n_name;
402 nc->c_label = label;
403 nc->c_files = files;
404 nc->c_cmds = subcmds;
405 nc->c_next = c;
406 if (prev == NULL)
407 cmds = nc;
408 else
409 prev->c_next = nc;
410 /* update last_cmd if appending nc to cmds */
411 if (c == NULL)
412 last_cmd = nc;
413 }
414 }
415
416 /*
417 * Append DCOLON command to the end of the command list since these are always
418 * executed in the order they appear in the distfile.
419 */
420 void
421 append(char *label, struct namelist *files, char *stamp,
422 struct subcmd *subcmds)
423 {
424 struct cmd *c;
425
426 c = ALLOC(cmd);
427 if (c == NULL)
428 fatal("ran out of memory\n");
429 c->c_type = DCOLON;
430 c->c_name = stamp;
431 c->c_label = label;
432 c->c_files = expand(files, E_ALL);
433 c->c_cmds = subcmds;
434 c->c_next = NULL;
435 if (cmds == NULL)
436 cmds = last_cmd = c;
437 else {
438 last_cmd->c_next = c;
439 last_cmd = c;
440 }
441 }
442
443 /*
444 * Error printing routine in parser.
445 */
446 void
447 yyerror(char *s)
448 {
449
450 ++nerrs;
451 fflush(stdout);
452 fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
453 }
454
455 /*
456 * Return a copy of the string.
457 */
458 static char *
459 makestr(char *str)
460 {
461 char *cp, *s;
462
463 str = cp = malloc(strlen(s = str) + 1);
464 if (cp == NULL)
465 fatal("ran out of memory\n");
466 while ((*cp++ = *s++) != NULL)
467 ;
468 return(str);
469 }
470
471 /*
472 * Allocate a namelist structure.
473 */
474 struct namelist *
475 makenl(char *name)
476 {
477 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(int type)
492 {
493 struct subcmd *sc;
494
495 sc = ALLOC(subcmd);
496 if (sc == NULL)
497 fatal("ran out of memory\n");
498 sc->sc_type = type;
499 sc->sc_args = NULL;
500 sc->sc_next = NULL;
501 sc->sc_name = NULL;
502 return(sc);
503 }
504