]> git.saurik.com Git - apple/libc.git/blobdiff - stdio/FreeBSD/vfprintf.c
Libc-1044.1.2.tar.gz
[apple/libc.git] / stdio / FreeBSD / vfprintf.c
index df992ced9506dd4e207db8496dacbf7f56800dda..72dd5cc8e3256a7c5bf2b77feea088a84c7538d9 100644 (file)
@@ -36,6 +36,8 @@ static char sccsid[] = "@(#)vfprintf.c        8.1 (Berkeley) 6/4/93";
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/lib/libc/stdio/vfprintf.c,v 1.90 2009/02/28 06:06:57 das Exp $");
 
+#include "xlocale_private.h"
+
 /*
  * Actual printf innards.
  *
@@ -54,7 +56,10 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/vfprintf.c,v 1.90 2009/02/28 06:06:57 das
 #include <stdlib.h>
 #include <string.h>
 #include <wchar.h>
+#if 0 // xprintf pending API review
 #include <printf.h>
+#endif
+#include <errno.h>
 
 #include <stdarg.h>
 #include "un-namespace.h"
@@ -64,10 +69,13 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/vfprintf.c,v 1.90 2009/02/28 06:06:57 das
 #include "fvwrite.h"
 #include "printflocal.h"
 
-static int     __sprint(FILE *, struct __suio *);
-static int     __sbprintf(FILE *, const char *, va_list) __printflike(2, 0)
-       __noinline;
-static char    *__wcsconv(wchar_t *, int);
+static int     __sprint(FILE *, locale_t, struct __suio *);
+#if 0
+static int     __sbprintf(FILE *, locale_t, const char *, va_list) __printflike(3, 0);
+#endif
+static char    *__wcsconv(wchar_t *, int, locale_t);
+
+__private_extern__ const char *__fix_nogrouping(const char *);
 
 #define        CHAR    char
 #include "printfcommon.h"
@@ -87,12 +95,12 @@ struct grouping_state {
  * of bytes that will be needed.
  */
 static int
-grouping_init(struct grouping_state *gs, int ndigits)
+grouping_init(struct grouping_state *gs, int ndigits, locale_t loc)
 {
        struct lconv *locale;
 
-       locale = localeconv();
-       gs->grouping = locale->grouping;
+       locale = localeconv_l(loc);
+       gs->grouping = __fix_nogrouping(locale->grouping);
        gs->thousands_sep = locale->thousands_sep;
        gs->thousep_len = strlen(gs->thousands_sep);
 
@@ -116,11 +124,11 @@ grouping_init(struct grouping_state *gs, int ndigits)
  */
 static int
 grouping_print(struct grouping_state *gs, struct io_state *iop,
-              const CHAR *cp, const CHAR *ep)
+              const CHAR *cp, const CHAR *ep, locale_t loc)
 {
        const CHAR *cp0 = cp;
 
-       if (io_printandpad(iop, cp, ep, gs->lead, zeroes))
+       if (io_printandpad(iop, cp, ep, gs->lead, zeroes, loc))
                return (-1);
        cp += gs->lead;
        while (gs->nseps > 0 || gs->nrepeats > 0) {
@@ -130,9 +138,9 @@ grouping_print(struct grouping_state *gs, struct io_state *iop,
                        gs->grouping--;
                        gs->nseps--;
                }
-               if (io_print(iop, gs->thousands_sep, gs->thousep_len))
+               if (io_print(iop, gs->thousands_sep, gs->thousep_len, loc))
                        return (-1);
-               if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes))
+               if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, loc))
                        return (-1);
                cp += *gs->grouping;
        }
