]> diplodocus.org Git - nmh/blobdiff - sbr/fmt_compile.c
Use RFC 2047 encoding for Content-Description, and make sure to encode
[nmh] / sbr / fmt_compile.c
index 27f1a1ed3003088383daf741201a33a3c293bb20..970e71e5abd3d489bd7f66ff765c32b37670bcd8 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.
  *
@@ -47,6 +47,7 @@
 #include <h/fmt_scan.h>
 #include <h/fmt_compile.h>
 #include <h/mts.h>
+#include <h/utils.h>
 
 #ifdef HAVE_SYS_TIME_H
 # include <sys/time.h>
@@ -81,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
@@ -99,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.
@@ -211,13 +221,48 @@ static struct ftable functable[] = {
      { "friendly",   TF_COMP,  FT_LS_FRIENDLY, FT_PARSEADDR,   TFL_PUTS },
 
      { "mymbox",     TF_COMP,  FT_LV_COMPFLAG, FT_MYMBOX,      TFL_PUTN },
-     { "addtoseq",   TF_STR,   FT_ADDTOSEQ,    0,              0 },
 
-     { "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
@@ -239,6 +284,7 @@ static struct ftable functable[] = {
 #define NEWCOMP(cm,name) do { \
        cm = ((struct comp *) calloc(1, sizeof (struct comp)));\
        cm->c_name = getcpy(name);\
+       cm->c_refcount++;\
        ncomp++;\
        i = CHASH(name);\
        cm->c_next = wantcomp[i];\
@@ -262,14 +308,14 @@ static struct ftable functable[] = {
        } 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 = (str); fp->f_flags |= FF_STRALLOC; } while (0)
+#define LS(type, str)          do { NEW(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); } 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)
 
 static char *format_string;
-static unsigned char *usr_fstring;     /* for CERROR */
+static char *usr_fstring;      /* for CERROR */
 
 #define CERROR(str) compile_error (str, cp)
 
@@ -288,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
  */
@@ -319,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] = '_';
     }
 
@@ -353,10 +394,6 @@ fmt_compile(char *fstring, struct format **fmt, int reset_comptable)
        comptable_initialized = 1;
     }
 
-    /* init the component hash table. */
-    for (i = 0; i < sizeof(wantcomp)/sizeof(wantcomp[0]); i++)
-       wantcomp[i] = 0;
-
     memset((char *) &fmt_mnull, 0, sizeof(fmt_mnull));
 
     /* it takes at least 4 char to generate one format so we
@@ -372,7 +409,6 @@ fmt_compile(char *fstring, struct format **fmt, int reset_comptable)
     if (next_fp == NULL)
        adios (NULL, "unable to allocate format storage");
 
-    ncomp = 0;
     infunction = 0;
 
     cp = compile(format_string);
@@ -636,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;
@@ -851,6 +943,7 @@ fmt_free(struct format *fmt, int reset_comptable)
                free(fp->f_text);
            if (fp->f_flags & FF_COMPREF)
                free_component(fp->f_comp);
+           fp++;
        }
        free(fmt);
     }
@@ -859,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.
@@ -874,6 +985,108 @@ fmt_findcomp(char *component)
     return cm;
 }
 
+/*
+ * Like fmt_findcomp, but case-insensitive.
+ */
+
+struct comp *
+fmt_findcasecomp(char *component)
+{
+    struct comp *cm;
+
+    for (cm = wantcomp[CHASH(component)]; cm; cm = cm->c_next)
+       if (strcasecmp(component, cm->c_name ? cm->c_name : "") == 0)
+           break;
+
+    return cm;
+}
+
+/*
+ * Add an entry to the component hash table
+ *
+ * Returns true if the component was added, 0 if it already existed.
+ *
+ */
+
+int
+fmt_addcompentry(char *component)
+{
+    struct comp *cm;
+    int i;
+
+    FINDCOMP(cm, component);
+
+    if (cm)
+       return 0;
+
+    NEWCOMP(cm, component);
+
+    /*
+     * ncomp is really meant for fmt_compile() and this function is
+     * meant to be used outside of it.  So decrement it just to be safe
+     * (internal callers should be using NEWCOMP()).
+     */
+
+    ncomp--;
+
+    return 1;
+}
+
+/*
+ * Add a string to a component hash table entry.
+ *
+ * Note the special handling for components marked with CT_ADDR.  The comments
+ * in fmt_scan.h explain this in more detail.
+ */
+
+int
+fmt_addcomptext(char *component, char *text)
+{
+    int i, found = 0, bucket = CHASH(component);
+    struct comp *cptr = wantcomp[bucket];
+    char *cp;
+
+    while (cptr) {
+       if (strcasecmp(component, cptr->c_name ? cptr->c_name : "") == 0) {
+           found++;
+           if (! cptr->c_text) {
+               cptr->c_text = getcpy(text);
+           } else {
+               i = strlen(cp = cptr->c_text) - 1;
+               if (cp[i] == '\n') {
+                   if (cptr->c_type & CT_ADDR) {
+                       cp[i] = '\0';
+                       cp = add(",\n\t", cp);
+                   } else {
+                       cp = add("\t", cp);
+                   }
+               }
+               cptr->c_text = add(text, cp);
+           }
+       }
+       cptr = cptr->c_next;
+    }
+
+    return found ? bucket : -1;
+}
+
+/*
+ * Append text to a component we've already found.  See notes in fmt_scan.h
+ * for more information.
+ */
+
+void
+fmt_appendcomp(int bucket, char *component, char *text)
+{
+    struct comp *cptr;
+
+    if (bucket != -1) {
+       for (cptr = wantcomp[bucket]; cptr; cptr = cptr->c_next)
+           if (strcasecmp(component, cptr->c_name ? cptr->c_name : "") == 0)
+               cptr->c_text = add(text, cptr->c_text);
+    }
+}
+
 /*
  * Free and reset our component hash table
  */
@@ -881,7 +1094,7 @@ fmt_findcomp(char *component)
 static void
 free_comptable(void)
 {
-    int i;
+    unsigned int i;
     struct comp *cm, *cm2;
 
     for (i = 0; i < sizeof(wantcomp)/sizeof(wantcomp[0]); i++) {
@@ -893,6 +1106,8 @@ free_comptable(void)
        }
        wantcomp[i] = 0;
     }
+
+    ncomp = 0;
 }
 
 /*