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