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