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