1 %{ 2 /* $NetBSD: gram.y,v 1.8 1997/10/19 13:59:00 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. 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.8 1997/10/19 13:59:00 lukem 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 __P((char *)); 54 void append __P((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 __P((void)); 207 208 int 209 yylex() 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(c, str) 361 int c; 362 char *str; 363 { 364 while (*str) 365 if (c == *str++) 366 return(1); 367 return(0); 368 } 369 370 /* 371 * Insert or append ARROW command to list of hosts to be updated. 372 */ 373 void 374 insert(label, files, hosts, subcmds) 375 char *label; 376 struct namelist *files, *hosts; 377 struct subcmd *subcmds; 378 { 379 struct cmd *c, *prev, *nc; 380 struct namelist *h, *nexth; 381 382 files = expand(files, E_VARS|E_SHELL); 383 hosts = expand(hosts, E_ALL); 384 for (h = hosts; h != NULL; nexth = h->n_next, free(h), h = nexth) { 385 /* 386 * Search command list for an update to the same host. 387 */ 388 for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) { 389 if (strcmp(c->c_name, h->n_name) == 0) { 390 do { 391 prev = c; 392 c = c->c_next; 393 } while (c != NULL && 394 strcmp(c->c_name, h->n_name) == 0); 395 break; 396 } 397 } 398 /* 399 * Insert new command to update host. 400 */ 401 nc = ALLOC(cmd); 402 if (nc == NULL) 403 fatal("ran out of memory\n"); 404 nc->c_type = ARROW; 405 nc->c_name = h->n_name; 406 nc->c_label = label; 407 nc->c_files = files; 408 nc->c_cmds = subcmds; 409 nc->c_next = c; 410 if (prev == NULL) 411 cmds = nc; 412 else 413 prev->c_next = nc; 414 /* update last_cmd if appending nc to cmds */ 415 if (c == NULL) 416 last_cmd = nc; 417 } 418 } 419 420 /* 421 * Append DCOLON command to the end of the command list since these are always 422 * executed in the order they appear in the distfile. 423 */ 424 void 425 append(label, files, stamp, subcmds) 426 char *label; 427 struct namelist *files; 428 char *stamp; 429 struct subcmd *subcmds; 430 { 431 struct cmd *c; 432 433 c = ALLOC(cmd); 434 if (c == NULL) 435 fatal("ran out of memory\n"); 436 c->c_type = DCOLON; 437 c->c_name = stamp; 438 c->c_label = label; 439 c->c_files = expand(files, E_ALL); 440 c->c_cmds = subcmds; 441 c->c_next = NULL; 442 if (cmds == NULL) 443 cmds = last_cmd = c; 444 else { 445 last_cmd->c_next = c; 446 last_cmd = c; 447 } 448 } 449 450 /* 451 * Error printing routine in parser. 452 */ 453 void 454 yyerror(s) 455 char *s; 456 { 457 458 ++nerrs; 459 fflush(stdout); 460 fprintf(stderr, "rdist: line %d: %s\n", yylineno, s); 461 } 462 463 /* 464 * Return a copy of the string. 465 */ 466 static char * 467 makestr(str) 468 char *str; 469 { 470 char *cp, *s; 471 472 str = cp = malloc(strlen(s = str) + 1); 473 if (cp == NULL) 474 fatal("ran out of memory\n"); 475 while ((*cp++ = *s++) != NULL) 476 ; 477 return(str); 478 } 479 480 /* 481 * Allocate a namelist structure. 482 */ 483 struct namelist * 484 makenl(name) 485 char *name; 486 { 487 struct namelist *nl; 488 489 nl = ALLOC(namelist); 490 if (nl == NULL) 491 fatal("ran out of memory\n"); 492 nl->n_name = name; 493 nl->n_next = NULL; 494 return(nl); 495 } 496 497 /* 498 * Make a sub command for lists of variables, commands, etc. 499 */ 500 struct subcmd * 501 makesubcmd(type) 502 int type; 503 { 504 struct subcmd *sc; 505 506 sc = ALLOC(subcmd); 507 if (sc == NULL) 508 fatal("ran out of memory\n"); 509 sc->sc_type = type; 510 sc->sc_args = NULL; 511 sc->sc_next = NULL; 512 sc->sc_name = NULL; 513 return(sc); 514 } 515