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