|
|
1.1 ! root 1: /* fmtcompile.c - "compile" format strings for fmtscan */ ! 2: ! 3: #include "../h/mh.h" ! 4: #include "../h/addrsbr.h" ! 5: #include "../h/formatsbr.h" ! 6: #include "../zotnet/tws.h" ! 7: #include "../h/fmtcompile.h" ! 8: #include <ctype.h> ! 9: #include <stdio.h> ! 10: #include <sys/types.h> ! 11: #include <sys/stat.h> ! 12: ! 13: static struct format *formatvec; /* array to hold formats */ ! 14: static struct format *next_fp; /* next free format slot */ ! 15: static struct format *fp; /* current format slot */ ! 16: static struct comp *cm; /* most recent comp ref */ ! 17: static struct ftable *ftbl; /* most recent func ref */ ! 18: static int ncomp; ! 19: static int infunction; /* function nesting cnt */ ! 20: ! 21: extern char *getusr(); ! 22: extern struct mailname fmt_mnull; ! 23: ! 24: struct ftable { ! 25: char *name; /* function name */ ! 26: char type; /* argument type */ ! 27: #define TF_COMP 0 /* component expected */ ! 28: #define TF_NUM 1 /* number expected */ ! 29: #define TF_STR 2 /* string expected */ ! 30: #define TF_EXPR 3 /* component or func. expected */ ! 31: #define TF_NONE 4 /* no argument */ ! 32: #define TF_MYBOX 5 /* special - get current user's mbox */ ! 33: #define TF_NOW 6 /* special - get current unix time */ ! 34: #define TF_EXPR_SV 7 /* like expr but save current str reg */ ! 35: #define TF_NOP 8 /* like expr but no result */ ! 36: #define TF_TERMCAP 9 /* special - get some termcap ent */ ! 37: char f_type; /* fmt type */ ! 38: char extra; /* arg. type dependent extra info */ ! 39: char flags; ! 40: #define TFL_PUTS 1 /* implicit putstr if top level */ ! 41: #define TFL_PUTN 2 /* implicit putnum if top level */ ! 42: }; ! 43: ! 44: static struct ftable functable[] = { ! 45: "nonzero", TF_EXPR, FT_V_NE, FT_IF_V_NE, 0, ! 46: "zero", TF_EXPR, FT_V_EQ, FT_IF_V_EQ, 0, ! 47: "eq", TF_NUM, FT_V_EQ, FT_IF_V_EQ, 0, ! 48: "ne", TF_NUM, FT_V_NE, FT_IF_V_NE, 0, ! 49: "gt", TF_NUM, FT_V_GT, FT_IF_V_GT, 0, ! 50: "null", TF_EXPR, FT_S_NULL, FT_IF_S_NULL, 0, ! 51: "nonnull", TF_EXPR, FT_S_NONNULL, FT_IF_S, 0, ! 52: "match", TF_STR, FT_V_MATCH, FT_IF_MATCH, 0, ! 53: "amatch", TF_STR, FT_V_AMATCH, FT_IF_AMATCH, 0, ! 54: ! 55: "putstr", TF_EXPR, FT_STR, 0, 0, ! 56: "putstrf", TF_EXPR, FT_STRF, 0, 0, ! 57: "putnum", TF_EXPR, FT_NUM, 0, 0, ! 58: "putnumf", TF_EXPR, FT_NUMF, 0, 0, ! 59: "putaddr", TF_STR, FT_PUTADDR, 0, 0, ! 60: "void", TF_NOP, 0, 0, 0, ! 61: ! 62: "comp", TF_COMP, FT_LS_COMP, 0, TFL_PUTS, ! 63: "lit", TF_STR, FT_LS_LIT, 0, TFL_PUTS, ! 64: "force", TF_STR, FT_LIT_FORCE, 0, 0, ! 65: "trim", TF_EXPR, FT_LS_TRIM, 0, 0, ! 66: "compval", TF_COMP, FT_LV_COMP, 0, TFL_PUTN, ! 67: "compflag", TF_COMP, FT_LV_COMPFLAG, 0, TFL_PUTN, ! 68: "num", TF_NUM, FT_LV_LIT, 0, TFL_PUTN, ! 69: "msg", TF_NONE, FT_LV_DAT, 0, TFL_PUTN, ! 70: "cur", TF_NONE, FT_LV_DAT, 1, TFL_PUTN, ! 71: "size", TF_NONE, FT_LV_DAT, 2, TFL_PUTN, ! 72: "width", TF_NONE, FT_LV_DAT, 3, TFL_PUTN, ! 73: "dat", TF_NUM, FT_LV_DAT, 0, TFL_PUTN, ! 74: "strlen", TF_NONE, FT_LV_STRLEN, 0, TFL_PUTN, ! 75: "me", TF_MYBOX, FT_LS_LIT, 0, TFL_PUTS, ! 76: "plus", TF_NUM, FT_LV_PLUS_L, 0, TFL_PUTN, ! 77: "minus", TF_NUM, FT_LV_MINUS_L, 0, TFL_PUTN, ! 78: "divide", TF_NUM, FT_LV_DIVIDE_L, 0, TFL_PUTN, ! 79: "charleft", TF_NONE, FT_LV_CHAR_LEFT, 0, TFL_PUTN, ! 80: "timenow", TF_NOW, FT_LV_LIT, 0, TFL_PUTN, ! 81: "termcap", TF_TERMCAP, FT_LIT_FORCE, 0, 0, ! 82: ! 83: "month", TF_COMP, FT_LS_MONTH, FT_PARSEDATE, TFL_PUTS, ! 84: "lmonth", TF_COMP, FT_LS_LMONTH, FT_PARSEDATE, TFL_PUTS, ! 85: "tzone", TF_COMP, FT_LS_ZONE, FT_PARSEDATE, TFL_PUTS, ! 86: "day", TF_COMP, FT_LS_DAY, FT_PARSEDATE, TFL_PUTS, ! 87: "weekday", TF_COMP, FT_LS_WEEKDAY, FT_PARSEDATE, TFL_PUTS, ! 88: "tws", TF_COMP, FT_LS_822DATE, FT_PARSEDATE, TFL_PUTS, ! 89: "sec", TF_COMP, FT_LV_SEC, FT_PARSEDATE, TFL_PUTN, ! 90: "min", TF_COMP, FT_LV_MIN, FT_PARSEDATE, TFL_PUTN, ! 91: "hour", TF_COMP, FT_LV_HOUR, FT_PARSEDATE, TFL_PUTN, ! 92: "mday", TF_COMP, FT_LV_MDAY, FT_PARSEDATE, TFL_PUTN, ! 93: "mon", TF_COMP, FT_LV_MON, FT_PARSEDATE, TFL_PUTN, ! 94: "year", TF_COMP, FT_LV_YEAR, FT_PARSEDATE, TFL_PUTN, ! 95: "yday", TF_COMP, FT_LV_YDAY, FT_PARSEDATE, TFL_PUTN, ! 96: "wday", TF_COMP, FT_LV_WDAY, FT_PARSEDATE, TFL_PUTN, ! 97: "zone", TF_COMP, FT_LV_ZONE, FT_PARSEDATE, TFL_PUTN, ! 98: "clock", TF_COMP, FT_LV_CLOCK, FT_PARSEDATE, TFL_PUTN, ! 99: "rclock", TF_COMP, FT_LV_RCLOCK, FT_PARSEDATE, TFL_PUTN, ! 100: "sday", TF_COMP, FT_LV_DAYF, FT_PARSEDATE, TFL_PUTN, ! 101: "szone", TF_COMP, FT_LV_ZONEF, FT_PARSEDATE, TFL_PUTN, ! 102: "dst", TF_COMP, FT_LV_DST, FT_PARSEDATE, TFL_PUTN, ! 103: "pretty", TF_COMP, FT_LS_PRETTY, FT_PARSEDATE, TFL_PUTS, ! 104: "nodate", TF_COMP, FT_LV_COMPFLAG, FT_PARSEDATE, TFL_PUTN, ! 105: "date2local", TF_COMP, FT_LOCALDATE, FT_PARSEDATE, 0, ! 106: "date2gmt", TF_COMP, FT_GMTDATE, FT_PARSEDATE, 0, ! 107: ! 108: "pers", TF_COMP, FT_LS_PERS, FT_PARSEADDR, TFL_PUTS, ! 109: "mbox", TF_COMP, FT_LS_MBOX, FT_PARSEADDR, TFL_PUTS, ! 110: "host", TF_COMP, FT_LS_HOST, FT_PARSEADDR, TFL_PUTS, ! 111: "path", TF_COMP, FT_LS_PATH, FT_PARSEADDR, TFL_PUTS, ! 112: "gname", TF_COMP, FT_LS_GNAME, FT_PARSEADDR, TFL_PUTS, ! 113: "note", TF_COMP, FT_LS_NOTE, FT_PARSEADDR, TFL_PUTS, ! 114: "proper", TF_COMP, FT_LS_822ADDR, FT_PARSEADDR, TFL_PUTS, ! 115: "type", TF_COMP, FT_LV_HOSTTYPE, FT_PARSEADDR, TFL_PUTN, ! 116: "ingrp", TF_COMP, FT_LV_INGRPF, FT_PARSEADDR, TFL_PUTN, ! 117: "nohost", TF_COMP, FT_LV_NOHOSTF, FT_PARSEADDR, TFL_PUTN, ! 118: "formataddr", TF_EXPR_SV, FT_FORMATADDR, FT_FORMATADDR, 0, ! 119: "friendly", TF_COMP, FT_LS_FRIENDLY, FT_PARSEADDR, TFL_PUTS, ! 120: ! 121: "mymbox", TF_COMP, FT_LV_COMPFLAG, FT_MYMBOX, TFL_PUTN, ! 122: "addtoseq", TF_STR, FT_ADDTOSEQ, 0, 0, ! 123: ! 124: (char *)0, 0, 0, 0, 0 ! 125: }; ! 126: ! 127: ! 128: long time(); ! 129: ! 130: static struct ftable * ! 131: lookup(name) ! 132: register char *name; ! 133: { ! 134: register struct ftable *t = functable; ! 135: register char *nm; ! 136: register char c = *name; ! 137: ! 138: while (nm = t->name) { ! 139: if (*nm == c && strcmp (nm, name) == 0) ! 140: return (ftbl = t); ! 141: ! 142: t++; ! 143: } ! 144: return (struct ftable *)0; ! 145: } ! 146: ! 147: ! 148: #define NEWCOMP(cm,name)\ ! 149: cm = ((struct comp *)calloc(1, sizeof (struct comp)));\ ! 150: cm->c_name = name; ncomp++;\ ! 151: i = CHASH(name); cm->c_next = wantcomp[i]; wantcomp[i] = cm; ! 152: ! 153: #define NEWFMT (next_fp++) ! 154: #define NEW(type,fill,wid)\ ! 155: fp=NEWFMT; fp->f_type=(type); fp->f_fill=(fill); fp->f_width=(wid); ! 156: ! 157: #define ADDC(name)\ ! 158: FINDCOMP( cm, name );\ ! 159: if ( ! cm ) {\ ! 160: NEWCOMP(cm,name);\ ! 161: }\ ! 162: fp->f_comp = cm; ! 163: ! 164: #define LV( type, value ) NEW(type,0,0); fp->f_value = (value); ! 165: #define LS( type, str ) NEW(type,0,0); fp->f_text = (str); ! 166: #define PUTCOMP( comp ) NEW(FT_COMP,0,0); ADDC(comp); ! 167: #define PUTLIT( str ) NEW(FT_LIT,0,0); fp->f_text = (str); ! 168: #define PUTC( c ) NEW(FT_CHAR,0,0); fp->f_char = (c); ! 169: ! 170: static char *compile(); ! 171: static char *do_spec(); ! 172: static char *do_name(); ! 173: static char *do_func(); ! 174: static char *do_expr(); ! 175: static char *do_if(); ! 176: ! 177: static char *format_string; ! 178: static char *usr_fstring; /* for CERROR */ ! 179: ! 180: #define CERROR(str) compile_error (str, cp) ! 181: ! 182: static void ! 183: compile_error(str, cp) ! 184: char *str; ! 185: char *cp; ! 186: { ! 187: int errpos = cp - format_string; ! 188: int errctx = errpos > 20 ? 20 : errpos; ! 189: int i; ! 190: ! 191: usr_fstring[errpos] = '\0'; ! 192: for (i = errpos-errctx; i < errpos; i++) ! 193: if (usr_fstring[i] < 32) ! 194: usr_fstring[i] = '_'; ! 195: advise(NULLCP, "\"%s\": format compile error - %s", ! 196: &usr_fstring[errpos-errctx], str); ! 197: adios (NULLCP, "%*s", errctx+1, "^"); ! 198: } ! 199: ! 200: /* ! 201: * Compile format string "fstring" into format list "fmt". ! 202: * Return the number of header components found in the format ! 203: * string. ! 204: */ ! 205: fmt_compile(fstring, fmt) ! 206: register char *fstring; ! 207: struct format **fmt; ! 208: { ! 209: register char *cp; ! 210: int i; ! 211: ! 212: if (format_string) ! 213: (void) free (format_string); ! 214: format_string = getcpy (fstring); ! 215: usr_fstring = fstring; ! 216: ! 217: /* init the component hash table. */ ! 218: for (i = 0; i < sizeof(wantcomp)/sizeof(wantcomp[0]); i++) ! 219: wantcomp[i] = 0; ! 220: ! 221: bzero ((char *) &fmt_mnull, sizeof fmt_mnull); ! 222: ! 223: /* it takes at least 4 char to generate one format so we ! 224: * allocate a worst-case format array using 1/4 the length ! 225: * of the format string. We actually need twice this much ! 226: * to handle both pre-processing (e.g., address parsing) and ! 227: * normal processing. ! 228: */ ! 229: i = strlen(fstring)/2 + 1; ! 230: next_fp = formatvec = (struct format *)calloc ((unsigned) i, ! 231: sizeof(struct format)); ! 232: if (next_fp == NULL) ! 233: adios (NULLCP, "unable to allocate format storage"); ! 234: ! 235: ncomp = 0; ! 236: infunction = 0; ! 237: ! 238: cp = compile(format_string); ! 239: if (*cp) { ! 240: CERROR("extra '%>' or '%|'"); ! 241: } ! 242: NEW(FT_DONE,0,0); ! 243: *fmt = formatvec; ! 244: ! 245: return (ncomp); ! 246: } ! 247: ! 248: static char * ! 249: compile(sp) ! 250: register char *sp; ! 251: { ! 252: register char *cp = sp; ! 253: register int c; ! 254: ! 255: for (;;) { ! 256: sp = cp; ! 257: while ((c = *cp) && c != '%') ! 258: cp++; ! 259: *cp = 0; ! 260: switch (cp-sp) { ! 261: case 0: ! 262: break; ! 263: case 1: ! 264: PUTC(*sp); ! 265: break; ! 266: default: ! 267: PUTLIT(sp); ! 268: break; ! 269: } ! 270: if (c == 0) ! 271: return (cp); ! 272: ! 273: switch (c = *++cp) { ! 274: case '%': ! 275: PUTC (*cp); ! 276: cp++; ! 277: break; ! 278: ! 279: case '|': ! 280: case '>': ! 281: return (cp); ! 282: ! 283: case '<': ! 284: cp = do_if(++cp); ! 285: break; ! 286: ! 287: default: ! 288: cp = do_spec(cp); ! 289: break; ! 290: } ! 291: } ! 292: } ! 293: ! 294: static char * ! 295: do_spec(sp) ! 296: register char *sp; ! 297: { ! 298: register char *cp = sp; ! 299: register int c; ! 300: register int ljust = 0; ! 301: register int wid = 0; ! 302: register char fill = ' '; ! 303: ! 304: c = *cp++; ! 305: if (c == '-') { ! 306: ljust++; ! 307: c = *cp++; ! 308: } ! 309: if (c == '0') { ! 310: fill = c; ! 311: c = *cp++; ! 312: } ! 313: while (isdigit(c)) { ! 314: wid = wid*10 + (c - '0'); ! 315: c = *cp++; ! 316: } ! 317: if (c == '{') { /* } paren match fodder */ ! 318: cp = do_name(cp, 0); ! 319: if (! infunction) ! 320: fp->f_type = wid? FT_COMPF : FT_COMP; ! 321: } ! 322: else if (c == '(') { ! 323: cp = do_func(cp); ! 324: if (! infunction) { ! 325: if (ftbl->flags & TFL_PUTS) { ! 326: LV( wid? FT_STRF : FT_STR, ftbl->extra); ! 327: } ! 328: else if (ftbl->flags & TFL_PUTN) { ! 329: LV( wid? FT_NUMF : FT_NUM, ftbl->extra); ! 330: } ! 331: } ! 332: } ! 333: else { ! 334: CERROR("component or function name expected"); ! 335: } ! 336: if (ljust) ! 337: wid = -wid; ! 338: fp->f_width = wid; ! 339: fp->f_fill = fill; ! 340: ! 341: return (cp); ! 342: } ! 343: ! 344: static char * ! 345: do_name(sp, preprocess) ! 346: char *sp; ! 347: int preprocess; ! 348: { ! 349: register char *cp = sp; ! 350: register int c; ! 351: register int i; ! 352: static int primed = 0; ! 353: ! 354: while (isalnum(c = *cp++) || c == '-') ! 355: ; ! 356: /* {{ paren match fodder */ ! 357: if (c != '}') { ! 358: CERROR("'}' expected"); ! 359: } ! 360: cp[-1] = '\0'; ! 361: PUTCOMP(sp); ! 362: switch (preprocess) { ! 363: ! 364: case FT_PARSEDATE: ! 365: if (cm->c_type & CT_ADDR) { ! 366: CERROR("component used as both date and address"); ! 367: } ! 368: if (! (cm->c_type & CT_DATE)) { ! 369: cm->c_tws = (struct tws *) ! 370: calloc((unsigned) 1, sizeof *cm -> c_tws); ! 371: fp->f_type = preprocess; ! 372: PUTCOMP(sp); ! 373: cm->c_type |= CT_DATE; ! 374: } ! 375: break; ! 376: ! 377: case FT_MYMBOX: ! 378: if (!primed) { ! 379: (void) ismymbox ((struct mailname *) 0); ! 380: primed++; ! 381: } ! 382: cm->c_type |= CT_MYMBOX; ! 383: /* fall through */ ! 384: case FT_PARSEADDR: ! 385: if (cm->c_type & CT_DATE) { ! 386: CERROR("component used as both date and address"); ! 387: } ! 388: if (! (cm->c_type & CT_ADDRPARSE)) { ! 389: cm->c_mn = &fmt_mnull; ! 390: fp->f_type = preprocess; ! 391: PUTCOMP(sp); ! 392: cm->c_type |= (CT_ADDR | CT_ADDRPARSE); ! 393: } ! 394: break; ! 395: ! 396: case FT_FORMATADDR: ! 397: if (cm->c_type & CT_DATE) { ! 398: CERROR("component used as both date and address"); ! 399: } ! 400: cm->c_type |= CT_ADDR; ! 401: break; ! 402: } ! 403: return (cp); ! 404: } ! 405: ! 406: static char * ! 407: do_func(sp) ! 408: char *sp; ! 409: { ! 410: register char *cp = sp; ! 411: register int c; ! 412: register struct ftable *t; ! 413: register int n; ! 414: extern char *get_termcap(); ! 415: ! 416: infunction++; ! 417: ! 418: while (isalnum(c = *cp++)) ! 419: ; ! 420: if (c != '(' && c != '{' && c != ' ' && c != ')') { ! 421: CERROR("'(', '{', ' ' or ')' expected"); /* }} paren match fodder */ ! 422: } ! 423: cp[-1] = '\0'; ! 424: if ((t = lookup (sp)) == 0) { ! 425: CERROR("unknown function"); ! 426: } ! 427: if (isspace(c)) ! 428: c = *cp++; ! 429: ! 430: switch (t->type) { ! 431: ! 432: case TF_COMP: ! 433: if (c != '{') { /* } paren match fodder */ ! 434: CERROR("component name expected"); ! 435: } ! 436: cp = do_name(cp, t->extra); ! 437: fp->f_type = t->f_type; ! 438: c = *cp++; ! 439: break; ! 440: ! 441: case TF_NUM: ! 442: n = 0; ! 443: while (isdigit(c)) { ! 444: n = n*10 + (c - '0'); ! 445: c = *cp++; ! 446: } ! 447: LV(t->f_type,n); ! 448: break; ! 449: ! 450: case TF_STR: ! 451: sp = cp - 1; ! 452: while (c && c != ')') ! 453: c = *cp++; ! 454: cp[-1] = '\0'; ! 455: LS(t->f_type,sp); ! 456: break; ! 457: ! 458: case TF_NONE: ! 459: LV(t->f_type,t->extra); ! 460: break; ! 461: ! 462: case TF_MYBOX: ! 463: LS(t->f_type, getusr()); ! 464: break; ! 465: ! 466: case TF_NOW: ! 467: LV(t->f_type, time((long *) 0)); ! 468: break; ! 469: ! 470: case TF_EXPR_SV: ! 471: LV(FT_SAVESTR, 0); ! 472: /* fall through */ ! 473: case TF_EXPR: ! 474: *--cp = c; ! 475: cp = do_expr(cp, t->extra); ! 476: LV(t->f_type, t->extra); ! 477: c = *cp++; ! 478: ftbl = t; ! 479: break; ! 480: ! 481: case TF_NOP: ! 482: *--cp = c; ! 483: cp = do_expr(cp, t->extra); ! 484: c = *cp++; ! 485: ftbl = t; ! 486: break; ! 487: ! 488: case TF_TERMCAP: ! 489: sp = cp - 1; ! 490: while (c && c != ')') ! 491: c = *cp++; ! 492: cp[-1] = '\0'; ! 493: if (*sp && *sp != ' ') { ! 494: sp = get_termcap(sp); ! 495: if (*sp != '\0') ! 496: LS(t->f_type, sp); ! 497: } ! 498: break; ! 499: } ! 500: if (c != ')') { ! 501: CERROR("')' expected"); ! 502: } ! 503: --infunction; ! 504: return (cp); ! 505: } ! 506: ! 507: static char * ! 508: do_expr(sp, preprocess) ! 509: char *sp; ! 510: { ! 511: register char *cp = sp; ! 512: register int c; ! 513: ! 514: if ((c = *cp++) == '{') { /* } parent match fodder */ ! 515: cp = do_name (cp, preprocess); ! 516: fp->f_type = FT_LS_COMP; ! 517: } else if (c == '(') { ! 518: cp = do_func (cp); ! 519: } else if (c == ')') { ! 520: return (--cp); ! 521: } else if (c == '%' && *cp == '<') { ! 522: cp = do_if (cp+1); ! 523: } else { ! 524: CERROR ("'(', '{', '%<' or ')' expected"); /* } parent match fodder */ ! 525: } ! 526: return (cp); ! 527: } ! 528: ! 529: static char * ! 530: do_if(sp) ! 531: register char *sp; ! 532: { ! 533: register char *cp = sp; ! 534: register struct format *fexpr, *fif, *felse; ! 535: register int c; ! 536: ! 537: if ((c = *cp++) == '{') { /* } paren match fodder */ ! 538: cp = do_name(cp, 0); ! 539: fp->f_type = FT_LS_COMP; ! 540: LV (FT_IF_S, 0); ! 541: } ! 542: else if (c == '(') { ! 543: cp = do_func(cp); ! 544: /* see if we can merge the load and the "if" */ ! 545: if (ftbl->f_type >= IF_FUNCS) ! 546: fp->f_type = ftbl->extra; ! 547: else { ! 548: LV (FT_IF_V_NE, 0); ! 549: } ! 550: } ! 551: else { ! 552: CERROR("'(' or '{' expected"); /* } paren match fodder */ ! 553: } ! 554: fexpr = fp; ! 555: cp = compile (cp); ! 556: if ((c = *cp++) == '|') { ! 557: LV(FT_GOTO, 0); ! 558: fif = fp; ! 559: felse = next_fp; ! 560: cp = compile(cp); ! 561: fif->f_skip = next_fp - fif; ! 562: c = *cp++; ! 563: } ! 564: else ! 565: felse = next_fp; ! 566: ! 567: if (c != '>') { ! 568: CERROR("'>' expected."); ! 569: } ! 570: fexpr->f_skip = felse - fexpr; ! 571: ! 572: return (cp); ! 573: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.