]> diplodocus.org Git - nmh/commitdiff
Add support for outputing a few (limited) terminal attributes in format
authorKen Hornstein <kenh@pobox.com>
Tue, 31 Dec 2013 20:20:22 +0000 (15:20 -0500)
committerKen Hornstein <kenh@pobox.com>
Tue, 31 Dec 2013 20:20:22 +0000 (15:20 -0500)
sequences.  Needs documentation and some expansion.

Makefile.am
etc/scan.curses [new file with mode: 0644]
sbr/fmt_compile.c

index 20532ea..564a1ba 100644 (file)
@@ -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 (file)
index 0000000..67518ac
--- /dev/null
@@ -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))
index 23e0726..4afe0c7 100644 (file)
@@ -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 <h/mts.h>
 #include <h/utils.h>
 
+#include <term.h>
+
 #ifdef HAVE_SYS_TIME_H
 # include <sys/time.h>
 #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;
+}