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