No empty .Rs/.Re
[netbsd-mini2440.git] / usr.bin / rdist / gram.y
blob1f61d9e4416e409d33e277563ba37f219472cda1
1 %{
2 /* $NetBSD: gram.y,v 1.12 2006/03/18 09:46:35 christos Exp $ */
4 /*
5 * Copyright (c) 1983, 1993
6 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 #ifndef lint
35 #if 0
36 static char sccsid[] = "@(#)gram.y 8.1 (Berkeley) 6/9/93";
37 #else
38 __RCSID("$NetBSD: gram.y,v 1.12 2006/03/18 09:46:35 christos Exp $");
39 #endif
40 #endif /* not lint */
42 #include "defs.h"
44 struct cmd *cmds = NULL;
45 struct cmd *last_cmd;
46 struct namelist *last_n;
47 struct subcmd *last_sc;
49 static char *makestr(char *);
50 void append(char *, struct namelist *, char *, struct subcmd *);
54 %term EQUAL 1
55 %term LP 2
56 %term RP 3
57 %term SM 4
58 %term ARROW 5
59 %term COLON 6
60 %term DCOLON 7
61 %term NAME 8
62 %term STRING 9
63 %term INSTALL 10
64 %term NOTIFY 11
65 %term EXCEPT 12
66 %term PATTERN 13
67 %term SPECIAL 14
68 %term OPTION 15
70 %union {
71 int intval;
72 char *string;
73 struct subcmd *subcmd;
74 struct namelist *namel;
77 %type <intval> OPTION, options
78 %type <string> NAME, STRING
79 %type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, cmdlist, cmd
80 %type <namel> namelist, names, opt_namelist
84 file: /* VOID */
85 | file command
88 command: NAME EQUAL namelist = {
89 (void) lookup($1, INSERT, $3);
91 | namelist ARROW namelist cmdlist = {
92 insert(NULL, $1, $3, $4);
94 | NAME COLON namelist ARROW namelist cmdlist = {
95 insert($1, $3, $5, $6);
97 | namelist DCOLON NAME cmdlist = {
98 append(NULL, $1, $3, $4);
100 | NAME COLON namelist DCOLON NAME cmdlist = {
101 append($1, $3, $5, $6);
103 | error
106 namelist: NAME = {
107 $$ = makenl($1);
109 | LP names RP = {
110 $$ = $2;
114 names: /* VOID */ {
115 $$ = last_n = NULL;
117 | names NAME = {
118 if (last_n == NULL)
119 $$ = last_n = makenl($2);
120 else {
121 last_n->n_next = makenl($2);
122 last_n = last_n->n_next;
123 $$ = $1;
128 cmdlist: /* VOID */ {
129 $$ = last_sc = NULL;
131 | cmdlist cmd = {
132 if (last_sc == NULL)
133 $$ = last_sc = $2;
134 else {
135 last_sc->sc_next = $2;
136 last_sc = $2;
137 $$ = $1;
142 cmd: INSTALL options opt_namelist SM = {
143 struct namelist *nl;
145 $1->sc_options = $2 | options;
146 if ($3 != NULL) {
147 nl = expand($3, E_VARS);
148 if (nl) {
149 if (nl->n_next != NULL)
150 yyerror("only one name allowed\n");
151 $1->sc_name = nl->n_name;
152 free(nl);
153 } else
154 $1->sc_name = NULL;
156 $$ = $1;
158 | NOTIFY namelist SM = {
159 if ($2 != NULL)
160 $1->sc_args = expand($2, E_VARS);
161 $$ = $1;
163 | EXCEPT namelist SM = {
164 if ($2 != NULL)
165 $1->sc_args = expand($2, E_ALL);
166 $$ = $1;
168 | PATTERN namelist SM = {
169 if ($2 != NULL)
170 $1->sc_args = expand($2, E_VARS);
171 $$ = $1;
173 | SPECIAL opt_namelist STRING SM = {
174 if ($2 != NULL)
175 $1->sc_args = expand($2, E_ALL);
176 $1->sc_name = $3;
177 $$ = $1;
181 options: /* VOID */ = {
182 $$ = 0;
184 | options OPTION = {
185 $$ |= $2;
189 opt_namelist: /* VOID */ = {
190 $$ = NULL;
192 | namelist = {
193 $$ = $1;
199 int yylineno = 1;
200 extern FILE *fin;
202 int yylex(void);
205 yylex(void)
207 static char yytext[INMAX];
208 int c;
209 char *cp1, *cp2;
210 static char quotechars[] = "[]{}*?$";
212 again:
213 switch (c = getc(fin)) {
214 case EOF: /* end of file */
215 return(0);
217 case '#': /* start of comment */
218 while ((c = getc(fin)) != EOF && c != '\n')
220 if (c == EOF)
221 return(0);
222 case '\n':
223 yylineno++;
224 case ' ':
225 case '\t': /* skip blanks */
226 goto again;
228 case '=': /* EQUAL */
229 return(EQUAL);
231 case '(': /* LP */
232 return(LP);
234 case ')': /* RP */
235 return(RP);
237 case ';': /* SM */
238 return(SM);
240 case '-': /* -> */
241 if ((c = getc(fin)) == '>')
242 return(ARROW);
243 ungetc(c, fin);
244 c = '-';
245 break;
247 case '"': /* STRING */
248 cp1 = yytext;
249 cp2 = &yytext[INMAX - 1];
250 for (;;) {
251 if (cp1 >= cp2) {
252 yyerror("command string too long\n");
253 break;
255 c = getc(fin);
256 if (c == EOF || c == '"')
257 break;
258 if (c == '\\') {
259 if ((c = getc(fin)) == EOF) {
260 *cp1++ = '\\';
261 break;
264 if (c == '\n') {
265 yylineno++;
266 c = ' '; /* can't send '\n' */
268 *cp1++ = c;
270 if (c != '"')
271 yyerror("missing closing '\"'\n");
272 *cp1 = '\0';
273 yylval.string = makestr(yytext);
274 return(STRING);
276 case ':': /* : or :: */
277 if ((c = getc(fin)) == ':')
278 return(DCOLON);
279 ungetc(c, fin);
280 return(COLON);
282 cp1 = yytext;
283 cp2 = &yytext[INMAX - 1];
284 for (;;) {
285 if (cp1 >= cp2) {
286 yyerror("input line too long\n");
287 break;
289 if (c == '\\') {
290 if ((c = getc(fin)) != EOF) {
291 if (any(c, quotechars))
292 c |= QUOTE;
293 } else {
294 *cp1++ = '\\';
295 break;
298 *cp1++ = c;
299 c = getc(fin);
300 if (c == EOF || any(c, " \"'\t()=;:\n")) {
301 ungetc(c, fin);
302 break;
305 *cp1 = '\0';
306 if (yytext[0] == '-' && yytext[2] == '\0') {
307 switch (yytext[1]) {
308 case 'b':
309 yylval.intval = COMPARE;
310 return(OPTION);
312 case 'R':
313 yylval.intval = REMOVE;
314 return(OPTION);
316 case 'v':
317 yylval.intval = VERIFY;
318 return(OPTION);
320 case 'w':
321 yylval.intval = WHOLE;
322 return(OPTION);
324 case 'y':
325 yylval.intval = YOUNGER;
326 return(OPTION);
328 case 'h':
329 yylval.intval = FOLLOW;
330 return(OPTION);
332 case 'i':
333 yylval.intval = IGNLNKS;
334 return(OPTION);
337 if (!strcmp(yytext, "install"))
338 c = INSTALL;
339 else if (!strcmp(yytext, "notify"))
340 c = NOTIFY;
341 else if (!strcmp(yytext, "except"))
342 c = EXCEPT;
343 else if (!strcmp(yytext, "except_pat"))
344 c = PATTERN;
345 else if (!strcmp(yytext, "special"))
346 c = SPECIAL;
347 else {
348 yylval.string = makestr(yytext);
349 return(NAME);
351 yylval.subcmd = makesubcmd(c);
352 return(c);
356 any(int c, const char *str)
358 while (*str)
359 if (c == *str++)
360 return(1);
361 return(0);
365 * Insert or append ARROW command to list of hosts to be updated.
367 void
368 insert(char *label, struct namelist *files, struct namelist *hosts,
369 struct subcmd *subcmds)
371 struct cmd *c, *prev, *nc;
372 struct namelist *h, *nexth;
374 files = expand(files, E_VARS|E_SHELL);
375 hosts = expand(hosts, E_ALL);
376 for (h = hosts; h != NULL; nexth = h->n_next, free(h), h = nexth) {
378 * Search command list for an update to the same host.
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;
391 * Insert new command to update host.
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;
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.
416 void
417 append(char *label, struct namelist *files, char *stamp,
418 struct subcmd *subcmds)
420 struct cmd *c;
422 c = ALLOC(cmd);
423 if (c == NULL)
424 fatal("ran out of memory\n");
425 c->c_type = DCOLON;
426 c->c_name = stamp;
427 c->c_label = label;
428 c->c_files = expand(files, E_ALL);
429 c->c_cmds = subcmds;
430 c->c_next = NULL;
431 if (cmds == NULL)
432 cmds = last_cmd = c;
433 else {
434 last_cmd->c_next = c;
435 last_cmd = c;
440 * Error printing routine in parser.
442 void
443 yyerror(const char *s)
446 ++nerrs;
447 fflush(stdout);
448 fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
452 * Return a copy of the string.
454 static char *
455 makestr(char *str)
457 char *cp, *s;
459 str = cp = malloc(strlen(s = str) + 1);
460 if (cp == NULL)
461 fatal("ran out of memory\n");
462 while ((*cp++ = *s++) != 0)
464 return(str);
468 * Allocate a namelist structure.
470 struct namelist *
471 makenl(char *name)
473 struct namelist *nl;
475 nl = ALLOC(namelist);
476 if (nl == NULL)
477 fatal("ran out of memory\n");
478 nl->n_name = name;
479 nl->n_next = NULL;
480 return(nl);
483 void
484 freenl(struct namelist *nl)
486 if (nl == NULL)
487 return;
488 freenl(nl->n_next);
489 free(nl);
492 void
493 freesubcmd(struct subcmd *cmd)
495 if (cmd == NULL)
496 return;
497 freesubcmd(cmd->sc_next);
498 free(cmd);
502 * Make a sub command for lists of variables, commands, etc.
504 struct subcmd *
505 makesubcmd(int type)
507 struct subcmd *sc;
509 sc = ALLOC(subcmd);
510 if (sc == NULL)
511 fatal("ran out of memory\n");
512 sc->sc_type = type;
513 sc->sc_args = NULL;
514 sc->sc_next = NULL;
515 sc->sc_name = NULL;
516 return(sc);