1 %{ 2 /* $NetBSD: gram.y,v 1.13 2009/04/13 04:35:36 lukem 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. 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. 19 * 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. 31 */ 32 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.13 2009/04/13 04:35:36 lukem Exp $"); 39 #endif 40 #endif /* not lint */ 41 42 #include "defs.h" 43 44 struct cmd *cmds = NULL; 45 struct cmd *last_cmd; 46 struct namelist *last_n; 47 struct subcmd *last_sc; 48 49 static char *makestr(char *); 50 void append(char *, struct namelist *, char *, struct subcmd *); 51 52 %} 53 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 69 70 %union { 71 int intval; 72 char *string; 73 struct subcmd *subcmd; 74 struct namelist *namel; 75 } 76 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 81 82 %% 83 84 file: /* VOID */ 85 | file command 86 ; 87 88 command: NAME EQUAL namelist = { 89 (void) lookup($1, INSERT, $3); 90 } 91 | namelist ARROW namelist cmdlist = { 92 insert(NULL, $1, $3, $4); 93 } 94 | NAME COLON namelist ARROW namelist cmdlist = { 95 insert($1, $3, $5, $6); 96 } 97 | namelist DCOLON NAME cmdlist = { 98 append(NULL, $1, $3, $4); 99 } 100 | NAME COLON namelist DCOLON NAME cmdlist = { 101 append($1, $3, $5, $6); 102 } 103 | error 104 ; 105 106 namelist: NAME = { 107 $$ = makenl($1); 108 } 109 | LP names RP = { 110 $$ = $2; 111 } 112 ; 113 114 names: /* VOID */ { 115 $$ = last_n = NULL; 116 } 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; 124 } 125 } 126 ; 127 128 cmdlist: /* VOID */ { 129 $$ = last_sc = NULL; 130 } 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; 138 } 139 } 140 ; 141 142 cmd: INSTALL options opt_namelist SM = { 143 struct namelist *nl; 144 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; 155 } 156 $$ = $1; 157 } 158 | NOTIFY namelist SM = { 159 if ($2 != NULL) 160 $1->sc_args = expand($2, E_VARS); 161 $$ = $1; 162 } 163 | EXCEPT namelist SM = { 164 if ($2 != NULL) 165 $1->sc_args = expand($2, E_ALL); 166 $$ = $1; 167 } 168 | PATTERN namelist SM = { 169 if ($2 != NULL) 170 $1->sc_args = expand($2, E_VARS); 171 $$ = $1; 172 } 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; 178 } 179 ; 180 181 options: /* VOID */ = { 182 $$ = 0; 183 } 184 | options OPTION = { 185 $$ |= $2; 186 } 187 ; 188 189 opt_namelist: /* VOID */ = { 190 $$ = NULL; 191 } 192 | namelist = { 193 $$ = $1; 194 } 195 ; 196 197 %% 198 199 int yylineno = 1; 200 extern FILE *fin; 201 202 int yylex(void); 203 204 int 205 yylex(void) 206 { 207 static char yytext[INMAX]; 208 int c; 209 char *cp1, *cp2; 210 static char quotechars[] = "[]{}*?$"; 211 212 again: 213 switch (c = getc(fin)) { 214 case EOF: /* end of file */ 215 return(0); 216 217 case '#': /* start of comment */ 218 while ((c = getc(fin)) != EOF && c != '\n') 219 ; 220 if (c == EOF) 221 return(0); 222 case '\n': 223 yylineno++; 224 case ' ': 225 case '\t': /* skip blanks */ 226 goto again; 227 228 case '=': /* EQUAL */ 229 return(EQUAL); 230 231 case '(': /* LP */ 232 return(LP); 233 234 case ')': /* RP */ 235 return(RP); 236 237 case ';': /* SM */ 238 return(SM); 239 240 case '-': /* -> */ 241 if ((c = getc(fin)) == '>') 242 return(ARROW); 243 ungetc(c, fin); 244 c = '-'; 245 break; 246 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; 254 } 255 c = getc(fin); 256 if (c == EOF || c == '"') 257 break; 258 if (c == '\\') { 259 if ((c = getc(fin)) == EOF) { 260 *cp1++ = '\\'; 261 break; 262 } 263 } 264 if (c == '\n') { 265 yylineno++; 266 c = ' '; /* can't send '\n' */ 267 } 268 *cp1++ = c; 269 } 270 if (c != '"') 271 yyerror("missing closing '\"'\n"); 272 *cp1 = '\0'; 273 yylval.string = makestr(yytext); 274 return(STRING); 275 276 case ':': /* : or :: */ 277 if ((c = getc(fin)) == ':') 278 return(DCOLON); 279 ungetc(c, fin); 280 return(COLON); 281 } 282 cp1 = yytext; 283 cp2 = &yytext[INMAX - 1]; 284 for (;;) { 285 if (cp1 >= cp2) { 286 yyerror("input line too long\n"); 287 break; 288 } 289 if (c == '\\') { 290 if ((c = getc(fin)) != EOF) { 291 if (any(c, quotechars)) 292 c |= QUOTE; 293 } else { 294 *cp1++ = '\\'; 295 break; 296 } 297 } 298 *cp1++ = c; 299 c = getc(fin); 300 if (c == EOF || any(c, " \"'\t()=;:\n")) { 301 ungetc(c, fin); 302 break; 303 } 304 } 305 *cp1 = '\0'; 306 if (yytext[0] == '-' && yytext[2] == '\0') { 307 switch (yytext[1]) { 308 case 'b': 309 yylval.intval = COMPARE; 310 return(OPTION); 311 312 case 'R': 313 yylval.intval = REMOVE; 314 return(OPTION); 315 316 case 'v': 317 yylval.intval = VERIFY; 318 return(OPTION); 319 320 case 'w': 321 yylval.intval = WHOLE; 322 return(OPTION); 323 324 case 'y': 325 yylval.intval = YOUNGER; 326 return(OPTION); 327 328 case 'h': 329 yylval.intval = FOLLOW; 330 return(OPTION); 331 332 case 'i': 333 yylval.intval = IGNLNKS; 334 return(OPTION); 335 } 336 } 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); 350 } 351 yylval.subcmd = makesubcmd(c); 352 return(c); 353 } 354 355 int 356 any(int c, const char *str) 357 { 358 while (*str) 359 if (c == *str++) 360 return(1); 361 return(0); 362 } 363 364 /* 365 * Insert or append ARROW command to list of hosts to be updated. 366 */ 367 void 368 insert(char *label, struct namelist *files, struct namelist *hosts, 369 struct subcmd *subcmds) 370 { 371 struct cmd *c, *prev, *nc; 372 struct namelist *h, *nexth; 373 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) { 377 /* 378 * Search command list for an update to the same host. 379 */ 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; 388 } 389 } 390 /* 391 * Insert new command to update host. 392 */ 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; 409 } 410 } 411 412 /* 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. 415 */ 416 void 417 append(char *label, struct namelist *files, char *stamp, 418 struct subcmd *subcmds) 419 { 420 struct cmd *c; 421 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; 436 } 437 } 438 439 /* 440 * Error printing routine in parser. 441 */ 442 void 443 yyerror(const char *s) 444 { 445 446 ++nerrs; 447 fflush(stdout); 448 fprintf(stderr, "rdist: line %d: %s\n", yylineno, s); 449 } 450 451 /* 452 * Return a copy of the string. 453 */ 454 static char * 455 makestr(char *str) 456 { 457 char *cp, *s; 458 459 str = cp = malloc(strlen(s = str) + 1); 460 if (cp == NULL) 461 fatal("ran out of memory\n"); 462 while ((*cp++ = *s++) != 0) 463 ; 464 return(str); 465 } 466 467 /* 468 * Allocate a namelist structure. 469 */ 470 struct namelist * 471 makenl(char *name) 472 { 473 struct namelist *nl; 474 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); 481 } 482 483 void 484 freenl(struct namelist *nl) 485 { 486 if (nl == NULL) 487 return; 488 freenl(nl->n_next); 489 free(nl); 490 } 491 492 void 493 freesubcmd(struct subcmd *cmd) 494 { 495 if (cmd == NULL) 496 return; 497 freesubcmd(cmd->sc_next); 498 free(cmd); 499 } 500 501 /* 502 * Make a sub command for lists of variables, commands, etc. 503 */ 504 struct subcmd * 505 makesubcmd(int type) 506 { 507 struct subcmd *sc; 508 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); 517 } 518