X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/567646c8da4264d87bb75332789cb457cd105a42..cdbb097c8f061dfea2e92f0beafc64fdf50a4eb7:/sbr/fmt_compile.c?ds=inline diff --git a/sbr/fmt_compile.c b/sbr/fmt_compile.c index 437c811c..970e71e5 100644 --- a/sbr/fmt_compile.c +++ b/sbr/fmt_compile.c @@ -16,7 +16,7 @@ * 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. + * generated by a format string can be seem with the nmh fmttest utility. * * A list of format instructions can be found in fmt_compile.h. * @@ -35,7 +35,7 @@ * * - Add the code in fmt_scan.c to handle your new function. * - * - Add code to fmtdump.c to display your new function. + * - Add code to fmttest.c to display your new function. * * - Document the new function in the mh-format(5) man page. * @@ -82,6 +82,13 @@ extern struct mailname fmt_mnull; #define TF_MYNAME 9 /* special - get current name of user */ #define TF_MYHOST 10 /* special - get "local" hostname */ #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_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 @@ -100,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. @@ -213,11 +222,47 @@ static struct ftable functable[] = { { "mymbox", TF_COMP, FT_LV_COMPFLAG, FT_MYMBOX, TFL_PUTN }, - { "unquote", TF_EXPR, FT_LS_UNQUOTE, 0, 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 } }; +/* + * 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. + */ + +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. The function should be * case independent and probably shouldn't involve a routine @@ -270,7 +315,7 @@ static struct ftable functable[] = { #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 char *usr_fstring; /* for CERROR */ #define CERROR(str) compile_error (str, cp) @@ -289,7 +334,6 @@ static char *do_if(char *); static void free_component(struct comp *); static void free_comptable(void); - /* * Lookup a function name in the functable */ @@ -320,11 +364,7 @@ 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 + if (iscntrl((unsigned char) usr_fstring[i])) usr_fstring[i] = '_'; } @@ -632,6 +672,62 @@ do_func(char *sp) LS(t->f_type, getlocalmbox()); break; + case TF_BOLD: + LS(t->f_type, get_term_stringcap("bold")); + break; + + case TF_UNDERLN: + LS(t->f_type, get_term_stringcap("smul")); + break; + + case TF_STNDOUT: + LS(t->f_type, get_term_stringcap("smso")); + break; + + case TF_RESET: + 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)); break; @@ -856,6 +952,24 @@ fmt_free(struct format *fmt, int reset_comptable) free_comptable(); } +/* + * Free just the text strings from all of the component hash table entries + */ + +void +fmt_freecomptext(void) +{ + unsigned int i; + 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; + } +} + /* * Find a component in our hash table. This is just a public interface to * the FINDCOMP macro, so we don't have to expose our hash table. @@ -881,7 +995,7 @@ fmt_findcasecomp(char *component) struct comp *cm; for (cm = wantcomp[CHASH(component)]; cm; cm = cm->c_next) - if (mh_strcasecmp(component, cm->c_name) == 0) + if (strcasecmp(component, cm->c_name ? cm->c_name : "") == 0) break; return cm; @@ -933,18 +1047,18 @@ fmt_addcomptext(char *component, char *text) char *cp; while (cptr) { - if (mh_strcasecmp(component, cptr->c_name) == 0) { + if (strcasecmp(component, cptr->c_name ? cptr->c_name : "") == 0) { found++; if (! cptr->c_text) { - cptr->c_text = getcpy(text); + cptr->c_text = getcpy(text); } else { - i = strlen(cp = cptr->c_text) - 1; + i = strlen(cp = cptr->c_text) - 1; if (cp[i] == '\n') { if (cptr->c_type & CT_ADDR) { - cp[i] = '\0'; + cp[i] = '\0'; cp = add(",\n\t", cp); } else { - cp = add("\t", cp); + cp = add("\t", cp); } } cptr->c_text = add(text, cp); @@ -968,7 +1082,7 @@ fmt_appendcomp(int bucket, char *component, char *text) if (bucket != -1) { for (cptr = wantcomp[bucket]; cptr; cptr = cptr->c_next) - if (mh_strcasecmp(component, cptr->c_name) == 0) + if (strcasecmp(component, cptr->c_name ? cptr->c_name : "") == 0) cptr->c_text = add(text, cptr->c_text); } }