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: }

Defined functions

compile defined in line 234; used 4 times
compile_error defined in line 169; used 1 times
do_expr defined in line 472; used 3 times
do_func defined in line 385; used 4 times
do_if defined in line 493; used 3 times
do_name defined in line 325; used 5 times
do_spec defined in line 278; used 2 times
fmt_compile defined in line 191; never used
lookup defined in line 118; used 1 times

Defined variables

cm defined in line 16; used 21 times
format_string defined in line 164; used 5 times
formatvec defined in line 13; used 2 times
fp defined in line 15; used 20 times
ftbl defined in line 17; used 9 times
functable defined in line 43; used 1 times
infunction defined in line 19; used 5 times
ncomp defined in line 18; used 3 times
next_fp defined in line 14; used 6 times
usr_fstring defined in line 165; used 5 times

Defined struct's

ftable defined in line 24; used 11 times

Defined macros

ADDC defined in line 144; used 1 times
CERROR defined in line 167; used 13 times
LS defined in line 152; used 2 times
LV defined in line 151; used 10 times
NEW defined in line 141; used 6 times
NEWCOMP defined in line 135; used 1 times
NEWFMT defined in line 140; used 1 times
PUTC defined in line 155; used 1 times
PUTCOMP defined in line 153; used 3 times
PUTLIT defined in line 154; used 1 times
TFL_PUTN defined in line 40; used 32 times
TFL_PUTS defined in line 39; used 19 times
TF_COMP defined in line 27; used 36 times
TF_EXPR defined in line 30; used 8 times
TF_EXPR_SV defined in line 34; used 1 times
TF_MYBOX defined in line 32; used 1 times
  • in line 72
TF_NONE defined in line 31; used 6 times
TF_NOP defined in line 35; used 1 times
  • in line 59
TF_NOW defined in line 33; used 1 times
  • in line 76
TF_NUM defined in line 28; used 7 times
TF_STR defined in line 29; used 4 times
Last modified: 1986-04-09
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2751
Valid CSS Valid XHTML 1.0 Strict