X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/0138ab0e9b1e8fa59be141338d599277095dec8c..892a81dbb7c632d80fb528609f5abbd3b7ba43c6:/sbr/fmt_scan.c diff --git a/sbr/fmt_scan.c b/sbr/fmt_scan.c index 6cceff32..d0bb16df 100644 --- a/sbr/fmt_scan.c +++ b/sbr/fmt_scan.c @@ -134,6 +134,7 @@ cptrimmed(char **dest, char **ep, char *str, unsigned int wid, char fill, 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 */ @@ -154,6 +155,17 @@ cptrimmed(char **dest, char **ep, char *str, unsigned int wid, char fill, #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); + } + if (char_len <= 0) break; @@ -196,9 +208,10 @@ cptrimmed(char **dest, char **ep, char *str, unsigned int wid, char fill, #ifdef MULTIBYTE_SUPPORT 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 @@ -239,6 +252,7 @@ cpstripped (char **dest, char **end, char *max, char *str) #ifdef MULTIBYTE_SUPPORT int char_len, w; wchar_t wide_char; + char *altstr = NULL; #endif /* MULTIBYTE_SUPPORT */ if (!str) @@ -269,6 +283,19 @@ cpstripped (char **dest, char **end, char *max, char *str) *end += char_len - w; } + /* + * 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; @@ -293,9 +320,10 @@ cpstripped (char **dest, char **end, char *max, 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 */ @@ -351,7 +379,8 @@ 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, *sp; char *savestr = NULL, *str = NULL; @@ -483,6 +512,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: @@ -898,12 +930,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: @@ -1015,6 +1053,14 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) } 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++; } @@ -1022,6 +1068,9 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) 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 @@ -1030,6 +1079,9 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) 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++; }