summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authortjr <tjr@FreeBSD.org>2005-07-24 12:12:44 +0000
committertjr <tjr@FreeBSD.org>2005-07-24 12:12:44 +0000
commitd5948017e9381368f9b2c698d387c982af9b4ffe (patch)
treede4ec994c99e2b7447f5cd9d592f59833aa61ed7 /lib
parentdae7e7f3e8cc89fb32a5e007cd67694e852b7fae (diff)
downloadFreeBSD-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.c64
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);
}
OpenPOWER on IntegriCloud