X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/799d60bd3ffa116dd0ee08cba1017cba3c4dbad8..cdbb097c8f061dfea2e92f0beafc64fdf50a4eb7:/sbr/fmt_compile.c diff --git a/sbr/fmt_compile.c b/sbr/fmt_compile.c index 4ae85bc9..970e71e5 100644 --- a/sbr/fmt_compile.c +++ b/sbr/fmt_compile.c @@ -49,9 +49,6 @@ #include #include -#include -#include - #ifdef HAVE_SYS_TIME_H # include #endif @@ -69,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; @@ -91,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 @@ -110,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. @@ -227,11 +226,43 @@ static struct ftable functable[] = { { "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 @@ -302,9 +333,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 @@ -336,11 +364,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] = '_'; } @@ -649,16 +673,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)); @@ -1063,101 +1131,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; -}