X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/832f687b6c2afdb9dd09e0c5bbc249e1bf22f433..959dbc18d02cb81512ee2d0904b76e9287c95ee4:/sbr/fmt_scan.c?ds=sidebyside diff --git a/sbr/fmt_scan.c b/sbr/fmt_scan.c index 51ba24cf..a7ad1249 100644 --- a/sbr/fmt_scan.c +++ b/sbr/fmt_scan.c @@ -25,11 +25,6 @@ # include #endif -#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 = { NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL }; @@ -54,13 +49,24 @@ match (char *str, char *sub) #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 = (isascii((unsigned char) c1) && isalpha((unsigned char) c1) && + isupper((unsigned char) c1)) ? tolower((unsigned char) c1) : c1; + while ((c2 = *str++) && c1 != ((isascii((unsigned char) c2) && + isalpha((unsigned char) c2) && + isupper((unsigned char) c2)) ? + tolower((unsigned char) c2) : 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++) && ((isascii((unsigned char) c1) && + isalpha((unsigned char) c1) && + isupper((unsigned char) c1)) ? + tolower(c1) : c1) == + ((isascii((unsigned char) (c2 =*s2++)) && + isalpha((unsigned char) c2) && + isupper((unsigned char) c2)) ? + tolower((unsigned char) c2) : c2)) ; if (! c1) return 1; @@ -118,7 +124,8 @@ cpnumber(char **dest, int num, unsigned int wid, char fill, size_t n) { * no more than n bytes are copied */ static void -cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n) { +cptrimmed(char **dest, char **ep, char *str, unsigned int wid, char fill, + char *epmax) { int remaining; /* remaining output width available */ int c, ljust; int end; /* number of input bytes remaining in str */ @@ -126,10 +133,10 @@ cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n) { 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 */ @@ -139,12 +146,40 @@ cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n) { ljust++; } if ((sp = (str))) { +#ifdef MULTIBYTE_SUPPORT 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); + + /* + * Multibyte characters can have a variable number of column + * widths, so use the column width to bump the end pointer when + * appropriate. + */ + if (char_len > 1 && epmax - *ep >= char_len - w) { + *ep += char_len - w; + } + + if (cp + w > *ep) break; end -= char_len; @@ -156,7 +191,7 @@ cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n) { end--; /* isnctrl(), etc., take an int argument. Cygwin's ctype.h intentionally warns if they are passed a char. */ - c = *sp; + c = (unsigned char) *sp; if (iscntrl(c) || isspace(c)) { sp++; #endif @@ -171,11 +206,11 @@ 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); + strncpy(cp, altstr ? altstr : sp, char_len); cp += char_len; remaining -= w; + altstr = NULL; } sp += char_len; #else @@ -186,9 +221,10 @@ cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n) { } if (ljust) { - if (cp + remaining > ep) - remaining = ep - cp; - ep = cp + remaining; + char *endfield; + if (cp + remaining > *ep) + remaining = *ep - cp; + endfield = cp + remaining; if (remaining > 0) { /* copy string to the right */ while (--cp >= *dest) @@ -198,23 +234,24 @@ cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n) { for (c=remaining; c>0; c--) *cp-- = fill; } - *dest = ep; + *dest = endfield; } else { /* pad remaining space */ - while (remaining-- > 0 && cp < ep) + while (remaining-- > 0 && cp < *ep) *cp++ = fill; *dest = cp; } } static void -cpstripped (char **dest, char *end, char *str) +cpstripped (char **dest, char **end, char *max, char *str) { int prevCtrl = 1; /* This is 1 so we strip out leading spaces */ int len; #ifdef MULTIBYTE_SUPPORT - int char_len; + int char_len, w; wchar_t wide_char; + char *altstr = NULL; #endif /* MULTIBYTE_SUPPORT */ if (!str) @@ -231,11 +268,34 @@ cpstripped (char **dest, char *end, char *str) * then deal with that here. */ - while (*str != '\0' && len > 0 && *dest < end) { + while (*str != '\0' && len > 0 && *dest < *end) { #ifdef MULTIBYTE_SUPPORT char_len = mbtowc(&wide_char, str, len); + w = wcwidth(wide_char); + + /* + * Account for multibyte characters, and increment the end pointer + * by the number of "extra" bytes in this character. That's the + * character length (char_len) minus the column width (w). + */ + if (char_len > 1 && max - *end >= char_len - w) { + *end += char_len - w; + } - if (char_len <= 0 || *dest + char_len > end) + /* + * 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 || *dest + char_len > *end) break; len -= char_len; @@ -243,7 +303,7 @@ cpstripped (char **dest, char *end, char *str) if (iswcntrl(wide_char) || iswspace(wide_char)) { str += char_len; #else /* MULTIBYTE_SUPPORT */ - int c = *str; + int c = (unsigned char) *str; len--; if (iscntrl(c) || isspace(c)) { str++; @@ -259,9 +319,10 @@ cpstripped (char **dest, char *end, char *str) prevCtrl = 0; #ifdef MULTIBYTE_SUPPORT - memcpy(*dest, str, char_len); + memcpy(*dest, altstr ? altstr : str, char_len); str += char_len; *dest += char_len; + altstr = NULL; #else /* MULTIBYE_SUPPORT */ *(*dest)++ = *str++ #endif /* MULTIBYTE_SUPPORT */ @@ -317,12 +378,11 @@ get_x400_comp (char *mbox, char *key, char *buffer, int buffer_len) } struct format * -fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) +fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat, + struct fmt_callbacks *callbacks) { - char *cp, *ep; - unsigned char *sp; - char *savestr = NULL; - unsigned char *str = NULL; + char *cp, *ep, *sp; + char *savestr = NULL, *str = NULL; char buffer[BUFSIZ], buffer2[BUFSIZ]; int i, c, ljust, n; int value = 0; @@ -356,11 +416,11 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) comp = fmt->f_comp; - if (! (comp->c_flags & CF_TRIMMED) && comp->c_text) { - i = strlen(comp->c_text); + 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) + strcmp(comp->c_name, "body") != 0 && + strcmp(comp->c_name, "text") != 0) comp->c_text[i - 1] = '\0'; comp->c_flags |= CF_TRIMMED; } @@ -373,10 +433,11 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) switch (fmt->f_type) { case FT_COMP: - cpstripped (&cp, ep, fmt->f_comp->c_text); + cpstripped (&cp, &ep, scanl + max - 1, 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 (&cp, &ep, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill, + scanl + max - 1); break; case FT_LIT: @@ -399,16 +460,36 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) break; case FT_STR: - cpstripped (&cp, ep, str); + cpstripped (&cp, &ep, scanl + max - 1, str); break; case FT_STRF: - cptrimmed (&cp, str, fmt->f_width, fmt->f_fill, ep - cp); + cptrimmed (&cp, &ep, str, fmt->f_width, fmt->f_fill, + scanl + max - 1); break; case FT_STRLIT: sp = str; while ((c = *sp++) && cp < ep) *cp++ = c; break; + case FT_STRLITZ: { + size_t len = strlen (str); + + /* 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. */ + if (cp - scanl + len + 1 < max) { + for (sp = str; *sp; *cp++ = *sp++) continue; + + /* This string doesn't count against the width. So + increase ep the same amount as cp, only if the + scan buffer will always be large enough. */ + if (ep - scanl + len + 1 < max) { + ep += len; + } + } + + break; + } case FT_STRFW: adios (NULL, "internal error (FT_STRFW)"); @@ -430,6 +511,9 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) break; case FT_DONE: + if (callbacks && callbacks->trace_func) + callbacks->trace_func(callbacks->trace_context, fmt, value, + str, scanl); goto finished; case FT_IF_S: @@ -548,12 +632,12 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) case FT_LS_TRIM: if (str) { - unsigned char *xp; + char *xp; strncpy(buffer, str, sizeof(buffer)); buffer[sizeof(buffer)-1] = '\0'; str = buffer; - while (isspace(*str)) + while (isspace((unsigned char) *str)) str++; ljust = 0; if ((i = fmt->f_width) < 0) { @@ -565,7 +649,7 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) 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 && (int) strlen(str) > i) str += strlen(str) - i; @@ -783,32 +867,10 @@ fmt_scan (struct format *format, char *scanl, size_t max, 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)); /* 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; @@ -845,12 +907,18 @@ fmt_scan (struct format *format, char *scanl, size_t max, 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 */ - str = concataddr (savestr, str); + if (callbacks && callbacks->concataddr) + str = callbacks->concataddr (savestr, str); + else + str = concataddr (savestr, str); break; case FT_PUTADDR: @@ -861,8 +929,7 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) * (e.g., "To: ") */ { - unsigned char *lp; - char *lastb; + char *lp, *lastb; int indent, wid, len; lp = str; @@ -875,21 +942,22 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) adios(NULL, "putaddr -- num register (%d) must be greater " "than label width (%d)", value, indent); } - while( (c = *sp++) && cp < ep) - *cp++ = c; + while( (c = (unsigned char) *sp++) && cp < ep) + *cp++ = (char) 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--; @@ -898,7 +966,7 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) len -= sp - lp + 1; while (cp < ep && lp <= sp) *cp++ = *lp++; - while (isspace(*lp)) + while (isspace((unsigned char) *lp)) lp++, len--; if (*lp) { if (cp < ep) @@ -907,7 +975,7 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) *cp++ = ' '; } } - cpstripped (&cp, ep, lp); + cpstripped (&cp, &ep, scanl + max - 1, lp); } break; @@ -918,7 +986,7 @@ fmt_scan (struct format *format, char *scanl, size_t max, 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("")) ; @@ -940,7 +1008,7 @@ fmt_scan (struct format *format, char *scanl, size_t max, 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)) comp->c_flags |= CF_TRUE; @@ -948,7 +1016,7 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) comp->c_flags &= ~CF_TRUE; while ((sp = getname(sp))) if ((comp->c_flags & CF_TRUE) == 0 && - (mn = getm (sp, NULL, 0, AD_NAME, NULL))) + (mn = getm (sp, NULL, 0, NULL, 0))) if (ismymbox(mn)) comp->c_flags |= CF_TRUE; } else { @@ -961,21 +1029,40 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) 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 - break; + /* + * Call our tracing callback function, if one was supplied + */ + + if (callbacks && callbacks->trace_func) + callbacks->trace_func(callbacks->trace_context, fmt, value, + str, scanl); + fmt++; + } + + /* 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, scanl); + } 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 (cp - scanl + strlen (str) + 1 < max) { + for (sp = str; *sp; *cp++ = *sp++) continue; + } + if (callbacks && callbacks->trace_func) + callbacks->trace_func(callbacks->trace_context, fmt, value, + str, scanl); } fmt++; } -#ifndef JLR + finished:; if (cp > scanl && cp[-1] != '\n') { if (cp - scanl < (int) max - 1) { @@ -986,15 +1073,4 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) } *cp = '\0'; return ((struct format *)0); -#else /* JLR */ - if (cp[-1] != '\n') - *cp++ = '\n'; - while (fmt->f_type != FT_DONE) - fmt++; - - finished:; - *cp = '\0'; - return (fmt->f_value ? ++fmt : (struct format *) 0); - -#endif /* JLR */ }