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