gram.y revision 1.6
1%{ 2/* $OpenBSD: gram.y,v 1.6 2003/05/06 22:10:11 millert Exp $ */ 3 4/* 5 * Copyright (c) 1993 Michael A. Cooper 6 * Copyright (c) 1993 Regents of the University of California. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38#ifndef lint 39#if 0 40static char RCSid[] = 41"$From: gram.y,v 6.29 1994/04/11 23:59:15 mcooper Exp mcooper $"; 42#else 43static char RCSid[] = 44"$OpenBSD: gram.y,v 1.6 2003/05/06 22:10:11 millert Exp $"; 45#endif 46 47static char *sccsid = "@(#)gram.y 5.2 (Berkeley) 85/06/21"; 48 49static char copyright[] = 50"@(#) Copyright (c) 1983 Regents of the University of California.\n\ 51 All rights reserved.\n"; 52#endif /* not lint */ 53 54/* 55 * Tell defs.h not to include y.tab.h 56 */ 57#ifndef yacc 58#define yacc 59#endif 60 61#include "defs.h" 62 63static struct namelist *addnl(), *subnl(), *andnl(); 64struct cmd *cmds = NULL; 65struct cmd *last_cmd; 66struct namelist *last_n; 67struct subcmd *last_sc; 68int parendepth = 0; 69 70%} 71 72%term ARROW 1 73%term COLON 2 74%term DCOLON 3 75%term NAME 4 76%term STRING 5 77%term INSTALL 6 78%term NOTIFY 7 79%term EXCEPT 8 80%term PATTERN 9 81%term SPECIAL 10 82%term CMDSPECIAL 11 83%term OPTION 12 84 85%union { 86 opt_t optval; 87 char *string; 88 struct subcmd *subcmd; 89 struct namelist *namel; 90} 91 92%type <optval> OPTION, options 93%type <string> NAME, STRING 94%type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, CMDSPECIAL, cmdlist, cmd 95%type <namel> namelist, names, opt_namelist nlist 96 97%% 98 99file: /* VOID */ 100 | file command 101 ; 102 103command: NAME '=' namelist = { 104 (void) lookup($1, INSERT, $3); 105 } 106 | namelist ARROW namelist cmdlist = { 107 insert((char *)NULL, $1, $3, $4); 108 } 109 | NAME COLON namelist ARROW namelist cmdlist = { 110 insert($1, $3, $5, $6); 111 } 112 | namelist DCOLON NAME cmdlist = { 113 append((char *)NULL, $1, $3, $4); 114 } 115 | NAME COLON namelist DCOLON NAME cmdlist = { 116 append($1, $3, $5, $6); 117 } 118 | error 119 ; 120 121namelist: nlist { 122 $$ = $1; 123 } 124 | nlist '-' nlist { 125 $$ = subnl($1, $3); 126 } 127 | nlist '+' nlist { 128 $$ = addnl($1, $3); 129 } 130 | nlist '&' nlist { 131 $$ = andnl($1, $3); 132 } 133 ; 134 135nlist: NAME = { 136 $$ = makenl($1); 137 } 138 | '(' names ')' = { 139 $$ = $2; 140 } 141 ; 142 143names: /* VOID */ { 144 $$ = last_n = NULL; 145 } 146 | names NAME = { 147 if (last_n == NULL) 148 $$ = last_n = makenl($2); 149 else { 150 last_n->n_next = makenl($2); 151 last_n = last_n->n_next; 152 $$ = $1; 153 } 154 } 155 ; 156 157cmdlist: /* VOID */ { 158 $$ = last_sc = NULL; 159 } 160 | cmdlist cmd = { 161 if (last_sc == NULL) 162 $$ = last_sc = $2; 163 else { 164 last_sc->sc_next = $2; 165 last_sc = $2; 166 $$ = $1; 167 } 168 } 169 ; 170 171cmd: INSTALL options opt_namelist ';' = { 172 register struct namelist *nl; 173 174 $1->sc_options = $2 | options; 175 if ($3 != NULL) { 176 nl = expand($3, E_VARS); 177 if (nl) { 178 if (nl->n_next != NULL) 179 yyerror("only one name allowed\n"); 180 $1->sc_name = nl->n_name; 181 free(nl); 182 } else 183 $1->sc_name = NULL; 184 } 185 $$ = $1; 186 } 187 | NOTIFY namelist ';' = { 188 if ($2 != NULL) 189 $1->sc_args = expand($2, E_VARS); 190 $$ = $1; 191 } 192 | EXCEPT namelist ';' = { 193 if ($2 != NULL) 194 $1->sc_args = expand($2, E_ALL); 195 $$ = $1; 196 } 197 | PATTERN namelist ';' = { 198 struct namelist *nl; 199 char ebuf[BUFSIZ]; 200 regex_t reg; 201 int ecode; 202 203 for (nl = $2; nl != NULL; nl = nl->n_next) { 204 /* check for a valid regex */ 205 ecode = regcomp(®, nl->n_name, REG_NOSUB); 206 if (ecode) { 207 regerror(ecode, ®, ebuf, 208 sizeof(ebuf)); 209 yyerror(ebuf); 210 } 211 regfree(®); 212 } 213 $1->sc_args = expand($2, E_VARS); 214 $$ = $1; 215 } 216 | SPECIAL opt_namelist STRING ';' = { 217 if ($2 != NULL) 218 $1->sc_args = expand($2, E_ALL); 219 $1->sc_name = $3; 220 $$ = $1; 221 } 222 | CMDSPECIAL opt_namelist STRING ';' = { 223 if ($2 != NULL) 224 $1->sc_args = expand($2, E_ALL); 225 $1->sc_name = $3; 226 $$ = $1; 227 } 228 ; 229 230options: /* VOID */ = { 231 $$ = 0; 232 } 233 | options OPTION = { 234 $$ |= $2; 235 } 236 ; 237 238opt_namelist: /* VOID */ = { 239 $$ = NULL; 240 } 241 | namelist = { 242 $$ = $1; 243 } 244 ; 245 246%% 247 248int yylineno = 1; 249extern FILE *fin; 250 251yylex() 252{ 253 static char yytext[INMAX]; 254 register int c; 255 register char *cp1, *cp2; 256 static char quotechars[] = "[]{}*?$"; 257 258again: 259 switch (c = getc(fin)) { 260 case EOF: /* end of file */ 261 return(0); 262 263 case '#': /* start of comment */ 264 while ((c = getc(fin)) != EOF && c != '\n') 265 ; 266 if (c == EOF) 267 return(0); 268 case '\n': 269 yylineno++; 270 case ' ': 271 case '\t': /* skip blanks */ 272 goto again; 273 274 case '=': /* EQUAL */ 275 case ';': /* SM */ 276 case '+': 277 case '&': 278 return(c); 279 280 case '(': /* LP */ 281 ++parendepth; 282 return(c); 283 284 case ')': /* RP */ 285 --parendepth; 286 return(c); 287 288 case '-': /* -> */ 289 if ((c = getc(fin)) == '>') 290 return(ARROW); 291 (void) ungetc(c, fin); 292 c = '-'; 293 break; 294 295 case '"': /* STRING */ 296 cp1 = yytext; 297 cp2 = &yytext[INMAX - 1]; 298 for (;;) { 299 if (cp1 >= cp2) { 300 yyerror("command string too long\n"); 301 break; 302 } 303 c = getc(fin); 304 if (c == EOF || c == '"') 305 break; 306 if (c == '\\') { 307 if ((c = getc(fin)) == EOF) { 308 *cp1++ = '\\'; 309 break; 310 } 311 } 312 if (c == '\n') { 313 yylineno++; 314 c = ' '; /* can't send '\n' */ 315 } 316 *cp1++ = c; 317 } 318 if (c != '"') 319 yyerror("missing closing '\"'\n"); 320 *cp1 = '\0'; 321 yylval.string = makestr(yytext); 322 return(STRING); 323 324 case ':': /* : or :: */ 325 if ((c = getc(fin)) == ':') 326 return(DCOLON); 327 (void) ungetc(c, fin); 328 return(COLON); 329 } 330 cp1 = yytext; 331 cp2 = &yytext[INMAX - 1]; 332 for (;;) { 333 if (cp1 >= cp2) { 334 yyerror("input line too long\n"); 335 break; 336 } 337 if (c == '\\') { 338 if ((c = getc(fin)) != EOF) { 339 if (any(c, quotechars)) 340 *cp1++ = QUOTECHAR; 341 } else { 342 *cp1++ = '\\'; 343 break; 344 } 345 } 346 *cp1++ = c; 347 c = getc(fin); 348 if (c == EOF || any(c, " \"'\t()=;:\n")) { 349 (void) ungetc(c, fin); 350 break; 351 } 352 } 353 *cp1 = '\0'; 354 if (yytext[0] == '-' && yytext[1] == CNULL) 355 return '-'; 356 if (yytext[0] == '-' && parendepth <= 0) { 357 opt_t opt = 0; 358 static char ebuf[BUFSIZ]; 359 360 switch (yytext[1]) { 361 case 'o': 362 if (parsedistopts(&yytext[2], &opt, TRUE)) { 363 (void) snprintf(ebuf, sizeof ebuf, 364 "Bad distfile options \"%s\".", 365 &yytext[2]); 366 yyerror(ebuf); 367 } 368 break; 369 370 /* 371 * These options are obsoleted by -o. 372 */ 373 case 'b': opt = DO_COMPARE; break; 374 case 'R': opt = DO_REMOVE; break; 375 case 'v': opt = DO_VERIFY; break; 376 case 'w': opt = DO_WHOLE; break; 377 case 'y': opt = DO_YOUNGER; break; 378 case 'h': opt = DO_FOLLOW; break; 379 case 'i': opt = DO_IGNLNKS; break; 380 case 'q': opt = DO_QUIET; break; 381 case 'x': opt = DO_NOEXEC; break; 382 case 'N': opt = DO_CHKNFS; break; 383 case 'O': opt = DO_CHKREADONLY; break; 384 case 's': opt = DO_SAVETARGETS; break; 385 case 'r': opt = DO_NODESCEND; break; 386 387 default: 388 (void) snprintf(ebuf, sizeof ebuf, 389 "Unknown option \"%s\".", yytext); 390 yyerror(ebuf); 391 } 392 393 yylval.optval = opt; 394 return(OPTION); 395 } 396 if (!strcmp(yytext, "install")) 397 c = INSTALL; 398 else if (!strcmp(yytext, "notify")) 399 c = NOTIFY; 400 else if (!strcmp(yytext, "except")) 401 c = EXCEPT; 402 else if (!strcmp(yytext, "except_pat")) 403 c = PATTERN; 404 else if (!strcmp(yytext, "special")) 405 c = SPECIAL; 406 else if (!strcmp(yytext, "cmdspecial")) 407 c = CMDSPECIAL; 408 else { 409 yylval.string = makestr(yytext); 410 return(NAME); 411 } 412 yylval.subcmd = makesubcmd(c); 413 return(c); 414} 415 416/* 417 * XXX We should use strchr(), but most versions can't handle 418 * some of the characters we use. 419 */ 420extern int any(c, str) 421 register int c; 422 register char *str; 423{ 424 while (*str) 425 if (c == *str++) 426 return(1); 427 return(0); 428} 429 430/* 431 * Insert or append ARROW command to list of hosts to be updated. 432 */ 433void 434insert(label, files, hosts, subcmds) 435 char *label; 436 struct namelist *files, *hosts; 437 struct subcmd *subcmds; 438{ 439 register struct cmd *c, *prev, *nc; 440 register struct namelist *h, *lasth; 441 442 debugmsg(DM_CALL, "insert(%s, %x, %x, %x) start, files = %s", 443 label == NULL ? "(null)" : label, 444 files, hosts, subcmds, getnlstr(files)); 445 446 files = expand(files, E_VARS|E_SHELL); 447 hosts = expand(hosts, E_ALL); 448 for (h = hosts; h != NULL; lasth = h, h = h->n_next, 449 free((char *)lasth)) { 450 /* 451 * Search command list for an update to the same host. 452 */ 453 for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) { 454 if (strcmp(c->c_name, h->n_name) == 0) { 455 do { 456 prev = c; 457 c = c->c_next; 458 } while (c != NULL && 459 strcmp(c->c_name, h->n_name) == 0); 460 break; 461 } 462 } 463 /* 464 * Insert new command to update host. 465 */ 466 nc = ALLOC(cmd); 467 nc->c_type = ARROW; 468 nc->c_name = h->n_name; 469 nc->c_label = label; 470 nc->c_files = files; 471 nc->c_cmds = subcmds; 472 nc->c_flags = 0; 473 nc->c_next = c; 474 if (prev == NULL) 475 cmds = nc; 476 else 477 prev->c_next = nc; 478 /* update last_cmd if appending nc to cmds */ 479 if (c == NULL) 480 last_cmd = nc; 481 } 482} 483 484/* 485 * Append DCOLON command to the end of the command list since these are always 486 * executed in the order they appear in the distfile. 487 */ 488void 489append(label, files, stamp, subcmds) 490 char *label; 491 struct namelist *files; 492 char *stamp; 493 struct subcmd *subcmds; 494{ 495 register struct cmd *c; 496 497 c = ALLOC(cmd); 498 c->c_type = DCOLON; 499 c->c_name = stamp; 500 c->c_label = label; 501 c->c_files = expand(files, E_ALL); 502 c->c_cmds = subcmds; 503 c->c_next = NULL; 504 if (cmds == NULL) 505 cmds = last_cmd = c; 506 else { 507 last_cmd->c_next = c; 508 last_cmd = c; 509 } 510} 511 512/* 513 * Error printing routine in parser. 514 */ 515void 516yyerror(s) 517 char *s; 518{ 519 error("Error in distfile: line %d: %s", yylineno, s); 520} 521 522/* 523 * Return a copy of the string. 524 */ 525char * 526makestr(str) 527 char *str; 528{ 529 char *cp; 530 531 cp = strdup(str); 532 if (cp == NULL) 533 fatalerr("ran out of memory"); 534 535 return(cp); 536} 537 538/* 539 * Allocate a namelist structure. 540 */ 541struct namelist * 542makenl(name) 543 char *name; 544{ 545 register struct namelist *nl; 546 547 debugmsg(DM_CALL, "makenl(%s)", name == NULL ? "null" : name); 548 549 nl = ALLOC(namelist); 550 nl->n_name = name; 551 nl->n_regex = NULL; 552 nl->n_next = NULL; 553 554 return(nl); 555} 556 557 558/* 559 * Is the name p in the namelist nl? 560 */ 561static int 562innl(nl, p) 563 struct namelist *nl; 564 char *p; 565{ 566 for ( ; nl; nl = nl->n_next) 567 if (!strcmp(p, nl->n_name)) 568 return(1); 569 return(0); 570} 571 572/* 573 * Join two namelists. 574 */ 575static struct namelist * 576addnl(n1, n2) 577 struct namelist *n1, *n2; 578{ 579 struct namelist *nl, *prev; 580 581 n1 = expand(n1, E_VARS); 582 n2 = expand(n2, E_VARS); 583 for (prev = NULL, nl = NULL; n1; n1 = n1->n_next, prev = nl) { 584 nl = makenl(n1->n_name); 585 nl->n_next = prev; 586 } 587 for (; n2; n2 = n2->n_next) 588 if (!innl(nl, n2->n_name)) { 589 nl = makenl(n2->n_name); 590 nl->n_next = prev; 591 prev = nl; 592 } 593 return(prev); 594} 595 596/* 597 * Copy n1 except for elements that are in n2. 598 */ 599static struct namelist * 600subnl(n1, n2) 601 struct namelist *n1, *n2; 602{ 603 struct namelist *nl, *prev; 604 605 n1 = expand(n1, E_VARS); 606 n2 = expand(n2, E_VARS); 607 for (prev = NULL; n1; n1 = n1->n_next) 608 if (!innl(n2, n1->n_name)) { 609 nl = makenl(n1->n_name); 610 nl->n_next = prev; 611 prev = nl; 612 } 613 return(prev); 614} 615 616/* 617 * Copy all items of n1 that are also in n2. 618 */ 619static struct namelist * 620andnl(n1, n2) 621 struct namelist *n1, *n2; 622{ 623 struct namelist *nl, *prev; 624 625 n1 = expand(n1, E_VARS); 626 n2 = expand(n2, E_VARS); 627 for (prev = NULL; n1; n1 = n1->n_next) 628 if (innl(n2, n1->n_name)) { 629 nl = makenl(n1->n_name); 630 nl->n_next = prev; 631 prev = nl; 632 } 633 return(prev); 634} 635 636/* 637 * Make a sub command for lists of variables, commands, etc. 638 */ 639extern struct subcmd * 640makesubcmd(type) 641 int type; 642{ 643 register struct subcmd *sc; 644 645 sc = ALLOC(subcmd); 646 sc->sc_type = type; 647 sc->sc_args = NULL; 648 sc->sc_next = NULL; 649 sc->sc_name = NULL; 650 651 return(sc); 652} 653