]> git.saurik.com Git - apple/libc.git/blobdiff - stdio/FreeBSD/vfwprintf.c
Libc-1044.1.2.tar.gz
[apple/libc.git] / stdio / FreeBSD / vfwprintf.c
index 5e1c059c0f106fece8ff817f20f9e5e1a58a3e46..31764a9110e116d0cdd1f0fe36a75adebeb410c7 100644 (file)
@@ -38,6 +38,8 @@ static char sccsid[] = "@(#)vfprintf.c        8.1 (Berkeley) 6/4/93";
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/lib/libc/stdio/vfwprintf.c,v 1.42 2009/11/25 04:27:55 wollman Exp $");
 
+#include "xlocale_private.h"
+
 /*
  * Actual wprintf innards.
  *
@@ -59,6 +61,7 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/vfwprintf.c,v 1.42 2009/11/25 04:27:55 wo
 #include <string.h>
 #include <wchar.h>
 #include <wctype.h>
+#include <errno.h>
 #include "un-namespace.h"
 
 #include "libc_private.h"
@@ -66,10 +69,11 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/vfwprintf.c,v 1.42 2009/11/25 04:27:55 wo
 #include "fvwrite.h"
 #include "printflocal.h"
 
-static int     __sprint(FILE *, struct __suio *);
-static int     __sbprintf(FILE *, const wchar_t *, va_list) __noinline;
-static wint_t  __xfputwc(wchar_t, FILE *);
-static wchar_t *__mbsconv(char *, int);
+static int     __sprint(FILE *, locale_t, struct __suio *);
+static int     __sbprintf(FILE *, locale_t, const wchar_t *, va_list);
+static wint_t  __xfputwc(wchar_t, FILE *, locale_t);
+static wchar_t *__mbsconv(char *, int, locale_t);
+__private_extern__ const char *__fix_nogrouping(const char *);
 
 #define        CHAR    wchar_t
 #include "printfcommon.h"
@@ -85,29 +89,29 @@ struct grouping_state {
 static const mbstate_t initial_mbs;
 
 static inline wchar_t
-get_decpt(void)
+get_decpt(locale_t loc)
 {
        mbstate_t mbs;
        wchar_t decpt;
        int nconv;
 
        mbs = initial_mbs;
-       nconv = mbrtowc(&decpt, localeconv()->decimal_point, MB_CUR_MAX, &mbs);
+       nconv = mbrtowc_l(&decpt, localeconv_l(loc)->decimal_point, MB_CUR_MAX_L(loc), &mbs, loc);
        if (nconv == (size_t)-1 || nconv == (size_t)-2)
                decpt = '.';    /* failsafe */
        return (decpt);
 }
 
 static inline wchar_t
