4.4BSD snapshot (revision 8.1)
[unix-history] / usr / src / usr.bin / rdist / gram.y
CommitLineData
d0dc5e26 1%{
2de3e885 2/*
6412e026
KB
3 * Copyright (c) 1983, 1993
4 * The Regents of the University of California. All rights reserved.
0718fb71 5 *
6d936b27 6 * %sccs.include.redist.c%
2de3e885
KM
7 */
8
d0dc5e26 9#ifndef lint
6412e026 10static char sccsid[] = "@(#)gram.y 8.1 (Berkeley) %G%";
0718fb71 11#endif /* not lint */
d0dc5e26
RC
12
13#include "defs.h"
14
0fccdfef
RC
15struct cmd *cmds = NULL;
16struct cmd *last_cmd;
17struct namelist *last_n;
18struct subcmd *last_sc;
d0dc5e26 19
a94625d9
KB
20static char *makestr __P((char *));
21
d0dc5e26
RC
22%}
23
d6bccb44
RC
24%term EQUAL 1
25%term LP 2
26%term RP 3
27%term SM 4
28%term ARROW 5
86d7a5c5
RC
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
4085f36f
RC
36%term PATTERN 13
37%term SPECIAL 14
38%term OPTION 15
d0dc5e26 39
3024eb6f 40%union {
3024eb6f 41 int intval;
d6bccb44 42 char *string;
0fccdfef
RC
43 struct subcmd *subcmd;
44 struct namelist *namel;
3024eb6f 45}
d0dc5e26 46
3024eb6f 47%type <intval> OPTION, options
0fccdfef 48%type <string> NAME, STRING
4085f36f 49%type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, cmdlist, cmd
0fccdfef 50%type <namel> namelist, names, opt_namelist
d0dc5e26
RC
51
52%%
53
54file: /* VOID */
55 | file command
56 ;
57
58command: NAME EQUAL namelist = {
0fccdfef 59 (void) lookup($1, INSERT, $3);
d0dc5e26
RC
60 }
61 | namelist ARROW namelist cmdlist = {
86d7a5c5
RC
62 insert(NULL, $1, $3, $4);
63 }
64 | NAME COLON namelist ARROW namelist cmdlist = {
65 insert($1, $3, $5, $6);
82572cb6 66 }
d6bccb44 67 | namelist DCOLON NAME cmdlist = {
86d7a5c5
RC
68 append(NULL, $1, $3, $4);
69 }
70 | NAME COLON namelist DCOLON NAME cmdlist = {
71 append($1, $3, $5, $6);
d0dc5e26
RC
72 }
73 | error
74 ;
75
76namelist: NAME = {
0fccdfef 77 $$ = makenl($1);
d0dc5e26
RC
78 }
79 | LP names RP = {
80 $$ = $2;
81 }
82 ;
83
84names: /* VOID */ {
0fccdfef 85 $$ = last_n = NULL;
d0dc5e26
RC
86 }
87 | names NAME = {
0fccdfef
RC
88 if (last_n == NULL)
89 $$ = last_n = makenl($2);
d0dc5e26 90 else {
0fccdfef
RC
91 last_n->n_next = makenl($2);
92 last_n = last_n->n_next;
d0dc5e26
RC
93 $$ = $1;
94 }
95 }
96 ;
97
98cmdlist: /* VOID */ {
0fccdfef 99 $$ = last_sc = NULL;
d0dc5e26
RC
100 }
101 | cmdlist cmd = {
0fccdfef
RC
102 if (last_sc == NULL)
103 $$ = last_sc = $2;
d0dc5e26 104 else {
0fccdfef
RC
105 last_sc->sc_next = $2;
106 last_sc = $2;
d0dc5e26
RC
107 $$ = $1;
108 }
109 }
110 ;
111
0fccdfef
RC
112cmd: INSTALL options opt_namelist SM = {
113 register struct namelist *nl;
82572cb6 114
0fccdfef 115 $1->sc_options = $2 | options;
d1dee8e8 116 if ($3 != NULL) {
0fccdfef 117 nl = expand($3, E_VARS);
bbe8acb8
KB
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;
d1dee8e8 125 }
d0dc5e26
RC
126 $$ = $1;
127 }
d1dee8e8 128 | NOTIFY namelist SM = {
0fccdfef
RC
129 if ($2 != NULL)
130 $1->sc_args = expand($2, E_VARS);
d0dc5e26
RC
131 $$ = $1;
132 }
d1dee8e8 133 | EXCEPT namelist SM = {
0fccdfef
RC
134 if ($2 != NULL)
135 $1->sc_args = expand($2, E_ALL);
d0dc5e26
RC
136 $$ = $1;
137 }
4085f36f
RC
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);
6bc62d90 145 $1->sc_args = expand($2, E_VARS);
4085f36f
RC
146 $$ = $1;
147 }
d6bccb44
RC
148 | SPECIAL opt_namelist STRING SM = {
149 if ($2 != NULL)
0fccdfef
RC
150 $1->sc_args = expand($2, E_ALL);
151 $1->sc_name = $3;
d6bccb44
RC
152 $$ = $1;
153 }
d0dc5e26 154 ;
d1dee8e8 155
3024eb6f
RC
156options: /* VOID */ = {
157 $$ = 0;
158 }
159 | options OPTION = {
160 $$ |= $2;
161 }
162 ;
d0dc5e26 163
d6bccb44
RC
164opt_namelist: /* VOID */ = {
165 $$ = NULL;
166 }
167 | namelist = {
168 $$ = $1;
169 }
170 ;
171
d0dc5e26
RC
172%%
173
174int yylineno = 1;
175extern FILE *fin;
176
a94625d9 177int
d0dc5e26
RC
178yylex()
179{
180 static char yytext[INMAX];
181 register int c;
182 register char *cp1, *cp2;
3024eb6f 183 static char quotechars[] = "[]{}*?$";
d0dc5e26 184
82572cb6
RC
185again:
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)
d0dc5e26 194 return(0);
82572cb6
RC
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
d1dee8e8
RC
210 case ';': /* SM */
211 return(SM);
212
82572cb6
RC
213 case '-': /* -> */
214 if ((c = getc(fin)) == '>')
215 return(ARROW);
216 ungetc(c, fin);
217 c = '-';
218 break;
219
d6bccb44
RC
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 }
86d7a5c5
RC
237 if (c == '\n') {
238 yylineno++;
d6bccb44 239 c = ' '; /* can't send '\n' */
86d7a5c5 240 }
d6bccb44
RC
241 *cp1++ = c;
242 }
243 if (c != '"')
244 yyerror("missing closing '\"'\n");
0fccdfef
RC
245 *cp1 = '\0';
246 yylval.string = makestr(yytext);
d6bccb44
RC
247 return(STRING);
248
86d7a5c5 249 case ':': /* : or :: */
82572cb6
RC
250 if ((c = getc(fin)) == ':')
251 return(DCOLON);
252 ungetc(c, fin);
86d7a5c5 253 return(COLON);
82572cb6 254 }
82572cb6
RC
255 cp1 = yytext;
256 cp2 = &yytext[INMAX - 1];
257 for (;;) {
258 if (cp1 >= cp2) {
d6bccb44 259 yyerror("input line too long\n");
82572cb6
RC
260 break;
261 }
262 if (c == '\\') {
263 if ((c = getc(fin)) != EOF) {
264 if (any(c, quotechars))
265 c |= QUOTE;
266 } else {
267 *cp1++ = '\\';
d0dc5e26
RC
268 break;
269 }
270 }
82572cb6
RC
271 *cp1++ = c;
272 c = getc(fin);
86d7a5c5 273 if (c == EOF || any(c, " \"'\t()=;:\n")) {
82572cb6
RC
274 ungetc(c, fin);
275 break;
276 }
d0dc5e26 277 }
82572cb6 278 *cp1 = '\0';
3024eb6f
RC
279 if (yytext[0] == '-' && yytext[2] == '\0') {
280 switch (yytext[1]) {
024fde5b
RC
281 case 'b':
282 yylval.intval = COMPARE;
283 return(OPTION);
284
d6bccb44 285 case 'R':
d1dee8e8
RC
286 yylval.intval = REMOVE;
287 return(OPTION);
288
3024eb6f
RC
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);
a3e6fd64
RC
300
301 case 'h':
302 yylval.intval = FOLLOW;
303 return(OPTION);
304
305 case 'i':
306 yylval.intval = IGNLNKS;
307 return(OPTION);
3024eb6f
RC
308 }
309 }
82572cb6
RC
310 if (!strcmp(yytext, "install"))
311 c = INSTALL;
82572cb6
RC
312 else if (!strcmp(yytext, "notify"))
313 c = NOTIFY;
314 else if (!strcmp(yytext, "except"))
315 c = EXCEPT;
56824092 316 else if (!strcmp(yytext, "except_pat"))
4085f36f 317 c = PATTERN;
d6bccb44
RC
318 else if (!strcmp(yytext, "special"))
319 c = SPECIAL;
0fccdfef
RC
320 else {
321 yylval.string = makestr(yytext);
322 return(NAME);
323 }
324 yylval.subcmd = makesubcmd(c);
82572cb6 325 return(c);
d0dc5e26
RC
326}
327
a94625d9 328int
d0dc5e26
RC
329any(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
0fccdfef
RC
339/*
340 * Insert or append ARROW command to list of hosts to be updated.
341 */
a94625d9 342void
86d7a5c5
RC
343insert(label, files, hosts, subcmds)
344 char *label;
0fccdfef
RC
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;
86d7a5c5 375 nc->c_label = label;
0fccdfef
RC
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 */
a94625d9 393void
86d7a5c5
RC
394append(label, files, stamp, subcmds)
395 char *label;
0fccdfef
RC
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;
86d7a5c5 407 c->c_label = label;
0fccdfef
RC
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
d0dc5e26
RC
419/*
420 * Error printing routine in parser.
421 */
a94625d9 422void
d0dc5e26
RC
423yyerror(s)
424 char *s;
425{
a94625d9 426 ++nerrs;
024fde5b 427 fflush(stdout);
d0dc5e26
RC
428 fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
429}
0fccdfef
RC
430
431/*
432 * Return a copy of the string.
433 */
a94625d9 434static char *
0fccdfef
RC
435makestr(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 */
451struct namelist *
452makenl(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 */
468struct subcmd *
a94625d9 469makesubcmd(type)
0fccdfef 470 int type;
0fccdfef 471{
0fccdfef
RC
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}