@@ -146,7 +154,7 @@ grouping_print(struct grouping_state *gs, struct io_state *iop,
  * then reset it so that it can be reused.
  */
 static int
-__sprint(FILE *fp, struct __suio *uio)
+__sprint(FILE *fp, locale_t loc __unused, struct __suio *uio)
 {
        int err;
 
@@ -160,17 +168,21 @@ __sprint(FILE *fp, struct __suio *uio)
        return (err);
 }
 
+#if 0
 /*
  * Helper function for `fprintf to unbuffered unix file': creates a
  * temporary buffer.  We only work on write-only files; this avoids
  * worries about ungetc buffers and so forth.
  */
 static int
-__sbprintf(FILE *fp, const char *fmt, va_list ap)
+__sbprintf(FILE *fp, locale_t loc, const char *fmt, va_list ap)
 {
        int ret;
        FILE fake;
        unsigned char buf[BUFSIZ];
+       struct __sFILEX ext;
+       fake._extra = &ext;
+       INITEXTRA(&fake);
 
        /* XXX This is probably not needed. */
        if (prepwrite(fp) != 0)
@@ -190,13 +202,14 @@ __sbprintf(FILE *fp, const char *fmt, va_list ap)
        fake._lbfsize = 0;      /* not actually used, but Just In Case */
 
        /* do the work, then copy any error status */
-       ret = __vfprintf(&fake, fmt, ap);
+       ret = __vfprintf(&fake, loc, fmt, ap);
        if (ret >= 0 && __fflush(&fake))
                ret = EOF;
        if (fake._flags & __SERR)
                fp->_flags |= __SERR;
        return (ret);
 }
+#endif
 
 /*
  * Convert a wide character string argument for the %ls format to a multibyte
@@ -205,7 +218,7 @@ __sbprintf(FILE *fp, const char *fmt, va_list ap)
  * string ends is null-terminated.
  */
 static char *
-__wcsconv(wchar_t *wcsarg, int prec)
+__wcsconv(wchar_t *wcsarg, int prec, locale_t loc)
 {
        static const mbstate_t initial;
        mbstate_t mbs;
@@ -218,7 +231,7 @@ __wcsconv(wchar_t *wcsarg, int prec)
        if (prec < 0) {
                p = wcsarg;
                mbs = initial;
-               nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
+               nbytes = wcsrtombs_l(NULL, (const wchar_t **)&p, 0, &mbs, loc);
                if (nbytes == (size_t)-1)
                        return (NULL);
        } else {
@@ -234,7 +247,7 @@ __wcsconv(wchar_t *wcsarg, int prec)
                        p = wcsarg;
                        mbs = initial;
                        for (;;) {
-                               clen = wcrtomb(buf, *p++, &mbs);
+                               clen = wcrtomb_l(buf, *p++, &mbs, loc);
                                if (clen == 0 || clen == (size_t)-1 ||
                                    nbytes + clen > prec)
                                        break;
@@ -248,8 +261,8 @@ __wcsconv(wchar_t *wcsarg, int prec)
        /* Fill the output buffer. */
        p = wcsarg;
        mbs = initial;
-       if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
-           nbytes, &mbs)) == (size_t)-1) {
+       if ((nbytes = wcsrtombs_l(convbuf, (const wchar_t **)&p,
+           nbytes, &mbs, loc)) == (size_t)-1) {
                free(convbuf);
                return (NULL);
        }
@@ -261,22 +274,29 @@ __wcsconv(wchar_t *wcsarg, int prec)
  * MT-safe version
  */
 int
-vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
+vfprintf_l(FILE * __restrict fp, locale_t loc, const char * __restrict fmt0, va_list ap)
 
 {
        int ret;
 
        FLOCKFILE(fp);
-       /* optimise fprintf(stderr) (and other unbuffered Unix files) */
-       if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
-           fp->_file >= 0)
-               ret = __sbprintf(fp, fmt0, ap);
-       else
-               ret = __vfprintf(fp, fmt0, ap);
+       ret = __xvprintf(XPRINTF_PLAIN, NULL, fp, loc, fmt0, ap);
        FUNLOCKFILE(fp);
        return (ret);
 }
 
+int
+vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
+
+{
+       int ret;
+
+       FLOCKFILE(fp);
+       ret = __xvprintf(XPRINTF_PLAIN, NULL, fp, __current_locale(), fmt0, ap);
+       FUNLOCKFILE(fp);
+       return ret;
+}
+
 /*
  * The size of the buffer we use as scratch space for integer
  * conversions, among other things.  We need enough space to
@@ -291,8 +311,8 @@ vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
 /*
  * Non-MT-safe version
  */
-int
-__vfprintf(FILE *fp, const char *fmt0, va_list ap)
+__private_extern__ int
+__vfprintf(FILE *fp, locale_t loc, const char *fmt0, va_list ap)
 {
        char *fmt;              /* format string */
        int ch;                 /* character from fmt */
@@ -334,6 +354,11 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
        int ndig;               /* actual number of digits returned by dtoa */
        char expstr[MAXEXPDIG+2];       /* buffer for exponent string: e+ZZZ */
        char *dtoaresult;       /* buffer allocated by dtoa */
+#endif
+#ifdef VECTORS
+       union arg vval;         /* Vector argument. */
+       char *pct;              /* Pointer to '%' at beginning of specifier. */
+       char vsep;              /* Vector separator character. */
 #endif
        u_long  ulval;          /* integer arguments %[diouxX] */
        uintmax_t ujval;        /* %j, %ll, %q, %t, %z integers */
@@ -357,19 +382,19 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
 
        /* BEWARE, these `goto error' on error. */
 #define        PRINT(ptr, len) { \
-       if (io_print(&io, (ptr), (len)))        \
+       if (io_print(&io, (ptr), (len), loc))   \
                goto error; \
 }
 #define        PAD(howmany, with) { \
-       if (io_pad(&io, (howmany), (with))) \
+       if (io_pad(&io, (howmany), (with), loc)) \
                goto error; \
 }
 #define        PRINTANDPAD(p, ep, len, with) { \