-get_thousep(void)
+get_thousep(locale_t loc)
 {
        mbstate_t mbs;
        wchar_t thousep;
        int nconv;
 
        mbs = initial_mbs;
-       nconv = mbrtowc(&thousep, localeconv()->thousands_sep,
-           MB_CUR_MAX, &mbs);
+       nconv = mbrtowc_l(&thousep, localeconv_l(loc)->thousands_sep,
+           MB_CUR_MAX_L(loc), &mbs, loc);
        if (nconv == (size_t)-1 || nconv == (size_t)-2)
                thousep = '\0';    /* failsafe */
        return (thousep);
@@ -119,11 +123,11 @@ get_thousep(void)
  * of wide characters that will be printed.
  */
 static int
-grouping_init(struct grouping_state *gs, int ndigits)
+grouping_init(struct grouping_state *gs, int ndigits, locale_t loc)
 {
 
-       gs->grouping = localeconv()->grouping;
-       gs->thousands_sep = get_thousep();
+       gs->grouping = __fix_nogrouping(localeconv_l(loc)->grouping);
+       gs->thousands_sep = get_thousep(loc);
 
        gs->nseps = gs->nrepeats = 0;
        gs->lead = ndigits;
@@ -145,11 +149,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) {
@@ -159,9 +163,9 @@ grouping_print(struct grouping_state *gs, struct io_state *iop,
                        gs->grouping--;
                        gs->nseps--;
                }
-               if (io_print(iop, &gs->thousands_sep, 1))
+               if (io_print(iop, &gs->thousands_sep, 1, 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;
        }
@@ -180,7 +184,7 @@ grouping_print(struct grouping_state *gs, struct io_state *iop,
  * string eclipses the benefits of buffering.
  */
 static int
-__sprint(FILE *fp, struct __suio *uio)
+__sprint(FILE *fp, locale_t loc, struct __suio *uio)
 {
        struct __siov *iov;
        wchar_t *p;
@@ -191,7 +195,7 @@ __sprint(FILE *fp, struct __suio *uio)
                p = (wchar_t *)iov->iov_base;
                len = iov->iov_len;
                for (i = 0; i < len; i++) {
-                       if (__xfputwc(p[i], fp) == WEOF)
+                       if (__xfputwc(p[i], fp, loc) == WEOF)
                                return (-1);
                }
        }
@@ -205,11 +209,14 @@ __sprint(FILE *fp, struct __suio *uio)
  * worries about ungetc buffers and so forth.
  */
 static int
-__sbprintf(FILE *fp, const wchar_t *fmt, va_list ap)
+__sbprintf(FILE *fp, locale_t loc, const wchar_t *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)
@@ -229,7 +236,7 @@ __sbprintf(FILE *fp, const wchar_t *fmt, va_list ap)
        fake._lbfsize = 0;      /* not actually used, but Just In Case */
 
        /* do the work, then copy any error status */
-       ret = __vfwprintf(&fake, fmt, ap);
+       ret = __vfwprintf(&fake, loc, fmt, ap);
        if (ret >= 0 && __fflush(&fake))
                ret = WEOF;
        if (fake._flags & __SERR)
@@ -242,7 +249,7 @@ __sbprintf(FILE *fp, const wchar_t *fmt, va_list ap)
  * File must already be locked.
  */
 static wint_t
-__xfputwc(wchar_t wc, FILE *fp)
+__xfputwc(wchar_t wc, FILE *fp, locale_t loc)
 {
        mbstate_t mbs;
        char buf[MB_LEN_MAX];
@@ -251,10 +258,10 @@ __xfputwc(wchar_t wc, FILE *fp)
        size_t len;
 
        if ((fp->_flags & __SSTR) == 0)
-               return (__fputwc(wc, fp));
+               return (__fputwc(wc, fp, loc));
 
        mbs = initial_mbs;
-       if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) {
+       if ((len = wcrtomb_l(buf, wc, &mbs, loc)) == (size_t)-1) {
                fp->_flags |= __SERR;
                return (WEOF);
        }
@@ -273,12 +280,13 @@ __xfputwc(wchar_t wc, FILE *fp)
  * that the multibyte char. string ends in a null character.
  */
 static wchar_t *
-__mbsconv(char *mbsarg, int prec)
+__mbsconv(char *mbsarg, int prec, locale_t loc)
 {
        mbstate_t mbs;
        wchar_t *convbuf, *wcp;
        const char *p;
-       size_t insize, nchars, nconv;
+       size_t insize, nchars, nconv = 0;
+       int mb_cur_max = MB_CUR_MAX_L(loc);
 
        if (mbsarg == NULL)
                return (NULL);
@@ -296,7 +304,7 @@ __mbsconv(char *mbsarg, int prec)
                insize = nchars = nconv = 0;
                mbs = initial_mbs;
                while (nchars != (size_t)prec) {
-                       nconv = mbrlen(p, MB_CUR_MAX, &mbs);
+                       nconv = mbrlen_l(p, mb_cur_max, &mbs, loc);
                        if (nconv == 0 || nconv == (size_t)-1 ||
                            nconv == (size_t)-2)
                                break;
@@ -323,7 +331,7 @@ __mbsconv(char *mbsarg, int prec)
        p = mbsarg;
        mbs = initial_mbs;
        while (insize != 0) {
-               nconv = mbrtowc(wcp, p, insize, &mbs);
+               nconv = mbrtowc_l(wcp, p, insize, &mbs, loc);
                if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2)
                        break;
                wcp++;
@@ -343,22 +351,28 @@ __mbsconv(char *mbsarg, int prec)
  * MT-safe version
  */
 int
-vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap)
-
+vfwprintf_l(FILE * __restrict fp, locale_t loc, const wchar_t * __restrict fmt0, va_list ap)
 {
        int ret;
 
+       NORMALIZE_LOCALE(loc);
        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);
+               ret = __sbprintf(fp, loc, fmt0, ap);
        else
-               ret = __vfwprintf(fp, fmt0, ap);
+               ret = __vfwprintf(fp, loc, fmt0, ap);
        FUNLOCKFILE(fp);
        return (ret);
 }
 
+int
+vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap)
+{
+       return vfwprintf_l(fp, __current_locale(), fmt0, ap);
+}
+
 /*
  * The size of the buffer we use as scratch space for integer
  * conversions, among other things.  We need enough space to
@@ -373,8 +387,8 @@ vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap)
 /*
  * Non-MT-safe version
  */
-int
-__vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap)
+__private_extern__ int
+__vfwprintf(FILE *fp, locale_t loc, const wchar_t *fmt0, va_list ap)
 {
        wchar_t *fmt;           /* format string */
        wchar_t ch;             /* character from fmt */
@@ -414,6 +428,11 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap)
        int ndig;               /* actual number of digits returned by dtoa */
        wchar_t expstr[MAXEXPDIG+2];    /* buffer for exponent string: e+ZZZ */
        char *dtoaresult;       /* buffer allocated by dtoa */
+#endif
+#ifdef VECTORS
+       union arg vval;         /* Vector argument. */
+       wchar_t *pct;           /* Pointer to '%' at beginning of specifier. */
+       wchar_t vsep;           /* Vector separator character. */
 #endif
        u_long  ulval;          /* integer arguments %[diouxX] */
        uintmax_t ujval;        /* %j, %ll, %q, %t, %z integers */
@@ -437,19 +456,19 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap)
 
        /* BEWARE, these `goto error' on error. */
 #define        PRINT(ptr, len) do {                    \
-       if (io_print(&io, (ptr), (len)))        \
+       if (io_print(&io, (ptr), (len), loc))   \
                goto error; \
 } while (0)
 #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; \
 }
 
