1 %{ 2 /* 3 * Copyright (c) 1983 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)gram.y 5.6 (Berkeley) 06/01/90"; 11 #endif /* not lint */ 12 13 #include "defs.h" 14 15 struct cmd *cmds = NULL; 16 struct cmd *last_cmd; 17 struct namelist *last_n; 18 struct subcmd *last_sc; 19 20 %} 21 22 %term EQUAL 1 23 %term LP 2 24 %term RP 3 25 %term SM 4 26 %term ARROW 5 27 %term COLON 6 28 %term DCOLON 7 29 %term NAME 8 30 %term STRING 9 31 %term INSTALL 10 32 %term NOTIFY 11 33 %term EXCEPT 12 34 %term PATTERN 13 35 %term SPECIAL 14 36 %term OPTION 15 37 38 %union { 39 int intval; 40 char *string; 41 struct subcmd *subcmd; 42 struct namelist *namel; 43 } 44 45 %type <intval> OPTION, options 46 %type <string> NAME, STRING 47 %type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, cmdlist, cmd 48 %type <namel> namelist, names, opt_namelist 49 50 %% 51 52 file: /* VOID */ 53 | file command 54 ; 55 56 command: NAME EQUAL namelist = { 57 (void) lookup($1, INSERT, $3); 58 } 59 | namelist ARROW namelist cmdlist = { 60 insert(NULL, $1, $3, $4); 61 } 62 | NAME COLON namelist ARROW namelist cmdlist = { 63 insert($1, $3, $5, $6); 64 } 65 | namelist DCOLON NAME cmdlist = { 66 append(NULL, $1, $3, $4); 67 } 68 | NAME COLON namelist DCOLON NAME cmdlist = { 69 append($1, $3, $5, $6); 70 } 71 | error 72 ; 73 74 namelist: NAME = { 75 $$ = makenl($1); 76 } 77 | LP names RP = { 78 $$ = $2; 79 } 80 ; 81 82 names: /* VOID */ { 83 $$ = last_n = NULL; 84 } 85 | names NAME = { 86 if (last_n == NULL) 87 $$ = last_n = makenl($2); 88 else { 89 last_n->n_next = makenl($2); 90 last_n = last_n->n_next; 91 $$ = $1; 92 } 93 } 94 ; 95 96 cmdlist: /* VOID */ { 97 $$ = last_sc = NULL; 98 } 99 | cmdlist cmd = { 100 if (last_sc == NULL) 101 $$ = last_sc = $2; 102 else { 103 last_sc->sc_next = $2; 104 last_sc = $2; 105 $$ = $1; 106 } 107 } 108 ; 109 110 cmd: INSTALL options opt_namelist SM = { 111 register struct namelist *nl; 112 113 $1->sc_options = $2 | options; 114 if ($3 != NULL) { 115 nl = expand($3, E_VARS); 116 if (nl) { 117 if (nl->n_next != NULL) 118 yyerror("only one name allowed\n"); 119 $1->sc_name = nl->n_name; 120 free(nl); 121 } else 122 $1->sc_name = NULL; 123 } 124 $$ = $1; 125 } 126 | NOTIFY namelist SM = { 127 if ($2 != NULL) 128 $1->sc_args = expand($2, E_VARS); 129 $$ = $1; 130 } 131 | EXCEPT namelist SM = { 132 if ($2 != NULL) 133 $1->sc_args = expand($2, E_ALL); 134 $$ = $1; 135 } 136 | PATTERN namelist SM = { 137 struct namelist *nl; 138 char *cp, *re_comp(); 139 140 for (nl = $2; nl != NULL; nl = nl->n_next) 141 if ((cp = re_comp(nl->n_name)) != NULL) 142 yyerror(cp); 143 $1->sc_args = expand($2, E_VARS); 144 $$ = $1; 145 } 146 | SPECIAL opt_namelist STRING SM = { 147 if ($2 != NULL) 148 $1->sc_args = expand($2, E_ALL); 149 $1->sc_name = $3; 150 $$ = $1; 151 } 152 ; 153 154 options: /* VOID */ = { 155 $$ = 0; 156 } 157 | options OPTION = { 158 $$ |= $2; 159 } 160 ; 161 162 opt_namelist: /* VOID */ = { 163 $$ = NULL; 164 } 165 | namelist = { 166 $$ = $1; 167 } 168 ; 169 170 %% 171 172 int yylineno = 1; 173 extern FILE *fin; 174 175 yylex() 176 { 177 static char yytext[INMAX]; 178 register int c; 179 register char *cp1, *cp2; 180 static char quotechars[] = "[]{}*?$"; 181 182 again: 183 switch (c = getc(fin)) { 184 case EOF: /* end of file */ 185 return(0); 186 187 case '#': /* start of comment */ 188 while ((c = getc(fin)) != EOF && c != '\n') 189 ; 190 if (c == EOF) 191 return(0); 192 case '\n': 193 yylineno++; 194 case ' ': 195 case '\t': /* skip blanks */ 196 goto again; 197 198 case '=': /* EQUAL */ 199 return(EQUAL); 200 201 case '(': /* LP */ 202 return(LP); 203 204 case ')': /* RP */ 205 return(RP); 206 207 case ';': /* SM */ 208 return(SM); 209 210 case '-': /* -> */ 211 if ((c = getc(fin)) == '>') 212 return(ARROW); 213 ungetc(c, fin); 214 c = '-'; 215 break; 216 217 case '"': /* STRING */ 218 cp1 = yytext; 219 cp2 = &yytext[INMAX - 1]; 220 for (;;) { 221 if (cp1 >= cp2) { 222 yyerror("command string too long\n"); 223 break; 224 } 225 c = getc(fin); 226 if (c == EOF || c == '"') 227 break; 228 if (c == '\\') { 229 if ((c = getc(fin)) == EOF) { 230 *cp1++ = '\\'; 231 break; 232 } 233 } 234 if (c == '\n') { 235 yylineno++; 236 c = ' '; /* can't send '\n' */ 237 } 238 *cp1++ = c; 239 } 240 if (c != '"') 241 yyerror("missing closing '\"'\n"); 242 *cp1 = '\0'; 243 yylval.string = makestr(yytext); 244 return(STRING); 245 246 case ':': /* : or :: */ 247 if ((c = getc(fin)) == ':') 248 return(DCOLON); 249 ungetc(c, fin); 250 return(COLON); 251 } 252 cp1 = yytext; 253 cp2 = &yytext[INMAX - 1]; 254 for (;;) { 255 if (cp1 >= cp2) { 256 yyerror("input line too long\n"); 257 break; 258 } 259 if (c == '\\') { 260 if ((c = getc(fin)) != EOF) { 261 if (any(c, quotechars)) 262 c |= QUOTE; 263 } else { 264 *cp1++ = '\\'; 265 break; 266 } 267 } 268 *cp1++ = c; 269 c = getc(fin); 270 if (c == EOF || any(c, " \"'\t()=;:\n")) { 271 ungetc(c, fin); 272 break; 273 } 274 } 275 *cp1 = '\0'; 276 if (yytext[0] == '-' && yytext[2] == '\0') { 277 switch (yytext[1]) { 278 case 'b': 279 yylval.intval = COMPARE; 280 return(OPTION); 281 282 case 'R': 283 yylval.intval = REMOVE; 284 return(OPTION); 285 286 case 'v': 287 yylval.intval = VERIFY; 288 return(OPTION); 289 290 case 'w': 291 yylval.intval = WHOLE; 292 return(OPTION); 293 294 case 'y': 295 yylval.intval = YOUNGER; 296 return(OPTION); 297 298 case 'h': 299 yylval.intval = FOLLOW; 300 return(OPTION); 301 302 case 'i': 303 yylval.intval = IGNLNKS; 304 return(OPTION); 305 } 306 } 307 if (!strcmp(yytext, "install")) 308 c = INSTALL; 309 else if (!strcmp(yytext, "notify")) 310 c = NOTIFY; 311 else if (!strcmp(yytext, "except")) 312 c = EXCEPT; 313 else if (!strcmp(yytext, "except_pat")) 314 c = PATTERN; 315 else if (!strcmp(yytext, "special")) 316 c = SPECIAL; 317 else { 318 yylval.string = makestr(yytext); 319 return(NAME); 320 } 321 yylval.subcmd = makesubcmd(c); 322 return(c); 323 } 324 325 any(c, str) 326 register int c; 327 register char *str; 328 { 329 while (*str) 330 if (c == *str++) 331 return(1); 332 return(0); 333 } 334 335 /* 336 * Insert or append ARROW command to list of hosts to be updated. 337 */ 338 insert(label, files, hosts, subcmds) 339 char *label; 340 struct namelist *files, *hosts; 341 struct subcmd *subcmds; 342 { 343 register struct cmd *c, *prev, *nc; 344 register struct namelist *h; 345 346 files = expand(files, E_VARS|E_SHELL); 347 hosts = expand(hosts, E_ALL); 348 for (h = hosts; h != NULL; free(h), h = h->n_next) { 349 /* 350 * Search command list for an update to the same host. 351 */ 352 for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) { 353 if (strcmp(c->c_name, h->n_name) == 0) { 354 do { 355 prev = c; 356 c = c->c_next; 357 } while (c != NULL && 358 strcmp(c->c_name, h->n_name) == 0); 359 break; 360 } 361 } 362 /* 363 * Insert new command to update host. 364 */ 365 nc = ALLOC(cmd); 366 if (nc == NULL) 367 fatal("ran out of memory\n"); 368 nc->c_type = ARROW; 369 nc->c_name = h->n_name; 370 nc->c_label = label; 371 nc->c_files = files; 372 nc->c_cmds = subcmds; 373 nc->c_next = c; 374 if (prev == NULL) 375 cmds = nc; 376 else 377 prev->c_next = nc; 378 /* update last_cmd if appending nc to cmds */ 379 if (c == NULL) 380 last_cmd = nc; 381 } 382 } 383 384 /* 385 * Append DCOLON command to the end of the command list since these are always 386 * executed in the order they appear in the distfile. 387 */ 388 append(label, files, stamp, subcmds) 389 char *label; 390 struct namelist *files; 391 char *stamp; 392 struct subcmd *subcmds; 393 { 394 register struct cmd *c; 395 396 c = ALLOC(cmd); 397 if (c == NULL) 398 fatal("ran out of memory\n"); 399 c->c_type = DCOLON; 400 c->c_name = stamp; 401 c->c_label = label; 402 c->c_files = expand(files, E_ALL); 403 c->c_cmds = subcmds; 404 c->c_next = NULL; 405 if (cmds == NULL) 406 cmds = last_cmd = c; 407 else { 408 last_cmd->c_next = c; 409 last_cmd = c; 410 } 411 } 412 413 /* 414 * Error printing routine in parser. 415 */ 416 yyerror(s) 417 char *s; 418 { 419 extern int yychar; 420 421 nerrs++; 422 fflush(stdout); 423 fprintf(stderr, "rdist: line %d: %s\n", yylineno, s); 424 } 425 426 /* 427 * Return a copy of the string. 428 */ 429 char * 430 makestr(str) 431 char *str; 432 { 433 register char *cp, *s; 434 435 str = cp = malloc(strlen(s = str) + 1); 436 if (cp == NULL) 437 fatal("ran out of memory\n"); 438 while (*cp++ = *s++) 439 ; 440 return(str); 441 } 442 443 /* 444 * Allocate a namelist structure. 445 */ 446 struct namelist * 447 makenl(name) 448 char *name; 449 { 450 register struct namelist *nl; 451 452 nl = ALLOC(namelist); 453 if (nl == NULL) 454 fatal("ran out of memory\n"); 455 nl->n_name = name; 456 nl->n_next = NULL; 457 return(nl); 458 } 459 460 /* 461 * Make a sub command for lists of variables, commands, etc. 462 */ 463 struct subcmd * 464 makesubcmd(type, name) 465 int type; 466 register char *name; 467 { 468 register char *cp; 469 register struct subcmd *sc; 470 471 sc = ALLOC(subcmd); 472 if (sc == NULL) 473 fatal("ran out of memory\n"); 474 sc->sc_type = type; 475 sc->sc_args = NULL; 476 sc->sc_next = NULL; 477 sc->sc_name = NULL; 478 return(sc); 479 } 480