From: Ken Hornstein Date: Tue, 31 Dec 2013 20:20:22 +0000 (-0500) Subject: Add support for outputing a few (limited) terminal attributes in format X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/a6af8ec9d9c78f7a74b93814fb6031f98496ed50?hp=253f3a96f00470bfc69ec3c5978bd152b708c255 Add support for outputing a few (limited) terminal attributes in format sequences. Needs documentation and some expansion. --- diff --git a/Makefile.am b/Makefile.am index 20532ea9..564a1ba1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -285,11 +285,11 @@ uip_burst_LDADD = $(LDADD) $(POSTLINK) uip_comp_SOURCES = uip/comp.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \ uip/annosbr.c uip/distsbr.c -uip_comp_LDADD = $(LDADD) $(ICONVLIB) $(READLINELIB) $(POSTLINK) +uip_comp_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(READLINELIB) $(POSTLINK) uip_dist_SOURCES = uip/dist.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \ uip/annosbr.c uip/distsbr.c uip/forwsbr.c -uip_dist_LDADD = $(LDADD) $(ICONVLIB) $(READLINELIB) $(POSTLINK) +uip_dist_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(READLINELIB) $(POSTLINK) uip_flist_SOURCES = uip/flist.c uip_flist_LDADD = $(LDADD) $(POSTLINK) @@ -299,7 +299,7 @@ uip_folder_LDADD = $(LDADD) $(POSTLINK) uip_forw_SOURCES = uip/forw.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \ uip/annosbr.c uip/distsbr.c uip/forwsbr.c -uip_forw_LDADD = $(LDADD) $(ICONVLIB) $(READLINELIB) $(POSTLINK) +uip_forw_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(READLINELIB) $(POSTLINK) uip_inc_SOURCES = uip/inc.c uip/scansbr.c uip/dropsbr.c uip/termsbr.c \ uip/popsbr.c @@ -372,7 +372,7 @@ uip_refile_LDADD = $(LDADD) $(POSTLINK) uip_repl_SOURCES = uip/repl.c uip/replsbr.c uip/whatnowproc.c \ uip/whatnowsbr.c uip/sendsbr.c uip/annosbr.c uip/distsbr.c -uip_repl_LDADD = $(LDADD) $(ICONVLIB) $(READLINELIB) $(POSTLINK) +uip_repl_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(READLINELIB) $(POSTLINK) uip_rmf_SOURCES = uip/rmf.c uip_rmf_LDADD = $(LDADD) $(POSTLINK) @@ -413,7 +413,7 @@ uip_dp_SOURCES = uip/dp.c uip/termsbr.c uip_dp_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK) uip_fmtdump_SOURCES = uip/fmtdump.c -uip_fmtdump_LDADD = $(LDADD) $(ICONVLIB) $(POSTLINK) +uip_fmtdump_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK) uip_fmttest_SOURCES = uip/fmttest.c uip/termsbr.c uip_fmttest_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK) @@ -430,7 +430,7 @@ uip_post_SOURCES = uip/post.c uip/aliasbr.c uip_post_LDADD = mts/libmts.a $(LDADD) $(SASLLIB) $(TLSLIB) $(POSTLINK) uip_rcvdist_SOURCES = uip/rcvdist.c uip/distsbr.c -uip_rcvdist_LDADD = $(LDADD) $(ICONVLIB) $(POSTLINK) +uip_rcvdist_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK) uip_rcvpack_SOURCES = uip/rcvpack.c uip/dropsbr.c uip_rcvpack_LDADD = $(LDADD) $(POSTLINK) diff --git a/etc/scan.curses b/etc/scan.curses new file mode 100644 index 00000000..67518ac9 --- /dev/null +++ b/etc/scan.curses @@ -0,0 +1,51 @@ +%; scan.curses +%; +%; This file shows how to use function escapes to enable hilighting +%; sequences for terminals that have the appropriate entries in their +%; termcap/terminfo files. Also it goes into more detail on exactly +%; what each line does. +%; +%; See mh-format(5) for more information on these function escapes. +%; +%; +%; First, test to see if this is the current message. If it is, then +%; output the bold sequence for this terminal. We use %(zputlit) so the +%; characters we output don't count against the terminal width. +%; +%<(cur)%(zputlit(bold))%>\ +%; +%; If it's unseen, mark it with an underline +%; +%<(unseen)%(zputlit(underline))%>\ +%; +%; Next, output the message number. We print it out using 4 digits, right- +%; justified, padding with spaces. +%; +%4(msg)\ +%; +%; If it's the current message, output a '+' in the next column, otherwise +%; a space. Also use '-' if it's got a "Replied" header and 'E' if it's +%; encrypted (not currently supported) +%; +%<(cur)+%| %>%<{replied}-%?{encrypted}E%| %>\ +%; +%; Output the date, but mark it with a '*' if it's missing and was synthesized. +%; Note the use of 02 to make sure the date is padded with a leading zero. +%; +%02(mon{date})/%02(mday{date})%<{date} %|*%>\ +%; +%; If the message is from me, print out who the message was sent to. +%; Otherwise, print out who it was from. +%<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>\ +%<(zero)%17(decode(friendly{from}))%> \ +%; +%; Print out the subject and any of th mesage body that will fit on the +%; rest of the line. After that, print the terminal reset code to reset +%; all of the attributes to the next line. +%; +%; There's actually special handling in the format engine that will output +%; any data specified with %(zputlit) even if you've exceeded the column +%; width, so it's safe to put any reset characters at the end; they'll +%; still be output. +%; +%(decode{subject})%<{body}<<%{body}>>%>%(zputlit(resetterm)) diff --git a/sbr/fmt_compile.c b/sbr/fmt_compile.c index 23e07263..4afe0c7d 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. * @@ -49,6 +49,8 @@ #include #include +#include + #ifdef HAVE_SYS_TIME_H # include #endif @@ -66,6 +68,10 @@ 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; @@ -82,6 +88,9 @@ 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_RESET 14 /* special - reset terminal modes */ /* ftable->flags */ /* NB that TFL_PUTS is also used to decide whether the test @@ -213,7 +222,11 @@ 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 }, + { "resetterm", TF_RESET, FT_LS_LIT, 0, TFL_PUTS }, { NULL, 0, 0, 0, 0 } }; @@ -288,7 +301,9 @@ 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 @@ -632,6 +647,18 @@ do_func(char *sp) LS(t->f_type, getlocalmbox()); break; + case TF_BOLD: + get_term_stringcap(t, "bold"); + break; + + case TF_UNDERLN: + get_term_stringcap(t, "smul"); + break; + + case TF_RESET: + get_term_stringcap(t, "sgr0"); + break; + case TF_NOW: LV(t->f_type, time((time_t *) 0)); break; @@ -1035,3 +1062,101 @@ 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; +}