@@ -485,7 +504,7 @@ __vfwprintf(FILE *fp, const wchar_t *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))
 
        /*
@@ -518,8 +537,11 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap)
 
 
        /* sorry, fwprintf(read_only_file, L"") returns WEOF, not 0 */
-       if (prepwrite(fp) != 0)
+       if (prepwrite(fp) != 0) {
+               errno = EBADF;
                return (EOF);
+       }
+       ORIENT(fp, 1);
 
        convbuf = NULL;
        fmt = (wchar_t *)fmt0;
@@ -529,7 +551,7 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap)
        io_init(&io, fp);
        ret = 0;
 #ifndef NO_FLOATING_POINT
-       decimal_point = get_decpt();
+       decimal_point = get_decpt(loc);
 #endif
 
        /*
@@ -548,6 +570,9 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap)
                }
                if (ch == '\0')
                        goto done;
+#ifdef VECTORS
+               pct = fmt;
+#endif /* VECTORS */
                fmt++;          /* skip over '%' */
 
                flags = 0;
@@ -557,6 +582,9 @@ __vfwprintf(FILE *fp, const wchar_t *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) {
@@ -572,6 +600,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
@@ -668,10 +701,14 @@ reswitch: switch (ch) {
                        flags |= LONGINT;
                        /*FALLTHROUGH*/
                case 'c':
+#ifdef VECTORS
+                       if (flags & VECTOR)
+                               break;
+#endif /* VECTORS */
                        if (flags & LONGINT)
                                *(cp = buf) = (wchar_t)GETARG(wint_t);
                        else
-                               *(cp = buf) = (wchar_t)btowc(GETARG(int));
+                               *(cp = buf) = (wchar_t)btowc_l(GETARG(int), loc);
                        size = 1;
                        sign = '\0';
                        break;
@@ -680,6 +717,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) {
@@ -698,6 +739,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;
@@ -727,11 +774,17 @@ reswitch: switch (ch) {
                        if (convbuf != NULL)
                                free(convbuf);
                        ndig = dtoaend - dtoaresult;
-                       cp = convbuf = __mbsconv(dtoaresult, -1);
+                       cp = convbuf = __mbsconv(dtoaresult, -1, loc);
                        freedtoa(dtoaresult);
                        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;
@@ -740,10 +793,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;
@@ -766,7 +831,7 @@ fp_begin:
                                        expt = INT_MAX;
                        }
                        ndig = dtoaend - dtoaresult;
-                       cp = convbuf = __mbsconv(dtoaresult, -1);
+                       cp = convbuf = __mbsconv(dtoaresult, -1, loc);
                        freedtoa(dtoaresult);
 fp_common:
                        if (signflag)
@@ -816,37 +881,46 @@ fp_common:
                                if (prec || flags & ALT)
                                        size += prec + 1;
                                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
@@ -861,6 +935,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;
@@ -882,7 +960,7 @@ fp_common:
                                if ((mbp = GETARG(char *)) == NULL)
                                        cp = L"(null)";
                                else {
-                                       convbuf = __mbsconv(mbp, prec);
+                                       convbuf = __mbsconv(mbp, prec, loc);
                                        if (convbuf == NULL) {
                                                fp->_flags |= __SERR;
                                                goto error;
@@ -890,13 +968,23 @@ fp_common:
                                        cp = convbuf;
                                }
                        }
+#if 0 // wcsnlen needs API review first
                        size = (prec >= 0) ? wcsnlen(cp, prec) : wcslen(cp);
+#else
+                       size = wcslen(cp);
+                       if(prec >= 0 && prec < size)
+                               size = prec;
+#endif
                        sign = '\0';
                        break;
                case 'U':
                        flags |= LONGINT;
                        /*FALLTHROUGH*/
                case 'u':
+#ifdef VECTORS
+                       if (flags & VECTOR)
+                               break;
+#endif /* VECTORS */
                        if (flags & INTMAX_SIZE)
                                ujval = UJARG();
                        else
@@ -909,6 +997,10 @@ fp_common:
                case 'x':
                        xdigs = xdigs_lower;
 hex:
+#ifdef VECTORS
+                       if (flags & VECTOR)
+                               break;
+#endif /* VECTORS */
                        if (flags & INTMAX_SIZE)
                                ujval = UJARG();
                        else
@@ -926,6 +1018,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;
@@ -953,10 +1046,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;
@@ -968,6 +1066,288 @@ 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);                                              \
+       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);                                              \
+       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
@@ -1018,7 +1398,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);
@@ -1036,7 +1416,7 @@ number:                   if ((dprec = prec) >= 0)
                                } else {
                                        if (gs.grouping) {
                                                n = grouping_print(&gs, &io,
-                                                   cp, convbuf + ndig);
+                                                   cp, convbuf + ndig, loc);
                                                if (n < 0)
                                                        goto error;
                                                cp += n;