diff options
author | tjr <tjr@FreeBSD.org> | 2005-07-24 12:12:44 +0000 |
---|---|---|
committer | tjr <tjr@FreeBSD.org> | 2005-07-24 12:12:44 +0000 |
commit | d5948017e9381368f9b2c698d387c982af9b4ffe (patch) | |
tree | de4ec994c99e2b7447f5cd9d592f59833aa61ed7 /lib | |
parent | dae7e7f3e8cc89fb32a5e007cd67694e852b7fae (diff) | |
download | FreeBSD-src-d5948017e9381368f9b2c698d387c982af9b4ffe.zip FreeBSD-src-d5948017e9381368f9b2c698d387c982af9b4ffe.tar.gz |
Speed up __wcsconv() (and hence the printf() %ls format):
- use wcsrtombs() instead of a wcrtomb() loop where possible.
- avoid wcrtomb() loop when output precision is small.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/stdio/vfprintf.c | 64 |
1 files changed, 30 insertions, 34 deletions
diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c index 790f687..c19b069 100644 --- a/lib/libc/stdio/vfprintf.c +++ b/lib/libc/stdio/vfprintf.c @@ -331,9 +331,9 @@ __ujtoa(uintmax_t val, char *endp, int base, int octzero, const char *xdigs, /* * Convert a wide character string argument for the %ls format to a multibyte - * string representation. ``prec'' specifies the maximum number of bytes - * to output. If ``prec'' is greater than or equal to zero, we can't assume - * that the wide char. string ends in a null character. + * string representation. If not -1, prec specifies the maximum number of + * bytes to output, and also means that we can't assume that the wide char. + * string ends is null-terminated. */ static char * __wcsconv(wchar_t *wcsarg, int prec) @@ -342,53 +342,49 @@ __wcsconv(wchar_t *wcsarg, int prec) mbstate_t mbs; char buf[MB_LEN_MAX]; wchar_t *p; - char *convbuf, *mbp; + char *convbuf; size_t clen, nbytes; - /* - * Determine the number of bytes to output and allocate space for - * the output. - */ - if (prec >= 0) { - nbytes = 0; - p = wcsarg; - mbs = initial; - for (;;) { - clen = wcrtomb(buf, *p++, &mbs); - if (clen == 0 || clen == (size_t)-1 || - nbytes + clen > prec) - break; - nbytes += clen; - } - } else { + /* Allocate space for the maximum number of bytes we could output. */ + if (prec < 0) { p = wcsarg; mbs = initial; nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); if (nbytes == (size_t)-1) return (NULL); + } else { + /* + * Optimisation: if the output precision is small enough, + * just allocate enough memory for the maximum instead of + * scanning the string. + */ + if (prec < 128) + nbytes = prec; + else { + nbytes = 0; + p = wcsarg; + mbs = initial; + for (;;) { + clen = wcrtomb(buf, *p++, &mbs); + if (clen == 0 || clen == (size_t)-1 || + nbytes + clen > prec) + break; + nbytes += clen; + } + } } if ((convbuf = malloc(nbytes + 1)) == NULL) return (NULL); - /* - * Fill the output buffer with the multibyte representations of as - * many wide characters as will fit. - */ - mbp = convbuf; + /* Fill the output buffer. */ p = wcsarg; mbs = initial; - while (mbp - convbuf < nbytes) { - clen = wcrtomb(mbp, *p++, &mbs); - if (clen == 0 || clen == (size_t)-1) - break; - mbp += clen; - } - if (clen == (size_t)-1) { + if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p, + nbytes, &mbs)) == (size_t)-1) { free(convbuf); return (NULL); } - *mbp = '\0'; - + convbuf[nbytes] = '\0'; return (convbuf); } |