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 #pragma ident "%Z%%M% %I% %E% SMI"
19
20 #include "defs.h"
21
22 struct cmd *cmds = NULL;
23 struct cmd *last_cmd;
24 struct namelist *last_n;
25 struct subcmd *last_sc;
26
27 static void append(char *label, struct namelist *files, char *stamp,
28 struct subcmd *subcmds);
29 void yyerror(char *s);
30
31 %}
32
33 %term EQUAL 1
34 %term LP 2
35 %term RP 3
36 %term SM 4
37 %term ARROW 5
38 %term COLON 6
39 %term DCOLON 7
40 %term NAME 8
41 %term STRING 9
42 %term INSTALL 10
43 %term NOTIFY 11
44 %term EXCEPT 12
45 %term PATTERN 13
46 %term SPECIAL 14
47 %term OPTION 15
48
49 %union {
50 int intval;
51 char *string;
52 struct subcmd *subcmd;
53 struct namelist *namel;
54 }
55
56 %type <intval> OPTION, options
57 %type <string> NAME, STRING
58 %type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, cmdlist, cmd
59 %type <namel> namelist, names, opt_namelist
60
61 %%
62
63 file: /* VOID */
64 | file command
65 ;
66
67 command: NAME EQUAL namelist = {
68 (void) lookup($1, INSERT, $3);
69 }
70 | namelist ARROW namelist cmdlist = {
71 insert(NULL, $1, $3, $4);
72 }
73 | NAME COLON namelist ARROW namelist cmdlist = {
74 insert($1, $3, $5, $6);
75 }
76 | namelist DCOLON NAME cmdlist = {
77 append(NULL, $1, $3, $4);
78 }
79 | NAME COLON namelist DCOLON NAME cmdlist = {
80 append($1, $3, $5, $6);
81 }
82 | error
83 ;
84
85 namelist: NAME = {
86 $$ = makenl($1);
87 }
88 | LP names RP = {
89 $$ = $2;
90 }
91 ;
92
93 names: /* VOID */ {
94 $$ = last_n = NULL;
95 }
96 | names NAME = {
97 if (last_n == NULL)
98 $$ = last_n = makenl($2);
99 else {
100 last_n->n_next = makenl($2);
101 last_n = last_n->n_next;
102 $$ = $1;
103 }
104 }
105 ;
106
107 cmdlist: /* VOID */ {
108 $$ = last_sc = NULL;
109 }
110 | cmdlist cmd = {
111 if (last_sc == NULL)
112 $$ = last_sc = $2;
113 else {
114 last_sc->sc_next = $2;
115 last_sc = $2;
116 $$ = $1;
117 }
118 }
119 ;
120
121 cmd: INSTALL options opt_namelist SM = {
122 register struct namelist *nl;
123
124 $1->sc_options = $2 | options;
125 if ($3 != NULL) {
126 nl = expand($3, E_VARS);
127 if (nl && nl->n_next != NULL)
128 yyerror("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 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 case '\n':
209 yylineno++;
210 case ' ':
211 case '\t': /* skip blanks */
212 goto again;
213
214 case '=': /* EQUAL */
215 return(EQUAL);
216
217 case '(': /* LP */
218 return(LP);
219
220 case ')': /* RP */
221 return(RP);
222
223 case ';': /* SM */
224 return(SM);
225
226 case '-': /* -> */
227 if ((c = getc(fin)) == '>')
228 return(ARROW);
229 ungetc(c, fin);
230 c = '-';
231 break;
232
233 case '"': /* STRING */
234 cp1 = yytext;
235 cp2 = &yytext[INMAX - 1];
236 for (;;) {
237 if (cp1 >= cp2) {
238 yyerror("command string too long\n");
239 break;
240 }
241 c = getc(fin);
242 if (c == EOF || c == '"')
243 break;
244 if (c == '\\') {
245 if ((c = getc(fin)) == EOF) {
246 *cp1++ = '\\';
247 break;
248 }
249 }
250 if (c == '\n') {
251 yylineno++;
252 c = ' '; /* can't send '\n' */
253 }
254 *cp1++ = c;
255 }
256 if (c != '"')
257 yyerror("missing closing '\"'\n");
258 *cp1 = '\0';
259 yylval.string = makestr(yytext);
260 return(STRING);
261
262 case ':': /* : or :: */
263 if ((c = getc(fin)) == ':')
264 return(DCOLON);
265 ungetc(c, fin);
266 return(COLON);
267 }
268 cp1 = yytext;
269 cp2 = &yytext[INMAX - 1];
270 for (;;) {
271 if (cp1 >= cp2) {
272 yyerror("input line too long\n");
273 break;
274 }
275 if (c == '\\') {
276 if ((c = getc(fin)) != EOF) {
277 if (any(c, quotechars))
278 c |= QUOTE;
279 } else {
280 *cp1++ = '\\';
281 break;
282 }
283 }
284 *cp1++ = c;
285 c = getc(fin);
286 if (c == EOF || any(c, " \"'\t()=;:\n")) {
287 ungetc(c, fin);
288 break;
289 }
290 }
291 *cp1 = '\0';
292 if (yytext[0] == '-' && yytext[2] == '\0') {
293 switch (yytext[1]) {
294 case 'b':
295 yylval.intval = COMPARE;
296 return(OPTION);
297
298 case 'R':
299 yylval.intval = REMOVE;
300 return(OPTION);
301
302 case 'v':
303 yylval.intval = VERIFY;
304 return(OPTION);
305
306 case 'w':
307 yylval.intval = WHOLE;
308 return(OPTION);
309
310 case 'y':
311 yylval.intval = YOUNGER;
312 return(OPTION);
313
314 case 'h':
315 yylval.intval = FOLLOW;
316 return(OPTION);
317
318 case 'i':
319 yylval.intval = IGNLNKS;
320 return(OPTION);
321 }
322 }
323 if (!strcmp(yytext, "install"))
324 c = INSTALL;
325 else if (!strcmp(yytext, "notify"))
326 c = NOTIFY;
327 else if (!strcmp(yytext, "except"))
328 c = EXCEPT;
329 else if (!strcmp(yytext, "except_pat"))
330 c = PATTERN;
331 else if (!strcmp(yytext, "special"))
332 c = SPECIAL;
333 else {
334 yylval.string = makestr(yytext);
335 return(NAME);
336 }
337 yylval.subcmd = makesubcmd(c);
338 return(c);
339 }
340
341 int
any(c,str)342 any(c, str)
343 register int c;
344 register char *str;
345 {
346 while (*str)
347 if (c == *str++)
348 return(1);
349 return(0);
350 }
351
352 /*
353 * Insert or append ARROW command to list of hosts to be updated.
354 */
355 void
insert(label,files,hosts,subcmds)356 insert(label, files, hosts, subcmds)
357 char *label;
358 struct namelist *files, *hosts;
359 struct subcmd *subcmds;
360 {
361 register struct cmd *c, *prev, *nc;
362 register struct namelist *h, *oldh;
363
364 files = expand(files, E_VARS|E_SHELL);
365 hosts = expand(hosts, E_ALL);
366 if (debug) {
367 printf("insert: files = ");
368 prnames(files);
369 printf("insert: hosts = ");
370 prnames(hosts);
371 if (cmds)
372 prcmd(cmds);
373 else
374 printf("insert: cmds NULL\n");
375 }
376 for (h = hosts; h != NULL; oldh = h, h = h->n_next, free(oldh)) {
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 static void
append(label,files,stamp,subcmds)417 append(label, files, stamp, subcmds)
418 char *label;
419 struct namelist *files;
420 char *stamp;
421 struct subcmd *subcmds;
422 {
423 register struct cmd *c;
424
425 c = ALLOC(cmd);
426 if (c == NULL)
427 fatal("ran out of memory\n");
428 c->c_type = DCOLON;
429 c->c_name = stamp;
430 c->c_label = label;
431 c->c_files = expand(files, E_ALL);
432 c->c_cmds = subcmds;
433 c->c_next = NULL;
434 if (cmds == NULL)
435 cmds = last_cmd = c;
436 else {
437 last_cmd->c_next = c;
438 last_cmd = c;
439 }
440 }
441
442 /*
443 * Error printing routine in parser.
444 */
445 void
yyerror(s)446 yyerror(s)
447 char *s;
448 {
449 extern int yychar;
450
451 nerrs++;
452 fflush(stdout);
453 fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
454 }
455
456 /*
457 * Return a copy of the string.
458 */
459 char *
makestr(str)460 makestr(str)
461 char *str;
462 {
463 register char *cp, *s;
464
465 str = cp = malloc(strlen(s = str) + 1);
466 if (cp == NULL)
467 fatal("ran out of memory\n");
468 while (*cp++ = *s++)
469 ;
470 return(str);
471 }
472
473 /*
474 * Allocate a namelist structure.
475 */
476 struct namelist *
makenl(name)477 makenl(name)
478 char *name;
479 {
480 register struct namelist *nl;
481
482 nl = ALLOC(namelist);
483 if (nl == NULL)
484 fatal("ran out of memory\n");
485 nl->n_name = name;
486 nl->n_next = NULL;
487 return(nl);
488 }
489
490 /*
491 * Duplicate an existing namelist structure. Only used by the PATTERN
492 * code, and then only because expand() is destructive.
493 */
494 struct namelist *
dupnl(old)495 dupnl(old)
496 struct namelist *old;
497 {
498 struct namelist *n;
499 struct namelist *new, *newhead = (struct namelist *) NULL;
500 struct namelist *prev = (struct namelist *) NULL;
501
502 for (n = old; n; n = n->n_next) {
503 new = ALLOC(namelist);
504 if (new == (struct namelist *) NULL)
505 fatal("ran out of memory\n");
506 if (newhead == (struct namelist *) NULL)
507 newhead = new;
508 if (n->n_name) {
509 if ((new->n_name = strdup(n->n_name)) == (char *) NULL)
510 fatal("ran out of memory\n");
511 } else
512 new->n_name = (char *) NULL;
513 if (prev)
514 prev->n_next = new;
515 prev = new;
516 }
517 if (prev)
518 prev->n_next = (struct namelist *) NULL;
519
520 return (newhead);
521 }
522
523 /*
524 * Make a sub command for lists of variables, commands, etc.
525 */
526 struct subcmd *
makesubcmd(type,name)527 makesubcmd(type, name)
528 int type;
529 register char *name;
530 {
531 register char *cp;
532 register struct subcmd *sc;
533
534 sc = ALLOC(subcmd);
535 if (sc == NULL)
536 fatal("ran out of memory\n");
537 sc->sc_type = type;
538 sc->sc_args = NULL;
539 sc->sc_next = NULL;
540 sc->sc_name = NULL;
541 return(sc);
542 }
543