X-Git-Url: http://git.marmaro.de/?p=mmh;a=blobdiff_plain;f=sbr%2Ffmt_compile.c;h=2b32e7152a9fe45d8b8a2d68d86a1765589a9fff;hp=a180c561a403f0280d8b7eb8492912c10afdf32b;hb=fc9279e818dfc96c63a5d75a89080cc68cfe1170;hpb=5dd6771b28c257af405d7248639ed0e3bcdce38b diff --git a/sbr/fmt_compile.c b/sbr/fmt_compile.c index a180c56..2b32e71 100644 --- a/sbr/fmt_compile.c +++ b/sbr/fmt_compile.c @@ -1,667 +1,742 @@ - /* - * fmt_compile.c -- "compile" format strings for fmt_scan - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** fmt_compile.c -- "compile" format strings for fmt_scan +** +** This code is Copyright (c) 2002, by the authors of nmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +** +** This code compiles the format strings (documented in mh-format(5)) into +** an internal form to be later processed by fmt_scan.c. +** +** What happens here is that the format strings are parsed and an array +** of struct format structures are returned. Each format structure is +** a single operation interpreted by the the routines in fmt_scan.c. +** +** There is a NOT a one-to-one correspondence between format strings and +** format instructions; some functions have side effects that can result +** in multiple instructions being generated. The exact list of instructions +** generated by a format string can be seem with the nmh fmtdump utility. +** +** A list of format instructions can be found in fmt_compile.h. +** +** If you wish to add a new function, you will need to do the following +** things: +** +** - Add a new instruction to the list of instructions in fmt_compile.h. +** Note that test instructions (starting with FT_IF_S_NULL) have special +** handling, so if you are NOT writing a test function then you need +** to insert it into the list before that _and_ bump all of the +** following instruction numbers. +** +** - Add the function name to the functable[] array below, and write any +** special code that your function may require in terms of parsing +** (it very well may not need anything). +** +** - Add the code in fmt_scan.c to handle your new function. +** +** - Document the new function in the mh-format(5) man page. +** +*/ #include +#include #include #include #include #include +#include +#include -#ifdef TIME_WITH_SYS_TIME +#ifdef HAVE_SYS_TIME_H # include -# include -#else -# ifdef TM_IN_SYS_TIME -# include -# else -# include -# endif #endif +#include /* - * hash table for deciding if a component is "interesting" - */ +** hash table for deciding if a component is "interesting" +*/ struct comp *wantcomp[128]; -static struct format *formatvec; /* array to hold formats */ -static struct format *next_fp; /* next free format slot */ -static struct format *fp; /* current format slot */ -static struct comp *cm; /* most recent comp ref */ -static struct ftable *ftbl; /* most recent func ref */ +static struct format *formatvec; /* array to hold formats */ +static struct format *next_fp; /* next free format slot */ +static struct format *fp; /* current format slot */ +static struct comp *cm; /* most recent comp ref */ +static struct ftable *ftbl; /* most recent func ref */ static int ncomp; -static int infunction; /* function nesting cnt */ +static int infunction; /* function nesting cnt */ extern struct mailname fmt_mnull; /* ftable->type (argument type) */ -#define TF_COMP 0 /* component expected */ -#define TF_NUM 1 /* number expected */ -#define TF_STR 2 /* string expected */ -#define TF_EXPR 3 /* component or func. expected */ -#define TF_NONE 4 /* no argument */ -#define TF_MYBOX 5 /* special - get current user's mbox */ -#define TF_NOW 6 /* special - get current unix time */ -#define TF_EXPR_SV 7 /* like expr but save current str reg */ -#define TF_NOP 8 /* like expr but no result */ +#define TF_COMP 0 /* component expected */ +#define TF_NUM 1 /* number expected */ +#define TF_STR 2 /* string expected */ +#define TF_EXPR 3 /* component or func. expected */ +#define TF_NONE 4 /* no argument */ +#define TF_MYBOX 5 /* special - get current user's mbox */ +#define TF_NOW 6 /* special - get current unix time */ +#define TF_EXPR_SV 7 /* like expr but save current str reg */ +#define TF_NOP 8 /* like expr but no result */ /* ftable->flags */ -/* NB that TFL_PUTS is also used to decide whether the test - * in a "%<(function)..." should be a string or numeric one. - */ -#define TFL_PUTS 1 /* implicit putstr if top level */ -#define TFL_PUTN 2 /* implicit putnum if top level */ +/* +** NB that TFL_PUTS is also used to decide whether the test +** in a "%<(function)..." should be a string or numeric one. +*/ +#define TFL_PUTS 1 /* implicit putstr if top level */ +#define TFL_PUTN 2 /* implicit putnum if top level */ +/* +** The functable array maps between the text names of format functions and +** the format instructions interpreted by the engine in fmt_scan.c. +** +** The elements of this structure are as follows: +** +** name: The name of the function as seen in the format string. This is +** what maps a particular function name into a format instruction. +** type: The type of argument this function expects. Those types are +** listed above (with the TF_ prefix). This affects what gets +** placed in the format instruction (the f_un union). +** f_type: The instruction corresponding to this function (from the list +** in fmt_compile.h). +** extra: Used by some functions to provide extra data to the compiler. +** Uses include: +** - Providing an alternate instruction to combine a load +** and test operation (see do_if()). +** - Passed in f_value in the format instruction to provide +** extra information for the engine (see FT_LV_DAT handling +** in fmt_scan.c). +** - Provide a hint as to preprocessing that is required for +** this instruction (see do_name()). +** flags: See the definitions for TFL_PUTS & TFL_PUTN above. +*/ struct ftable { - char *name; /* function name */ - char type; /* argument type */ - char f_type; /* fmt type */ - char extra; /* arg. type dependent extra info */ - char flags; + char *name; /* function name */ + char type; /* argument type */ + char f_type; /* fmt type */ + char extra; /* arg. type dependent extra info */ + char flags; }; static struct ftable functable[] = { - { "nonzero", TF_EXPR, FT_V_NE, FT_IF_V_NE, 0 }, - { "zero", TF_EXPR, FT_V_EQ, FT_IF_V_EQ, 0 }, - { "eq", TF_NUM, FT_V_EQ, FT_IF_V_EQ, 0 }, - { "ne", TF_NUM, FT_V_NE, FT_IF_V_NE, 0 }, - { "gt", TF_NUM, FT_V_GT, FT_IF_V_GT, 0 }, - { "null", TF_EXPR, FT_S_NULL, FT_IF_S_NULL, 0 }, - { "nonnull", TF_EXPR, FT_S_NONNULL, FT_IF_S, 0 }, - { "match", TF_STR, FT_V_MATCH, FT_IF_MATCH, 0 }, - { "amatch", TF_STR, FT_V_AMATCH, FT_IF_AMATCH, 0 }, - - { "putstr", TF_EXPR, FT_STR, 0, 0 }, - { "putstrf", TF_EXPR, FT_STRF, 0, 0 }, - { "putnum", TF_EXPR, FT_NUM, 0, 0 }, - { "putnumf", TF_EXPR, FT_NUMF, 0, 0 }, - { "putaddr", TF_STR, FT_PUTADDR, 0, 0 }, - { "void", TF_NOP, 0, 0, 0 }, - - { "comp", TF_COMP, FT_LS_COMP, 0, TFL_PUTS }, - { "lit", TF_STR, FT_LS_LIT, 0, TFL_PUTS }, - { "getenv", TF_STR, FT_LS_GETENV, 0, TFL_PUTS }, - { "profile", TF_STR, FT_LS_CFIND, 0, TFL_PUTS }, - { "decodecomp", TF_COMP, FT_LS_DECODECOMP, 0, TFL_PUTS }, - { "decode", TF_EXPR, FT_LS_DECODE, 0, TFL_PUTS }, - { "trim", TF_EXPR, FT_LS_TRIM, 0, 0 }, - { "compval", TF_COMP, FT_LV_COMP, 0, TFL_PUTN }, - { "compflag", TF_COMP, FT_LV_COMPFLAG, 0, TFL_PUTN }, - { "num", TF_NUM, FT_LV_LIT, 0, TFL_PUTN }, - { "msg", TF_NONE, FT_LV_DAT, 0, TFL_PUTN }, - { "cur", TF_NONE, FT_LV_DAT, 1, TFL_PUTN }, - { "size", TF_NONE, FT_LV_DAT, 2, TFL_PUTN }, - { "width", TF_NONE, FT_LV_DAT, 3, TFL_PUTN }, - { "unseen", TF_NONE, FT_LV_DAT, 4, TFL_PUTN }, - { "dat", TF_NUM, FT_LV_DAT, 0, TFL_PUTN }, - { "strlen", TF_NONE, FT_LV_STRLEN, 0, TFL_PUTN }, - { "me", TF_MYBOX, FT_LS_LIT, 0, TFL_PUTS }, - { "plus", TF_NUM, FT_LV_PLUS_L, 0, TFL_PUTN }, - { "minus", TF_NUM, FT_LV_MINUS_L, 0, TFL_PUTN }, - { "divide", TF_NUM, FT_LV_DIVIDE_L, 0, TFL_PUTN }, - { "modulo", TF_NUM, FT_LV_MODULO_L, 0, TFL_PUTN }, - { "charleft", TF_NONE, FT_LV_CHAR_LEFT, 0, TFL_PUTN }, - { "timenow", TF_NOW, FT_LV_LIT, 0, TFL_PUTN }, - - { "month", TF_COMP, FT_LS_MONTH, FT_PARSEDATE, TFL_PUTS }, - { "lmonth", TF_COMP, FT_LS_LMONTH, FT_PARSEDATE, TFL_PUTS }, - { "tzone", TF_COMP, FT_LS_ZONE, FT_PARSEDATE, TFL_PUTS }, - { "day", TF_COMP, FT_LS_DAY, FT_PARSEDATE, TFL_PUTS }, - { "weekday", TF_COMP, FT_LS_WEEKDAY, FT_PARSEDATE, TFL_PUTS }, - { "tws", TF_COMP, FT_LS_822DATE, FT_PARSEDATE, TFL_PUTS }, - { "sec", TF_COMP, FT_LV_SEC, FT_PARSEDATE, TFL_PUTN }, - { "min", TF_COMP, FT_LV_MIN, FT_PARSEDATE, TFL_PUTN }, - { "hour", TF_COMP, FT_LV_HOUR, FT_PARSEDATE, TFL_PUTN }, - { "mday", TF_COMP, FT_LV_MDAY, FT_PARSEDATE, TFL_PUTN }, - { "mon", TF_COMP, FT_LV_MON, FT_PARSEDATE, TFL_PUTN }, - { "year", TF_COMP, FT_LV_YEAR, FT_PARSEDATE, TFL_PUTN }, - { "yday", TF_COMP, FT_LV_YDAY, FT_PARSEDATE, TFL_PUTN }, - { "wday", TF_COMP, FT_LV_WDAY, FT_PARSEDATE, TFL_PUTN }, - { "zone", TF_COMP, FT_LV_ZONE, FT_PARSEDATE, TFL_PUTN }, - { "clock", TF_COMP, FT_LV_CLOCK, FT_PARSEDATE, TFL_PUTN }, - { "rclock", TF_COMP, FT_LV_RCLOCK, FT_PARSEDATE, TFL_PUTN }, - { "sday", TF_COMP, FT_LV_DAYF, FT_PARSEDATE, TFL_PUTN }, - { "szone", TF_COMP, FT_LV_ZONEF, FT_PARSEDATE, TFL_PUTN }, - { "dst", TF_COMP, FT_LV_DST, FT_PARSEDATE, TFL_PUTN }, - { "pretty", TF_COMP, FT_LS_PRETTY, FT_PARSEDATE, TFL_PUTS }, - { "nodate", TF_COMP, FT_LV_COMPFLAG, FT_PARSEDATE, TFL_PUTN }, - { "date2local", TF_COMP, FT_LOCALDATE, FT_PARSEDATE, 0 }, - { "date2gmt", TF_COMP, FT_GMTDATE, FT_PARSEDATE, 0 }, - - { "pers", TF_COMP, FT_LS_PERS, FT_PARSEADDR, TFL_PUTS }, - { "mbox", TF_COMP, FT_LS_MBOX, FT_PARSEADDR, TFL_PUTS }, - { "host", TF_COMP, FT_LS_HOST, FT_PARSEADDR, TFL_PUTS }, - { "path", TF_COMP, FT_LS_PATH, FT_PARSEADDR, TFL_PUTS }, - { "gname", TF_COMP, FT_LS_GNAME, FT_PARSEADDR, TFL_PUTS }, - { "note", TF_COMP, FT_LS_NOTE, FT_PARSEADDR, TFL_PUTS }, - { "addr", TF_COMP, FT_LS_ADDR, FT_PARSEADDR, TFL_PUTS }, - { "proper", TF_COMP, FT_LS_822ADDR, FT_PARSEADDR, TFL_PUTS }, - { "type", TF_COMP, FT_LV_HOSTTYPE, FT_PARSEADDR, TFL_PUTN }, - { "ingrp", TF_COMP, FT_LV_INGRPF, FT_PARSEADDR, TFL_PUTN }, - { "nohost", TF_COMP, FT_LV_NOHOSTF, FT_PARSEADDR, TFL_PUTN }, - { "formataddr", TF_EXPR_SV,FT_FORMATADDR, FT_FORMATADDR, 0 }, - { "friendly", TF_COMP, FT_LS_FRIENDLY, FT_PARSEADDR, TFL_PUTS }, - - { "mymbox", TF_COMP, FT_LV_COMPFLAG, FT_MYMBOX, TFL_PUTN }, - { "addtoseq", TF_STR, FT_ADDTOSEQ, 0, 0 }, - - { "unquote", TF_EXPR, FT_LS_UNQUOTE, 0, TFL_PUTS}, - - { NULL, 0, 0, 0, 0 } + { "nonzero", TF_EXPR, FT_V_NE, FT_IF_V_NE, 0 }, + { "zero", TF_EXPR, FT_V_EQ, FT_IF_V_EQ, 0 }, + { "eq", TF_NUM, FT_V_EQ, FT_IF_V_EQ, 0 }, + { "ne", TF_NUM, FT_V_NE, FT_IF_V_NE, 0 }, + { "gt", TF_NUM, FT_V_GT, FT_IF_V_GT, 0 }, + { "null", TF_EXPR, FT_S_NULL, FT_IF_S_NULL, 0 }, + { "nonnull", TF_EXPR, FT_S_NONNULL, FT_IF_S, 0 }, + { "match", TF_STR, FT_V_MATCH, FT_IF_MATCH, 0 }, + { "amatch", TF_STR, FT_V_AMATCH, FT_IF_AMATCH, 0 }, + + { "putstr", TF_EXPR, FT_STR, 0, 0 }, + { "putstrf", TF_EXPR, FT_STRF, 0, 0 }, + { "putnum", TF_EXPR, FT_NUM, 0, 0 }, + { "putnumf", TF_EXPR, FT_NUMF, 0, 0 }, + { "putaddr", TF_STR, FT_PUTADDR, 0, 0 }, + { "void", TF_NOP, 0, 0, 0 }, + + { "comp", TF_COMP, FT_LS_COMP, 0, TFL_PUTS }, + { "lit", TF_STR, FT_LS_LIT, 0, TFL_PUTS }, + { "getenv", TF_STR, FT_LS_GETENV, 0, TFL_PUTS }, + { "profile", TF_STR, FT_LS_CFIND, 0, TFL_PUTS }, + { "decodecomp", TF_COMP, FT_LS_DECODECOMP, 0, TFL_PUTS }, + { "decode", TF_EXPR, FT_LS_DECODE, 0, TFL_PUTS }, + { "trim", TF_EXPR, FT_LS_TRIM, 0, 0 }, + { "compval", TF_COMP, FT_LV_COMP, 0, TFL_PUTN }, + { "compflag", TF_COMP, FT_LV_COMPFLAG, 0, TFL_PUTN }, + { "num", TF_NUM, FT_LV_LIT, 0, TFL_PUTN }, + { "msg", TF_NONE, FT_LV_DAT, 0, TFL_PUTN }, + { "cur", TF_NONE, FT_LV_DAT, 1, TFL_PUTN }, + { "size", TF_NONE, FT_LV_DAT, 2, TFL_PUTN }, + { "width", TF_NONE, FT_LV_DAT, 3, TFL_PUTN }, + { "unseen", TF_NONE, FT_LV_DAT, 4, TFL_PUTN }, + { "dat", TF_NUM, FT_LV_DAT, 0, TFL_PUTN }, + { "strlen", TF_NONE, FT_LV_STRLEN, 0, TFL_PUTN }, + { "me", TF_MYBOX, FT_LS_LIT, 0, TFL_PUTS }, + { "plus", TF_NUM, FT_LV_PLUS_L, 0, TFL_PUTN }, + { "minus", TF_NUM, FT_LV_MINUS_L, 0, TFL_PUTN }, + { "divide", TF_NUM, FT_LV_DIVIDE_L, 0, TFL_PUTN }, + { "modulo", TF_NUM, FT_LV_MODULO_L, 0, TFL_PUTN }, + { "charleft", TF_NONE, FT_LV_CHAR_LEFT, 0, TFL_PUTN }, + { "timenow", TF_NOW, FT_LV_LIT, 0, TFL_PUTN }, + + { "month", TF_COMP, FT_LS_MONTH, FT_PARSEDATE, TFL_PUTS }, + { "lmonth", TF_COMP, FT_LS_LMONTH, FT_PARSEDATE, TFL_PUTS }, + { "tzone", TF_COMP, FT_LS_ZONE, FT_PARSEDATE, TFL_PUTS }, + { "day", TF_COMP, FT_LS_DAY, FT_PARSEDATE, TFL_PUTS }, + { "weekday", TF_COMP, FT_LS_WEEKDAY, FT_PARSEDATE, TFL_PUTS }, + { "tws", TF_COMP, FT_LS_822DATE, FT_PARSEDATE, TFL_PUTS }, + { "sec", TF_COMP, FT_LV_SEC, FT_PARSEDATE, TFL_PUTN }, + { "min", TF_COMP, FT_LV_MIN, FT_PARSEDATE, TFL_PUTN }, + { "hour", TF_COMP, FT_LV_HOUR, FT_PARSEDATE, TFL_PUTN }, + { "mday", TF_COMP, FT_LV_MDAY, FT_PARSEDATE, TFL_PUTN }, + { "mon", TF_COMP, FT_LV_MON, FT_PARSEDATE, TFL_PUTN }, + { "year", TF_COMP, FT_LV_YEAR, FT_PARSEDATE, TFL_PUTN }, + { "yday", TF_COMP, FT_LV_YDAY, FT_PARSEDATE, TFL_PUTN }, + { "wday", TF_COMP, FT_LV_WDAY, FT_PARSEDATE, TFL_PUTN }, + { "zone", TF_COMP, FT_LV_ZONE, FT_PARSEDATE, TFL_PUTN }, + { "clock", TF_COMP, FT_LV_CLOCK, FT_PARSEDATE, TFL_PUTN }, + { "rclock", TF_COMP, FT_LV_RCLOCK, FT_PARSEDATE, TFL_PUTN }, + { "sday", TF_COMP, FT_LV_DAYF, FT_PARSEDATE, TFL_PUTN }, + { "szone", TF_COMP, FT_LV_ZONEF, FT_PARSEDATE, TFL_PUTN }, + { "dst", TF_COMP, FT_LV_DST, FT_PARSEDATE, TFL_PUTN }, + { "pretty", TF_COMP, FT_LS_PRETTY, FT_PARSEDATE, TFL_PUTS }, + { "nodate", TF_COMP, FT_LV_COMPFLAG, FT_PARSEDATE, TFL_PUTN }, + { "date2local", TF_COMP, FT_LOCALDATE, FT_PARSEDATE, 0 }, + { "date2gmt", TF_COMP, FT_GMTDATE, FT_PARSEDATE, 0 }, + + { "pers", TF_COMP, FT_LS_PERS, FT_PARSEADDR, TFL_PUTS }, + { "mbox", TF_COMP, FT_LS_MBOX, FT_PARSEADDR, TFL_PUTS }, + { "host", TF_COMP, FT_LS_HOST, FT_PARSEADDR, TFL_PUTS }, + { "path", TF_COMP, FT_LS_PATH, FT_PARSEADDR, TFL_PUTS }, + { "gname", TF_COMP, FT_LS_GNAME, FT_PARSEADDR, TFL_PUTS }, + { "note", TF_COMP, FT_LS_NOTE, FT_PARSEADDR, TFL_PUTS }, + { "addr", TF_COMP, FT_LS_ADDR, FT_PARSEADDR, TFL_PUTS }, + { "proper", TF_COMP, FT_LS_822ADDR, FT_PARSEADDR, TFL_PUTS }, + { "type", TF_COMP, FT_LV_HOSTTYPE, FT_PARSEADDR, TFL_PUTN }, + { "ingrp", TF_COMP, FT_LV_INGRPF, FT_PARSEADDR, TFL_PUTN }, + { "nohost", TF_COMP, FT_LV_NOHOSTF, FT_PARSEADDR, TFL_PUTN }, + { "formataddr", TF_EXPR_SV, FT_FORMATADDR, FT_FORMATADDR, 0 }, + { "friendly", TF_COMP, FT_LS_FRIENDLY, FT_PARSEADDR, TFL_PUTS }, + + { "mymbox", TF_COMP, FT_LV_COMPFLAG, FT_MYMBOX, TFL_PUTN }, + + { "unquote", TF_EXPR, FT_LS_UNQUOTE, 0, TFL_PUTS}, + { "unmailto", TF_EXPR, FT_LS_UNMAILTO, 0, TFL_PUTS}, + + { NULL, 0, 0, 0, 0 } }; /* Add new component to the hash table */ #define NEWCOMP(cm,name) do { \ - cm = ((struct comp *) calloc(1, sizeof (struct comp)));\ - cm->c_name = name;\ - ncomp++;\ - i = CHASH(name);\ - cm->c_next = wantcomp[i];\ - wantcomp[i] = cm; \ + cm = (mh_xcalloc(1, sizeof (struct comp)));\ + cm->c_name = name;\ + ncomp++;\ + i = CHASH(name);\ + cm->c_next = wantcomp[i];\ + wantcomp[i] = cm; \ } while (0) #define NEWFMT (next_fp++) #define NEW(type,fill,wid) do {\ - fp=NEWFMT; fp->f_type=(type); fp->f_fill=(fill); fp->f_width=(wid); \ + fp=NEWFMT; fp->f_type=(type); fp->f_fill=(fill); fp->f_width=(wid); \ } while (0) /* Add (possibly new) component to the hash table */ #define ADDC(name) do { \ - FINDCOMP(cm, name);\ - if (!cm) {\ - NEWCOMP(cm,name);\ - }\ - fp->f_comp = cm; \ + FINDCOMP(cm, name);\ + if (!cm) {\ + NEWCOMP(cm,name);\ + }\ + fp->f_comp = cm; \ } while (0) -#define LV(type, value) do { NEW(type,0,0); fp->f_value = (value); } while (0) -#define LS(type, str) do { NEW(type,0,0); fp->f_text = (str); } while (0) +#define LV(type, value) do { NEW(type,0,0); fp->f_value = (value); } while (0) +#define LS(type, str) do { NEW(type,0,0); fp->f_text = (str); } while (0) -#define PUTCOMP(comp) do { NEW(FT_COMP,0,0); ADDC(comp); } while (0) -#define PUTLIT(str) do { NEW(FT_LIT,0,0); fp->f_text = (str); } while (0) -#define PUTC(c) do { NEW(FT_CHAR,0,0); fp->f_char = (c); } while (0) +#define PUTCOMP(comp) do { NEW(FT_COMP,0,0); ADDC(comp); } while (0) +#define PUTLIT(str) do { NEW(FT_LIT,0,0); fp->f_text = (str); } while (0) +#define PUTC(c) do { NEW(FT_CHAR,0,0); fp->f_char = (c); } while (0) static char *format_string; -static unsigned char *usr_fstring; /* for CERROR */ +static unsigned char *usr_fstring; /* for CERROR */ -#define CERROR(str) compile_error (str, cp) - -/* - * external prototypes - */ -extern char *getusername(void); +#define CERROR(str) compile_error(str, cp) /* - * static prototypes - */ +** static prototypes +*/ static struct ftable *lookup(char *); static void compile_error(char *, char *); -static char *compile (char *); +static char *compile(char *); static char *do_spec(char *); static char *do_name(char *, int); static char *do_func(char *); -static char *do_expr (char *, int); +static char *do_expr(char *, int); static char *do_loop(char *); static char *do_if(char *); +/* +** Lookup a function name in the functable +*/ static struct ftable * lookup(char *name) { - register struct ftable *t = functable; - register char *nm; - register char c = *name; + struct ftable *t = functable; + char *nm; + char c = *name; - while ((nm = t->name)) { - if (*nm == c && strcmp (nm, name) == 0) - return (ftbl = t); + while ((nm = t->name)) { + if (*nm == c && strcmp(nm, name) == 0) + return (ftbl = t); - t++; - } - return (struct ftable *) 0; + t++; + } + return (struct ftable *) 0; } static void compile_error(char *str, char *cp) { - int i, errpos, errctx; + int i, errpos, errctx; - errpos = cp - format_string; - errctx = errpos > 20 ? 20 : errpos; - usr_fstring[errpos] = '\0'; + errpos = cp - format_string; + errctx = errpos > 20 ? 20 : errpos; + usr_fstring[errpos] = '\0'; - for (i = errpos-errctx; i < errpos; i++) { -#ifdef LOCALE - if (iscntrl(usr_fstring[i])) -#else - if (usr_fstring[i] < 32) -#endif - usr_fstring[i] = '_'; - } + for (i = errpos-errctx; i < errpos; i++) { + if (iscntrl(usr_fstring[i])) + usr_fstring[i] = '_'; + } - advise(NULL, "\"%s\": format compile error - %s", - &usr_fstring[errpos-errctx], str); - adios (NULL, "%*s", errctx+1, "^"); + advise(NULL, "\"%s\": format compile error - %s", + &usr_fstring[errpos-errctx], str); + adios(EX_SOFTWARE, NULL, "%*s", errctx+1, "^"); } /* - * Compile format string "fstring" into format list "fmt". - * Return the number of header components found in the format - * string. - */ - +** Compile format string "fstring" into format list "fmt". +** Return the number of header components found in the format +** string. +*/ int fmt_compile(char *fstring, struct format **fmt) { - register char *cp; - int i; - - if (format_string) - free (format_string); - format_string = getcpy (fstring); - usr_fstring = fstring; - - /* init the component hash table. */ - for (i = 0; i < sizeof(wantcomp)/sizeof(wantcomp[0]); i++) - wantcomp[i] = 0; - - memset((char *) &fmt_mnull, 0, sizeof(fmt_mnull)); - - /* it takes at least 4 char to generate one format so we - * allocate a worst-case format array using 1/4 the length - * of the format string. We actually need twice this much - * to handle both pre-processing (e.g., address parsing) and - * normal processing. - */ - i = strlen(fstring)/2 + 1; - if (i==1) i++; - next_fp = formatvec = (struct format *)calloc ((size_t) i, - sizeof(struct format)); - if (next_fp == NULL) - adios (NULL, "unable to allocate format storage"); - - ncomp = 0; - infunction = 0; - - cp = compile(format_string); - if (*cp) { - CERROR("extra '%>', '%|' or '%?'"); - } - LV(FT_DONE, 0); /* really done */ - *fmt = formatvec; - - return (ncomp); + char *cp; + size_t i; + + if (format_string) + mh_free0(&format_string); + format_string = mh_xstrdup(fstring); + usr_fstring = fstring; + + /* init the component hash table. */ + for (i = 0; i < sizeof(wantcomp)/sizeof(wantcomp[0]); i++) + wantcomp[i] = 0; + + memset((char *) &fmt_mnull, 0, sizeof(fmt_mnull)); + + /* + ** it takes at least 4 char to generate one format so we + ** allocate a worst-case format array using 1/4 the length + ** of the format string. We actually need twice this much + ** to handle both pre-processing (e.g., address parsing) and + ** normal processing. + */ + i = strlen(fstring)/2 + 1; + if (i == 1) + i++; + next_fp = formatvec = mh_xcalloc(i, sizeof(struct format)); + if (next_fp == NULL) + adios(EX_OSERR, NULL, "unable to allocate format storage"); + + ncomp = 0; + infunction = 0; + + cp = compile(format_string); + if (*cp) { + CERROR("extra '%>', '%|' or '%?'"); + } + LV(FT_DONE, 0); /* really done */ + *fmt = formatvec; + + return (ncomp); } static char * -compile (char *sp) +compile(char *sp) { - register char *cp = sp; - register int c; - - for (;;) { - sp = cp; - while ((c = *cp) && c != '%') - cp++; - *cp = 0; - switch (cp-sp) { - case 0: - break; - case 1: - PUTC(*sp); - break; - default: - PUTLIT(sp); - break; - } - if (c == 0) - return (cp); - - switch (c = *++cp) { - case '%': - PUTC (*cp); - cp++; - break; - - case '|': - case '>': - case '?': - case ']': - return (cp); - - case '<': - cp = do_if(++cp); - break; - - case '[': /* ] */ - cp = do_loop(++cp); - break; - - case ';': /* comment line */ - cp++; - while ((c = *cp++) && c != '\n') - continue; - break; - - default: - cp = do_spec(cp); - break; + char *cp = sp; + int c; + + for (;;) { + sp = cp; + while ((c = *cp) && c != '%') + cp++; + *cp = 0; + switch (cp-sp) { + case 0: + break; + case 1: + PUTC(*sp); + break; + default: + PUTLIT(sp); + break; + } + if (c == 0) + return (cp); + + switch (c = *++cp) { + case '%': + PUTC(*cp); + cp++; + break; + + case '|': + case '>': + case '?': + case ']': + return (cp); + + case '<': + cp = do_if(++cp); + break; + + case '[': /* ] */ + cp = do_loop(++cp); + break; + + case ';': /* comment line */ + cp++; + while ((c = *cp++) && c != '\n') + continue; + break; + + default: + cp = do_spec(cp); + break; + } } - } } +/* +** Process functions & components (handle field width here as well +*/ static char * do_spec(char *sp) { - register char *cp = sp; - register int c; -#ifndef lint - register int ljust = 0; -#endif /* not lint */ - register int wid = 0; - register char fill = ' '; - - c = *cp++; - if (c == '-') { - ljust++; - c = *cp++; - } - if (c == '0') { - fill = c; - c = *cp++; - } - while (isdigit(c)) { - wid = wid*10 + (c - '0'); + char *cp = sp; + int c; + int ljust = 0; + int wid = 0; + char fill = ' '; + c = *cp++; - } - if (c == '{') { - cp = do_name(cp, 0); - if (! infunction) - fp->f_type = wid? FT_COMPF : FT_COMP; - } - else if (c == '(') { - cp = do_func(cp); - if (! infunction) { - if (ftbl->flags & TFL_PUTS) { - LV( wid? FT_STRF : FT_STR, ftbl->extra); - } - else if (ftbl->flags & TFL_PUTN) { - LV( wid? FT_NUMF : FT_NUM, ftbl->extra); - } + if (c == '-') { + ljust++; + c = *cp++; + } + if (c == '0') { + fill = c; + c = *cp++; } - } - else { - CERROR("component or function name expected"); - } - if (ljust) - wid = -wid; - fp->f_width = wid; - fp->f_fill = fill; - - return (cp); + while (isdigit(c)) { + wid = wid*10 + (c - '0'); + c = *cp++; + } + if (c == '{') { + cp = do_name(cp, 0); + if (! infunction) + fp->f_type = wid? FT_COMPF : FT_COMP; + } else if (c == '(') { + cp = do_func(cp); + if (! infunction) { + if (ftbl->flags & TFL_PUTS) { + LV( wid? FT_STRF : FT_STR, ftbl->extra); + } else if (ftbl->flags & TFL_PUTN) { + LV( wid? FT_NUMF : FT_NUM, ftbl->extra); + } + } + } else { + CERROR("component or function name expected"); + } + if (ljust) + wid = -wid; + fp->f_width = wid; + fp->f_fill = fill; + + return (cp); } + +/* +** Process a component name. Normally this involves generating an FT_COMP +** instruction for the specified component. If preprocess is set, then we +** do some extra processing. +*/ static char * do_name(char *sp, int preprocess) { - register char *cp = sp; - register int c; - register int i; - static int primed = 0; - - while (isalnum(c = *cp++) || c == '-' || c == '_') - ; - if (c != '}') { - CERROR("'}' expected"); - } - cp[-1] = '\0'; - PUTCOMP(sp); - switch (preprocess) { - - case FT_PARSEDATE: - if (cm->c_type & CT_ADDR) { - CERROR("component used as both date and address"); - } - cm->c_tws = (struct tws *) - calloc((size_t) 1, sizeof(*cm->c_tws)); - fp->f_type = preprocess; - PUTCOMP(sp); - cm->c_type |= CT_DATE; - break; - - case FT_MYMBOX: - if (!primed) { - ismymbox ((struct mailname *) 0); - primed++; - } - /* fall through */ - case FT_PARSEADDR: - if (cm->c_type & CT_DATE) { - CERROR("component used as both date and address"); + char *cp = sp; + int c; + int i; + static int primed = 0; + + while (isalnum(c = *cp++) || c == '-' || c == '_') + ; + if (c != '}') { + CERROR("'}' expected"); } - cm->c_mn = &fmt_mnull; - fp->f_type = preprocess; + cp[-1] = '\0'; PUTCOMP(sp); - cm->c_type |= CT_ADDR; - break; + switch (preprocess) { - case FT_FORMATADDR: - if (cm->c_type & CT_DATE) { - CERROR("component used as both date and address"); + case FT_PARSEDATE: + if (cm->c_type & CT_ADDR) { + CERROR("component used as both date and address"); + } + cm->c_tws = mh_xcalloc(1, sizeof(*cm->c_tws)); + fp->f_type = preprocess; + PUTCOMP(sp); + cm->c_type |= CT_DATE; + break; + + case FT_MYMBOX: + if (!primed) { + ismymbox((struct mailname *) 0); + primed++; + } + /* fall through */ + case FT_PARSEADDR: + if (cm->c_type & CT_DATE) { + CERROR("component used as both date and address"); + } + cm->c_mn = &fmt_mnull; + fp->f_type = preprocess; + PUTCOMP(sp); + cm->c_type |= CT_ADDR; + break; + + case FT_FORMATADDR: + if (cm->c_type & CT_DATE) { + CERROR("component used as both date and address"); + } + cm->c_type |= CT_ADDR; + break; } - cm->c_type |= CT_ADDR; - break; - } - return (cp); + return (cp); } + +/* +** Generate one or more instructions corresponding to the named function. +** The different type of function arguments are handled here. +*/ static char * do_func(char *sp) { - register char *cp = sp; - register int c; - register struct ftable *t; - register int n; - int mflag; /* minus sign in NUM */ - - infunction++; - - while (isalnum(c = *cp++)) - ; - if (c != '(' && c != '{' && c != ' ' && c != ')') { - CERROR("'(', '{', ' ' or ')' expected"); - } - cp[-1] = '\0'; - if ((t = lookup (sp)) == 0) { - CERROR("unknown function"); - } - if (isspace(c)) - c = *cp++; + char *cp = sp; + int c; + struct ftable *t; + int n; + int mflag; /* minus sign in NUM */ + + infunction++; + + while (isalnum(c = *cp++)) + ; + if (c != '(' && c != '{' && c != ' ' && c != ')') { + CERROR("'(', '{', ' ' or ')' expected"); + } + cp[-1] = '\0'; + if ((t = lookup(sp)) == 0) { + CERROR("unknown function"); + } + if (isspace(c)) + c = *cp++; - switch (t->type) { + switch (t->type) { - case TF_COMP: - if (c != '{') { - CERROR("component name expected"); + case TF_COMP: + if (c != '{') { + CERROR("component name expected"); + } + cp = do_name(cp, t->extra); + fp->f_type = t->f_type; + c = *cp++; + break; + + case TF_NUM: + if ((mflag = (c == '-'))) + c = *cp++; + n = 0; + while (isdigit(c)) { + n = n*10 + (c - '0'); + c = *cp++; + } + if (mflag) + n = (-n); + LV(t->f_type,n); + break; + + case TF_STR: + sp = cp - 1; + while (c && c != ')') + c = *cp++; + cp[-1] = '\0'; + LS(t->f_type,sp); + break; + + case TF_NONE: + LV(t->f_type,t->extra); + break; + + case TF_MYBOX: + LS(t->f_type, getusername()); + break; + + case TF_NOW: + LV(t->f_type, time((time_t *) 0)); + break; + + case TF_EXPR_SV: + LV(FT_SAVESTR, 0); + /* fall through */ + case TF_EXPR: + *--cp = c; + cp = do_expr(cp, t->extra); + LV(t->f_type, 0); + c = *cp++; + ftbl = t; + break; + + case TF_NOP: + *--cp = c; + cp = do_expr(cp, t->extra); + c = *cp++; + ftbl = t; + break; } - cp = do_name(cp, t->extra); - fp->f_type = t->f_type; - c = *cp++; - break; - - case TF_NUM: - if ((mflag = (c == '-'))) - c = *cp++; - n = 0; - while (isdigit(c)) { - n = n*10 + (c - '0'); - c = *cp++; + if (c != ')') { + CERROR("')' expected"); } - if (mflag) - n = (-n); - LV(t->f_type,n); - break; - - case TF_STR: - sp = cp - 1; - while (c && c != ')') - c = *cp++; - cp[-1] = '\0'; - LS(t->f_type,sp); - break; - - case TF_NONE: - LV(t->f_type,t->extra); - break; - - case TF_MYBOX: - LS(t->f_type, getusername()); - break; - - case TF_NOW: - LV(t->f_type, time((time_t *) 0)); - break; - - case TF_EXPR_SV: - LV(FT_SAVESTR, 0); - /* fall through */ - case TF_EXPR: - *--cp = c; - cp = do_expr(cp, t->extra); - LV(t->f_type, 0); - c = *cp++; - ftbl = t; - break; - - case TF_NOP: - *--cp = c; - cp = do_expr(cp, t->extra); - c = *cp++; - ftbl = t; - break; - } - if (c != ')') { - CERROR("')' expected"); - } - --infunction; - return (cp); + --infunction; + return (cp); } + +/* +** Handle an expression as an argument. Basically we call one of do_name(), +** do_func(), or do_if() +*/ static char * -do_expr (char *sp, int preprocess) +do_expr(char *sp, int preprocess) { - register char *cp = sp; - register int c; - - if ((c = *cp++) == '{') { - cp = do_name (cp, preprocess); - fp->f_type = FT_LS_COMP; - } else if (c == '(') { - cp = do_func (cp); - } else if (c == ')') { - return (--cp); - } else if (c == '%' && *cp == '<') { - cp = do_if (cp+1); - } else { - CERROR ("'(', '{', '%<' or ')' expected"); - } - return (cp); + char *cp = sp; + int c; + + if ((c = *cp++) == '{') { + cp = do_name(cp, preprocess); + fp->f_type = FT_LS_COMP; + } else if (c == '(') { + cp = do_func(cp); + } else if (c == ')') { + return (--cp); + } else if (c == '%' && *cp == '<') { + cp = do_if(cp+1); + } else { + CERROR("'(', '{', '%<' or ')' expected"); + } + return (cp); } + +/* +** I am guessing this was for some kind of loop statement, which would have +** looked like %[ .... %]. It looks like the way this would have worked +** is that the format engine would have seen that FT_DONE had a 1 in the +** f_un.f_un_value and then decided whether or not to continue the loop. +** There is no support for this in the format engine, so right now if +** you try using it you will reach the FT_DONE and simply stop. I'm leaving +** this here in case someone wants to continue the work. +*/ static char * do_loop(char *sp) { - register char *cp = sp; - struct format *floop; + char *cp = sp; + struct format *floop; - floop = next_fp; - cp = compile (cp); - if (*cp++ != ']') - CERROR ("']' expected"); + floop = next_fp; + cp = compile(cp); + if (*cp++ != ']') + CERROR("']' expected"); - LV(FT_DONE, 1); /* not yet done */ - LV(FT_GOTO, 0); - fp->f_skip = floop - fp; /* skip backwards */ + LV(FT_DONE, 1); /* not yet done */ + LV(FT_GOTO, 0); + fp->f_skip = floop - fp; /* skip backwards */ - return cp; + return cp; } + +/* +** Handle an if-elsif-endif statement. Note here that the branching +** is handled by the f_skip member of the struct format (which is really +** just f_width overloaded). This number controls how far to move forward +** (or back) in the format instruction array. +*/ static char * do_if(char *sp) { - register char *cp = sp; - register struct format *fexpr, - *fif = (struct format *)NULL; - register int c = '<'; - - for (;;) { - if (c == '<') { /* doing an IF */ - if ((c = *cp++) == '{') /*}*/{ - cp = do_name(cp, 0); - fp->f_type = FT_LS_COMP; - LV (FT_IF_S, 0); - } - else if (c == '(') { - cp = do_func(cp); - /* see if we can merge the load and the "if" */ - if (ftbl->f_type >= IF_FUNCS) - fp->f_type = ftbl->extra; - else { - /* Put out a string test or a value test depending - * on what this function's return type is. - */ - if (ftbl->flags & TFL_PUTS) { - LV (FT_IF_S, 0); - } else { - LV (FT_IF_V_NE, 0); - } + char *cp = sp; + struct format *fexpr, *fif = (struct format *)NULL; + int c = '<'; + + for (;;) { + if (c == '<') { /* doing an IF */ + if ((c = *cp++) == '{') /*}*/{ + cp = do_name(cp, 0); + fp->f_type = FT_LS_COMP; + LV(FT_IF_S, 0); + } else if (c == '(') { + cp = do_func(cp); + /* see if we can merge the load and the "if" */ + if (ftbl->f_type >= IF_FUNCS) + fp->f_type = ftbl->extra; + else { + /* + ** Put out a string test or a value + ** test depending on what this + ** function 's return type is. + */ + if (ftbl->flags & TFL_PUTS) { + LV(FT_IF_S, 0); + } else { + LV(FT_IF_V_NE, 0); + } + } + } else { + CERROR("'(' or '{' expected"); /*}*/ + } } - } - else { - CERROR("'(' or '{' expected"); /*}*/ - } - } - fexpr = fp; /* loc of [ELS]IF */ - cp = compile (cp); /* compile IF TRUE stmts */ - if (fif) - fif->f_skip = next_fp - fif; + fexpr = fp; /* loc of [ELS]IF */ + cp = compile(cp); /* compile IF TRUE stmts */ + if (fif) + fif->f_skip = next_fp - fif; - if ((c = *cp++) == '|') { /* the last ELSE */ - LV(FT_GOTO, 0); - fif = fp; /* loc of GOTO */ - fexpr->f_skip = next_fp - fexpr; + if ((c = *cp++) == '|') { /* the last ELSE */ + LV(FT_GOTO, 0); + fif = fp; /* loc of GOTO */ + fexpr->f_skip = next_fp - fexpr; - fexpr = (struct format *)NULL;/* no extra ENDIF */ + fexpr = (struct format *)NULL;/* no extra ENDIF */ - cp = compile (cp); /* compile ELSE stmts */ - fif->f_skip = next_fp - fif; - c = *cp++; - } - else if (c == '?') { /* another ELSIF */ - LV(FT_GOTO, 0); - fif = fp; /* loc of GOTO */ - fexpr->f_skip = next_fp - fexpr; + cp = compile(cp); /* compile ELSE stmts */ + fif->f_skip = next_fp - fif; + c = *cp++; + } else if (c == '?') { /* another ELSIF */ + LV(FT_GOTO, 0); + fif = fp; /* loc of GOTO */ + fexpr->f_skip = next_fp - fexpr; - c = '<'; /* impersonate an IF */ - continue; + c = '<'; /* impersonate an IF */ + continue; + } + break; } - break; - } - if (c != '>') { - CERROR("'>' expected."); - } + if (c != '>') { + CERROR("'>' expected."); + } - if (fexpr) /* IF ... [ELSIF ...] ENDIF */ - fexpr->f_skip = next_fp - fexpr; + if (fexpr) /* IF ... [ELSIF ...] ENDIF */ + fexpr->f_skip = next_fp - fexpr; - return (cp); + return (cp); }