-       if (io_printandpad(&io, (p), (ep), (len), (with))) \
+       if (io_printandpad(&io, (p), (ep), (len), (with), loc)) \
                goto error; \
 }
 #define        FLUSH() { \
-       if (io_flush(&io)) \
+       if (io_flush(&io, loc)) \
                goto error; \
 }
 
@@ -405,7 +430,7 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
 #define        UJARG() \
        (flags&INTMAXT ? GETARG(uintmax_t) : \
            flags&SIZET ? (uintmax_t)GETARG(size_t) : \
-           flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
+           flags&PTRDIFFT ? (uintmax_t)(unsigned long)GETARG(ptrdiff_t) : \
            (uintmax_t)GETARG(unsigned long long))
 
        /*
@@ -436,14 +461,15 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
                val = GETARG (int); \
        }
 
-       if (__use_xprintf == 0 && getenv("USE_XPRINTF"))
-               __use_xprintf = 1;
-       if (__use_xprintf > 0)
-               return (__xvprintf(fp, fmt0, ap));
-
+       /* The following has been moved to __v2printf() */
+#if 0
        /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
-       if (prepwrite(fp) != 0)
+       if (prepwrite(fp) != 0) {
+               errno = EBADF;
                return (EOF);
+       }
+       ORIENT(fp, -1);
+#endif
 
        convbuf = NULL;
        fmt = (char *)fmt0;
@@ -454,7 +480,7 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
        ret = 0;
 #ifndef NO_FLOATING_POINT
        dtoaresult = NULL;
-       decimal_point = localeconv()->decimal_point;
+       decimal_point = localeconv_l(loc)->decimal_point;
        /* The overwhelmingly common case is decpt_len == 1. */
        decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point));
 #endif
@@ -475,6 +501,9 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
                }
                if (ch == '\0')
                        goto done;
+#ifdef VECTORS
+               pct = fmt;
+#endif /* VECTORS */
                fmt++;          /* skip over '%' */
 
                flags = 0;
@@ -484,6 +513,9 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
                gs.grouping = NULL;
                sign = '\0';
                ox[1] = '\0';
