From 3755188848d66fd8c0638ce8514fbf57aa94518f Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sat, 2 Dec 2006 20:55:57 +0100 Subject: [PATCH] fully rework mutt_FormatString, fix a lot of issues, no more stack squashing. fix bugs with pads. this is PASS1. soon, the number of columns to prepare the string for will be computed by the caller rather than the callee. enable nonliteral formats warning again, those are also meant to disappear. Signed-off-by: Pierre Habouzit --- cflags.mk | 2 +- mutt.h | 14 +-- muttlib.c | 304 +++++++++++++++++++++--------------------------------- protos.h | 4 +- 4 files changed, 129 insertions(+), 195 deletions(-) diff --git a/cflags.mk b/cflags.mk index a734def..1e4dafa 100644 --- a/cflags.mk +++ b/cflags.mk @@ -44,6 +44,6 @@ CFLAGS += -Wpointer-arith # warn about multiple declarations CFLAGS += -Wredundant-decls # warn if the format string is not a string literal -#CFLAGS += -Wformat-nonliteral +CFLAGS += -Wformat-nonliteral # missing prototypes CFLAGS += -Wmissing-prototypes diff --git a/mutt.h b/mutt.h index d43cab7..15af96a 100644 --- a/mutt.h +++ b/mutt.h @@ -32,13 +32,13 @@ typedef struct { /* flags for mutt_FormatString() */ typedef enum { - M_FORMAT_FORCESUBJ = (1 << 0), /* print the subject even if unchanged */ - M_FORMAT_TREE = (1 << 1), /* draw the thread tree */ - M_FORMAT_MAKEPRINT = (1 << 2), /* make sure that all chars are printable */ - 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_FORCESUBJ = (1 << 0), /* print the subject even if unchanged */ + M_FORMAT_TREE = (1 << 1), /* draw the thread tree */ + M_FORMAT_MAKEPRINT = (1 << 2), /* make sure that all chars are printable */ + 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 */ } format_flag; /* types for mutt_add_hook() */ diff --git a/muttlib.c b/muttlib.c index 590b53a..e56bbcd 100644 --- a/muttlib.c +++ b/muttlib.c @@ -328,209 +328,143 @@ void mutt_safe_path(char *s, ssize_t l, address_t *a) } } -void mutt_FormatString (char *dest, /* output buffer */ - ssize_t destlen, /* output buffer len */ - const char *src, /* template string */ - format_t * callback, /* callback for processing */ - unsigned long data, /* callback data */ - format_flag flags) -{ /* callback flags */ - char prefix[STRING], buf[LONG_STRING], *cp, *wptr = dest, ch; - char ifstring[STRING], elsestring[STRING]; - ssize_t wlen, wid, count, col, len; - - prefix[0] = '\0'; - destlen--; /* save room for the terminal \0 */ - wlen = (flags & M_FORMAT_ARROWCURSOR && option (OPTARROWCURSOR)) ? 3 : 0; - col = wlen; - - while (*src && wlen < destlen) { - if (*src == '%') { - if (*++src == '%') { - *wptr++ = '%'; - wlen++; - col++; - src++; - continue; - } +ssize_t +mutt_FormatString(char *dst, ssize_t dlen, const char *fmt, + format_t *callback, unsigned long data, format_flag flags) +{ + ssize_t pos = (flags & M_FORMAT_ARROWCURSOR && option (OPTARROWCURSOR)) ? 3 : 0; - if (*src == '?') { - flags |= M_FORMAT_OPTIONAL; - src++; - } - else { - flags &= ~M_FORMAT_OPTIONAL; - - /* eat the format string */ - cp = prefix; - count = 0; - while (count < ssizeof (prefix) && - (isdigit ((unsigned char) *src) || *src == '.' || *src == '-')) - { - *cp++ = *src++; - count++; - } - *cp = 0; - } + while (*fmt) { + char ifstring[STRING] = "", elsestring[STRING] = "", prefix[STRING] = ""; + int ch; - if (!*src) - break; /* bad format */ + if (*fmt == '%') { + if (*++fmt == '%') { + pos += m_strputc(dst + pos, dlen - pos, '%'); + fmt++; + continue; + } - ch = *src++; /* save the character to switch on */ + if (*fmt == '?') { + flags |= M_FORMAT_OPTIONAL; + fmt++; + } else { + ssize_t pfxlen; + flags &= ~M_FORMAT_OPTIONAL; - if (flags & M_FORMAT_OPTIONAL) { - if (*src != '?') - break; /* bad format */ - src++; + /* eat the format string */ + pfxlen = strspn(fmt, "0123456789.-"); + m_strncpy(prefix, sizeof(prefix), fmt, pfxlen); + fmt += pfxlen; + } - /* eat the `if' part of the string */ - cp = ifstring; - count = 0; - while (count < ssizeof (ifstring) && *src && *src != '?' - && *src != '&') { - *cp++ = *src++; - count++; - } - *cp = 0; - - /* eat the `else' part of the string (optional) */ - if (*src == '&') - src++; /* skip the & */ - cp = elsestring; - count = 0; - while (count < ssizeof (elsestring) && *src && *src != '?') { - *cp++ = *src++; - count++; - } - *cp = 0; + /* save the character to switch on */ + if (!(ch = *fmt++)) + break; - if (!*src) - break; /* bad format */ + if (flags & M_FORMAT_OPTIONAL) { + ssize_t iflen; + const char *p; - src++; /* move past the trailing `?' */ - } + if (*fmt++ != '?') + break; /* bad format */ - /* handle generic cases first */ - if (ch == '>') { - /* right justify to EOL */ - ch = *src++; /* pad char */ - /* calculate space left on line. if we've already written more data - than will fit on the line, ignore the rest of the line */ - if (DrawFullLine || option (OPTSTATUSONTOP)) - count = (COLS < destlen ? COLS : destlen); - else - count = ((COLS - SW) < destlen ? (COLS - SW) : destlen); - if (count > col) { - count -= col; /* how many columns left on this line */ - mutt_FormatString (buf, sizeof (buf), src, callback, data, flags); - wid = m_strlen(buf); - if (count > wid) { - count -= wid; /* how many chars to pad */ - memset (wptr, ch, count); - wptr += count; - col += count; - } - if (wid + wlen > destlen) - len = destlen - wlen; - else - len = wid; - memcpy (wptr, buf, len); - wptr += len; - wlen += len; - col += mutt_strwidth (buf); - } - break; /* skip rest of input */ - } - else if (ch == '|') { - /* pad to EOL */ - ch = *src++; - if (destlen > COLS) - destlen = COLS; - if (destlen > wlen) { - count = destlen - wlen; - memset (wptr, ch, count); - wptr += count; - } - break; /* skip rest of input */ - } - else { - short lower = 0; - short nodots = 0; + /* eat the `if' part of the string */ + iflen = strcspn(fmt, "?&"); + m_strncpy(ifstring, ssizeof(ifstring), fmt, iflen); + fmt += iflen; - while (ch == '_' || ch == ':') { - if (ch == '_') - lower = 1; - else if (ch == ':') - nodots = 1; + /* eat the `else' part of the string (optional) */ + if (*fmt == '&') + fmt++; /* skip the & */ - ch = *src++; - } + p = m_strchrnul(fmt, '?'); + m_strncpy(elsestring, ssizeof(elsestring), fmt, p - fmt); + fmt = p; + + if (!*fmt++) /* move past the trailing `?' */ + break; /* bad format */ + } + + switch (ch) { + ssize_t col; + char lower, nodots, buf[LONG_STRING]; + + case '>': /* right justify to EOL */ + col = mutt_strwidth(dst); + + ch = *fmt++; /* pad char */ + + if (COLS - SW > col) { + ssize_t wid; + + mutt_FormatString(buf, sizeof(buf), fmt, callback, data, flags); + wid = mutt_strwidth(buf); + + pos += m_strpad(dst + pos, dlen - pos, ch, COLS - SW - col - wid); + pos += m_strcpy(dst + pos, dlen - pos, buf); + } + return pos; /* skip rest of input */ - /* use callback function to handle this case */ - src = - callback (buf, sizeof (buf), ch, src, prefix, ifstring, elsestring, - data, flags); + case '|': + col = mutt_strwidth(dst); - if (lower) - m_strtolower(buf); - if (nodots) { - char *p = buf; + ch = *fmt++; + /* pad to EOL */ + pos += m_strpad(dst + pos, dlen - pos, ch, COLS - SW - col); + return pos; /* skip rest of input */ - for (; *p; p++) - if (*p == '.') - *p = '_'; + default: + lower = nodots = 0; + + while (ch == '_' || ch == ':') { + lower |= ch == '_'; + nodots |= ch == ':'; + ch = *fmt++; + } + + /* use callback function to handle this case */ + fmt = callback(buf, sizeof (buf), ch, fmt, prefix, + ifstring, elsestring, data, flags); + + if (lower) + m_strtolower(buf); + + if (nodots) { + char *p; + + for (p = buf; *p; p++) { + if (*p == '.') + *p = '_'; + } + } + + pos += m_strcpy(dst + pos, dlen - pos, buf); + continue; + } } - if ((len = m_strlen(buf)) + wlen > destlen) - len = (destlen - wlen > 0) ? (destlen - wlen) : 0; + if (*fmt == '\\') { + if (!*++fmt) + break; + switch (*fmt) { + case 'n': pos += m_strputc(dst + pos, dlen - pos, '\n'); break; + case 't': pos += m_strputc(dst + pos, dlen - pos, '\t'); break; + case 'r': pos += m_strputc(dst + pos, dlen - pos, '\r'); break; + case 'f': pos += m_strputc(dst + pos, dlen - pos, '\f'); break; + case 'v': pos += m_strputc(dst + pos, dlen - pos, '\v'); break; + default: pos += m_strputc(dst + pos, dlen - pos, *fmt); break; + } + fmt++; + } else { + ssize_t len = strcspn(fmt, "%\\"); - memcpy (wptr, buf, len); - wptr += len; - wlen += len; - col += mutt_strwidth (buf); - } - } - else if (*src == '\\') { - if (!*++src) - break; - switch (*src) { - case 'n': - *wptr = '\n'; - break; - case 't': - *wptr = '\t'; - break; - case 'r': - *wptr = '\r'; - break; - case 'f': - *wptr = '\f'; - break; - case 'v': - *wptr = '\v'; - break; - default: - *wptr = *src; - break; - } - src++; - wptr++; - wlen++; - col++; + pos += m_strncpy(dst + pos, dlen - pos, fmt, len); + fmt += len; + } } - else { - unsigned int bar = strcspn(src, "%\\"); - char *bar2 = p_dupstr(src, bar); - while (bar--) { - *wptr++ = *src++; - wlen++; - } - col += mutt_strwidth (bar2); - p_delete(&bar2); - } - } - *wptr = 0; + return pos; } /* returns 0 if OK to proceed, -1 to abort, 1 to retry */ diff --git a/protos.h b/protos.h index 4fd3c00..a989214 100644 --- a/protos.h +++ b/protos.h @@ -18,8 +18,8 @@ typedef const char *format_t (char *, ssize_t, char, const char *, const char *, const char *, const char *, unsigned long, format_flag); -void mutt_FormatString (char *, ssize_t, const char *, format_t *, - unsigned long, format_flag); +ssize_t mutt_FormatString(char *, ssize_t, const char *, format_t *, + unsigned long, format_flag); void set_quadoption (int, int); int query_quadoption (int, const char *); -- 2.20.1