X-Git-Url: http://git.marmaro.de/?p=mmh;a=blobdiff_plain;f=sbr%2Ffmt_compile.c;h=2b32e7152a9fe45d8b8a2d68d86a1765589a9fff;hp=9d8f41d016d5dff1bff32315af21c68591d09f35;hb=fc9279e818dfc96c63a5d75a89080cc68cfe1170;hpb=ced6090a330d3d83d0bce709f756aa3d7d65fea4 diff --git a/sbr/fmt_compile.c b/sbr/fmt_compile.c index 9d8f41d..2b32e71 100644 --- a/sbr/fmt_compile.c +++ b/sbr/fmt_compile.c @@ -4,24 +4,53 @@ ** 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" @@ -57,6 +86,30 @@ extern struct mailname fmt_mnull; #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 */ @@ -148,16 +201,16 @@ static struct ftable functable[] = { { "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}, + { "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 = (mh_xcalloc(1, sizeof (struct comp)));\ cm->c_name = name;\ ncomp++;\ i = CHASH(name);\ @@ -189,36 +242,34 @@ static struct ftable functable[] = { static char *format_string; 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 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) + if (*nm == c && strcmp(nm, name) == 0) return (ftbl = t); t++; @@ -237,17 +288,13 @@ compile_error(char *str, char *cp) 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] = '_'; } advise(NULL, "\"%s\": format compile error - %s", - &usr_fstring[errpos-errctx], str); - adios (NULL, "%*s", errctx+1, "^"); + &usr_fstring[errpos-errctx], str); + adios(EX_SOFTWARE, NULL, "%*s", errctx+1, "^"); } /* @@ -255,16 +302,15 @@ compile_error(char *str, char *cp) ** Return the number of header components found in the format ** string. */ - int fmt_compile(char *fstring, struct format **fmt) { - register char *cp; - int i; + char *cp; + size_t i; if (format_string) - free (format_string); - format_string = getcpy (fstring); + mh_free0(&format_string); + format_string = mh_xstrdup(fstring); usr_fstring = fstring; /* init the component hash table. */ @@ -283,10 +329,9 @@ fmt_compile(char *fstring, struct format **fmt) i = strlen(fstring)/2 + 1; if (i == 1) i++; - next_fp = formatvec = (struct format *)calloc ((size_t) i, - sizeof(struct format)); + next_fp = formatvec = mh_xcalloc(i, sizeof(struct format)); if (next_fp == NULL) - adios (NULL, "unable to allocate format storage"); + adios(EX_OSERR, NULL, "unable to allocate format storage"); ncomp = 0; infunction = 0; @@ -302,10 +347,10 @@ fmt_compile(char *fstring, struct format **fmt) } static char * -compile (char *sp) +compile(char *sp) { - register char *cp = sp; - register int c; + char *cp = sp; + int c; for (;;) { sp = cp; @@ -327,7 +372,7 @@ compile (char *sp) switch (c = *++cp) { case '%': - PUTC (*cp); + PUTC(*cp); cp++; break; @@ -359,16 +404,17 @@ compile (char *sp) } +/* +** 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 = ' '; + char *cp = sp; + int c; + int ljust = 0; + int wid = 0; + char fill = ' '; c = *cp++; if (c == '-') { @@ -407,12 +453,18 @@ do_spec(char *sp) 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; + char *cp = sp; + int c; + int i; static int primed = 0; while (isalnum(c = *cp++) || c == '-' || c == '_') @@ -428,8 +480,7 @@ do_name(char *sp, int preprocess) 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)); + cm->c_tws = mh_xcalloc(1, sizeof(*cm->c_tws)); fp->f_type = preprocess; PUTCOMP(sp); cm->c_type |= CT_DATE; @@ -437,7 +488,7 @@ do_name(char *sp, int preprocess) case FT_MYMBOX: if (!primed) { - ismymbox ((struct mailname *) 0); + ismymbox((struct mailname *) 0); primed++; } /* fall through */ @@ -461,13 +512,18 @@ do_name(char *sp, int preprocess) 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; + char *cp = sp; + int c; + struct ftable *t; + int n; int mflag; /* minus sign in NUM */ infunction++; @@ -478,7 +534,7 @@ do_func(char *sp) CERROR("'(', '{', ' ' or ')' expected"); } cp[-1] = '\0'; - if ((t = lookup (sp)) == 0) { + if ((t = lookup(sp)) == 0) { CERROR("unknown function"); } if (isspace(c)) @@ -553,37 +609,52 @@ do_func(char *sp) 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; + char *cp = sp; + int c; if ((c = *cp++) == '{') { - cp = do_name (cp, preprocess); + cp = do_name(cp, preprocess); fp->f_type = FT_LS_COMP; } else if (c == '(') { - cp = do_func (cp); + cp = do_func(cp); } else if (c == ')') { return (--cp); } else if (c == '%' && *cp == '<') { - cp = do_if (cp+1); + cp = do_if(cp+1); } else { - CERROR ("'(', '{', '%<' or ')' expected"); + 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; + char *cp = sp; struct format *floop; floop = next_fp; - cp = compile (cp); + cp = compile(cp); if (*cp++ != ']') - CERROR ("']' expected"); + CERROR("']' expected"); LV(FT_DONE, 1); /* not yet done */ LV(FT_GOTO, 0); @@ -592,19 +663,26 @@ do_loop(char *sp) 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 = '<'; + 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); + LV(FT_IF_S, 0); } else if (c == '(') { cp = do_func(cp); /* see if we can merge the load and the "if" */ @@ -617,9 +695,9 @@ do_if(char *sp) ** function 's return type is. */ if (ftbl->flags & TFL_PUTS) { - LV (FT_IF_S, 0); + LV(FT_IF_S, 0); } else { - LV (FT_IF_V_NE, 0); + LV(FT_IF_V_NE, 0); } } } else { @@ -628,7 +706,7 @@ do_if(char *sp) } fexpr = fp; /* loc of [ELS]IF */ - cp = compile (cp); /* compile IF TRUE stmts */ + cp = compile(cp); /* compile IF TRUE stmts */ if (fif) fif->f_skip = next_fp - fif; @@ -639,7 +717,7 @@ do_if(char *sp) fexpr = (struct format *)NULL;/* no extra ENDIF */ - cp = compile (cp); /* compile ELSE stmts */ + cp = compile(cp); /* compile ELSE stmts */ fif->f_skip = next_fp - fif; c = *cp++; } else if (c == '?') { /* another ELSIF */