+#ifdef VECTORS
+               vsep = 'X'; /* Illegal value, changed to defaults later. */
+#endif /* VECTORS */
 
 rflag:         ch = *fmt++;
 reswitch:      switch (ch) {
@@ -499,6 +531,11 @@ reswitch:  switch (ch) {
                case '#':
                        flags |= ALT;
                        goto rflag;
+#ifdef VECTORS
+               case ',': case ';': case ':': case '_':
+                       vsep = ch;
+                       goto rflag;
+#endif /* VECTORS */
                case '*':
                        /*-
                         * ``A negative field width argument is taken as a
@@ -595,14 +632,18 @@ reswitch: switch (ch) {
                        flags |= LONGINT;
                        /*FALLTHROUGH*/
                case 'c':
+#ifdef VECTORS
+                       if (flags & VECTOR)
+                               break;
+#endif /* VECTORS */
                        if (flags & LONGINT) {
                                static const mbstate_t initial;
                                mbstate_t mbs;
                                size_t mbseqlen;
 
                                mbs = initial;
-                               mbseqlen = wcrtomb(cp = buf,
-                                   (wchar_t)GETARG(wint_t), &mbs);
+                               mbseqlen = wcrtomb_l(cp = buf,
+                                   (wchar_t)GETARG(wint_t), &mbs, loc);
                                if (mbseqlen == (size_t)-1) {
                                        fp->_flags |= __SERR;
                                        goto error;
@@ -619,6 +660,10 @@ reswitch:  switch (ch) {
                        /*FALLTHROUGH*/
                case 'd':
                case 'i':
+#ifdef VECTORS
+                       if (flags & VECTOR)
+                               break;
+#endif /* VECTORS */
                        if (flags & INTMAX_SIZE) {
                                ujval = SJARG();
                                if ((intmax_t)ujval < 0) {
@@ -637,6 +682,12 @@ reswitch:  switch (ch) {
 #ifndef NO_FLOATING_POINT
                case 'a':
                case 'A':
+#ifdef VECTORS
+                       if (flags & VECTOR) {
+                               flags |= FPT;
+                               break;
+                       }
+#endif /* VECTORS */
                        if (ch == 'a') {
                                ox[1] = 'x';
                                xdigs = xdigs_lower;
@@ -668,6 +719,12 @@ reswitch:  switch (ch) {
                        goto fp_common;
                case 'e':
                case 'E':
+#ifdef VECTORS
+                       if (flags & VECTOR) {
+                               flags |= FPT;
+                               break;
+                       }
+#endif /* VECTORS */
                        expchar = ch;
                        if (prec < 0)   /* account for digit before decpt */
                                prec = DEFPREC + 1;
@@ -676,10 +733,22 @@ reswitch: switch (ch) {
                        goto fp_begin;
                case 'f':
                case 'F':
+#ifdef VECTORS
+                       if (flags & VECTOR) {
+                               flags |= FPT;
+                               break;
+                       }
+#endif /* VECTORS */
                        expchar = '\0';
                        goto fp_begin;
                case 'g':
                case 'G':
+#ifdef VECTORS
+                       if (flags & VECTOR) {
+                               flags |= FPT;
+                               break;
+                       }
+#endif /* VECTORS */
                        expchar = ch - ('g' - 'e');
                        if (prec == 0)
                                prec = 1;
@@ -750,37 +819,46 @@ fp_common:
                                if (prec || flags & ALT)
                                        size += prec + decpt_len;
                                if ((flags & GROUPING) && expt > 0)
-                                       size += grouping_init(&gs, expt);
+                                       size += grouping_init(&gs, expt, loc);
                        }
                        break;
 #endif /* !NO_FLOATING_POINT */
                case 'n':
+               {
                        /*
                         * Assignment-like behavior is specified if the
                         * value overflows or is otherwise unrepresentable.
                         * C99 says to use `signed char' for %hhn conversions.
                         */
-                       if (flags & LLONGINT)
-                               *GETARG(long long *) = ret;
+                       void *ptr = GETARG(void *);
+                       if (ptr == NULL)
+                               continue;
+                       else if (flags & LLONGINT)
+                               *(long long *)ptr = ret;
                        else if (flags & SIZET)
-                               *GETARG(ssize_t *) = (ssize_t)ret;
+                               *(ssize_t *)ptr = (ssize_t)ret;
                        else if (flags & PTRDIFFT)
-                               *GETARG(ptrdiff_t *) = ret;
+                               *(ptrdiff_t *)ptr = ret;
                        else if (flags & INTMAXT)
-                               *GETARG(intmax_t *) = ret;
+                               *(intmax_t *)ptr = ret;
                        else if (flags & LONGINT)
-                               *GETARG(long *) = ret;
+                               *(long *)ptr = ret;
                        else if (flags & SHORTINT)
-                               *GETARG(short *) = ret;
+                               *(short *)ptr = ret;
                        else if (flags & CHARINT)
-                               *GETARG(signed char *) = ret;
+                               *(signed char *)ptr = ret;
                        else
-                               *GETARG(int *) = ret;
+                               *(int *)ptr = ret;
                        continue;       /* no output */
+               }
                case 'O':
                        flags |= LONGINT;
                        /*FALLTHROUGH*/
                case 'o':
+#ifdef VECTORS
+                       if (flags & VECTOR)
+                               break;
+#endif /* VECTORS */
                        if (flags & INTMAX_SIZE)
                                ujval = UJARG();
                        else
@@ -795,6 +873,10 @@ fp_common:
                         * defined manner.''
                         *      -- ANSI X3J11
                         */
+#ifdef VECTORS
+                       if (flags & VECTOR)
+                               break;
+#endif /* VECTORS */
                        ujval = (uintmax_t)(uintptr_t)GETARG(void *);
                        base = 16;
                        xdigs = xdigs_lower;
@@ -813,7 +895,7 @@ fp_common:
                                if ((wcp = GETARG(wchar_t *)) == NULL)
                                        cp = "(null)";
                                else {
-                                       convbuf = __wcsconv(wcp, prec);
+                                       convbuf = __wcsconv(wcp, prec, loc);
                                        if (convbuf == NULL) {
                                                fp->_flags |= __SERR;
                                                goto error;
@@ -829,6 +911,10 @@ fp_common:
                        flags |= LONGINT;
                        /*FALLTHROUGH*/
                case 'u':
+#ifdef VECTORS
+                       if (flags & VECTOR)
+                               break;
+#endif /* VECTORS */
                        if (flags & INTMAX_SIZE)
                                ujval = UJARG();
                        else
@@ -841,6 +927,10 @@ fp_common:
                case 'x':
                        xdigs = xdigs_lower;
 hex:
+#ifdef VECTORS
+                       if (flags & VECTOR)
+                               break;
+#endif /* VECTORS */
                        if (flags & INTMAX_SIZE)
                                ujval = UJARG();
                        else
@@ -858,6 +948,7 @@ nosign:                     sign = '\0';
                         * ``... diouXx conversions ... if a precision is
                         * specified, the 0 flag will be ignored.''
                         *      -- ANSI X3J11
+                        * except for %#.0o and zero value
                         */
 number:                        if ((dprec = prec) >= 0)
                                flags &= ~ZEROPAD;
@@ -885,10 +976,15 @@ number:                   if ((dprec = prec) >= 0)
                        }
                        size = buf + BUF - cp;
                        if (size > BUF) /* should never happen */
-                               abort();
+                               LIBC_ABORT("size (%d) > BUF (%d)", size, BUF);
                        if ((flags & GROUPING) && size != 0)
-                               size += grouping_init(&gs, size);
+                               size += grouping_init(&gs, size, loc);
                        break;
+#ifdef VECTORS
+               case 'v':
+                       flags |= VECTOR;
+                       goto rflag;
+#endif /* VECTORS */
                default:        /* "%?" prints ?, unless ? is NUL */
                        if (ch == '\0')
                                goto done;
@@ -900,6 +996,290 @@ number:                   if ((dprec = prec) >= 0)
                        break;
                }
 
+#ifdef VECTORS
+               if (flags & VECTOR) {
+                       /*
+                        * Do the minimum amount of work necessary to construct
+                        * a format specifier that can be used to recursively
+                        * call vfprintf() for each element in the vector.
+                        */
+                       int i, j;       /* Counter. */
+                       int vcnt;       /* Number of elements in vector. */
+                       char *vfmt;     /* Pointer to format specifier. */
+#define EXTRAHH 2
+                       char vfmt_buf[32 + EXTRAHH]; /* Static buffer for format spec. */
+                       int vwidth = 0; /* Width specified via '*'. */
+                       int vprec = 0;  /* Precision specified via '*'. */
+                       char *vstr;     /* Used for asprintf(). */
+                       int vlen;       /* Length returned by asprintf(). */
+                       enum {
+                           V_CHAR, V_SHORT, V_INT,
+                           V_PCHAR, V_PSHORT, V_PINT,
+                           V_FLOAT,
+#ifdef V64TYPE
+                           V_LONGLONG, V_PLONGLONG,
+                           V_DOUBLE,
+#endif /* V64TYPE */
+                       } vtype;
+
+                       vval.vectorarg = GETARG(VECTORTYPE);
+                       /*
+                        * Set vfmt.  If vfmt_buf may not be big enough,
+                        * malloc() space, taking care to free it later.
+                        * (EXTRAHH is for possible extra "hh")
+                        */
+                       if (&fmt[-1] - pct + EXTRAHH < sizeof(vfmt_buf))
+                               vfmt = vfmt_buf;
+                       else
+                               vfmt = (char *)malloc(&fmt[-1] - pct + EXTRAHH + 1);
+
+                       /* Set the separator character, if not specified. */
+                       if (vsep == 'X') {
+                               if (ch == 'c')
+                                       vsep = '\0';
+                               else
+                                       vsep = ' ';
+                       }
+
+                       /* Create the format specifier. */
+                       for (i = j = 0; i < &fmt[-1] - pct; i++) {
+                               switch (pct[i]) {
+                               case ',': case ';': case ':': case '_':
+                               case 'v': case 'h': case 'l':
+                                       /* Ignore. */
+                                       break;
+                               case '*':
+                                       if (pct[i - 1] != '.')
+                                               vwidth = 1;
+                                       else
+                                               vprec = 1;
+                                       /* FALLTHROUGH */
+                               default:
+                                       vfmt[j++] = pct[i];
+                               }
+                       }
+               
+                       /*
+                        * Determine the number of elements in the vector and
+                        * finish up the format specifier.
+                        */
+                       if (flags & SHORTINT) {
+                               switch (ch) {
+                               case 'c':
+                                       vtype = V_SHORT;
+                                       break;
+                               case 'p':
+                                       vtype = V_PSHORT;
+                                       break;
+                               default:
+                                       vfmt[j++] = 'h';
+                                       vtype = V_SHORT;
+                                       break;
+                               }
+                               vcnt = 8;
+                       } else if (flags & LONGINT) {
+                               vcnt = 4;
+                               vtype = (ch == 'p') ? V_PINT : V_INT;
+#ifdef V64TYPE
+                       } else if (flags & LLONGINT) {
+                               switch (ch) {
+                               case 'a':
+                               case 'A':
+                               case 'e':
+                               case 'E':
+                               case 'f':
+                               case 'g':
+                               case 'G':
+                                       vcnt = 2;
+                                       vtype = V_DOUBLE;
+                                       break;
+                               case 'd':
+                               case 'i':
+                               case 'u':
+                               case 'o':
+                               case 'p':
+                               case 'x':
+                               case 'X':
+                                       vfmt[j++] = 'l';
+                                       vfmt[j++] = 'l';
+                                       vcnt = 2;
+                                       vtype = (ch == 'p') ? V_PLONGLONG : V_LONGLONG;
+                                       break;
+                               default:
+                                       /*
+                                        * The default case should never
+                                        * happen.
+                                        */
+                               case 'c':
+                                       vcnt = 16;
+                                       vtype = V_CHAR;
+                               }
+#endif /* V64TYPE */
+                       } else {
+                               switch (ch) {
+                               case 'a':
+                               case 'A':
+                               case 'e':
+                               case 'E':
+                               case 'f':
+                               case 'g':
+                               case 'G':
+                                       vcnt = 4;
+                                       vtype = V_FLOAT;
+                                       break;
+                               default:
+                                       /*
+                                        * The default case should never
+                                        * happen.
+                                        */
+                               case 'd':
+                               case 'i':
+                               case 'u':
+                               case 'o':
+                               case 'x':
+                               case 'X':
+                                       vfmt[j++] = 'h';
+                                       vfmt[j++] = 'h';
+                                       /* drop through */
+                               case 'p':
+                               case 'c':
+                                       vcnt = 16;
+                                       vtype = (ch == 'p') ? V_PCHAR : V_CHAR;
+                               }
+                       }
+                       vfmt[j++] = ch;
+                       vfmt[j++] = '\0';
+
+/* Get a vector element. */
+#ifdef V64TYPE
+#define VPRINT(type, ind, args...) do {                                        \
+       switch (type) {                                                 \
+       case V_CHAR:                                                    \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vuchararg[ind]); \
+               break;                                                  \
+       case V_PCHAR:                                                   \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vuchararg[ind]); \
+               break;                                                  \
+       case V_SHORT:                                                   \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vushortarg[ind]); \
+               break;                                                  \
+       case V_PSHORT:                                                  \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vushortarg[ind]); \
+               break;                                                  \
+       case V_INT:                                                     \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vuintarg[ind]); \
+               break;                                                  \
+       case V_PINT:                                                    \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vuintarg[ind]); \
+               break;                                                  \
+       case V_LONGLONG:                                                \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vulonglongarg[ind]); \
+               break;                                                  \
+       case V_PLONGLONG:                                               \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vulonglongarg[ind]); \
+               break;                                                  \
+       case V_FLOAT:                                                   \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vfloatarg[ind]); \
+               break;                                                  \
+       case V_DOUBLE:                                                  \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vdoublearg[ind]); \
+               break;                                                  \
+       }                                                               \
+       ret += vlen;                                                    \
+       PRINT(vstr, vlen);                                              \
+       FLUSH();                                                        \
+       free(vstr);                                                     \
+} while (0)
+#else /* !V64TYPE */
+#define VPRINT(type, ind, args...) do {                                        \
+       switch (type) {                                                 \
+       case V_CHAR:                                                    \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vuchararg[ind]); \
+               break;                                                  \
+       case V_PCHAR:                                                   \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vuchararg[ind]); \
+               break;                                                  \
+       case V_SHORT:                                                   \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vushortarg[ind]); \
+               break;                                                  \
+       case V_PSHORT:                                                  \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vushortarg[ind]); \
+               break;                                                  \
+       case V_INT:                                                     \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vuintarg[ind]); \
+               break;                                                  \
+       case V_PINT:                                                    \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, (void *)(uintptr_t)vval.vuintarg[ind]); \
+               break;                                                  \
+       case V_FLOAT:                                                   \
+               vlen = asprintf_l(&vstr, loc, vfmt , ## args, vval.vfloatarg[ind]); \
+               break;                                                  \
+       }                                                               \
+       ret += vlen;                                                    \
+       PRINT(vstr, vlen);                                              \
+       FLUSH();                                                        \
+       free(vstr);                                                     \
+} while (0)
+#endif /* V64TYPE */
+
+                       /* Actually print. */
+                       if (vwidth == 0) {
+                               if (vprec == 0) {
+                                       /* First element. */
+                                       VPRINT(vtype, 0);
+                                       for (i = 1; i < vcnt; i++) {
+                                               /* Separator. */
+                                               if(vsep)
+                                                       PRINT(&vsep, 1);
+
+                                               /* Element. */
+                                               VPRINT(vtype, i);
+                                       }
+                               } else {
+                                       /* First element. */
+                                       VPRINT(vtype, 0, prec);
+                                       for (i = 1; i < vcnt; i++) {
+                                               /* Separator. */
+                                               if(vsep)
+                                                       PRINT(&vsep, 1);
+
+                                               /* Element. */
+                                               VPRINT(vtype, i, prec);
+                                       }
+                               }
+                       } else {
+                               if (vprec == 0) {
+                                       /* First element. */
+                                       VPRINT(vtype, 0, width);
+                                       for (i = 1; i < vcnt; i++) {
+                                               /* Separator. */
+                                               if(vsep)
+                                                       PRINT(&vsep, 1);
+
+                                               /* Element. */
+                                               VPRINT(vtype, i, width);
+                                       }
+                               } else {
+                                       /* First element. */
+                                       VPRINT(vtype, 0, width, prec);
+                                       for (i = 1; i < vcnt; i++) {
+                                               /* Separator. */
+                                               if(vsep)
+                                                       PRINT(&vsep, 1);
+
+                                               /* Element. */
+                                               VPRINT(vtype, i, width, prec);
+                                       }
+                               }
+                       }
+#undef VPRINT
+
+                       if (vfmt != vfmt_buf)
+                               free(vfmt);
+
+                       continue;
+               }
+#endif /* VECTORS */
                /*
                 * All reasonable formats wind up here.  At this point, `cp'
                 * points to a string which (if not flags&LADJUST) should be
@@ -950,7 +1330,7 @@ number:                    if ((dprec = prec) >= 0)
                        /* leading zeroes from decimal precision */
                        PAD(dprec - size, zeroes);
                        if (gs.grouping) {
-                               if (grouping_print(&gs, &io, cp, buf+BUF) < 0)
+                               if (grouping_print(&gs, &io, cp, buf+BUF, loc) < 0)
                                        goto error;
                        } else {
                                PRINT(cp, size);
@@ -968,7 +1348,7 @@ number:                    if ((dprec = prec) >= 0)
                                } else {
                                        if (gs.grouping) {
                                                n = grouping_print(&gs, &io,
-                                                   cp, dtoaend);
+                                                   cp, dtoaend, loc);
                                                if (n < 0)
                                                        goto error;
                                                cp += n;