X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/e8635a8a1c577636becd53428ff290860280238f..792d7e1e:/sbr/fmt_scan.c?ds=inline diff --git a/sbr/fmt_scan.c b/sbr/fmt_scan.c index 7558eca5..1ea5e623 100644 --- a/sbr/fmt_scan.c +++ b/sbr/fmt_scan.c @@ -2,11 +2,12 @@ /* * fmt_scan.c -- format string interpretation * - * $Id$ - * * This code is Copyright (c) 2002, by the authors of nmh. See the * COPYRIGHT file in the root directory of the nmh distribution for * complete copyright information. + * + * This is the engine that processes the format instructions created by + * fmt_compile (found in fmt_compile.c). */ #include @@ -14,28 +15,19 @@ #include #include #include +#include -#ifdef TIME_WITH_SYS_TIME +#ifdef HAVE_SYS_TIME_H # include -# include -#else -# ifdef TM_IN_SYS_TIME -# include -# else -# include -# endif #endif - -#define NFMTS MAXARGS - -extern char *formataddr (); /* hook for custom address formatting */ - -#ifdef LBL -struct msgs *fmt_current_folder; /* current folder (set by main program) */ +#include +#ifdef MULTIBYTE_SUPPORT +# include +# include #endif -extern int fmt_norm; /* defined in sbr/fmt_def.c = AD_NAME */ -struct mailname fmt_mnull; +struct mailname fmt_mnull = { NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, + NULL, NULL }; /* * static prototypes @@ -56,160 +48,267 @@ match (char *str, char *sub) int c1, c2; char *s1, *s2; -#ifdef LOCALE while ((c1 = *sub)) { - c1 = (isalpha(c1) && isupper(c1)) ? tolower(c1) : c1; - while ((c2 = *str++) && c1 != ((isalpha(c2) && isupper(c2)) ? tolower(c2) : c2)) + c1 = tolower((unsigned char)c1); + while ((c2 = *str++) && c1 != tolower((unsigned char)c2)) ; if (! c2) return 0; s1 = sub + 1; s2 = str; - while ((c1 = *s1++) && ((isalpha(c1) && isupper(c1)) ? tolower(c1) : c1) == ((isalpha(c2 =*s2++) && isupper(c2)) ? tolower(c2) : c2)) + while ((c1 = *s1++) && + tolower((unsigned char)c1) == tolower((unsigned char)(c2 = *s2++))) ; if (! c1) return 1; } -#else - while ((c1 = *sub)) { - while ((c2 = *str++) && (c1 | 040) != (c2 | 040)) - ; - if (! c2) - return 0; - s1 = sub + 1; s2 = str; - while ((c1 = *s1++) && (c1 | 040) == (*s2++ | 040)) - ; - if (! c1) - return 1; - } -#endif return 1; } /* - * macros to format data + * copy a number to the destination subject to a maximum width */ -#define PUTDF(cp, num, wid, fill)\ - if (cp + wid < ep) {\ - if ((i = (num)) < 0)\ - i = -(num);\ - if ((c = (wid)) < 0)\ - c = -c;\ - sp = cp + c;\ - do {\ - *--sp = (i % 10) + '0';\ - i /= 10;\ - } while (i > 0 && sp > cp);\ - if (i > 0)\ - *sp = '?';\ - else if ((num) < 0 && sp > cp)\ - *--sp = '-';\ - while (sp > cp)\ - *--sp = fill;\ - cp += c;\ - } - -#ifdef LOCALE -#define PUTSF(cp, str, wid, fill) {\ - ljust = 0;\ - if ((i = (wid)) < 0) {\ - i = -i;\ - ljust++;\ - }\ - if ((sp = (str))) {\ - if (ljust) {\ - c = strlen(sp);\ - if (c > i)\ - sp += c - i;\ - else {\ - while( --i >= c && cp < ep)\ - *cp++ = fill;\ - i++;\ - }\ - } else {\ - while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\ - sp++;\ - }\ - while ((c = (unsigned char) *sp++) && --i >= 0 && cp < ep)\ - if (!iscntrl(c) && !isspace(c)) \ - *cp++ = c;\ - else {\ - while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\ - sp++;\ - *cp++ = ' ';\ - }\ - }\ - if (!ljust)\ - while( --i >= 0 && cp < ep)\ - *cp++ = fill;\ +void +cpnumber(charstring_t dest, int num, unsigned int wid, char fill, size_t max) { + if (wid < (num >= 0 ? max : max-1)) { + /* Build up the string representation of num in reverse. */ + charstring_t rev = charstring_create (0); + int i = num >= 0 ? num : -num; + + do { + charstring_push_back (rev, i % 10 + '0'); + i /= 10; + } while (--wid > 0 && i > 0); + if (i > 0) { + /* Overflowed the field (wid). */ + charstring_push_back (rev, '?'); + } else if (num < 0 && wid > 0) { + /* Shouldn't need the wid > 0 check, that's why the condition + at the top checks wid < max-1 when num < 0. */ + --wid; + if (fill == ' ') { + charstring_push_back (rev, '-'); + } + } + while (wid-- > 0 && fill != 0) { + charstring_push_back (rev, fill); } + if (num < 0 && fill == '0') { + charstring_push_back (rev, '-'); + } + + { + /* Output the string in reverse. */ + size_t b = charstring_bytes (rev); + const char *cp = b ? &charstring_buffer (rev)[b] : NULL; -#define PUTS(cp, str) {\ - if ((sp = (str))) {\ - while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\ - sp++;\ - while((c = (unsigned char) *sp++) && cp < ep)\ - if (!iscntrl(c) && !isspace(c)) \ - *cp++ = c;\ - else {\ - while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\ - sp++;\ - *cp++ = ' ';\ - }\ - }\ + for (; b > 0; --b) { + charstring_push_back (dest, *--cp); + } } -#else /* LOCALE */ -#define PUTSF(cp, str, wid, fill) {\ - ljust = 0;\ - if ((i = (wid)) < 0) {\ - i = -i;\ - ljust++;\ - }\ - if (sp = (str)) {\ - if (ljust) {\ - c = strlen(sp);\ - if (c > i)\ - sp += c - i;\ - else {\ - while( --i >= c && cp < ep)\ - *cp++ = fill;\ - i++;\ - }\ - } else {\ - while ((c = *sp) && c <= 32)\ - sp++;\ - }\ - while ((c = *sp++) && --i >= 0 && cp < ep)\ - if (c > 32) \ - *cp++ = c;\ - else {\ - while ((c = *sp) && c <= 32)\ - sp++;\ - *cp++ = ' ';\ - }\ - }\ - if (!ljust)\ - while( --i >= 0 && cp < ep)\ - *cp++ = fill;\ - } + charstring_free (rev); + } +} + +/* + * copy string from str to dest padding with the fill character to a + * size of wid characters. if wid is negative, the string is right + * aligned no more than max characters are copied + */ +void +cptrimmed(charstring_t dest, char *str, int wid, char fill, size_t max) { + int remaining; /* remaining output width available */ + int rjust; + size_t end; /* number of input bytes remaining in str */ +#ifdef MULTIBYTE_SUPPORT + int char_len; /* bytes in current character */ + int w; + wchar_t wide_char; + char *altstr = NULL; +#endif + char *sp; /* current position in source string */ + int prevCtrl = 1; + + /* get alignment */ + rjust = 0; + if ((remaining = wid) < 0) { + remaining = -remaining; + rjust++; + } + if (remaining > (int) max) { remaining = max; } + + if ((sp = str)) { +#ifdef MULTIBYTE_SUPPORT + if (mbtowc(NULL, NULL, 0)) {} /* reset shift state */ +#endif + end = strlen(str); + while (*sp && remaining > 0 && end > 0) { +#ifdef MULTIBYTE_SUPPORT + char_len = mbtowc(&wide_char, sp, end); + + /* + * See the relevant comments in cpstripped() to explain what's + * going on here; we want to handle the case where we get + * characters that mbtowc() cannot handle + */ + + if (char_len < 0) { + altstr = "?"; + char_len = mbtowc(&wide_char, altstr, 1); + } -#define PUTS(cp, str) {\ - if (sp = (str)) {\ - while ((c = *sp) && c <= 32)\ - sp++;\ - while( (c = *sp++) && cp < ep)\ - if ( c > 32 ) \ - *cp++ = c;\ - else {\ - while ( (c = *sp) && c <= 32 )\ - sp++;\ - *cp++ = ' ';\ - }\ - }\ + if (char_len <= 0) { + break; + } + + w = wcwidth(wide_char); + + /* If w > remaining, w must be positive. */ + if (w > remaining) { + break; + } + + end -= char_len; + + if (iswcntrl(wide_char) || iswspace(wide_char)) { + sp += char_len; +#else + int c; + end--; + /* isnctrl(), etc., take an int argument. Cygwin's ctype.h + intentionally warns if they are passed a char. */ + c = (unsigned char) *sp; + if (iscntrl(c) || isspace(c)) { + sp++; +#endif + if (!prevCtrl) { + charstring_push_back (dest, ' '); + remaining--; } -#endif /* LOCALE */ + prevCtrl = 1; + continue; + } + prevCtrl = 0; + +#ifdef MULTIBYTE_SUPPORT + if (w >= 0 && remaining >= w) { + charstring_push_back_chars (dest, altstr ? altstr : sp, + char_len, w); + remaining -= w; + altstr = NULL; + } + sp += char_len; +#else + charstring_push_back (dest, *sp++); + remaining--; +#endif + } + } + + if (rjust) { + if (remaining > 0) { + /* copy string to the right */ + charstring_t copy = charstring_copy (dest); + + /* add padding at the beginning */ + charstring_clear (dest); + for (; remaining > 0; --remaining) { + charstring_push_back (dest, fill); + } + + charstring_append (dest, copy); + + charstring_free (copy); + } + } else { + /* pad remaining space */ + while (remaining-- > 0) { + charstring_push_back (dest, fill); + } + } +} + +static void +cpstripped (charstring_t dest, size_t max, char *str) +{ + int prevCtrl = 1; /* This is 1 so we strip out leading spaces */ + int len; +#ifdef MULTIBYTE_SUPPORT + int char_len, w; + wchar_t wide_char; + char *altstr = NULL; +#endif /* MULTIBYTE_SUPPORT */ + + if (!str) { + return; + } + + len = strlen(str); + +#ifdef MULTIBYTE_SUPPORT + if (mbtowc(NULL, NULL, 0)) {} /* Reset shift state */ +#endif /* MULTIBYTE_SUPPORT */ + + /* + * Process each character at a time; if we have multibyte support + * then deal with that here. + */ + + while (*str != '\0' && len > 0 && max > 0) { +#ifdef MULTIBYTE_SUPPORT + char_len = mbtowc(&wide_char, str, len); + w = wcwidth(wide_char); + + /* + * If mbrtowc() failed, then we have a character that isn't valid + * in the current encoding. Replace it with a '?'. We do that by + * setting the alstr variable to the value of the replacement string; + * altstr is used below when the bytes are copied into the output + * buffer. + */ + + if (char_len < 0) { + altstr = "?"; + char_len = mbtowc(&wide_char, altstr, 1); + } + + if (char_len <= 0) { + break; + } + + len -= char_len; + + if (iswcntrl(wide_char) || iswspace(wide_char)) { + str += char_len; +#else /* MULTIBYTE_SUPPORT */ + int c = (unsigned char) *str; + len--; + if (iscntrl(c) || isspace(c)) { + str++; +#endif /* MULTIBYTE_SUPPORT */ + if (! prevCtrl) { + charstring_push_back (dest, ' '); + --max; + } + + prevCtrl = 1; + continue; + } + prevCtrl = 0; + +#ifdef MULTIBYTE_SUPPORT + charstring_push_back_chars (dest, altstr ? altstr : str, char_len, w); + max -= w; + str += char_len; + altstr = NULL; +#else /* MULTIBYE_SUPPORT */ + charstring_push_back (dest, *str++); + --max; +#endif /* MULTIBYTE_SUPPORT */ + } +} static char *lmonth[] = { "January", "February","March", "April", "May", "June", "July", "August", @@ -255,26 +354,33 @@ get_x400_comp (char *mbox, char *key, char *buffer, int buffer_len) || !(cp = strchr(mbox += idx + strlen (key), '/'))) return 0; - snprintf (buffer, buffer_len, "%*.*s", cp - mbox, cp - mbox, mbox); + snprintf (buffer, buffer_len, "%*.*s", (int)(cp - mbox), (int)(cp - mbox), mbox); return 1; } struct format * -fmt_scan (struct format *format, char *scanl, int width, int *dat) +fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, + struct fmt_callbacks *callbacks) { - char *cp, *ep, *sp; - char *savestr, *str = NULL; - char buffer[BUFSIZ], buffer2[BUFSIZ]; - int i, c, ljust, n; - int value = 0; + char *sp; + char *savestr, *str; + char buffer[NMH_BUFSIZ], buffer2[NMH_BUFSIZ]; + int i, c, rjust; + int value; time_t t; + size_t max; struct format *fmt; struct comp *comp; struct tws *tws; struct mailname *mn; - cp = scanl; - ep = scanl + width - 1; + /* + * max is the same as width, but unsigned so comparisons + * with charstring_chars() won't raise compile warnings. + */ + max = width; + savestr = str = NULL; + value = 0; for (fmt = format; fmt->f_type != FT_DONE; fmt++) switch (fmt->f_type) { @@ -282,65 +388,167 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) case FT_PARSEDATE: fmt->f_comp->c_flags &= ~CF_PARSED; break; + case FT_COMP: + case FT_COMPF: + case FT_LS_COMP: + case FT_LS_DECODECOMP: + /* + * Trim these components of any newlines. + * + * But don't trim the "body" and "text" components. + */ + + comp = fmt->f_comp; + + if (! (comp->c_flags & CF_TRIMMED) && comp->c_text && + (i = strlen(comp->c_text)) > 0) { + if (comp->c_text[i - 1] == '\n' && + strcmp(comp->c_name, "body") != 0 && + strcmp(comp->c_name, "text") != 0) + comp->c_text[i - 1] = '\0'; + comp->c_flags |= CF_TRIMMED; + } + break; } fmt = format; - while (cp < ep) { + for ( ; charstring_chars (scanlp) < max; ) { switch (fmt->f_type) { case FT_COMP: - PUTS (cp, fmt->f_comp->c_text); + cpstripped (scanlp, max - charstring_chars (scanlp), + fmt->f_comp->c_text); break; case FT_COMPF: - PUTSF (cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill); + cptrimmed (scanlp, fmt->f_comp->c_text, fmt->f_width, + fmt->f_fill, max - charstring_chars (scanlp)); break; case FT_LIT: sp = fmt->f_text; - while( (c = *sp++) && cp < ep) - *cp++ = c; + while ((c = *sp++) && charstring_chars (scanlp) < max) { + charstring_push_back (scanlp, c); + } break; case FT_LITF: sp = fmt->f_text; - ljust = 0; + rjust = 0; i = fmt->f_width; if (i < 0) { i = -i; - ljust++; /* XXX should do something with this */ + rjust++; /* XXX should do something with this */ + } + while ((c = *sp++) && --i >= 0 && charstring_chars (scanlp) < max) { + charstring_push_back (scanlp, c); + } + while (--i >= 0 && charstring_chars (scanlp) < max) { + charstring_push_back (scanlp, fmt->f_fill); } - while( (c = *sp++) && --i >= 0 && cp < ep) - *cp++ = c; - while( --i >= 0 && cp < ep) - *cp++ = fmt->f_fill; break; case FT_STR: - PUTS (cp, str); + cpstripped (scanlp, max - charstring_chars (scanlp), str); break; case FT_STRF: - PUTSF (cp, str, fmt->f_width, fmt->f_fill); + cptrimmed (scanlp, str, fmt->f_width, fmt->f_fill, + max - charstring_chars (scanlp)); + break; + case FT_STRLIT: + if (str) { + sp = str; + while ((c = *sp++) && charstring_chars (scanlp) < max) { + charstring_push_back (scanlp, c); + } + } + break; + case FT_STRLITZ: + if (str) charstring_push_back_chars (scanlp, str, strlen (str), 0); break; case FT_STRFW: adios (NULL, "internal error (FT_STRFW)"); - case FT_NUM: - n = snprintf(cp, ep - cp, "%d", value); - if (n >= 0) cp += n; + case FT_NUM: { + int num = value; + unsigned int wid; + + for (wid = num <= 0 ? 1 : 0; num; ++wid, num /= 10) {} + cpnumber (scanlp, value, wid, ' ', + max - charstring_chars (scanlp)); + break; + } + case FT_LS_KILO: + case FT_LS_KIBI: + { + char *unitcp; + unsigned int whole, tenths; + unsigned int scale = 0; + unsigned int val = (unsigned int)value; + char *kibisuff = NULL; + + switch (fmt->f_type) { + case FT_LS_KILO: scale = 1000; kibisuff = ""; break; + case FT_LS_KIBI: scale = 1024; kibisuff = "i"; break; + } + + if (val < scale) { + snprintf(buffer, sizeof(buffer), "%u", val); + } else { + /* To prevent divide by 0, found by clang static + analyzer. */ + if (scale == 0) { scale = 1; } + + /* find correct scale for size (Kilo/Mega/Giga/Tera) */ + for (unitcp = "KMGT"; val > (scale * scale); val /= scale) { + if (!*++unitcp) + break; + } + + if (!*unitcp) { + strcpy(buffer, "huge"); + } else { + /* val is scale times too big. we want tenths */ + val *= 10; + + /* round up */ + val += (scale - 1); + val /= scale; + + whole = val / 10; + tenths = val - (whole * 10); + + if (tenths) { + snprintf(buffer, sizeof(buffer), "%u.%u%c%s", + whole, tenths, *unitcp, kibisuff); + } else { + snprintf(buffer, sizeof(buffer), "%u%c%s", + whole, *unitcp, kibisuff); + } + } + } + str = buffer; + } break; case FT_NUMF: - PUTDF (cp, value, fmt->f_width, fmt->f_fill); + cpnumber (scanlp, value, fmt->f_width, fmt->f_fill, + max - charstring_chars (scanlp)); break; case FT_CHAR: - *cp++ = fmt->f_char; + charstring_push_back (scanlp, fmt->f_char); break; case FT_DONE: + if (callbacks && callbacks->trace_func) + callbacks->trace_func(callbacks->trace_context, fmt, value, + str, charstring_buffer (scanlp)); goto finished; case FT_IF_S: if (!(value = (str && *str))) { + if (callbacks && callbacks->trace_func) + callbacks->trace_func(callbacks->trace_context, fmt, value, + str, charstring_buffer (scanlp)); fmt += fmt->f_skip; continue; } @@ -348,6 +556,9 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) case FT_IF_S_NULL: if (!(value = (str == NULL || *str == 0))) { + if (callbacks && callbacks->trace_func) + callbacks->trace_func(callbacks->trace_context, fmt, value, + str, charstring_buffer (scanlp)); fmt += fmt->f_skip; continue; } @@ -355,6 +566,9 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) case FT_IF_V_EQ: if (value != fmt->f_value) { + if (callbacks && callbacks->trace_func) + callbacks->trace_func(callbacks->trace_context, fmt, value, + str, charstring_buffer (scanlp)); fmt += fmt->f_skip; continue; } @@ -362,6 +576,9 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) case FT_IF_V_NE: if (value == fmt->f_value) { + if (callbacks && callbacks->trace_func) + callbacks->trace_func(callbacks->trace_context, fmt, value, + str, charstring_buffer (scanlp)); fmt += fmt->f_skip; continue; } @@ -369,6 +586,9 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) case FT_IF_V_GT: if (value <= fmt->f_value) { + if (callbacks && callbacks->trace_func) + callbacks->trace_func(callbacks->trace_context, fmt, value, + str, charstring_buffer (scanlp)); fmt += fmt->f_skip; continue; } @@ -376,6 +596,9 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) case FT_IF_MATCH: if (!(value = (str && match (str, fmt->f_text)))) { + if (callbacks && callbacks->trace_func) + callbacks->trace_func(callbacks->trace_context, fmt, value, + str, charstring_buffer (scanlp)); fmt += fmt->f_skip; continue; } @@ -390,6 +613,9 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) case FT_IF_AMATCH: if (!(value = (str && uprf (str, fmt->f_text)))) { + if (callbacks && callbacks->trace_func) + callbacks->trace_func(callbacks->trace_context, fmt, value, + str, charstring_buffer (scanlp)); fmt += fmt->f_skip; continue; } @@ -420,6 +646,9 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) break; case FT_GOTO: + if (callbacks && callbacks->trace_func) + callbacks->trace_func(callbacks->trace_context, fmt, value, + str, charstring_buffer (scanlp)); fmt += fmt->f_skip; continue; @@ -442,14 +671,14 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) break; case FT_LS_DECODECOMP: - if (decode_rfc2047(fmt->f_comp->c_text, buffer2)) + if (decode_rfc2047(fmt->f_comp->c_text, buffer2, sizeof(buffer2))) str = buffer2; else str = fmt->f_comp->c_text; break; case FT_LS_DECODE: - if (str && decode_rfc2047(str, buffer2)) + if (str && decode_rfc2047(str, buffer2, sizeof(buffer2))) str = buffer2; break; @@ -457,23 +686,25 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) if (str) { char *xp; - strncpy(buffer, str, sizeof(buffer)); + if (str != buffer) + strncpy(buffer, str, sizeof(buffer)); + buffer[sizeof(buffer)-1] = '\0'; str = buffer; - while (isspace(*str)) + while (isspace((unsigned char) *str)) str++; - ljust = 0; + rjust = 0; if ((i = fmt->f_width) < 0) { i = -i; - ljust++; + rjust++; } - if (!ljust && i > 0 && strlen(str) > i) + if (!rjust && i > 0 && (int) strlen(str) > i) str[i] = '\0'; xp = str; xp += strlen(str) - 1; - while (xp > str && isspace(*xp)) + while (xp > str && isspace((unsigned char) *xp)) *xp-- = '\0'; - if (ljust && i > 0 && strlen(str) > i) + if (rjust && i > 0 && (int) strlen(str) > i) str += strlen(str) - i; } break; @@ -497,7 +728,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) value = 0; break; case FT_LV_CHAR_LEFT: - value = width - (cp - scanl); + value = max - charstring_bytes (scanlp); break; case FT_LV_PLUS_L: value += fmt->f_value; @@ -505,6 +736,9 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) case FT_LV_MINUS_L: value = fmt->f_value - value; break; + case FT_LV_MULTIPLY_L: + value *= fmt->f_value; + break; case FT_LV_DIVIDE_L: if (fmt->f_value) value = value / fmt->f_value; @@ -589,6 +823,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) default: value = -1; break; } + break; case FT_LV_ZONEF: if ((fmt->f_comp->c_tws->tw_flags & TW_SZONE) == TW_SZEXP) value = 1; @@ -596,7 +831,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) value = -1; break; case FT_LV_DST: - value = fmt->f_comp->c_tws->tw_flags & TW_DST; + value = fmt->f_comp->c_tws->tw_flags & TW_DST ? 1 : 0; break; case FT_LS_822DATE: str = dasctime (fmt->f_comp->c_tws , TW_ZONE); @@ -645,7 +880,9 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) goto unfriendly; if ((str = mn->m_pers) == NULL) { if ((str = mn->m_note)) { - strncpy (buffer, str, sizeof(buffer)); + if (str != buffer) + strncpy (buffer, str, sizeof(buffer)); + buffer[sizeof(buffer)-1] = '\0'; str = buffer; if (*str == '(') str++; @@ -660,7 +897,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) } } else if (!(str = get_x400_friendly (mn->m_mbox, buffer, sizeof(buffer)))) { - unfriendly: ; + unfriendly: switch (mn->m_type) { case LOCALHOST: str = mn->m_mbox; @@ -682,36 +919,17 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) } } } - break; + break; /* UNQUOTEs RFC-2822 quoted-string and quoted-pair */ case FT_LS_UNQUOTE: if (str) { - int m; - strncpy(buffer, str, sizeof(buffer)); - str = buffer; - - /* we will parse from buffer to buffer2 */ - n = 0; /* n is the input position in str */ - m = 0; /* m is the ouput position in buffer2 */ - - while ( str[n] != '\0') { - switch ( str[n] ) { - case '\\': - n++; - if ( str[n] != '\0') - buffer2[m++] = str[n++]; - break; - case '"': - n++; - break; - default: - buffer2[m++] = str[n++]; - break; - } - } - buffer2[m] = '\0'; + if (str != buffer) + strncpy(buffer, str, sizeof(buffer)); + /* strncpy doesn't NUL-terminate if it fills the buffer */ + buffer[sizeof(buffer)-1] = '\0'; + unquote_string(buffer, buffer2); str = buffer2; } break; @@ -740,7 +958,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) *comp->c_tws = *tws; comp->c_flags &= ~CF_TRUE; } else if ((comp->c_flags & CF_DATEFAB) == 0) { - memset ((char *) comp->c_tws, 0, sizeof *comp->c_tws); + memset (comp->c_tws, 0, sizeof *comp->c_tws); comp->c_flags = CF_TRUE; } comp->c_flags |= CF_PARSED; @@ -748,7 +966,18 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) case FT_FORMATADDR: /* hook for custom address list formatting (see replsbr.c) */ - str = formataddr (savestr, str); + if (callbacks && callbacks->formataddr) + str = callbacks->formataddr (savestr, str); + else + str = formataddr (savestr, str); + break; + + case FT_CONCATADDR: + /* The same as formataddr, but doesn't do duplicate suppression */ + if (callbacks && callbacks->concataddr) + str = callbacks->concataddr (savestr, str); + else + str = concataddr (savestr, str); break; case FT_PUTADDR: @@ -764,43 +993,53 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) lp = str; wid = value; - len = strlen (str); + len = str ? strlen (str) : 0; sp = fmt->f_text; indent = strlen (sp); wid -= indent; - while( (c = *sp++) && cp < ep) - *cp++ = c; + if (wid <= 0) { + adios(NULL, "putaddr -- num register (%d) must be greater " + "than label width (%d)", value, indent); + } + while ((c = *sp++) && charstring_chars (scanlp) < max) { + charstring_push_back (scanlp, c); + } while (len > wid) { /* try to break at a comma; failing that, break at a * space. */ lastb = 0; sp = lp + wid; - while (sp > lp && (c = *--sp) != ',') { + while (sp > lp && (c = (unsigned char) *--sp) != ',') { if (! lastb && isspace(c)) lastb = sp - 1; } if (sp == lp) { if (! (sp = lastb)) { sp = lp + wid - 1; - while (*sp && *sp != ',' && !isspace(*sp)) + while (*sp && *sp != ',' && + !isspace((unsigned char) *sp)) sp++; if (*sp != ',') sp--; } } len -= sp - lp + 1; - while (cp < ep && lp <= sp) - *cp++ = *lp++; - while (isspace(*lp)) + while (lp <= sp && charstring_chars (scanlp) < max) { + charstring_push_back (scanlp, *lp++); + } + while (isspace((unsigned char) *lp)) lp++, len--; if (*lp) { - if (cp < ep) - *cp++ = '\n'; - for (i=indent; cp < ep && i > 0; i--) - *cp++ = ' '; + if (charstring_chars (scanlp) < max) { + charstring_push_back (scanlp, '\n'); + } + for (i=indent; + charstring_chars (scanlp) < max && i > 0; + i--) + charstring_push_back (scanlp, ' '); } } - PUTS (cp, lp); + cpstripped (scanlp, max - charstring_chars (scanlp), lp); } break; @@ -811,7 +1050,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) if (comp->c_mn != &fmt_mnull) mnfree (comp->c_mn); if ((sp = comp->c_text) && (sp = getname(sp)) && - (mn = getm (sp, NULL, 0, fmt_norm, NULL))) { + (mn = getm (sp, NULL, 0, NULL, 0))) { comp->c_mn = mn; while (getname("")) ; @@ -822,8 +1061,10 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) comp->c_mn = &fmt_mnull; } break; - + case FT_MYMBOX: + case FT_GETMYMBOX: + case FT_GETMYADDR: /* * if there's no component, we say true. Otherwise we * say "true" only if we can parse the address and it @@ -833,56 +1074,106 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) if (comp->c_mn != &fmt_mnull) mnfree (comp->c_mn); if ((sp = comp->c_text) && (sp = getname(sp)) && - (mn = getm (sp, NULL, 0, AD_NAME, NULL))) { + (mn = getm (sp, NULL, 0, NULL, 0))) { comp->c_mn = mn; - if (ismymbox(mn)) + if (ismymbox(mn)) { comp->c_flags |= CF_TRUE; - else + /* Set str for use with FT_GETMYMBOX. With + FT_GETMYADDR, comp->c_mn will be run through + FT_LS_ADDR, which will strip off any pers + name. */ + str = mn->m_text; + } else { comp->c_flags &= ~CF_TRUE; + } while ((sp = getname(sp))) if ((comp->c_flags & CF_TRUE) == 0 && - (mn = getm (sp, NULL, 0, AD_NAME, NULL))) - if (ismymbox(mn)) + (mn = getm (sp, NULL, 0, NULL, 0))) + if (ismymbox(mn)) { comp->c_flags |= CF_TRUE; + /* Set str and comp->c_text for use with + FT_GETMYMBOX. With FT_GETMYADDR, + comp->c_mn will be run through + FT_LS_ADDR, which will strip off any + pers name. */ + free (comp->c_text); + comp->c_text = str = strdup (mn->m_text); + comp->c_mn = mn; + } + comp->c_flags |= CF_PARSED; } else { while (getname("")) /* XXX */ ; if (comp->c_text == 0) comp->c_flags |= CF_TRUE; - else + else { comp->c_flags &= ~CF_TRUE; + } comp->c_mn = &fmt_mnull; } - break; - - case FT_ADDTOSEQ: -#ifdef LBL - /* If we're working on a folder (as opposed to a file), add the - * current msg to sequence given in literal field. Don't - * disturb string or value registers. - */ - if (fmt_current_folder) - seq_addmsg(fmt_current_folder, fmt->f_text, dat[0], -1); -#endif + if ((comp->c_flags & CF_TRUE) == 0 && + (fmt->f_type == FT_GETMYMBOX || fmt->f_type == FT_GETMYADDR)) { + /* Fool FT_LS_ADDR into not producing an address. */ + comp->c_mn = &fmt_mnull; comp->c_text = NULL; + } break; } + + /* + * Call our tracing callback function, if one was supplied + */ + + if (callbacks && callbacks->trace_func) + callbacks->trace_func(callbacks->trace_context, fmt, value, + str, charstring_buffer (scanlp)); fmt++; } -#ifndef JLR - finished:; - if (cp[-1] != '\n') - *cp++ = '\n'; - *cp = 0; - return ((struct format *)0); -#else /* JLR */ - if (cp[-1] != '\n') - *cp++ = '\n'; - while (fmt->f_type != FT_DONE) + + /* Emit any trailing sequences of zero display length. */ + while (fmt->f_type != FT_DONE) { + if (fmt->f_type == FT_LS_LIT) { + str = fmt->f_text; + if (callbacks && callbacks->trace_func) + callbacks->trace_func(callbacks->trace_context, fmt, value, + str, charstring_buffer (scanlp)); + } else if (fmt->f_type == FT_STRLITZ) { + /* Don't want to emit part of an escape sequence. So if + there isn't enough room in the buffer for the entire + string, skip it completely. Need room for null + terminator, and maybe trailing newline (added below). */ + if (str) { + for (sp = str; *sp; ++sp) { + charstring_push_back (scanlp, *sp); + } + } + if (callbacks && callbacks->trace_func) + callbacks->trace_func(callbacks->trace_context, fmt, value, + str, charstring_buffer (scanlp)); + } fmt++; + } - finished:; - *cp = '\0'; - return (fmt->f_value ? ++fmt : (struct format *) 0); + finished: + if (charstring_bytes (scanlp) > 0) { + /* + * Append a newline if the last character wasn't. + */ +#ifdef MULTIBYTE_SUPPORT + /* + * It's a little tricky because the last byte might be part of + * a multibyte character, in which case we assume that wasn't + * a newline. + */ + size_t last_char_len = charstring_last_char_len (scanlp); +#else /* ! MULTIBYTE_SUPPORT */ + size_t last_char_len = 1; +#endif /* ! MULTIBYTE_SUPPORT */ + + if (last_char_len > 1 || + charstring_buffer (scanlp)[charstring_bytes (scanlp) - 1] != '\n') { + charstring_push_back (scanlp, '\n'); + } + } -#endif /* JLR */ + return (NULL); }