Add %(unmailto) format function for List-Post headers
[mmh] / sbr / fmt_compile.c
index d699916..2b32e71 100644 (file)
-
 /*
- * fmt_compile.c -- "compile" format strings for fmt_scan
- *
- * $Id$
- *
- * 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 <h/mh.h>
+#include <h/utils.h>
 #include <h/addrsbr.h>
 #include <h/tws.h>
 #include <h/fmt_scan.h>
 #include <h/fmt_compile.h>
+#include <ctype.h>
+#include <sysexits.h>
 
-#ifdef TIME_WITH_SYS_TIME
+#ifdef HAVE_SYS_TIME_H
 # include <sys/time.h>
-# include <time.h>
-#else
-# ifdef TM_IN_SYS_TIME
-#  include <sys/time.h>
-# else
-#  include <time.h>
-# endif
 #endif
+#include <time.h>
 
 /*
- * 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 */
-#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)\
-       cm = ((struct comp *) calloc(1, sizeof (struct comp)));\
-       cm->c_name = name;\
-       ncomp++;\
-       i = CHASH(name);\
-       cm->c_next = wantcomp[i];\
-       wantcomp[i] = cm;
+#define NEWCOMP(cm,name) do { \
+               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)\
-       fp=NEWFMT; fp->f_type=(type); fp->f_fill=(fill); fp->f_width=(wid);
+#define NEW(type,fill,wid) do {\
+               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)\
-       FINDCOMP(cm, name);\
-       if (!cm) {\
-           NEWCOMP(cm,name);\
-       }\
-       fp->f_comp = cm;
+#define ADDC(name) do { \
+               FINDCOMP(cm, name);\
+               if (!cm) {\
+                       NEWCOMP(cm,name);\
+               }\
+               fp->f_comp = cm; \
+       } while (0)
 
-#define LV(type, value)                NEW(type,0,0); fp->f_value = (value);
-#define LS(type, str)          NEW(type,0,0); fp->f_text = (str);
+#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)          NEW(FT_COMP,0,0); ADDC(comp);
-#define PUTLIT(str)            NEW(FT_LIT,0,0); fp->f_text = (str);
-#define PUTC(c)                        NEW(FT_CHAR,0,0); fp->f_char = (c);
+#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 {
-                   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);
 }