1 %{
2 /*
3 * Copyright (c) 1983 Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms are permitted
7 * provided that the above copyright notice and this paragraph are
8 * duplicated in all such forms and that any documentation,
9 * advertising materials, and other materials related to such
10 * distribution and use acknowledge that the software was developed
11 * by the University of California, Berkeley. The name of the
12 * University may not be used to endorse or promote products derived
13 * from this software without specific prior written permission.
14 *
15 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
16 * Use is subject to license terms.
17 */
18
19 #include "defs.h"
20
21 struct cmd *cmds = NULL;
22 struct cmd *last_cmd;
23 struct namelist *last_n;
24 struct subcmd *last_sc;
25
26 static void append(char *label, struct namelist *files, char *stamp,
27 struct subcmd *subcmds);
28 int yyerror(const char *s);
29
30 %}
31
32 %term EQUAL 1
33 %term LP 2
34 %term RP 3
35 %term SM 4
36 %term ARROW 5
37 %term COLON 6
38 %term DCOLON 7
39 %term NAME 8
40 %term STRING 9
41 %term INSTALL 10
42 %term NOTIFY 11
43 %term EXCEPT 12
44 %term PATTERN 13
45 %term SPECIAL 14
46 %term OPTION 15
47
48 %union {
49 int intval;
50 char *string;
51 struct subcmd *subcmd;
52 struct namelist *namel;
53 }
54
55 %type <intval> OPTION options
56 %type <string> NAME STRING
57 %type <subcmd> INSTALL NOTIFY EXCEPT PATTERN SPECIAL cmdlist cmd
58 %type <namel> namelist names opt_namelist
59
60 %%
61
62 file: /* VOID */
63 | file command
64 ;
65
66 command: NAME EQUAL namelist {
67 (void) lookup($1, INSERT, $3);
68 }
69 | namelist ARROW namelist cmdlist {
70 insert(NULL, $1, $3, $4);
71 }
72 | NAME COLON namelist ARROW namelist cmdlist {
73 insert($1, $3, $5, $6);
74 }
75 | namelist DCOLON NAME cmdlist {
76 append(NULL, $1, $3, $4);
77 }
78 | NAME COLON namelist DCOLON NAME cmdlist {
79 append($1, $3, $5, $6);
80 }
81 | error
82 ;
83
84 namelist: NAME {
85 $$ = makenl($1);
86 }
87 | LP names RP {
88 $$ = $2;
89 }
90 ;
91
92 names: /* VOID */ {
93 $$ = last_n = NULL;
94 }
95 | names NAME {
96 if (last_n == NULL)
97 $$ = last_n = makenl($2);
98 else {
99 last_n->n_next = makenl($2);
100 last_n = last_n->n_next;
101 $$ = $1;
102 }
103 }
104 ;
105
106 cmdlist: /* VOID */ {
107 $$ = last_sc = NULL;
108 }
109 | cmdlist cmd {
110 if (last_sc == NULL)
111 $$ = last_sc = $2;
112 else {
113 last_sc->sc_next = $2;
114 last_sc = $2;
115 $$ = $1;
116 }
117 }
118 ;
119
120 cmd: INSTALL options opt_namelist SM {
121 register struct namelist *nl;
122
123 $1->sc_options = $2 | options;
124 if ($3 != NULL) {
125 nl = expand($3, E_VARS);
126 if (nl && nl->n_next != NULL)
127 (void) yyerror(
128 "only one name allowed\n");
129 $1->sc_name = nl ? nl->n_name: NULL;
130 if (nl)
131 free(nl);
132 }
133 $$ = $1;
134 }
135 | NOTIFY namelist SM {
136 if ($2 != NULL)
137 $1->sc_args = expand($2, E_VARS);
138 $$ = $1;
139 }
140 | EXCEPT namelist SM {
141 if ($2 != NULL)
142 $1->sc_args = expand($2, E_ALL);
143 $$ = $1;
144 }
145 | PATTERN namelist SM {
146 struct namelist *nl;
147 char *cp, *re_comp();
148
149 /*
150 * We dup the namelist in $2 because expand()
151 * destroys the list referred to in its first
152 * argument.
153 */
154 for (nl = expand(dupnl($2), E_VARS); nl != NULL;
155 nl = nl->n_next)
156 if ((cp = re_comp(nl->n_name)) != NULL)
157 (void) yyerror(cp);
158 $1->sc_args = expand($2, E_VARS);
159 $$ = $1;
160 }
161 | SPECIAL opt_namelist STRING SM {
162 if ($2 != NULL)
163 $1->sc_args = expand($2, E_ALL);
164 $1->sc_name = $3;
165 $$ = $1;
166 }
167 ;
168
169 options: /* VOID */ {
170 $$ = 0;
171 }
172 | options OPTION {
173 $$ |= $2;
174 }
175 ;
176
177 opt_namelist: /* VOID */ {
178 $$ = NULL;
179 }
180 | namelist {
181 $$ = $1;
182 }
183 ;
184
185 %%
186
187 int yylineno = 1;
188 extern FILE *fin;
189
190 int
yylex()191 yylex()
192 {
193 static char yytext[INMAX];
194 register int c;
195 register char *cp1, *cp2;
196 static char quotechars[] = "[]{}*?$";
197
198 again:
199 switch (c = getc(fin)) {
200 case EOF: /* end of file */
201 return(0);
202
203 case '#': /* start of comment */
204 while ((c = getc(fin)) != EOF && c != '\n')
205 ;
206 if (c == EOF)
207 return(0);
208 /* FALLTHROUGH */
209 case '\n':
210 yylineno++;
211 case ' ':
212 case '\t': /* skip blanks */
213 goto again;
214
215 case '=': /* EQUAL */
216 return(EQUAL);
217
218 case '(': /* LP */
219 return(LP);
220
221 case ')': /* RP */
222 return(RP);
223
224 case ';': /* SM */
225 return(SM);
226
227 case '-': /* -> */
228 if ((c = getc(fin)) == '>')
229 return(ARROW);
230 ungetc(c, fin);
231 c = '-';
232 break;
233
234 case '"': /* STRING */
235 cp1 = yytext;
236 cp2 = &yytext[INMAX - 1];
237 for (;;) {
238 if (cp1 >= cp2) {
239 (void) yyerror("command string too long\n");
240 break;
241 }
242 c = getc(fin);
243 if (c == EOF || c == '"')
244 break;
245 if (c == '\\') {
246 if ((c = getc(fin)) == EOF) {
247 *cp1++ = '\\';
248 break;
249 }
250 }
251 if (c == '\n') {
252 yylineno++;
253 c = ' '; /* can't send '\n' */
254 }
255 *cp1++ = c;
256 }
257 if (c != '"')
258 (void) yyerror("missing closing '\"'\n");
259 *cp1 = '\0';
260 yylval.string = makestr(yytext);
261 return(STRING);
262
263 case ':': /* : or :: */
264 if ((c = getc(fin)) == ':')
265 return(DCOLON);
266 ungetc(c, fin);
267 return(COLON);
268 }
269 cp1 = yytext;
270 cp2 = &yytext[INMAX - 1];
271 for (;;) {
272 if (cp1 >= cp2) {
273 (void) yyerror("input line too long\n");
274 break;
275 }
276 if (c == '\\') {
277 if ((c = getc(fin)) != EOF) {
278 if (any(c, quotechars))
279 c |= QUOTE;
280 } else {
281 *cp1++ = '\\';
282 break;
283 }
284 }
285 *cp1++ = c;
286 c = getc(fin);
287 if (c == EOF || any(c, " \"'\t()=;:\n")) {
288 ungetc(c, fin);
289 break;
290 }
291 }
292 *cp1 = '\0';
293 if (yytext[0] == '-' && yytext[2] == '\0') {
294 switch (yytext[1]) {
295 case 'b':
296 yylval.intval = COMPARE;
297 return(OPTION);
298
299 case 'R':
300 yylval.intval = REMOVE;
301 return(OPTION);
302
303 case 'v':
304 yylval.intval = VERIFY;
305 return(OPTION);
306
307 case 'w':
308 yylval.intval = WHOLE;
309 return(OPTION);
310
311 case 'y':
312 yylval.intval = YOUNGER;
313 return(OPTION);
314
315 case 'h':
316 yylval.intval = FOLLOW;
317 return(OPTION);
318
319 case 'i':
320 yylval.intval = IGNLNKS;
321 return(OPTION);
322 }
323 }
324 if (!strcmp(yytext, "install"))
325 c = INSTALL;
326 else if (!strcmp(yytext, "notify"))
327 c = NOTIFY;
328 else if (!strcmp(yytext, "except"))
329 c = EXCEPT;
330 else if (!strcmp(yytext, "except_pat"))
331 c = PATTERN;
332 else if (!strcmp(yytext, "special"))
333 c = SPECIAL;
334 else {
335 yylval.string = makestr(yytext);
336 return(NAME);
337 }
338 yylval.subcmd = makesubcmd(c);
339 return(c);
340 }
341
342 int
any(c,str)343 any(c, str)
344 register int c;
345 register char *str;
346 {
347 while (*str)
348 if (c == *str++)
349 return(1);
350 return(0);
351 }
352
353 /*
354 * Insert or append ARROW command to list of hosts to be updated.
355 */
356 void
insert(label,files,hosts,subcmds)357 insert(label, files, hosts, subcmds)
358 char *label;
359 struct namelist *files, *hosts;
360 struct subcmd *subcmds;
361 {
362 register struct cmd *c, *prev, *nc;
363 register struct namelist *h, *oldh;
364
365 files = expand(files, E_VARS|E_SHELL);
366 hosts = expand(hosts, E_ALL);
367 if (debug) {
368 printf("insert: files = ");
369 prnames(files);
370 printf("insert: hosts = ");
371 prnames(hosts);
372 if (cmds)
373 prcmd(cmds);
374 else
375 printf("insert: cmds NULL\n");
376 }
377 for (h = hosts; h != NULL; oldh = h, h = h->n_next, free(oldh)) {
378 /*
379 * Search command list for an update to the same host.
380 */
381 for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) {
382 if (strcmp(c->c_name, h->n_name) == 0) {
383 do {
384 prev = c;
385 c = c->c_next;
386 } while (c != NULL &&
387 strcmp(c->c_name, h->n_name) == 0);
388 break;
389 }
390 }
391 /*
392 * Insert new command to update host.
393 */
394 nc = ALLOC(cmd);
395 if (nc == NULL)
396 fatal("ran out of memory\n");
397 nc->c_type = ARROW;
398 nc->c_name = h->n_name;
399 nc->c_label = label;
400 nc->c_files = files;
401 nc->c_cmds = subcmds;
402 nc->c_next = c;
403 if (prev == NULL)
404 cmds = nc;
405 else
406 prev->c_next = nc;
407 /* update last_cmd if appending nc to cmds */
408 if (c == NULL)
409 last_cmd = nc;
410 }
411 }
412
413 /*
414 * Append DCOLON command to the end of the command list since these are always
415 * executed in the order they appear in the distfile.
416 */
417 static void
append(label,files,stamp,subcmds)418 append(label, files, stamp, subcmds)
419 char *label;
420 struct namelist *files;
421 char *stamp;
422 struct subcmd *subcmds;
423 {
424 register 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 int
yyerror(const char * s)447 yyerror(const char *s)
448 {
449 extern int yychar;
450
451 nerrs++;
452 fflush(stdout);
453 fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
454 return (0);
455 }
456
457 /*
458 * Return a copy of the string.
459 */
460 char *
makestr(str)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 *
makenl(name)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 * Duplicate an existing namelist structure. Only used by the PATTERN
493 * code, and then only because expand() is destructive.
494 */
495 struct namelist *
dupnl(old)496 dupnl(old)
497 struct namelist *old;
498 {
499 struct namelist *n;
500 struct namelist *new, *newhead = (struct namelist *) NULL;
501 struct namelist *prev = (struct namelist *) NULL;
502
503 for (n = old; n; n = n->n_next) {
504 new = ALLOC(namelist);
505 if (new == (struct namelist *) NULL)
506 fatal("ran out of memory\n");
507 if (newhead == (struct namelist *) NULL)
508 newhead = new;
509 if (n->n_name) {
510 if ((new->n_name = strdup(n->n_name)) == (char *) NULL)
511 fatal("ran out of memory\n");
512 } else
513 new->n_name = (char *) NULL;
514 if (prev)
515 prev->n_next = new;
516 prev = new;
517 }
518 if (prev)
519 prev->n_next = (struct namelist *) NULL;
520
521 return (newhead);
522 }
523
524 /*
525 * Make a sub command for lists of variables, commands, etc.
526 */
527 struct subcmd *
makesubcmd(type,name)528 makesubcmd(type, name)
529 int type;
530 register char *name;
531 {
532 register char *cp;
533 register struct subcmd *sc;
534
535 sc = ALLOC(subcmd);
536 if (sc == NULL)
537 fatal("ran out of memory\n");
538 sc->sc_type = type;
539 sc->sc_args = NULL;
540 sc->sc_next = NULL;
541 sc->sc_name = NULL;
542 return(sc);
543 }
544