* 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;
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)");
*cp++ = ' ';
}
}
- cpstripped (&cp, ep, lp);
+ cpstripped (&cp, ep, scanl + max - 1, lp);
}
break;
}
fmt++;
}
-#ifndef JLR
+
+ /* 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;
+ } 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;
+ }
+ }
+ fmt++;
+ }
+
finished:;
if (cp > scanl && cp[-1] != '\n') {
if (cp - scanl < (int) max - 1) {
}
*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 */
}