]> granicus.if.org Git - neomutt/commitdiff
Allow format strings to be filtered.
authorDavid Champion <dgc@uchicago.edu>
Wed, 14 Mar 2007 20:49:11 +0000 (13:49 -0700)
committerDavid Champion <dgc@uchicago.edu>
Wed, 14 Mar 2007 20:49:11 +0000 (13:49 -0700)
Any format string ending in | will be expanded and piped through the
first word in the string. The string returned will be used for
display. If the returned string ends in %, it will be passed through
the formatter a second time. This allows the filter to generate a
replacement format string including % expandos.

mutt.h
muttlib.c

diff --git a/mutt.h b/mutt.h
index 48878d2da2923052368eec71c2e94ad19d395fd5..7f4493f206878598e56c3d73c8fa9154519872ca 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -143,7 +143,8 @@ typedef enum
   M_FORMAT_OPTIONAL    = (1<<3),
   M_FORMAT_STAT_FILE   = (1<<4), /* used by mutt_attach_fmt */
   M_FORMAT_ARROWCURSOR = (1<<5), /* reserve space for arrow_cursor */
-  M_FORMAT_INDEX       = (1<<6)  /* this is a main index entry */
+  M_FORMAT_INDEX       = (1<<6), /* this is a main index entry */
+  M_FORMAT_NOFILTER    = (1<<7)  /* do not allow filtering on this pass */
 } format_flag;
 
 /* types for mutt_add_hook() */
index 8b061116ddd3311e8ad3e389585678df33341064..748bf081517ab7517ed784160d57b1cfc0cf45da 100644 (file)
--- a/muttlib.c
+++ b/muttlib.c
@@ -996,12 +996,122 @@ void mutt_FormatString (char *dest,              /* output buffer */
   char prefix[SHORT_STRING], buf[LONG_STRING], *cp, *wptr = dest, ch;
   char ifstring[SHORT_STRING], elsestring[SHORT_STRING];
   size_t wlen, count, len, col, wid;
+  pid_t pid;
+  FILE *filter;
+  int n;
+  char *recycler;
 
   prefix[0] = '\0';
   destlen--; /* save room for the terminal \0 */
   wlen = (flags & M_FORMAT_ARROWCURSOR && option (OPTARROWCURSOR)) ? 3 : 0;
   col = wlen;
-    
+
+  if ((flags & M_FORMAT_NOFILTER) == 0)
+  {
+    int off = -1;
+
+    /* Do not consider filters if no pipe at end */
+    n = mutt_strlen(src);
+    if (n > 0 && src[n-1] == '|')
+    {
+      /* Scan backwards for backslashes */
+      off = n;
+      while (off > 0 && src[off-2] == '\\')
+        off--;
+    }
+
+    /* If number of backslashes is even, the pipe is real. */
+    /* n-off is the number of backslashes. */
+    if (off > 0 && ((n-off) % 2) == 0)
+    {
+      BUFFER *srcbuf, *word, *command;
+      char    srccopy[LONG_STRING];
+      int     i = 0;
+
+      dprint(2, (debugfile, "fmtpipe = %s\n", src));
+
+      strncpy(srccopy, src, n);
+      srccopy[n-1] = '\0';
+
+      /* prepare BUFFERs */
+      srcbuf = mutt_buffer_from(NULL, srccopy);
+      srcbuf->dptr = srcbuf->data;
+      word = mutt_buffer_init(NULL);
+      command = mutt_buffer_init(NULL);
+
+      /* Iterate expansions across successive arguments */
+      do {
+        char *p;
+
+        /* Extract the command name and copy to command line */
+        dprint(2, (debugfile, "fmtpipe +++: %s\n", srcbuf->dptr));
+        if (word->data)
+          *word->data = '\0';
+        mutt_extract_token(word, srcbuf, 0);
+        dprint(2, (debugfile, "fmtpipe %2d: %s\n", i++, word->data));
+        mutt_buffer_addch(command, '\'');
+        mutt_FormatString(buf, sizeof(buf), word->data, callback, data,
+                          flags | M_FORMAT_NOFILTER);
+        for (p = buf; p && *p; p++)
+        {
+          if (*p == '\'')
+            /* shell quoting doesn't permit escaping a single quote within
+             * single-quoted material.  double-quoting instead will lead
+             * shell variable expansions, so break out of the single-quoted
+             * span, insert a double-quoted single quote, and resume. */
+            mutt_buffer_addstr(command, "'\"'\"'");
+          else
+            mutt_buffer_addch(command, *p);
+        }
+        mutt_buffer_addch(command, '\'');
+        mutt_buffer_addch(command, ' ');
+      } while (MoreArgs(srcbuf));
+
+      dprint(2, (debugfile, "fmtpipe > %s\n", command->data));
+
+      wptr = dest;      /* reset write ptr */
+      wlen = (flags & M_FORMAT_ARROWCURSOR && option (OPTARROWCURSOR)) ? 3 : 0;
+      if ((pid = mutt_create_filter(command->data, NULL, &filter, NULL)))
+      {
+        n = fread(dest, 1, destlen /* already decremented */, filter);
+        fclose(filter);
+        dest[n] = '\0';
+        dprint(2, (debugfile, "fmtpipe < %s\n", dest));
+
+        if (pid != -1)
+          mutt_wait_filter(pid);
+  
+        /* If the result ends with '%', this indicates that the filter
+         * generated %-tokens that mutt can expand.  Eliminate the '%'
+         * marker and recycle the string through mutt_FormatString().
+         * To literally end with "%", use "%%". */
+        if (dest[--n] == '%')
+        {
+          dest[n] = '\0';               /* remove '%' */
+          if (dest[--n] != '%')
+          {
+            recycler = safe_strdup(dest);
+            if (recycler)
+            {
+              mutt_FormatString(dest, destlen++, recycler, callback, data, flags);
+              safe_free(&recycler);
+            }
+          }
+        }
+      }
+      else
+      {
+        /* Filter failed; erase write buffer */
+        *wptr = '\0';
+      }
+
+      mutt_buffer_free(&command);
+      mutt_buffer_free(&srcbuf);
+      mutt_buffer_free(&word);
+      return;
+    }
+  }
+
   while (*src && wlen < destlen)
   {
     if (*src == '%')