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