-ssize_t m_strformat(char *dst, ssize_t dlen, int width, const char *fmt,
- format_t *callback, anytype cdata, format_flag flags)
-{
- ssize_t pos = flags & M_FORMAT_ARROWCURSOR ? 3 : 0;
-
- m_strpad(dst, dlen, '\0', pos + 1);
- if (!fmt)
- return pos;
-
- while (*fmt) {
- int ch;
-
- if (*fmt == '%') {
- char ifstr[STRING], elstr[STRING], prefix[STRING];
-
- *ifstr = *elstr = *prefix = '\0';
-
- if (*++fmt == '%') {
- pos += m_strputc(dst + pos, dlen - pos, *fmt++);
- continue;
- }
-
- if (*fmt == '?') {
- flags |= M_FORMAT_OPTIONAL;
- fmt++;
- } else {
- ssize_t pfxlen;
- flags &= ~M_FORMAT_OPTIONAL;
-
- /* eat the format string */
- pfxlen = strspn(fmt, "0123456789.-");
- m_strncpy(prefix, sizeof(prefix), fmt, pfxlen);
- fmt += pfxlen;
- }
-
- /* save the character to switch on */
- if (!(ch = *fmt++))
- break;
-
- if (flags & M_FORMAT_OPTIONAL) {
- ssize_t iflen;
- const char *p;
-
- if (*fmt++ != '?')
- break; /* bad format */
-
- /* eat the `if' part of the string */
- iflen = strcspn(fmt, "?&");
- m_strncpy(ifstr, ssizeof(ifstr), fmt, iflen);
- fmt += iflen;
-
- /* eat the `else' part of the string (optional) */
- if (*fmt == '&')
- fmt++; /* skip the & */
-
- p = m_strchrnul(fmt, '?');
- m_strncpy(elstr, ssizeof(elstr), fmt, p - fmt);
- fmt = p;
-
- if (!*fmt++) /* move past the trailing `?' */
- break; /* bad format */
- }
-
- switch (ch) {
- char lower, nodots, buf[LONG_STRING];
-
- case '>': /* right justify to EOL */
- width -= mutt_strwidth(dst);
-
- ch = *fmt++; /* pad char */
-
- if (width > 0) {
- m_strformat(buf, sizeof(buf), 0, fmt, callback, cdata, flags);
- width -= mutt_strwidth(buf);
- pos += m_strpad(dst + pos, dlen - pos, ch, width);
- pos += m_strcpy(dst + pos, dlen - pos, buf);
- }
- return pos; /* skip rest of input */
-
- case '|': /* pad to EOL */
- width -= mutt_strwidth(dst);
- return pos + m_strpad(dst + pos, dlen - pos, *fmt, width);
-
- 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,
- ifstr, elstr, cdata, 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);
- break;
- }
- continue;
- }
-
- if (*fmt == '\\') {
- if (!*++fmt)
- break;
- switch ((ch = *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, ch); break;
- }
- } else {
- ssize_t len = strcspn(fmt, "%\\");
-
- pos += m_strncpy(dst + pos, dlen - pos, fmt, len);
- fmt += len;
- }
- }
-
- return pos;
-}
-