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