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