X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/03fe41ba1d68108808c966c6d7ff74bd8c1d648c..4a56a28ac439137ba2b71fcb5952b4e4abd1e2fc:/sbr/fmt_scan.c?ds=inline diff --git a/sbr/fmt_scan.c b/sbr/fmt_scan.c index 8d038360..c75db3ec 100644 --- a/sbr/fmt_scan.c +++ b/sbr/fmt_scan.c @@ -1,10 +1,11 @@ - -/* - * fmt_scan.c -- format string interpretation +/* fmt_scan.c -- format string interpretation * * 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 @@ -12,32 +13,20 @@ #include #include #include +#include +#include "unquote.h" -#ifdef TIME_WITH_SYS_TIME +#ifdef HAVE_SYS_TIME_H # include -# include -#else -# ifdef TM_IN_SYS_TIME -# include -# else -# include -# endif #endif +#include #ifdef MULTIBYTE_SUPPORT # include # include #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) */ -#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 @@ -58,112 +47,144 @@ 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; } /* * copy a number to the destination subject to a maximum width */ -static void -cpnumber(char **dest, int num, unsigned int wid, char fill, size_t n) { - int i, c; - char *sp; - char *cp = *dest; - char *ep = cp + n; - - if (cp + wid < ep) { - if ((i = (num)) < 0) - i = -(num); - if ((c = (wid)) < 0) - c = -c; - sp = cp + c; +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 { - *--sp = (i % 10) + '0'; + charstring_push_back (rev, 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; + } 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; + + for (; b > 0; --b) { + charstring_push_back (dest, *--cp); + } + } + + charstring_free (rev); } - *dest = cp; } /* - * 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 n bytes are copied + * 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 */ -static void -cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n) { +void +cptrimmed(charstring_t dest, char *str, int wid, char fill, size_t max) { int remaining; /* remaining output width available */ - int c, ljust; - int end; /* number of input bytes remaining in str */ + int rjust; + struct charstring *trimmed; + 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 */ - char *cp = *dest; /* current position in destination string */ - char *ep = cp + n; /* end of destination buffer */ int prevCtrl = 1; /* get alignment */ - ljust = 0; - if ((remaining = (wid)) < 0) { + rjust = 0; + if ((remaining = wid) < 0) { remaining = -remaining; - ljust++; + rjust++; } - if ((sp = (str))) { - mbtowc(NULL, NULL, 0); /* reset shift state */ + if (remaining > (int) max) { remaining = max; } + + trimmed = rjust ? charstring_create(remaining) : dest; + + 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); - if (char_len <= 0 || (cp + char_len > ep)) + + /* + * 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); + } + + 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--; - if (iscntrl(*sp) || isspace(*sp)) { + /* 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) { - *cp++ = ' '; + charstring_push_back (trimmed, ' '); remaining--; } @@ -173,74 +194,119 @@ cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n) { prevCtrl = 0; #ifdef MULTIBYTE_SUPPORT - w = wcwidth(wide_char); if (w >= 0 && remaining >= w) { - strncpy(cp, sp, char_len); - cp += char_len; + charstring_push_back_chars (trimmed, altstr ? altstr : sp, + char_len, w); remaining -= w; + altstr = NULL; } sp += char_len; #else - *cp++ = *sp++; + charstring_push_back (trimmed, *sp++); remaining--; #endif } } - if (ljust) { - if (cp + remaining > ep) - remaining = ep - cp; - ep = cp + remaining; - if (remaining > 0) { - /* copy string to the right */ - while (--cp >= *dest) - *(cp + remaining) = *cp; - /* add padding at the beginning */ - cp += remaining; - for (c=remaining; c>0; c--) - *cp-- = fill; - } - *dest = ep; - } else { - /* pad remaining space */ - while (remaining-- > 0 && cp < ep) - *cp++ = fill; - *dest = cp; + while (remaining-- > 0) { + charstring_push_back(dest, fill); + } + + if (rjust) { + charstring_append(dest, trimmed); + charstring_free(trimmed); } } static void -cpstripped (char **start, char *end, char *str) +cpstripped (charstring_t dest, size_t max, char *str) { - int c; - char *s = 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 (!s) + if (!str) { return; + } - /* skip any initial control characters or spaces */ - while ((c = (unsigned char) *s) && -#ifdef LOCALE - (iscntrl(c) || isspace(c))) -#else - (c <= 32)) -#endif - s++; - - /* compact repeated control characters and spaces into a single space */ - while((c = (unsigned char) *s++) && *start < end) - if (!iscntrl(c) && !isspace(c)) - *(*start)++ = c; - else { - while ((c = (unsigned char) *s) && -#ifdef LOCALE - (iscntrl(c) || isspace(c))) -#else - (c <= 32)) -#endif - s++; - *(*start)++ = ' '; + 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); + + /* + * If mbrtowc() failed, then we have a character that isn't valid + * in the current encoding, or len wasn't enough for the whole + * multi-byte rune to be read. 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 + w = wcwidth(wide_char); + assert(w >= 0); + if (max >= (size_t) w) { + charstring_push_back_chars (dest, altstr ? altstr : str, char_len, w); + max -= w; + str += char_len; + altstr = NULL; + } else { + /* Not enough width available for the last character. Output + space(s) to fill. */ + while (max-- > 0) { + charstring_push_back (dest, ' '); + } + break; + } +#else /* MULTIBYE_SUPPORT */ + charstring_push_back (dest, *str++); + --max; +#endif /* MULTIBYTE_SUPPORT */ + } } static char *lmonth[] = { "January", "February","March", "April", @@ -292,23 +358,28 @@ get_x400_comp (char *mbox, char *key, char *buffer, int buffer_len) } 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; - unsigned char *sp; - char *savestr = NULL; - unsigned char *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) { @@ -316,70 +387,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: - cpstripped (&cp, ep, fmt->f_comp->c_text); + cpstripped (scanlp, max - charstring_chars (scanlp), + fmt->f_comp->c_text); break; case FT_COMPF: - cptrimmed (&cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill, ep - cp); + 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: - cpstripped (&cp, ep, str); + cpstripped (scanlp, max - charstring_chars (scanlp), str); break; case FT_STRF: - cptrimmed (&cp, str, fmt->f_width, fmt->f_fill, ep - cp); + 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 + 1, "%d", value); - if (n >= 0) { - if (n >= ep - cp) { - cp = ep; - } else - cp += n; + case FT_NUM: { + int num = value; + unsigned int wid; + + for (wid = num <= 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: - cpnumber (&cp, value, fmt->f_width, fmt->f_fill, ep - cp); + 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; } @@ -387,6 +555,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; } @@ -394,6 +565,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; } @@ -401,6 +575,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; } @@ -408,6 +585,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; } @@ -415,6 +595,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; } @@ -429,6 +612,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; } @@ -459,6 +645,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; @@ -494,26 +683,27 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) case FT_LS_TRIM: if (str) { - unsigned char *xp; + 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; @@ -537,7 +727,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; @@ -545,15 +735,18 @@ 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; + value /= fmt->f_value; else value = 0; break; case FT_LV_MODULO_L: if (fmt->f_value) - value = value % fmt->f_value; + value %= fmt->f_value; else value = 0; break; @@ -629,14 +822,15 @@ 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) + if (fmt->f_comp->c_tws->tw_flags & TW_SZEXP) value = 1; else 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); @@ -685,7 +879,8 @@ 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 == '(') @@ -701,7 +896,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; @@ -729,32 +924,11 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) /* UNQUOTEs RFC-2822 quoted-string and quoted-pair */ case FT_LS_UNQUOTE: if (str) { - int m; - strncpy(buffer, str, sizeof(buffer)); + if (str != buffer) + strncpy(buffer, str, sizeof(buffer)); /* strncpy doesn't NUL-terminate if it fills the buffer */ buffer[sizeof(buffer)-1] = '\0'; - 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'; + unquote_string(buffer, buffer2); str = buffer2; } break; @@ -783,7 +957,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; @@ -791,7 +965,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: @@ -802,49 +987,58 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) * (e.g., "To: ") */ { - unsigned char *lp; - char *lastb; + char *lp, *lastb; int indent, wid, len; 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, ' '); } } - cpstripped (&cp, ep, lp); + cpstripped (scanlp, max - charstring_chars (scanlp), lp); } break; @@ -855,7 +1049,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("")) ; @@ -868,6 +1062,8 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) 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 @@ -877,56 +1073,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); }