X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/a6af8ec9d9c78f7a74b93814fb6031f98496ed50..a0250745de00aacfe03f82bdcc7e5e86f0768dd7:/sbr/fmt_compile.c?ds=sidebyside diff --git a/sbr/fmt_compile.c b/sbr/fmt_compile.c index 4afe0c7d..c8618ed8 100644 --- a/sbr/fmt_compile.c +++ b/sbr/fmt_compile.c @@ -49,8 +49,6 @@ #include #include -#include - #ifdef HAVE_SYS_TIME_H # include #endif @@ -68,10 +66,6 @@ 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 termstatus = 0; /* 0=uninit,1=ok,-1=fail */ -static char *termcbuf = NULL; /* Capability output str */ -static char *termcbufp = NULL; /* Capability buf ptr */ -static size_t termcbufsz = 0; /* Size of termcbuf */ extern struct mailname fmt_mnull; @@ -90,7 +84,11 @@ extern struct mailname fmt_mnull; #define TF_LMBOX 11 /* special - get full local mailbox */ #define TF_BOLD 12 /* special - enter terminal bold mode */ #define TF_UNDERLN 13 /* special - enter underline mode */ -#define TF_RESET 14 /* special - reset terminal modes */ +#define TF_STNDOUT 14 /* special - enter underline mode */ +#define TF_RESET 15 /* special - reset terminal modes */ +#define TF_HASCLR 16 /* special - terminal have color? */ +#define TF_FGCOLR 17 /* special - foreground term color */ +#define TF_BGCOLR 18 /* special - background term color */ /* ftable->flags */ /* NB that TFL_PUTS is also used to decide whether the test @@ -109,7 +107,9 @@ extern struct mailname fmt_mnull; * 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). + * placed in the format instruction (the f_un union). Also, + * instructions that require special handling are distinguished + * here (TF_MYMBOX is one example). * 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. @@ -159,6 +159,8 @@ static struct ftable functable[] = { { "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 }, + { "kilo", TF_EXPR, FT_LS_KILO, 0, TFL_PUTS }, + { "kibi", TF_EXPR, FT_LS_KIBI, 0, TFL_PUTS }, { "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 }, @@ -175,6 +177,7 @@ static struct ftable functable[] = { { "localmbox", TF_LMBOX, 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 }, + { "multiply", TF_NUM, FT_LV_MULTIPLY_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 }, @@ -221,23 +224,59 @@ static struct ftable functable[] = { { "friendly", TF_COMP, FT_LS_FRIENDLY, FT_PARSEADDR, TFL_PUTS }, { "mymbox", TF_COMP, FT_LV_COMPFLAG, FT_MYMBOX, TFL_PUTN }, + { "getmymbox", TF_COMP, FT_STR, FT_GETMYMBOX, 0 }, + { "getmyaddr", TF_COMP, FT_LS_ADDR, FT_GETMYADDR, TFL_PUTS }, { "unquote", TF_EXPR, FT_LS_UNQUOTE, 0, TFL_PUTS }, { "bold", TF_BOLD, FT_LS_LIT, 0, TFL_PUTS }, { "underline", TF_UNDERLN,FT_LS_LIT, 0, TFL_PUTS }, + { "standout", TF_STNDOUT,FT_LS_LIT, 0, TFL_PUTS }, { "resetterm", TF_RESET, FT_LS_LIT, 0, TFL_PUTS }, + { "hascolor", TF_HASCLR, FT_LV_LIT, 0, 0 }, + { "fgcolor", TF_FGCOLR, FT_LS_LIT, 0, TFL_PUTS }, + { "bgcolor", TF_BGCOLR, FT_LS_LIT, 0, TFL_PUTS }, { NULL, 0, 0, 0, 0 } }; -/* - * Hash function for component name. The function should be - * case independent and probably shouldn't involve a routine - * call. This function is pretty good but will not work on - * single character component names. +/* + * A mapping of color names to terminfo color numbers. + * + * There are two sets of terminal-setting codes: 'setaf/setab' (ANSI) and + * 'setf/setb'. Different terminals support different capabilities, so + * we provide a mapping for both. I'm not crazy about putting numbers + * directly in here, but it seems these are well defined by terminfo + * so it should be okay. */ -#define CHASH(nm) (((((nm)[0]) - ((nm)[1])) & 0x1f) + (((nm)[2]) & 0x5f)) + +struct colormap { + char *colorname; /* Name of color */ + int ansinum; /* The ANSI escape color number */ + int nonansinum; /* The non-ANSI escape color number */ +}; + +static struct colormap colortable[] = { + { "black", 0, 0 }, + { "red", 1, 4 }, + { "green", 2, 2 }, + { "yellow", 3, 6 }, + { "blue", 4, 1 }, + { "magenta", 5, 5 }, + { "cyan", 6, 3 }, + { "white", 7, 7 }, + { NULL, 0, 0 } +}; + +/* Hash function for component name. Deliberately avoids a function + * call. Is case independent. Covers interval [0, 126] so never uses + * the last element of wantcomp[]. This function is "pretty good". */ +#define CHASH(nm) ( \ + (( \ + ((nm)[0]) - ((nm)[0] ? ((nm)[1]) : 0) \ + ) & 0x1f) + \ + ((nm[1]) ? (((nm)[2]) & 0x5f) : 0) \ + ) /* * Find a component in the hash table. @@ -250,8 +289,8 @@ static struct ftable functable[] = { /* Add new component to the hash table */ #define NEWCOMP(cm,name) do { \ - cm = ((struct comp *) calloc(1, sizeof (struct comp)));\ - cm->c_name = getcpy(name);\ + NEW0(cm);\ + cm->c_name = mh_xstrdup(name);\ cm->c_refcount++;\ ncomp++;\ i = CHASH(name);\ @@ -260,7 +299,7 @@ static struct ftable functable[] = { } while (0) #define NEWFMT (next_fp++) -#define NEW(type,fill,wid) do {\ +#define NEW_FP(type,fill,wid) do {\ fp=NEWFMT; fp->f_type=(type); fp->f_fill=(fill); fp->f_width=(wid); \ } while (0) @@ -275,12 +314,12 @@ static struct ftable functable[] = { cm->c_refcount++; \ } 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 = getcpy(str); fp->f_flags |= FF_STRALLOC; } while (0) +#define LV(type, value) do { NEW_FP(type,0,0); fp->f_value = (value); } while (0) +#define LS(type, str) do { NEW_FP(type,0,0); fp->f_text = getcpy(str); fp->f_flags |= FF_STRALLOC; } 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 = getcpy(str); fp->f_flags |= FF_STRALLOC; } while (0) -#define PUTC(c) do { NEW(FT_CHAR,0,0); fp->f_char = (c); } while (0) +#define PUTCOMP(comp) do { NEW_FP(FT_COMP,0,0); ADDC(comp); } while (0) +#define PUTLIT(str) do { NEW_FP(FT_LIT,0,0); fp->f_text = getcpy(str); fp->f_flags |= FF_STRALLOC; } while (0) +#define PUTC(c) do { NEW_FP(FT_CHAR,0,0); fp->f_char = (c); } while (0) static char *format_string; static char *usr_fstring; /* for CERROR */ @@ -301,9 +340,6 @@ static char *do_loop(char *); static char *do_if(char *); static void free_component(struct comp *); static void free_comptable(void); -static void initialize_terminfo(void); -static void get_term_stringcap(struct ftable *, char *); -static int termbytes(int); /* * Lookup a function name in the functable @@ -311,9 +347,9 @@ static int termbytes(int); 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) @@ -335,11 +371,7 @@ compile_error(char *str, char *cp) usr_fstring[errpos] = '\0'; for (i = errpos-errctx; i < errpos; i++) { -#ifdef LOCALE if (iscntrl((unsigned char) usr_fstring[i])) -#else - if (usr_fstring[i] < 32) -#endif usr_fstring[i] = '_'; } @@ -357,11 +389,11 @@ compile_error(char *str, char *cp) int fmt_compile(char *fstring, struct format **fmt, int reset_comptable) { - register char *cp; + char *cp; size_t i; static int comptable_initialized = 0; - format_string = getcpy (fstring); + format_string = mh_xstrdup(fstring); usr_fstring = fstring; if (reset_comptable || !comptable_initialized) { @@ -369,8 +401,6 @@ fmt_compile(char *fstring, struct format **fmt, int reset_comptable) comptable_initialized = 1; } - 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 @@ -379,11 +409,7 @@ fmt_compile(char *fstring, struct format **fmt, int reset_comptable) */ 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"); - + next_fp = formatvec = mh_xcalloc(i, sizeof *next_fp); infunction = 0; cp = compile(format_string); @@ -400,8 +426,8 @@ fmt_compile(char *fstring, struct format **fmt, int reset_comptable) static char * compile (char *sp) { - register char *cp = sp; - register int c; + char *cp = sp; + int c; for (;;) { sp = cp; @@ -461,13 +487,13 @@ compile (char *sp) static char * do_spec(char *sp) { - register char *cp = sp; - register int c; + char *cp = sp; + int c; #ifndef lint - register int ljust = 0; + int ljust = 0; #endif /* not lint */ - register int wid = 0; - register char fill = ' '; + int wid = 0; + char fill = ' '; c = *cp++; if (c == '-') { @@ -517,9 +543,9 @@ do_spec(char *sp) 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 == '_') @@ -535,14 +561,19 @@ 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)); + if (cm->c_tws) { + memset (cm->c_tws, 0, sizeof *cm->c_tws); + } else { + NEW0(cm->c_tws); + } fp->f_type = preprocess; PUTCOMP(sp); cm->c_type |= CT_DATE; break; case FT_MYMBOX: + case FT_GETMYMBOX: + case FT_GETMYADDR: if (!primed) { ismymbox ((struct mailname *) 0); primed++; @@ -575,10 +606,10 @@ do_name(char *sp, int preprocess) 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++; @@ -648,16 +679,60 @@ do_func(char *sp) break; case TF_BOLD: - get_term_stringcap(t, "bold"); + LS(t->f_type, get_term_stringcap("bold")); break; case TF_UNDERLN: - get_term_stringcap(t, "smul"); + LS(t->f_type, get_term_stringcap("smul")); + break; + + case TF_STNDOUT: + LS(t->f_type, get_term_stringcap("smso")); break; case TF_RESET: - get_term_stringcap(t, "sgr0"); + LS(t->f_type, get_term_stringcap("sgr0")); + break; + + case TF_HASCLR: + LV(t->f_type, get_term_numcap("colors") > 1); + break; + + case TF_FGCOLR: + case TF_BGCOLR: { + struct colormap *cmap = colortable; + char *code; + + sp = cp - 1; + while (c && c != ')') + c = *cp++; + cp[-1] = '\0'; + + while (cmap->colorname != NULL) { + if (strcasecmp(sp, cmap->colorname) == 0) + break; + cmap++; + } + + if (cmap->colorname == NULL) { + CERROR("Unknown color name"); + break; + } + + code = get_term_stringparm(t->type == TF_FGCOLR ? "setaf" : "setab", + cmap->ansinum, 0); + + /* + * If this doesn't have anything, try falling back to setf/setb + */ + + if (! code) + code = get_term_stringparm(t->type == TF_FGCOLR ? "setf" : "setb", + cmap->nonansinum, 0); + + LS(t->f_type, code); break; + } case TF_NOW: LV(t->f_type, time((time_t *) 0)); @@ -695,8 +770,8 @@ do_func(char *sp) static char * 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); @@ -756,7 +831,7 @@ do_expr (char *sp, int preprocess) static char * do_loop(char *sp) { - register char *cp = sp; + char *cp = sp; struct format *floop; floop = next_fp; @@ -780,10 +855,10 @@ do_loop(char *sp) static char * do_if(char *sp) { - register char *cp = sp; - register struct format *fexpr, + char *cp = sp; + struct format *fexpr, *fif = (struct format *)NULL; - register int c = '<'; + int c = '<'; for (;;) { if (c == '<') { /* doing an IF */ @@ -894,11 +969,10 @@ fmt_freecomptext(void) struct comp *cm; for (i = 0; i < sizeof(wantcomp)/sizeof(wantcomp[0]); i++) - for (cm = wantcomp[i]; cm; cm = cm->c_next) - if (cm->c_text) { - free(cm->c_text); - cm->c_text = NULL; - } + for (cm = wantcomp[i]; cm; cm = cm->c_next) { + mh_xfree(cm->c_text); + cm->c_text = NULL; + } } /* @@ -1018,6 +1092,25 @@ fmt_appendcomp(int bucket, char *component, char *text) } } +/* + * Iterate over our component hash table + */ + +struct comp * +fmt_nextcomp(struct comp *comp, unsigned int *bucket) +{ + if (comp == NULL) + *bucket = 0; + else + comp = comp->c_next; + + while (comp == NULL && *bucket < sizeof(wantcomp)/sizeof(wantcomp[0])) { + comp = wantcomp[(*bucket)++]; + } + + return comp; +} + /* * Free and reset our component hash table */ @@ -1051,10 +1144,8 @@ free_component(struct comp *cm) { if (--cm->c_refcount <= 0) { /* Shouldn't ever be NULL, but just in case ... */ - if (cm->c_name) - free(cm->c_name); - if (cm->c_text) - free(cm->c_text); + mh_xfree(cm->c_name); + mh_xfree(cm->c_text); if (cm->c_type & CT_DATE) free(cm->c_tws); if (cm->c_type & CT_ADDR && cm->c_mn && cm->c_mn != &fmt_mnull) @@ -1062,101 +1153,3 @@ free_component(struct comp *cm) free(cm); } } - -/* - * These functions handles the case of outputting terminal strings depending - * on the terminfo setting. - */ - -/* - * We should only be called if we haven't yet called setupterm() - */ - -void -initialize_terminfo(void) -{ - int errret, rc; - - rc = setupterm(NULL, fileno(stdout), &errret); - - if (rc != 0 || errret != 1) - termstatus = -1; - else - termstatus = 1; -} - -/* - * Place the results of the specified string entry into the str register. - * - * Arguments are: - * - * t - Pointer to instruction table entry (used to create fmt instruction) - * cap - Name of terminfo capability to insert (e.g., "bold", or "sgr0"). - * - * This ended up being more complicated than I hoped. You need to fetch the - * entry via tigetstr(), but there MAY be a padding format embedded in what - * gets returned by tigetstr(), so you have to run it through tputs(). - * And of course tputs() is designed to output to a terminal, so you have - * capture every byte output by the tputs() callback to get the final - * string to write to the format engine. - * - * If padding bytes are NULs that will be a problem for us, but some quick - * experimentation suggests that padding bytes are mostly a non-issue anymore. - * If they still crop up we'll have to figure out how to deal with them. - */ - -void -get_term_stringcap(struct ftable *t, char *cap) -{ - char *parm; - - /* - * Common to all functions; initialize the termcap if we need it. - * If it didn't initialize successfully, return silently - */ - - if (termstatus == 0) - initialize_terminfo(); - - if (termstatus == -1) - return; - - parm = tigetstr(cap); - - if (parm == (char *) -1 || parm == NULL) { - return; - } - - termcbufp = termcbuf; - - tputs(parm, 1, termbytes); - - termcbufp = '\0'; - - LS(t->f_type, termcbuf); -} - -/* - * Store a sequence of characters in our local buffer - */ - -static int -termbytes(int c) -{ - size_t offset; - - /* - * Bump up the buffer size if we've reached the end (leave room for - * a trailing NUL) - */ - - if ((offset = termcbufp - termcbuf) - 1 >= termcbufsz) { - termcbufsz += 64; - termcbuf = mh_xrealloc(termcbuf, termcbufsz); - termcbufp = termcbuf + offset; - } - - *termcbufp++ = c; - - return 0; -}