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