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