* 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 *str, unsigned int wid, char fill, size_t n,
+ size_t max) {
int remaining; /* remaining output width available */
int c, ljust;
int end; /* number of input bytes remaining in str */
#endif
char *sp; /* current position in source string */
char *cp = *dest; /* current position in destination string */
- char *ep = cp + n; /* end of destination buffer */
+ char *ep = cp + n; /* end of destination buffer based on desired width */
+ char *epmax = cp + max; /* true end of destination buffer */
int prevCtrl = 1;
/* get alignment */
while (*sp && remaining > 0 && end > 0) {
#ifdef MULTIBYTE_SUPPORT
char_len = mbtowc(&wide_char, sp, end);
+
+ /* Account for multibyte characters taking only one character's
+ width of output. */
+ if (char_len > 1 && epmax - ep >= char_len - 1) {
+ ep += char_len - 1;
+ }
+
if (char_len <= 0 || (cp + char_len > ep))
break;
}
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
char_len = mbtowc(&wide_char, str, len);
+ /* Account for multibyte characters taking only one character's
+ width of output. */
+ if (char_len > 1 && max - end >= char_len - 1) {
+ end += char_len - 1;
+ }
+
if (char_len <= 0 || *dest + char_len > end)
break;
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, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill,
+ ep - cp, scanl - cp + max - 1);
break;
case FT_LIT:
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, str, fmt->f_width, fmt->f_fill, ep - cp,
+ scanl - cp + max - 1);
break;
case FT_STRLIT:
sp = str;
*cp++ = ' ';
}
}
- cpstripped (&cp, ep, lp);
+ cpstripped (&cp, ep, scanl + max - 1, lp);
}
break;