From: David Champion <dgc@bikeshed.us> Date: Wed, 14 Mar 2007 20:49:11 +0000 (-0700) Subject: Allow format strings to be filtered. X-Git-Tag: mutt-1-5-15-rel~47^2~18^2~24 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=963606e2ae2026483d0ad90ccdbbb7cb8e65791c;p=mutt Allow format strings to be filtered. 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. --- diff --git a/mutt.h b/mutt.h index 48878d2d..7f4493f2 100644 --- 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() */ diff --git a/muttlib.c b/muttlib.c index 8b061116..748bf081 100644 --- 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 == '%')