1 %{ 2 /* $NetBSD: gram.y,v 1.14 2019/02/03 03:19:29 mrg 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.14 2019/02/03 03:19:29 mrg 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 /* FALLTHROUGH */ 223 case '\n': 224 yylineno++; 225 /* FALLTHROUGH */ 226 case ' ': 227 case '\t': /* skip blanks */ 228 goto again; 229 230 case '=': /* EQUAL */ 231 return(EQUAL); 232 233 case '(': /* LP */ 234 return(LP); 235 236 case ')': /* RP */ 237 return(RP); 238 239 case ';': /* SM */ 240 return(SM); 241 242 case '-': /* -> */ 243 if ((c = getc(fin)) == '>') 244 return(ARROW); 245 ungetc(c, fin); 246 c = '-'; 247 break; 248 249 case '"': /* STRING */ 250 cp1 = yytext; 251 cp2 = &yytext[INMAX - 1]; 252 for (;;) { 253 if (cp1 >= cp2) { 254 yyerror("command string too long\n"); 255 break; 256 } 257 c = getc(fin); 258 if (c == EOF || c == '"') 259 break; 260 if (c == '\\') { 261 if ((c = getc(fin)) == EOF) { 262 *cp1++ = '\\'; 263 break; 264 } 265 } 266 if (c == '\n') { 267 yylineno++; 268 c = ' '; /* can't send '\n' */ 269 } 270 *cp1++ = c; 271 } 272 if (c != '"') 273 yyerror("missing closing '\"'\n"); 274 *cp1 = '\0'; 275 yylval.string = makestr(yytext); 276 return(STRING); 277 278 case ':': /* : or :: */ 279 if ((c = getc(fin)) == ':') 280 return(DCOLON); 281 ungetc(c, fin); 282 return(COLON); 283 } 284 cp1 = yytext; 285 cp2 = &yytext[INMAX - 1]; 286 for (;;) { 287 if (cp1 >= cp2) { 288 yyerror("input line too long\n"); 289 break; 290 } 291 if (c == '\\') { 292 if ((c = getc(fin)) != EOF) { 293 if (any(c, quotechars)) 294 c |= QUOTE; 295 } else { 296 *cp1++ = '\\'; 297 break; 298 } 299 } 300 *cp1++ = c; 301 c = getc(fin); 302 if (c == EOF || any(c, " \"'\t()=;:\n")) { 303 ungetc(c, fin); 304 break; 305 } 306 } 307 *cp1 = '\0'; 308 if (yytext[0] == '-' && yytext[2] == '\0') { 309 switch (yytext[1]) { 310 case 'b': 311 yylval.intval = COMPARE; 312 return(OPTION); 313 314 case 'R': 315 yylval.intval = REMOVE; 316 return(OPTION); 317 318 case 'v': 319 yylval.intval = VERIFY; 320 return(OPTION); 321 322 case 'w': 323 yylval.intval = WHOLE; 324 return(OPTION); 325 326 case 'y': 327 yylval.intval = YOUNGER; 328 return(OPTION); 329 330 case 'h': 331 yylval.intval = FOLLOW; 332 return(OPTION); 333 334 case 'i': 335 yylval.intval = IGNLNKS; 336 return(OPTION); 337 } 338 } 339 if (!strcmp(yytext, "install")) 340 c = INSTALL; 341 else if (!strcmp(yytext, "notify")) 342 c = NOTIFY; 343 else if (!strcmp(yytext, "except")) 344 c = EXCEPT; 345 else if (!strcmp(yytext, "except_pat")) 346 c = PATTERN; 347 else if (!strcmp(yytext, "special")) 348 c = SPECIAL; 349 else { 350 yylval.string = makestr(yytext); 351 return(NAME); 352 } 353 yylval.subcmd = makesubcmd(c); 354 return(c); 355 } 356 357 int 358 any(int c, const char *str) 359 { 360 while (*str) 361 if (c == *str++) 362 return(1); 363 return(0); 364 } 365 366 /* 367 * Insert or append ARROW command to list of hosts to be updated. 368 */ 369 void 370 insert(char *label, struct namelist *files, struct namelist *hosts, 371 struct subcmd *subcmds) 372 { 373 struct cmd *c, *prev, *nc; 374 struct namelist *h, *nexth; 375 376 files = expand(files, E_VARS|E_SHELL); 377 hosts = expand(hosts, E_ALL); 378 for (h = hosts; h != NULL; nexth = h->n_next, free(h), h = nexth) { 379 /* 380 * Search command list for an update to the same host. 381 */ 382 for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) { 383 if (strcmp(c->c_name, h->n_name) == 0) { 384 do { 385 prev = c; 386 c = c->c_next; 387 } while (c != NULL && 388 strcmp(c->c_name, h->n_name) == 0); 389 break; 390 } 391 } 392 /* 393 * Insert new command to update host. 394 */ 395 nc = ALLOC(cmd); 396 if (nc == NULL) 397 fatal("ran out of memory\n"); 398 nc->c_type = ARROW; 399 nc->c_name = h->n_name; 400 nc->c_label = label; 401 nc->c_files = files; 402 nc->c_cmds = subcmds; 403 nc->c_next = c; 404 if (prev == NULL) 405 cmds = nc; 406 else 407 prev->c_next = nc; 408 /* update last_cmd if appending nc to cmds */ 409 if (c == NULL) 410 last_cmd = nc; 411 } 412 } 413 414 /* 415 * Append DCOLON command to the end of the command list since these are always 416 * executed in the order they appear in the distfile. 417 */ 418 void 419 append(char *label, struct namelist *files, char *stamp, 420 struct subcmd *subcmds) 421 { 422 struct cmd *c; 423 424 c = ALLOC(cmd); 425 if (c == NULL) 426 fatal("ran out of memory\n"); 427 c->c_type = DCOLON; 428 c->c_name = stamp; 429 c->c_label = label; 430 c->c_files = expand(files, E_ALL); 431 c->c_cmds = subcmds; 432 c->c_next = NULL; 433 if (cmds == NULL) 434 cmds = last_cmd = c; 435 else { 436 last_cmd->c_next = c; 437 last_cmd = c; 438 } 439 } 440 441 /* 442 * Error printing routine in parser. 443 */ 444 void 445 yyerror(const char *s) 446 { 447 448 ++nerrs; 449 fflush(stdout); 450 fprintf(stderr, "rdist: line %d: %s\n", yylineno, s); 451 } 452 453 /* 454 * Return a copy of the string. 455 */ 456 static char * 457 makestr(char *str) 458 { 459 char *cp, *s; 460 461 str = cp = malloc(strlen(s = str) + 1); 462 if (cp == NULL) 463 fatal("ran out of memory\n"); 464 while ((*cp++ = *s++) != 0) 465 ; 466 return(str); 467 } 468 469 /* 470 * Allocate a namelist structure. 471 */ 472 struct namelist * 473 makenl(char *name) 474 { 475 struct namelist *nl; 476 477 nl = ALLOC(namelist); 478 if (nl == NULL) 479 fatal("ran out of memory\n"); 480 nl->n_name = name; 481 nl->n_next = NULL; 482 return(nl); 483 } 484 485 void 486 freenl(struct namelist *nl) 487 { 488 if (nl == NULL) 489 return; 490 freenl(nl->n_next); 491 free(nl); 492 } 493 494 void 495 freesubcmd(struct subcmd *cmd) 496 { 497 if (cmd == NULL) 498 return; 499 freesubcmd(cmd->sc_next); 500 free(cmd); 501 } 502 503 /* 504 * Make a sub command for lists of variables, commands, etc. 505 */ 506 struct subcmd * 507 makesubcmd(int type) 508 { 509 struct subcmd *sc; 510 511 sc = ALLOC(subcmd); 512 if (sc == NULL) 513 fatal("ran out of memory\n"); 514 sc->sc_type = type; 515 sc->sc_args = NULL; 516 sc->sc_next = NULL; 517 sc->sc_name = NULL; 518 return(sc); 519 } 520