16f1e2b38SJoerg Sonnenberger /*-
26f1e2b38SJoerg Sonnenberger * Copyright (c) 1990, 1993
36f1e2b38SJoerg Sonnenberger * The Regents of the University of California. All rights reserved.
46f1e2b38SJoerg Sonnenberger *
56f1e2b38SJoerg Sonnenberger * This code is derived from software contributed to Berkeley by
66f1e2b38SJoerg Sonnenberger * Chris Torek.
76f1e2b38SJoerg Sonnenberger *
8*0d5acd74SJohn Marino * Copyright (c) 2011 The FreeBSD Foundation
9*0d5acd74SJohn Marino * All rights reserved.
10*0d5acd74SJohn Marino * Portions of this software were developed by David Chisnall
11*0d5acd74SJohn Marino * under sponsorship from the FreeBSD Foundation.
12*0d5acd74SJohn Marino *
136f1e2b38SJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without
146f1e2b38SJoerg Sonnenberger * modification, are permitted provided that the following conditions
156f1e2b38SJoerg Sonnenberger * are met:
166f1e2b38SJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright
176f1e2b38SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer.
186f1e2b38SJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright
196f1e2b38SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the
206f1e2b38SJoerg Sonnenberger * documentation and/or other materials provided with the distribution.
21dc71b7abSJustin C. Sherrill * 3. Neither the name of the University nor the names of its contributors
226f1e2b38SJoerg Sonnenberger * may be used to endorse or promote products derived from this software
236f1e2b38SJoerg Sonnenberger * without specific prior written permission.
246f1e2b38SJoerg Sonnenberger *
256f1e2b38SJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
266f1e2b38SJoerg Sonnenberger * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
276f1e2b38SJoerg Sonnenberger * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
286f1e2b38SJoerg Sonnenberger * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
296f1e2b38SJoerg Sonnenberger * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
306f1e2b38SJoerg Sonnenberger * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
316f1e2b38SJoerg Sonnenberger * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
326f1e2b38SJoerg Sonnenberger * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
336f1e2b38SJoerg Sonnenberger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
346f1e2b38SJoerg Sonnenberger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
356f1e2b38SJoerg Sonnenberger * SUCH DAMAGE.
366f1e2b38SJoerg Sonnenberger *
37e0f95098SPeter Avalos * @(#)vfprintf.c 8.1 (Berkeley) 6/4/93
38*0d5acd74SJohn Marino * $FreeBSD: head/lib/libc/stdio/vfwprintf.c 249808 2013-04-23 13:33:13Z emaste $
396f1e2b38SJoerg Sonnenberger */
406f1e2b38SJoerg Sonnenberger
416f1e2b38SJoerg Sonnenberger /*
426f1e2b38SJoerg Sonnenberger * Actual wprintf innards.
436f1e2b38SJoerg Sonnenberger *
446f1e2b38SJoerg Sonnenberger * Avoid making gratuitous changes to this source file; it should be kept
456f1e2b38SJoerg Sonnenberger * as close as possible to vfprintf.c for ease of maintenance.
466f1e2b38SJoerg Sonnenberger */
476f1e2b38SJoerg Sonnenberger
486f1e2b38SJoerg Sonnenberger #include "namespace.h"
496f1e2b38SJoerg Sonnenberger #include <sys/types.h>
506f1e2b38SJoerg Sonnenberger
516f1e2b38SJoerg Sonnenberger #include <ctype.h>
52*0d5acd74SJohn Marino #include <errno.h>
536f1e2b38SJoerg Sonnenberger #include <limits.h>
546f1e2b38SJoerg Sonnenberger #include <locale.h>
556f1e2b38SJoerg Sonnenberger #include <stdarg.h>
566f1e2b38SJoerg Sonnenberger #include <stddef.h>
576f1e2b38SJoerg Sonnenberger #include <stdint.h>
586f1e2b38SJoerg Sonnenberger #include <stdio.h>
596f1e2b38SJoerg Sonnenberger #include <stdlib.h>
606f1e2b38SJoerg Sonnenberger #include <string.h>
616f1e2b38SJoerg Sonnenberger #include <wchar.h>
626f1e2b38SJoerg Sonnenberger #include <wctype.h>
636f1e2b38SJoerg Sonnenberger #include "un-namespace.h"
646f1e2b38SJoerg Sonnenberger
656f1e2b38SJoerg Sonnenberger #include "libc_private.h"
666f1e2b38SJoerg Sonnenberger #include "local.h"
67e0f95098SPeter Avalos #include "printflocal.h"
68*0d5acd74SJohn Marino #include "xlocale_private.h"
696f1e2b38SJoerg Sonnenberger
70*0d5acd74SJohn Marino static int __sprint(FILE *, struct __suio *, locale_t);
71*0d5acd74SJohn Marino static int __sbprintf(FILE *, locale_t, const wchar_t *, va_list) __noinline;
72*0d5acd74SJohn Marino static wint_t __xfputwc(wchar_t, FILE *, locale_t);
73e0f95098SPeter Avalos static wchar_t *__mbsconv(char *, int);
746f1e2b38SJoerg Sonnenberger
75e0f95098SPeter Avalos #define CHAR wchar_t
76e0f95098SPeter Avalos #include "printfcommon.h"
77e0f95098SPeter Avalos
78e0f95098SPeter Avalos struct grouping_state {
79e0f95098SPeter Avalos wchar_t thousands_sep; /* locale-specific thousands separator */
80e0f95098SPeter Avalos const char *grouping; /* locale-specific numeric grouping rules */
81e0f95098SPeter Avalos int lead; /* sig figs before decimal or group sep */
82e0f95098SPeter Avalos int nseps; /* number of group separators with ' */
83e0f95098SPeter Avalos int nrepeats; /* number of repeats of the last group */
846f1e2b38SJoerg Sonnenberger };
856f1e2b38SJoerg Sonnenberger
86e0f95098SPeter Avalos static const mbstate_t initial_mbs;
87e0f95098SPeter Avalos
88e0f95098SPeter Avalos static inline wchar_t
get_decpt(locale_t locale)89*0d5acd74SJohn Marino get_decpt(locale_t locale)
90e0f95098SPeter Avalos {
91e0f95098SPeter Avalos mbstate_t mbs;
92e0f95098SPeter Avalos wchar_t decpt;
93e0f95098SPeter Avalos int nconv;
94e0f95098SPeter Avalos
95e0f95098SPeter Avalos mbs = initial_mbs;
96*0d5acd74SJohn Marino nconv = mbrtowc(&decpt, localeconv_l(locale)->decimal_point, MB_CUR_MAX, &mbs);
97e0f95098SPeter Avalos if (nconv == (size_t)-1 || nconv == (size_t)-2)
98e0f95098SPeter Avalos decpt = '.'; /* failsafe */
99e0f95098SPeter Avalos return (decpt);
100e0f95098SPeter Avalos }
101e0f95098SPeter Avalos
102e0f95098SPeter Avalos static inline wchar_t
get_thousep(locale_t locale)103*0d5acd74SJohn Marino get_thousep(locale_t locale)
104e0f95098SPeter Avalos {
105e0f95098SPeter Avalos mbstate_t mbs;
106e0f95098SPeter Avalos wchar_t thousep;
107e0f95098SPeter Avalos int nconv;
108e0f95098SPeter Avalos
109e0f95098SPeter Avalos mbs = initial_mbs;
110*0d5acd74SJohn Marino nconv = mbrtowc(&thousep, localeconv_l(locale)->thousands_sep,
111e0f95098SPeter Avalos MB_CUR_MAX, &mbs);
112e0f95098SPeter Avalos if (nconv == (size_t)-1 || nconv == (size_t)-2)
113e0f95098SPeter Avalos thousep = '\0'; /* failsafe */
114e0f95098SPeter Avalos return (thousep);
115e0f95098SPeter Avalos }
116e0f95098SPeter Avalos
1176f1e2b38SJoerg Sonnenberger /*
118e0f95098SPeter Avalos * Initialize the thousands' grouping state in preparation to print a
119e0f95098SPeter Avalos * number with ndigits digits. This routine returns the total number
120e0f95098SPeter Avalos * of wide characters that will be printed.
1216f1e2b38SJoerg Sonnenberger */
122e0f95098SPeter Avalos static int
grouping_init(struct grouping_state * gs,int ndigits,locale_t locale)123*0d5acd74SJohn Marino grouping_init(struct grouping_state *gs, int ndigits, locale_t locale)
124e0f95098SPeter Avalos {
1256f1e2b38SJoerg Sonnenberger
126*0d5acd74SJohn Marino gs->grouping = localeconv_l(locale)->grouping;
127*0d5acd74SJohn Marino gs->thousands_sep = get_thousep(locale);
128e0f95098SPeter Avalos
129e0f95098SPeter Avalos gs->nseps = gs->nrepeats = 0;
130e0f95098SPeter Avalos gs->lead = ndigits;
131e0f95098SPeter Avalos while (*gs->grouping != CHAR_MAX) {
132e0f95098SPeter Avalos if (gs->lead <= *gs->grouping)
133e0f95098SPeter Avalos break;
134e0f95098SPeter Avalos gs->lead -= *gs->grouping;
135e0f95098SPeter Avalos if (*(gs->grouping+1)) {
136e0f95098SPeter Avalos gs->nseps++;
137e0f95098SPeter Avalos gs->grouping++;
138e0f95098SPeter Avalos } else
139e0f95098SPeter Avalos gs->nrepeats++;
140e0f95098SPeter Avalos }
141e0f95098SPeter Avalos return (gs->nseps + gs->nrepeats);
142e0f95098SPeter Avalos }
143e0f95098SPeter Avalos
144e0f95098SPeter Avalos /*
145e0f95098SPeter Avalos * Print a number with thousands' separators.
146e0f95098SPeter Avalos */
147e0f95098SPeter Avalos static int
grouping_print(struct grouping_state * gs,struct io_state * iop,const CHAR * cp,const CHAR * ep,locale_t locale)148e0f95098SPeter Avalos grouping_print(struct grouping_state *gs, struct io_state *iop,
149*0d5acd74SJohn Marino const CHAR *cp, const CHAR *ep, locale_t locale)
150e0f95098SPeter Avalos {
151e0f95098SPeter Avalos const CHAR *cp0 = cp;
152e0f95098SPeter Avalos
153*0d5acd74SJohn Marino if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale))
154e0f95098SPeter Avalos return (-1);
155e0f95098SPeter Avalos cp += gs->lead;
156e0f95098SPeter Avalos while (gs->nseps > 0 || gs->nrepeats > 0) {
157e0f95098SPeter Avalos if (gs->nrepeats > 0)
158e0f95098SPeter Avalos gs->nrepeats--;
159e0f95098SPeter Avalos else {
160e0f95098SPeter Avalos gs->grouping--;
161e0f95098SPeter Avalos gs->nseps--;
162e0f95098SPeter Avalos }
163*0d5acd74SJohn Marino if (io_print(iop, &gs->thousands_sep, 1, locale))
164e0f95098SPeter Avalos return (-1);
165*0d5acd74SJohn Marino if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale))
166e0f95098SPeter Avalos return (-1);
167e0f95098SPeter Avalos cp += *gs->grouping;
168e0f95098SPeter Avalos }
169e0f95098SPeter Avalos if (cp > ep)
170e0f95098SPeter Avalos cp = ep;
171e0f95098SPeter Avalos return (cp - cp0);
172e0f95098SPeter Avalos }
173e0f95098SPeter Avalos
174e0f95098SPeter Avalos
175e0f95098SPeter Avalos /*
176e0f95098SPeter Avalos * Flush out all the vectors defined by the given uio,
177e0f95098SPeter Avalos * then reset it so that it can be reused.
178e0f95098SPeter Avalos *
179e0f95098SPeter Avalos * XXX The fact that we do this a character at a time and convert to a
180e0f95098SPeter Avalos * multibyte character sequence even if the destination is a wide
181e0f95098SPeter Avalos * string eclipses the benefits of buffering.
182e0f95098SPeter Avalos */
183e0f95098SPeter Avalos static int
__sprint(FILE * fp,struct __suio * uio,locale_t locale)184*0d5acd74SJohn Marino __sprint(FILE *fp, struct __suio *uio, locale_t locale)
185e0f95098SPeter Avalos {
186e0f95098SPeter Avalos struct __siov *iov;
187e0f95098SPeter Avalos wchar_t *p;
188e0f95098SPeter Avalos int i, len;
189e0f95098SPeter Avalos
190e0f95098SPeter Avalos iov = uio->uio_iov;
191e0f95098SPeter Avalos for (; uio->uio_resid != 0; uio->uio_resid -= len, iov++) {
192e0f95098SPeter Avalos p = (wchar_t *)iov->iov_base;
193e0f95098SPeter Avalos len = iov->iov_len;
194e0f95098SPeter Avalos for (i = 0; i < len; i++) {
195*0d5acd74SJohn Marino if (__xfputwc(p[i], fp, locale) == WEOF)
196e0f95098SPeter Avalos return (-1);
197e0f95098SPeter Avalos }
198e0f95098SPeter Avalos }
199e0f95098SPeter Avalos uio->uio_iovcnt = 0;
200e0f95098SPeter Avalos return (0);
201e0f95098SPeter Avalos }
2026f1e2b38SJoerg Sonnenberger
2036f1e2b38SJoerg Sonnenberger /*
2046f1e2b38SJoerg Sonnenberger * Helper function for `fprintf to unbuffered unix file': creates a
2056f1e2b38SJoerg Sonnenberger * temporary buffer. We only work on write-only files; this avoids
2066f1e2b38SJoerg Sonnenberger * worries about ungetc buffers and so forth.
2076f1e2b38SJoerg Sonnenberger */
2086f1e2b38SJoerg Sonnenberger static int
__sbprintf(FILE * fp,locale_t locale,const wchar_t * fmt,va_list ap)209*0d5acd74SJohn Marino __sbprintf(FILE *fp, locale_t locale, const wchar_t *fmt, va_list ap)
2106f1e2b38SJoerg Sonnenberger {
2116f1e2b38SJoerg Sonnenberger int ret;
2126f1e2b38SJoerg Sonnenberger FILE fake;
2136f1e2b38SJoerg Sonnenberger unsigned char buf[BUFSIZ];
2146f1e2b38SJoerg Sonnenberger
215e0f95098SPeter Avalos /* XXX This is probably not needed. */
216e0f95098SPeter Avalos if (prepwrite(fp) != 0)
217e0f95098SPeter Avalos return (EOF);
218e0f95098SPeter Avalos
2196f1e2b38SJoerg Sonnenberger /* copy the important variables */
2206f1e2b38SJoerg Sonnenberger fake.pub._flags = fp->pub._flags & ~__SNBF;
2216f1e2b38SJoerg Sonnenberger fake.pub._fileno = fp->pub._fileno;
2226f1e2b38SJoerg Sonnenberger fake._cookie = fp->_cookie;
2236f1e2b38SJoerg Sonnenberger fake._write = fp->_write;
2246f1e2b38SJoerg Sonnenberger
2256f1e2b38SJoerg Sonnenberger /* set up the buffer */
2266f1e2b38SJoerg Sonnenberger fake._bf._base = fake.pub._p = buf;
2276f1e2b38SJoerg Sonnenberger fake._bf._size = fake.pub._w = sizeof(buf);
2286f1e2b38SJoerg Sonnenberger fake.pub._lbfsize = 0; /* not actually used, but Just In Case */
2296f1e2b38SJoerg Sonnenberger
2306f1e2b38SJoerg Sonnenberger /* do the work, then copy any error status */
231*0d5acd74SJohn Marino ret = __vfwprintf(&fake, locale, fmt, ap);
2326f1e2b38SJoerg Sonnenberger if (ret >= 0 && __fflush(&fake))
2336f1e2b38SJoerg Sonnenberger ret = WEOF;
2346f1e2b38SJoerg Sonnenberger if (fake.pub._flags & __SERR)
2356f1e2b38SJoerg Sonnenberger fp->pub._flags |= __SERR;
2366f1e2b38SJoerg Sonnenberger return (ret);
2376f1e2b38SJoerg Sonnenberger }
2386f1e2b38SJoerg Sonnenberger
2396f1e2b38SJoerg Sonnenberger /*
2406f1e2b38SJoerg Sonnenberger * Like __fputwc, but handles fake string (__SSTR) files properly.
2416f1e2b38SJoerg Sonnenberger * File must already be locked.
2426f1e2b38SJoerg Sonnenberger */
2436f1e2b38SJoerg Sonnenberger static wint_t
__xfputwc(wchar_t wc,FILE * fp,locale_t locale)244*0d5acd74SJohn Marino __xfputwc(wchar_t wc, FILE *fp, locale_t locale)
2456f1e2b38SJoerg Sonnenberger {
2466f1e2b38SJoerg Sonnenberger mbstate_t mbs;
2476f1e2b38SJoerg Sonnenberger char buf[MB_LEN_MAX];
2486f1e2b38SJoerg Sonnenberger struct __suio uio;
2496f1e2b38SJoerg Sonnenberger struct __siov iov;
2506f1e2b38SJoerg Sonnenberger size_t len;
2516f1e2b38SJoerg Sonnenberger
2526f1e2b38SJoerg Sonnenberger if ((fp->pub._flags & __SSTR) == 0)
253*0d5acd74SJohn Marino return (__fputwc(wc, fp, locale));
2546f1e2b38SJoerg Sonnenberger
255e0f95098SPeter Avalos mbs = initial_mbs;
2566f1e2b38SJoerg Sonnenberger if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) {
2576f1e2b38SJoerg Sonnenberger fp->pub._flags |= __SERR;
2586f1e2b38SJoerg Sonnenberger return (WEOF);
2596f1e2b38SJoerg Sonnenberger }
2606f1e2b38SJoerg Sonnenberger uio.uio_iov = &iov;
2616f1e2b38SJoerg Sonnenberger uio.uio_resid = len;
2626f1e2b38SJoerg Sonnenberger uio.uio_iovcnt = 1;
2636f1e2b38SJoerg Sonnenberger iov.iov_base = buf;
2646f1e2b38SJoerg Sonnenberger iov.iov_len = len;
2656f1e2b38SJoerg Sonnenberger return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF);
2666f1e2b38SJoerg Sonnenberger }
2676f1e2b38SJoerg Sonnenberger
2686f1e2b38SJoerg Sonnenberger /*
2696f1e2b38SJoerg Sonnenberger * Convert a multibyte character string argument for the %s format to a wide
2706f1e2b38SJoerg Sonnenberger * string representation. ``prec'' specifies the maximum number of bytes
2716f1e2b38SJoerg Sonnenberger * to output. If ``prec'' is greater than or equal to zero, we can't assume
2726f1e2b38SJoerg Sonnenberger * that the multibyte char. string ends in a null character.
2736f1e2b38SJoerg Sonnenberger */
2746f1e2b38SJoerg Sonnenberger static wchar_t *
__mbsconv(char * mbsarg,int prec)2756f1e2b38SJoerg Sonnenberger __mbsconv(char *mbsarg, int prec)
2766f1e2b38SJoerg Sonnenberger {
2776f1e2b38SJoerg Sonnenberger mbstate_t mbs;
2786f1e2b38SJoerg Sonnenberger wchar_t *convbuf, *wcp;
2796f1e2b38SJoerg Sonnenberger const char *p;
2806f1e2b38SJoerg Sonnenberger size_t insize, nchars, nconv;
2816f1e2b38SJoerg Sonnenberger
2826f1e2b38SJoerg Sonnenberger if (mbsarg == NULL)
2836f1e2b38SJoerg Sonnenberger return (NULL);
2846f1e2b38SJoerg Sonnenberger
2856f1e2b38SJoerg Sonnenberger /*
2866f1e2b38SJoerg Sonnenberger * Supplied argument is a multibyte string; convert it to wide
2876f1e2b38SJoerg Sonnenberger * characters first.
2886f1e2b38SJoerg Sonnenberger */
2896f1e2b38SJoerg Sonnenberger if (prec >= 0) {
2906f1e2b38SJoerg Sonnenberger /*
2916f1e2b38SJoerg Sonnenberger * String is not guaranteed to be NUL-terminated. Find the
2926f1e2b38SJoerg Sonnenberger * number of characters to print.
2936f1e2b38SJoerg Sonnenberger */
2946f1e2b38SJoerg Sonnenberger p = mbsarg;
295*0d5acd74SJohn Marino insize = nchars = nconv = 0;
296e0f95098SPeter Avalos mbs = initial_mbs;
2976f1e2b38SJoerg Sonnenberger while (nchars != (size_t)prec) {
2986f1e2b38SJoerg Sonnenberger nconv = mbrlen(p, MB_CUR_MAX, &mbs);
2996f1e2b38SJoerg Sonnenberger if (nconv == 0 || nconv == (size_t)-1 ||
3006f1e2b38SJoerg Sonnenberger nconv == (size_t)-2)
3016f1e2b38SJoerg Sonnenberger break;
3026f1e2b38SJoerg Sonnenberger p += nconv;
3036f1e2b38SJoerg Sonnenberger nchars++;
3046f1e2b38SJoerg Sonnenberger insize += nconv;
3056f1e2b38SJoerg Sonnenberger }
3066f1e2b38SJoerg Sonnenberger if (nconv == (size_t)-1 || nconv == (size_t)-2)
3076f1e2b38SJoerg Sonnenberger return (NULL);
308e0f95098SPeter Avalos } else {
3096f1e2b38SJoerg Sonnenberger insize = strlen(mbsarg);
310e0f95098SPeter Avalos nconv = 0;
311e0f95098SPeter Avalos }
3126f1e2b38SJoerg Sonnenberger
3136f1e2b38SJoerg Sonnenberger /*
3146f1e2b38SJoerg Sonnenberger * Allocate buffer for the result and perform the conversion,
3156f1e2b38SJoerg Sonnenberger * converting at most `size' bytes of the input multibyte string to
3166f1e2b38SJoerg Sonnenberger * wide characters for printing.
3176f1e2b38SJoerg Sonnenberger */
3186f1e2b38SJoerg Sonnenberger convbuf = malloc((insize + 1) * sizeof(*convbuf));
3196f1e2b38SJoerg Sonnenberger if (convbuf == NULL)
3206f1e2b38SJoerg Sonnenberger return (NULL);
3216f1e2b38SJoerg Sonnenberger wcp = convbuf;
3226f1e2b38SJoerg Sonnenberger p = mbsarg;
323e0f95098SPeter Avalos mbs = initial_mbs;
3246f1e2b38SJoerg Sonnenberger while (insize != 0) {
3256f1e2b38SJoerg Sonnenberger nconv = mbrtowc(wcp, p, insize, &mbs);
3266f1e2b38SJoerg Sonnenberger if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2)
3276f1e2b38SJoerg Sonnenberger break;
3286f1e2b38SJoerg Sonnenberger wcp++;
3296f1e2b38SJoerg Sonnenberger p += nconv;
3306f1e2b38SJoerg Sonnenberger insize -= nconv;
3316f1e2b38SJoerg Sonnenberger }
3326f1e2b38SJoerg Sonnenberger if (nconv == (size_t)-1 || nconv == (size_t)-2) {
3336f1e2b38SJoerg Sonnenberger free(convbuf);
3346f1e2b38SJoerg Sonnenberger return (NULL);
3356f1e2b38SJoerg Sonnenberger }
3366f1e2b38SJoerg Sonnenberger *wcp = L'\0';
3376f1e2b38SJoerg Sonnenberger
3386f1e2b38SJoerg Sonnenberger return (convbuf);
3396f1e2b38SJoerg Sonnenberger }
3406f1e2b38SJoerg Sonnenberger
3416f1e2b38SJoerg Sonnenberger /*
3426f1e2b38SJoerg Sonnenberger * MT-safe version
3436f1e2b38SJoerg Sonnenberger */
3446f1e2b38SJoerg Sonnenberger int
vfwprintf_l(FILE * __restrict fp,locale_t locale,const wchar_t * __restrict fmt0,va_list ap)345*0d5acd74SJohn Marino vfwprintf_l(FILE * __restrict fp, locale_t locale,
346*0d5acd74SJohn Marino const wchar_t * __restrict fmt0, va_list ap)
347*0d5acd74SJohn Marino
3486f1e2b38SJoerg Sonnenberger {
3496f1e2b38SJoerg Sonnenberger int ret;
350*0d5acd74SJohn Marino FIX_LOCALE(locale);
3516f1e2b38SJoerg Sonnenberger FLOCKFILE(fp);
352e0f95098SPeter Avalos /* optimise fprintf(stderr) (and other unbuffered Unix files) */
353e0f95098SPeter Avalos if ((fp->pub._flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
354e0f95098SPeter Avalos fp->pub._fileno >= 0)
355*0d5acd74SJohn Marino ret = __sbprintf(fp, locale, fmt0, ap);
356e0f95098SPeter Avalos else
357*0d5acd74SJohn Marino ret = __vfwprintf(fp, locale, fmt0, ap);
3586f1e2b38SJoerg Sonnenberger FUNLOCKFILE(fp);
3596f1e2b38SJoerg Sonnenberger return (ret);
3606f1e2b38SJoerg Sonnenberger }
361*0d5acd74SJohn Marino int
vfwprintf(FILE * __restrict fp,const wchar_t * __restrict fmt0,va_list ap)362*0d5acd74SJohn Marino vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap)
363*0d5acd74SJohn Marino {
364*0d5acd74SJohn Marino return vfwprintf_l(fp, __get_locale(), fmt0, ap);
365*0d5acd74SJohn Marino }
3666f1e2b38SJoerg Sonnenberger
3676f1e2b38SJoerg Sonnenberger /*
3686f1e2b38SJoerg Sonnenberger * The size of the buffer we use as scratch space for integer
369e0f95098SPeter Avalos * conversions, among other things. We need enough space to
370e0f95098SPeter Avalos * write a uintmax_t in octal (plus one byte).
3716f1e2b38SJoerg Sonnenberger */
372e0f95098SPeter Avalos #if UINTMAX_MAX <= UINT64_MAX
373e0f95098SPeter Avalos #define BUF 32
374e0f95098SPeter Avalos #else
375e0f95098SPeter Avalos #error "BUF must be large enough to format a uintmax_t"
376e0f95098SPeter Avalos #endif
3776f1e2b38SJoerg Sonnenberger
3786f1e2b38SJoerg Sonnenberger /*
3796f1e2b38SJoerg Sonnenberger * Non-MT-safe version
3806f1e2b38SJoerg Sonnenberger */
3816f1e2b38SJoerg Sonnenberger int
__vfwprintf(FILE * fp,locale_t locale,const wchar_t * fmt0,va_list ap)382*0d5acd74SJohn Marino __vfwprintf(FILE *fp, locale_t locale, const wchar_t *fmt0, va_list ap)
3836f1e2b38SJoerg Sonnenberger {
3846f1e2b38SJoerg Sonnenberger wchar_t *fmt; /* format string */
3856f1e2b38SJoerg Sonnenberger wchar_t ch; /* character from fmt */
386e0f95098SPeter Avalos int n, n2; /* handy integer (short term usage) */
3876f1e2b38SJoerg Sonnenberger wchar_t *cp; /* handy char pointer (short term usage) */
3886f1e2b38SJoerg Sonnenberger int flags; /* flags as above */
3896f1e2b38SJoerg Sonnenberger int ret; /* return value accumulator */
3906f1e2b38SJoerg Sonnenberger int width; /* width from format (%8d), or 0 */
3916f1e2b38SJoerg Sonnenberger int prec; /* precision from format; <0 for N/A */
3926f1e2b38SJoerg Sonnenberger wchar_t sign; /* sign prefix (' ', '+', '-', or \0) */
393e0f95098SPeter Avalos struct grouping_state gs; /* thousands' grouping info */
3946f1e2b38SJoerg Sonnenberger #ifndef NO_FLOATING_POINT
3956f1e2b38SJoerg Sonnenberger /*
3966f1e2b38SJoerg Sonnenberger * We can decompose the printed representation of floating
3976f1e2b38SJoerg Sonnenberger * point numbers into several parts, some of which may be empty:
3986f1e2b38SJoerg Sonnenberger *
3996f1e2b38SJoerg Sonnenberger * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
4006f1e2b38SJoerg Sonnenberger * A B ---C--- D E F
4016f1e2b38SJoerg Sonnenberger *
4026f1e2b38SJoerg Sonnenberger * A: 'sign' holds this value if present; '\0' otherwise
4036f1e2b38SJoerg Sonnenberger * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
4046f1e2b38SJoerg Sonnenberger * C: cp points to the string MMMNNN. Leading and trailing
4056f1e2b38SJoerg Sonnenberger * zeros are not in the string and must be added.
4066f1e2b38SJoerg Sonnenberger * D: expchar holds this character; '\0' if no exponent, e.g. %f
4076f1e2b38SJoerg Sonnenberger * F: at least two digits for decimal, at least one digit for hex
4086f1e2b38SJoerg Sonnenberger */
409e0f95098SPeter Avalos wchar_t decimal_point; /* locale specific decimal point */
4106f1e2b38SJoerg Sonnenberger int signflag; /* true if float is negative */
4116f1e2b38SJoerg Sonnenberger union { /* floating point arguments %[aAeEfFgG] */
4126f1e2b38SJoerg Sonnenberger double dbl;
4136f1e2b38SJoerg Sonnenberger long double ldbl;
4146f1e2b38SJoerg Sonnenberger } fparg;
4156f1e2b38SJoerg Sonnenberger int expt; /* integer value of exponent */
4166f1e2b38SJoerg Sonnenberger char expchar; /* exponent character: [eEpP\0] */
417e0f95098SPeter Avalos char *dtoaend; /* pointer to end of converted digits */
4186f1e2b38SJoerg Sonnenberger int expsize; /* character count for expstr */
4196f1e2b38SJoerg Sonnenberger int ndig; /* actual number of digits returned by dtoa */
4206f1e2b38SJoerg Sonnenberger wchar_t expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */
421e0f95098SPeter Avalos char *dtoaresult; /* buffer allocated by dtoa */
4226f1e2b38SJoerg Sonnenberger #endif
4236f1e2b38SJoerg Sonnenberger u_long ulval; /* integer arguments %[diouxX] */
4246f1e2b38SJoerg Sonnenberger uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */
4256f1e2b38SJoerg Sonnenberger int base; /* base for [diouxX] conversion */
4266f1e2b38SJoerg Sonnenberger int dprec; /* a copy of prec if [diouxX], 0 otherwise */
4276f1e2b38SJoerg Sonnenberger int realsz; /* field size expanded by dprec, sign, etc */
4286f1e2b38SJoerg Sonnenberger int size; /* size of converted field or string */
4296f1e2b38SJoerg Sonnenberger int prsize; /* max size of printed field */
4306f1e2b38SJoerg Sonnenberger const char *xdigs; /* digits for [xX] conversion */
431e0f95098SPeter Avalos struct io_state io; /* I/O buffering state */
4326f1e2b38SJoerg Sonnenberger wchar_t buf[BUF]; /* buffer with space for digits of uintmax_t */
4336f1e2b38SJoerg Sonnenberger wchar_t ox[2]; /* space for 0x hex-prefix */
4346f1e2b38SJoerg Sonnenberger union arg *argtable; /* args, built due to positional arg */
4356f1e2b38SJoerg Sonnenberger union arg statargtable [STATIC_ARG_TBL_SIZE];
4366f1e2b38SJoerg Sonnenberger int nextarg; /* 1-based argument index */
4376f1e2b38SJoerg Sonnenberger va_list orgap; /* original argument pointer */
4386f1e2b38SJoerg Sonnenberger wchar_t *convbuf; /* multibyte to wide conversion result */
4396f1e2b38SJoerg Sonnenberger
4406f1e2b38SJoerg Sonnenberger static const char xdigs_lower[16] = "0123456789abcdef";
4416f1e2b38SJoerg Sonnenberger static const char xdigs_upper[16] = "0123456789ABCDEF";
4426f1e2b38SJoerg Sonnenberger
443e0f95098SPeter Avalos /* BEWARE, these `goto error' on error. */
4446f1e2b38SJoerg Sonnenberger #define PRINT(ptr, len) do { \
445*0d5acd74SJohn Marino if (io_print(&io, (ptr), (len), locale)) \
446e0f95098SPeter Avalos goto error; \
447e0f95098SPeter Avalos } while (0)
448e0f95098SPeter Avalos #define PAD(howmany, with) { \
449*0d5acd74SJohn Marino if (io_pad(&io, (howmany), (with), locale)) \
450e0f95098SPeter Avalos goto error; \
451e0f95098SPeter Avalos }
452e0f95098SPeter Avalos #define PRINTANDPAD(p, ep, len, with) { \
453*0d5acd74SJohn Marino if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \
454e0f95098SPeter Avalos goto error; \
455e0f95098SPeter Avalos }
456e0f95098SPeter Avalos #define FLUSH() { \
457*0d5acd74SJohn Marino if (io_flush(&io, locale)) \
458e0f95098SPeter Avalos goto error; \
459e0f95098SPeter Avalos }
4606f1e2b38SJoerg Sonnenberger
4616f1e2b38SJoerg Sonnenberger /*
4626f1e2b38SJoerg Sonnenberger * Get the argument indexed by nextarg. If the argument table is
4636f1e2b38SJoerg Sonnenberger * built, use it to get the argument. If its not, get the next
4646f1e2b38SJoerg Sonnenberger * argument (and arguments must be gotten sequentially).
4656f1e2b38SJoerg Sonnenberger */
4666f1e2b38SJoerg Sonnenberger #define GETARG(type) \
467e0f95098SPeter Avalos ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
4686f1e2b38SJoerg Sonnenberger (nextarg++, va_arg(ap, type)))
4696f1e2b38SJoerg Sonnenberger
4706f1e2b38SJoerg Sonnenberger /*
4716f1e2b38SJoerg Sonnenberger * To extend shorts properly, we need both signed and unsigned
4726f1e2b38SJoerg Sonnenberger * argument extraction methods.
4736f1e2b38SJoerg Sonnenberger */
4746f1e2b38SJoerg Sonnenberger #define SARG() \
4756f1e2b38SJoerg Sonnenberger (flags&LONGINT ? GETARG(long) : \
4766f1e2b38SJoerg Sonnenberger flags&SHORTINT ? (long)(short)GETARG(int) : \
4776f1e2b38SJoerg Sonnenberger flags&CHARINT ? (long)(signed char)GETARG(int) : \
4786f1e2b38SJoerg Sonnenberger (long)GETARG(int))
4796f1e2b38SJoerg Sonnenberger #define UARG() \
4806f1e2b38SJoerg Sonnenberger (flags&LONGINT ? GETARG(u_long) : \
4816f1e2b38SJoerg Sonnenberger flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
4826f1e2b38SJoerg Sonnenberger flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
4836f1e2b38SJoerg Sonnenberger (u_long)GETARG(u_int))
4846f1e2b38SJoerg Sonnenberger #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT)
4856f1e2b38SJoerg Sonnenberger #define SJARG() \
4866f1e2b38SJoerg Sonnenberger (flags&INTMAXT ? GETARG(intmax_t) : \
487e0f95098SPeter Avalos flags&SIZET ? (intmax_t)GETARG(ssize_t) : \
4886f1e2b38SJoerg Sonnenberger flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
489e0f95098SPeter Avalos (intmax_t)GETARG(long long))
4906f1e2b38SJoerg Sonnenberger #define UJARG() \
4916f1e2b38SJoerg Sonnenberger (flags&INTMAXT ? GETARG(uintmax_t) : \
4926f1e2b38SJoerg Sonnenberger flags&SIZET ? (uintmax_t)GETARG(size_t) : \
4936f1e2b38SJoerg Sonnenberger flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
494e0f95098SPeter Avalos (uintmax_t)GETARG(unsigned long long))
4956f1e2b38SJoerg Sonnenberger
4966f1e2b38SJoerg Sonnenberger /*
4976f1e2b38SJoerg Sonnenberger * Get * arguments, including the form *nn$. Preserve the nextarg
4986f1e2b38SJoerg Sonnenberger * that the argument can be gotten once the type is determined.
4996f1e2b38SJoerg Sonnenberger */
5006f1e2b38SJoerg Sonnenberger #define GETASTER(val) \
5016f1e2b38SJoerg Sonnenberger n2 = 0; \
5026f1e2b38SJoerg Sonnenberger cp = fmt; \
5036f1e2b38SJoerg Sonnenberger while (is_digit(*cp)) { \
5046f1e2b38SJoerg Sonnenberger n2 = 10 * n2 + to_digit(*cp); \
5056f1e2b38SJoerg Sonnenberger cp++; \
5066f1e2b38SJoerg Sonnenberger } \
5076f1e2b38SJoerg Sonnenberger if (*cp == '$') { \
5086f1e2b38SJoerg Sonnenberger int hold = nextarg; \
5096f1e2b38SJoerg Sonnenberger if (argtable == NULL) { \
5106f1e2b38SJoerg Sonnenberger argtable = statargtable; \
511e0f95098SPeter Avalos if (__find_warguments (fmt0, orgap, &argtable)) { \
512e0f95098SPeter Avalos ret = EOF; \
513e0f95098SPeter Avalos goto error; \
514e0f95098SPeter Avalos } \
5156f1e2b38SJoerg Sonnenberger } \
5166f1e2b38SJoerg Sonnenberger nextarg = n2; \
5176f1e2b38SJoerg Sonnenberger val = GETARG (int); \
5186f1e2b38SJoerg Sonnenberger nextarg = hold; \
5196f1e2b38SJoerg Sonnenberger fmt = ++cp; \
5206f1e2b38SJoerg Sonnenberger } else { \
5216f1e2b38SJoerg Sonnenberger val = GETARG (int); \
5226f1e2b38SJoerg Sonnenberger }
5236f1e2b38SJoerg Sonnenberger
5246f1e2b38SJoerg Sonnenberger
5256f1e2b38SJoerg Sonnenberger /* sorry, fwprintf(read_only_file, L"") returns WEOF, not 0 */
526e0f95098SPeter Avalos if (prepwrite(fp) != 0)
527e0f95098SPeter Avalos return (EOF);
5286f1e2b38SJoerg Sonnenberger
529e0f95098SPeter Avalos convbuf = NULL;
530*0d5acd74SJohn Marino fmt = (wchar_t *)fmt0;
5316f1e2b38SJoerg Sonnenberger argtable = NULL;
5326f1e2b38SJoerg Sonnenberger nextarg = 1;
5336f1e2b38SJoerg Sonnenberger va_copy(orgap, ap);
534e0f95098SPeter Avalos io_init(&io, fp);
5356f1e2b38SJoerg Sonnenberger ret = 0;
536e0f95098SPeter Avalos #ifndef NO_FLOATING_POINT
537*0d5acd74SJohn Marino decimal_point = get_decpt(locale);
538e0f95098SPeter Avalos #endif
5396f1e2b38SJoerg Sonnenberger
5406f1e2b38SJoerg Sonnenberger /*
5416f1e2b38SJoerg Sonnenberger * Scan the format for conversions (`%' character).
5426f1e2b38SJoerg Sonnenberger */
5436f1e2b38SJoerg Sonnenberger for (;;) {
5446f1e2b38SJoerg Sonnenberger for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
5456f1e2b38SJoerg Sonnenberger /* void */;
5466f1e2b38SJoerg Sonnenberger if ((n = fmt - cp) != 0) {
5476f1e2b38SJoerg Sonnenberger if ((unsigned)ret + n > INT_MAX) {
5486f1e2b38SJoerg Sonnenberger ret = EOF;
549*0d5acd74SJohn Marino errno = EOVERFLOW;
5506f1e2b38SJoerg Sonnenberger goto error;
5516f1e2b38SJoerg Sonnenberger }
5526f1e2b38SJoerg Sonnenberger PRINT(cp, n);
5536f1e2b38SJoerg Sonnenberger ret += n;
5546f1e2b38SJoerg Sonnenberger }
5556f1e2b38SJoerg Sonnenberger if (ch == '\0')
5566f1e2b38SJoerg Sonnenberger goto done;
5576f1e2b38SJoerg Sonnenberger fmt++; /* skip over '%' */
5586f1e2b38SJoerg Sonnenberger
5596f1e2b38SJoerg Sonnenberger flags = 0;
5606f1e2b38SJoerg Sonnenberger dprec = 0;
5616f1e2b38SJoerg Sonnenberger width = 0;
5626f1e2b38SJoerg Sonnenberger prec = -1;
563e0f95098SPeter Avalos gs.grouping = NULL;
5646f1e2b38SJoerg Sonnenberger sign = '\0';
5656f1e2b38SJoerg Sonnenberger ox[1] = '\0';
5666f1e2b38SJoerg Sonnenberger
5676f1e2b38SJoerg Sonnenberger rflag: ch = *fmt++;
5686f1e2b38SJoerg Sonnenberger reswitch: switch (ch) {
5696f1e2b38SJoerg Sonnenberger case ' ':
570e0f95098SPeter Avalos /*-
5716f1e2b38SJoerg Sonnenberger * ``If the space and + flags both appear, the space
5726f1e2b38SJoerg Sonnenberger * flag will be ignored.''
5736f1e2b38SJoerg Sonnenberger * -- ANSI X3J11
5746f1e2b38SJoerg Sonnenberger */
5756f1e2b38SJoerg Sonnenberger if (!sign)
5766f1e2b38SJoerg Sonnenberger sign = ' ';
5776f1e2b38SJoerg Sonnenberger goto rflag;
5786f1e2b38SJoerg Sonnenberger case '#':
5796f1e2b38SJoerg Sonnenberger flags |= ALT;
5806f1e2b38SJoerg Sonnenberger goto rflag;
5816f1e2b38SJoerg Sonnenberger case '*':
582e0f95098SPeter Avalos /*-
5836f1e2b38SJoerg Sonnenberger * ``A negative field width argument is taken as a
5846f1e2b38SJoerg Sonnenberger * - flag followed by a positive field width.''
5856f1e2b38SJoerg Sonnenberger * -- ANSI X3J11
5866f1e2b38SJoerg Sonnenberger * They don't exclude field widths read from args.
5876f1e2b38SJoerg Sonnenberger */
5886f1e2b38SJoerg Sonnenberger GETASTER (width);
5896f1e2b38SJoerg Sonnenberger if (width >= 0)
5906f1e2b38SJoerg Sonnenberger goto rflag;
5916f1e2b38SJoerg Sonnenberger width = -width;
5926f1e2b38SJoerg Sonnenberger /* FALLTHROUGH */
5936f1e2b38SJoerg Sonnenberger case '-':
5946f1e2b38SJoerg Sonnenberger flags |= LADJUST;
5956f1e2b38SJoerg Sonnenberger goto rflag;
5966f1e2b38SJoerg Sonnenberger case '+':
5976f1e2b38SJoerg Sonnenberger sign = '+';
5986f1e2b38SJoerg Sonnenberger goto rflag;
5996f1e2b38SJoerg Sonnenberger case '\'':
6006f1e2b38SJoerg Sonnenberger flags |= GROUPING;
6016f1e2b38SJoerg Sonnenberger goto rflag;
6026f1e2b38SJoerg Sonnenberger case '.':
6036f1e2b38SJoerg Sonnenberger if ((ch = *fmt++) == '*') {
6046f1e2b38SJoerg Sonnenberger GETASTER (prec);
6056f1e2b38SJoerg Sonnenberger goto rflag;
6066f1e2b38SJoerg Sonnenberger }
6076f1e2b38SJoerg Sonnenberger prec = 0;
6086f1e2b38SJoerg Sonnenberger while (is_digit(ch)) {
6096f1e2b38SJoerg Sonnenberger prec = 10 * prec + to_digit(ch);
6106f1e2b38SJoerg Sonnenberger ch = *fmt++;
6116f1e2b38SJoerg Sonnenberger }
6126f1e2b38SJoerg Sonnenberger goto reswitch;
6136f1e2b38SJoerg Sonnenberger case '0':
614e0f95098SPeter Avalos /*-
6156f1e2b38SJoerg Sonnenberger * ``Note that 0 is taken as a flag, not as the
6166f1e2b38SJoerg Sonnenberger * beginning of a field width.''
6176f1e2b38SJoerg Sonnenberger * -- ANSI X3J11
6186f1e2b38SJoerg Sonnenberger */
6196f1e2b38SJoerg Sonnenberger flags |= ZEROPAD;
6206f1e2b38SJoerg Sonnenberger goto rflag;
6216f1e2b38SJoerg Sonnenberger case '1': case '2': case '3': case '4':
6226f1e2b38SJoerg Sonnenberger case '5': case '6': case '7': case '8': case '9':
6236f1e2b38SJoerg Sonnenberger n = 0;
6246f1e2b38SJoerg Sonnenberger do {
6256f1e2b38SJoerg Sonnenberger n = 10 * n + to_digit(ch);
6266f1e2b38SJoerg Sonnenberger ch = *fmt++;
6276f1e2b38SJoerg Sonnenberger } while (is_digit(ch));
6286f1e2b38SJoerg Sonnenberger if (ch == '$') {
6296f1e2b38SJoerg Sonnenberger nextarg = n;
6306f1e2b38SJoerg Sonnenberger if (argtable == NULL) {
6316f1e2b38SJoerg Sonnenberger argtable = statargtable;
632e0f95098SPeter Avalos if (__find_warguments (fmt0, orgap,
633e0f95098SPeter Avalos &argtable)) {
634e0f95098SPeter Avalos ret = EOF;
635e0f95098SPeter Avalos goto error;
636e0f95098SPeter Avalos }
6376f1e2b38SJoerg Sonnenberger }
6386f1e2b38SJoerg Sonnenberger goto rflag;
6396f1e2b38SJoerg Sonnenberger }
6406f1e2b38SJoerg Sonnenberger width = n;
6416f1e2b38SJoerg Sonnenberger goto reswitch;
6426f1e2b38SJoerg Sonnenberger #ifndef NO_FLOATING_POINT
6436f1e2b38SJoerg Sonnenberger case 'L':
6446f1e2b38SJoerg Sonnenberger flags |= LONGDBL;
6456f1e2b38SJoerg Sonnenberger goto rflag;
6466f1e2b38SJoerg Sonnenberger #endif
6476f1e2b38SJoerg Sonnenberger case 'h':
6486f1e2b38SJoerg Sonnenberger if (flags & SHORTINT) {
6496f1e2b38SJoerg Sonnenberger flags &= ~SHORTINT;
6506f1e2b38SJoerg Sonnenberger flags |= CHARINT;
651*0d5acd74SJohn Marino } else
6526f1e2b38SJoerg Sonnenberger flags |= SHORTINT;
6536f1e2b38SJoerg Sonnenberger goto rflag;
6546f1e2b38SJoerg Sonnenberger case 'j':
6556f1e2b38SJoerg Sonnenberger flags |= INTMAXT;
6566f1e2b38SJoerg Sonnenberger goto rflag;
6576f1e2b38SJoerg Sonnenberger case 'l':
6586f1e2b38SJoerg Sonnenberger if (flags & LONGINT) {
6596f1e2b38SJoerg Sonnenberger flags &= ~LONGINT;
6606f1e2b38SJoerg Sonnenberger flags |= LLONGINT;
661*0d5acd74SJohn Marino } else
6626f1e2b38SJoerg Sonnenberger flags |= LONGINT;
6636f1e2b38SJoerg Sonnenberger goto rflag;
6646f1e2b38SJoerg Sonnenberger case 'q':
6656f1e2b38SJoerg Sonnenberger flags |= LLONGINT; /* not necessarily */
6666f1e2b38SJoerg Sonnenberger goto rflag;
6676f1e2b38SJoerg Sonnenberger case 't':
6686f1e2b38SJoerg Sonnenberger flags |= PTRDIFFT;
6696f1e2b38SJoerg Sonnenberger goto rflag;
6706f1e2b38SJoerg Sonnenberger case 'z':
6716f1e2b38SJoerg Sonnenberger flags |= SIZET;
6726f1e2b38SJoerg Sonnenberger goto rflag;
6736f1e2b38SJoerg Sonnenberger case 'C':
6746f1e2b38SJoerg Sonnenberger flags |= LONGINT;
6756f1e2b38SJoerg Sonnenberger /*FALLTHROUGH*/
6766f1e2b38SJoerg Sonnenberger case 'c':
6776f1e2b38SJoerg Sonnenberger if (flags & LONGINT)
6786f1e2b38SJoerg Sonnenberger *(cp = buf) = (wchar_t)GETARG(wint_t);
6796f1e2b38SJoerg Sonnenberger else
6806f1e2b38SJoerg Sonnenberger *(cp = buf) = (wchar_t)btowc(GETARG(int));
6816f1e2b38SJoerg Sonnenberger size = 1;
6826f1e2b38SJoerg Sonnenberger sign = '\0';
6836f1e2b38SJoerg Sonnenberger break;
6846f1e2b38SJoerg Sonnenberger case 'D':
6856f1e2b38SJoerg Sonnenberger flags |= LONGINT;
6866f1e2b38SJoerg Sonnenberger /*FALLTHROUGH*/
6876f1e2b38SJoerg Sonnenberger case 'd':
6886f1e2b38SJoerg Sonnenberger case 'i':
6896f1e2b38SJoerg Sonnenberger if (flags & INTMAX_SIZE) {
6906f1e2b38SJoerg Sonnenberger ujval = SJARG();
6916f1e2b38SJoerg Sonnenberger if ((intmax_t)ujval < 0) {
6926f1e2b38SJoerg Sonnenberger ujval = -ujval;
6936f1e2b38SJoerg Sonnenberger sign = '-';
6946f1e2b38SJoerg Sonnenberger }
6956f1e2b38SJoerg Sonnenberger } else {
6966f1e2b38SJoerg Sonnenberger ulval = SARG();
6976f1e2b38SJoerg Sonnenberger if ((long)ulval < 0) {
6986f1e2b38SJoerg Sonnenberger ulval = -ulval;
6996f1e2b38SJoerg Sonnenberger sign = '-';
7006f1e2b38SJoerg Sonnenberger }
7016f1e2b38SJoerg Sonnenberger }
7026f1e2b38SJoerg Sonnenberger base = 10;
7036f1e2b38SJoerg Sonnenberger goto number;
7046f1e2b38SJoerg Sonnenberger #ifndef NO_FLOATING_POINT
7056f1e2b38SJoerg Sonnenberger case 'a':
7066f1e2b38SJoerg Sonnenberger case 'A':
7076f1e2b38SJoerg Sonnenberger if (ch == 'a') {
7086f1e2b38SJoerg Sonnenberger ox[1] = 'x';
7096f1e2b38SJoerg Sonnenberger xdigs = xdigs_lower;
7106f1e2b38SJoerg Sonnenberger expchar = 'p';
7116f1e2b38SJoerg Sonnenberger } else {
7126f1e2b38SJoerg Sonnenberger ox[1] = 'X';
7136f1e2b38SJoerg Sonnenberger xdigs = xdigs_upper;
7146f1e2b38SJoerg Sonnenberger expchar = 'P';
7156f1e2b38SJoerg Sonnenberger }
7166f1e2b38SJoerg Sonnenberger if (prec >= 0)
7176f1e2b38SJoerg Sonnenberger prec++;
7186f1e2b38SJoerg Sonnenberger if (flags & LONGDBL) {
7196f1e2b38SJoerg Sonnenberger fparg.ldbl = GETARG(long double);
7206f1e2b38SJoerg Sonnenberger dtoaresult =
7216f1e2b38SJoerg Sonnenberger __hldtoa(fparg.ldbl, xdigs, prec,
7226f1e2b38SJoerg Sonnenberger &expt, &signflag, &dtoaend);
7236f1e2b38SJoerg Sonnenberger } else {
7246f1e2b38SJoerg Sonnenberger fparg.dbl = GETARG(double);
7256f1e2b38SJoerg Sonnenberger dtoaresult =
7266f1e2b38SJoerg Sonnenberger __hdtoa(fparg.dbl, xdigs, prec,
7276f1e2b38SJoerg Sonnenberger &expt, &signflag, &dtoaend);
7286f1e2b38SJoerg Sonnenberger }
7296f1e2b38SJoerg Sonnenberger if (prec < 0)
7306f1e2b38SJoerg Sonnenberger prec = dtoaend - dtoaresult;
7316f1e2b38SJoerg Sonnenberger if (expt == INT_MAX)
7326f1e2b38SJoerg Sonnenberger ox[1] = '\0';
7336f1e2b38SJoerg Sonnenberger if (convbuf != NULL)
7346f1e2b38SJoerg Sonnenberger free(convbuf);
7356f1e2b38SJoerg Sonnenberger ndig = dtoaend - dtoaresult;
7366f1e2b38SJoerg Sonnenberger cp = convbuf = __mbsconv(dtoaresult, -1);
7376f1e2b38SJoerg Sonnenberger freedtoa(dtoaresult);
7386f1e2b38SJoerg Sonnenberger goto fp_common;
7396f1e2b38SJoerg Sonnenberger case 'e':
7406f1e2b38SJoerg Sonnenberger case 'E':
7416f1e2b38SJoerg Sonnenberger expchar = ch;
7426f1e2b38SJoerg Sonnenberger if (prec < 0) /* account for digit before decpt */
7436f1e2b38SJoerg Sonnenberger prec = DEFPREC + 1;
7446f1e2b38SJoerg Sonnenberger else
7456f1e2b38SJoerg Sonnenberger prec++;
7466f1e2b38SJoerg Sonnenberger goto fp_begin;
7476f1e2b38SJoerg Sonnenberger case 'f':
7486f1e2b38SJoerg Sonnenberger case 'F':
7496f1e2b38SJoerg Sonnenberger expchar = '\0';
7506f1e2b38SJoerg Sonnenberger goto fp_begin;
7516f1e2b38SJoerg Sonnenberger case 'g':
7526f1e2b38SJoerg Sonnenberger case 'G':
7536f1e2b38SJoerg Sonnenberger expchar = ch - ('g' - 'e');
7546f1e2b38SJoerg Sonnenberger if (prec == 0)
7556f1e2b38SJoerg Sonnenberger prec = 1;
7566f1e2b38SJoerg Sonnenberger fp_begin:
7576f1e2b38SJoerg Sonnenberger if (prec < 0)
7586f1e2b38SJoerg Sonnenberger prec = DEFPREC;
7596f1e2b38SJoerg Sonnenberger if (convbuf != NULL)
7606f1e2b38SJoerg Sonnenberger free(convbuf);
7616f1e2b38SJoerg Sonnenberger if (flags & LONGDBL) {
7626f1e2b38SJoerg Sonnenberger fparg.ldbl = GETARG(long double);
7636f1e2b38SJoerg Sonnenberger dtoaresult =
7646f1e2b38SJoerg Sonnenberger __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
7656f1e2b38SJoerg Sonnenberger &expt, &signflag, &dtoaend);
7666f1e2b38SJoerg Sonnenberger } else {
7676f1e2b38SJoerg Sonnenberger fparg.dbl = GETARG(double);
7686f1e2b38SJoerg Sonnenberger dtoaresult =
7696f1e2b38SJoerg Sonnenberger dtoa(fparg.dbl, expchar ? 2 : 3, prec,
7706f1e2b38SJoerg Sonnenberger &expt, &signflag, &dtoaend);
7716f1e2b38SJoerg Sonnenberger if (expt == 9999)
7726f1e2b38SJoerg Sonnenberger expt = INT_MAX;
7736f1e2b38SJoerg Sonnenberger }
7746f1e2b38SJoerg Sonnenberger ndig = dtoaend - dtoaresult;
7756f1e2b38SJoerg Sonnenberger cp = convbuf = __mbsconv(dtoaresult, -1);
7766f1e2b38SJoerg Sonnenberger freedtoa(dtoaresult);
7776f1e2b38SJoerg Sonnenberger fp_common:
7786f1e2b38SJoerg Sonnenberger if (signflag)
7796f1e2b38SJoerg Sonnenberger sign = '-';
7806f1e2b38SJoerg Sonnenberger if (expt == INT_MAX) { /* inf or nan */
7816f1e2b38SJoerg Sonnenberger if (*cp == 'N') {
7826f1e2b38SJoerg Sonnenberger cp = (ch >= 'a') ? L"nan" : L"NAN";
7836f1e2b38SJoerg Sonnenberger sign = '\0';
7846f1e2b38SJoerg Sonnenberger } else
7856f1e2b38SJoerg Sonnenberger cp = (ch >= 'a') ? L"inf" : L"INF";
7866f1e2b38SJoerg Sonnenberger size = 3;
787e0f95098SPeter Avalos flags &= ~ZEROPAD;
7886f1e2b38SJoerg Sonnenberger break;
7896f1e2b38SJoerg Sonnenberger }
7906f1e2b38SJoerg Sonnenberger flags |= FPT;
7916f1e2b38SJoerg Sonnenberger if (ch == 'g' || ch == 'G') {
7926f1e2b38SJoerg Sonnenberger if (expt > -4 && expt <= prec) {
7936f1e2b38SJoerg Sonnenberger /* Make %[gG] smell like %[fF] */
7946f1e2b38SJoerg Sonnenberger expchar = '\0';
7956f1e2b38SJoerg Sonnenberger if (flags & ALT)
7966f1e2b38SJoerg Sonnenberger prec -= expt;
7976f1e2b38SJoerg Sonnenberger else
7986f1e2b38SJoerg Sonnenberger prec = ndig - expt;
7996f1e2b38SJoerg Sonnenberger if (prec < 0)
8006f1e2b38SJoerg Sonnenberger prec = 0;
8016f1e2b38SJoerg Sonnenberger } else {
8026f1e2b38SJoerg Sonnenberger /*
8036f1e2b38SJoerg Sonnenberger * Make %[gG] smell like %[eE], but
8046f1e2b38SJoerg Sonnenberger * trim trailing zeroes if no # flag.
8056f1e2b38SJoerg Sonnenberger */
8066f1e2b38SJoerg Sonnenberger if (!(flags & ALT))
8076f1e2b38SJoerg Sonnenberger prec = ndig;
8086f1e2b38SJoerg Sonnenberger }
8096f1e2b38SJoerg Sonnenberger }
8106f1e2b38SJoerg Sonnenberger if (expchar) {
8116f1e2b38SJoerg Sonnenberger expsize = exponent(expstr, expt - 1, expchar);
8126f1e2b38SJoerg Sonnenberger size = expsize + prec;
8136f1e2b38SJoerg Sonnenberger if (prec > 1 || flags & ALT)
8146f1e2b38SJoerg Sonnenberger ++size;
8156f1e2b38SJoerg Sonnenberger } else {
8166f1e2b38SJoerg Sonnenberger /* space for digits before decimal point */
8176f1e2b38SJoerg Sonnenberger if (expt > 0)
8186f1e2b38SJoerg Sonnenberger size = expt;
8196f1e2b38SJoerg Sonnenberger else /* "0" */
8206f1e2b38SJoerg Sonnenberger size = 1;
8216f1e2b38SJoerg Sonnenberger /* space for decimal pt and following digits */
8226f1e2b38SJoerg Sonnenberger if (prec || flags & ALT)
8236f1e2b38SJoerg Sonnenberger size += prec + 1;
824e0f95098SPeter Avalos if ((flags & GROUPING) && expt > 0)
825*0d5acd74SJohn Marino size += grouping_init(&gs, expt, locale);
8266f1e2b38SJoerg Sonnenberger }
8276f1e2b38SJoerg Sonnenberger break;
8286f1e2b38SJoerg Sonnenberger #endif /* !NO_FLOATING_POINT */
8296f1e2b38SJoerg Sonnenberger case 'n':
8306f1e2b38SJoerg Sonnenberger /*
8316f1e2b38SJoerg Sonnenberger * Assignment-like behavior is specified if the
8326f1e2b38SJoerg Sonnenberger * value overflows or is otherwise unrepresentable.
8336f1e2b38SJoerg Sonnenberger * C99 says to use `signed char' for %hhn conversions.
8346f1e2b38SJoerg Sonnenberger */
8356f1e2b38SJoerg Sonnenberger if (flags & LLONGINT)
836e0f95098SPeter Avalos *GETARG(long long *) = ret;
8376f1e2b38SJoerg Sonnenberger else if (flags & SIZET)
8386f1e2b38SJoerg Sonnenberger *GETARG(ssize_t *) = (ssize_t)ret;
8396f1e2b38SJoerg Sonnenberger else if (flags & PTRDIFFT)
8406f1e2b38SJoerg Sonnenberger *GETARG(ptrdiff_t *) = ret;
8416f1e2b38SJoerg Sonnenberger else if (flags & INTMAXT)
8426f1e2b38SJoerg Sonnenberger *GETARG(intmax_t *) = ret;
8436f1e2b38SJoerg Sonnenberger else if (flags & LONGINT)
8446f1e2b38SJoerg Sonnenberger *GETARG(long *) = ret;
8456f1e2b38SJoerg Sonnenberger else if (flags & SHORTINT)
8466f1e2b38SJoerg Sonnenberger *GETARG(short *) = ret;
8476f1e2b38SJoerg Sonnenberger else if (flags & CHARINT)
8486f1e2b38SJoerg Sonnenberger *GETARG(signed char *) = ret;
8496f1e2b38SJoerg Sonnenberger else
8506f1e2b38SJoerg Sonnenberger *GETARG(int *) = ret;
8516f1e2b38SJoerg Sonnenberger continue; /* no output */
8526f1e2b38SJoerg Sonnenberger case 'O':
8536f1e2b38SJoerg Sonnenberger flags |= LONGINT;
8546f1e2b38SJoerg Sonnenberger /*FALLTHROUGH*/
8556f1e2b38SJoerg Sonnenberger case 'o':
8566f1e2b38SJoerg Sonnenberger if (flags & INTMAX_SIZE)
8576f1e2b38SJoerg Sonnenberger ujval = UJARG();
8586f1e2b38SJoerg Sonnenberger else
8596f1e2b38SJoerg Sonnenberger ulval = UARG();
8606f1e2b38SJoerg Sonnenberger base = 8;
8616f1e2b38SJoerg Sonnenberger goto nosign;
8626f1e2b38SJoerg Sonnenberger case 'p':
863e0f95098SPeter Avalos /*-
8646f1e2b38SJoerg Sonnenberger * ``The argument shall be a pointer to void. The
8656f1e2b38SJoerg Sonnenberger * value of the pointer is converted to a sequence
8666f1e2b38SJoerg Sonnenberger * of printable characters, in an implementation-
8676f1e2b38SJoerg Sonnenberger * defined manner.''
8686f1e2b38SJoerg Sonnenberger * -- ANSI X3J11
8696f1e2b38SJoerg Sonnenberger */
8706f1e2b38SJoerg Sonnenberger ujval = (uintmax_t)(uintptr_t)GETARG(void *);
8716f1e2b38SJoerg Sonnenberger base = 16;
8726f1e2b38SJoerg Sonnenberger xdigs = xdigs_lower;
8736f1e2b38SJoerg Sonnenberger flags = flags | INTMAXT;
8746f1e2b38SJoerg Sonnenberger ox[1] = 'x';
8756f1e2b38SJoerg Sonnenberger goto nosign;
8766f1e2b38SJoerg Sonnenberger case 'S':
8776f1e2b38SJoerg Sonnenberger flags |= LONGINT;
8786f1e2b38SJoerg Sonnenberger /*FALLTHROUGH*/
8796f1e2b38SJoerg Sonnenberger case 's':
8806f1e2b38SJoerg Sonnenberger if (flags & LONGINT) {
8816f1e2b38SJoerg Sonnenberger if ((cp = GETARG(wchar_t *)) == NULL)
8826f1e2b38SJoerg Sonnenberger cp = L"(null)";
8836f1e2b38SJoerg Sonnenberger } else {
8846f1e2b38SJoerg Sonnenberger char *mbp;
8856f1e2b38SJoerg Sonnenberger
8866f1e2b38SJoerg Sonnenberger if (convbuf != NULL)
8876f1e2b38SJoerg Sonnenberger free(convbuf);
8886f1e2b38SJoerg Sonnenberger if ((mbp = GETARG(char *)) == NULL)
8896f1e2b38SJoerg Sonnenberger cp = L"(null)";
8906f1e2b38SJoerg Sonnenberger else {
8916f1e2b38SJoerg Sonnenberger convbuf = __mbsconv(mbp, prec);
8926f1e2b38SJoerg Sonnenberger if (convbuf == NULL) {
8936f1e2b38SJoerg Sonnenberger fp->pub._flags |= __SERR;
8946f1e2b38SJoerg Sonnenberger goto error;
8956f1e2b38SJoerg Sonnenberger }
8966f1e2b38SJoerg Sonnenberger cp = convbuf;
8976f1e2b38SJoerg Sonnenberger }
8986f1e2b38SJoerg Sonnenberger }
899e0f95098SPeter Avalos size = (prec >= 0) ? wcsnlen(cp, prec) : wcslen(cp);
9006f1e2b38SJoerg Sonnenberger sign = '\0';
9016f1e2b38SJoerg Sonnenberger break;
9026f1e2b38SJoerg Sonnenberger case 'U':
9036f1e2b38SJoerg Sonnenberger flags |= LONGINT;
9046f1e2b38SJoerg Sonnenberger /*FALLTHROUGH*/
9056f1e2b38SJoerg Sonnenberger case 'u':
9066f1e2b38SJoerg Sonnenberger if (flags & INTMAX_SIZE)
9076f1e2b38SJoerg Sonnenberger ujval = UJARG();
9086f1e2b38SJoerg Sonnenberger else
9096f1e2b38SJoerg Sonnenberger ulval = UARG();
9106f1e2b38SJoerg Sonnenberger base = 10;
9116f1e2b38SJoerg Sonnenberger goto nosign;
9126f1e2b38SJoerg Sonnenberger case 'X':
9136f1e2b38SJoerg Sonnenberger xdigs = xdigs_upper;
9146f1e2b38SJoerg Sonnenberger goto hex;
9156f1e2b38SJoerg Sonnenberger case 'x':
9166f1e2b38SJoerg Sonnenberger xdigs = xdigs_lower;
9176f1e2b38SJoerg Sonnenberger hex:
9186f1e2b38SJoerg Sonnenberger if (flags & INTMAX_SIZE)
9196f1e2b38SJoerg Sonnenberger ujval = UJARG();
9206f1e2b38SJoerg Sonnenberger else
9216f1e2b38SJoerg Sonnenberger ulval = UARG();
9226f1e2b38SJoerg Sonnenberger base = 16;
9236f1e2b38SJoerg Sonnenberger /* leading 0x/X only if non-zero */
9246f1e2b38SJoerg Sonnenberger if (flags & ALT &&
9256f1e2b38SJoerg Sonnenberger (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
9266f1e2b38SJoerg Sonnenberger ox[1] = ch;
9276f1e2b38SJoerg Sonnenberger
9286f1e2b38SJoerg Sonnenberger flags &= ~GROUPING;
9296f1e2b38SJoerg Sonnenberger /* unsigned conversions */
9306f1e2b38SJoerg Sonnenberger nosign: sign = '\0';
931e0f95098SPeter Avalos /*-
9326f1e2b38SJoerg Sonnenberger * ``... diouXx conversions ... if a precision is
9336f1e2b38SJoerg Sonnenberger * specified, the 0 flag will be ignored.''
9346f1e2b38SJoerg Sonnenberger * -- ANSI X3J11
9356f1e2b38SJoerg Sonnenberger */
9366f1e2b38SJoerg Sonnenberger number: if ((dprec = prec) >= 0)
9376f1e2b38SJoerg Sonnenberger flags &= ~ZEROPAD;
9386f1e2b38SJoerg Sonnenberger
939e0f95098SPeter Avalos /*-
9406f1e2b38SJoerg Sonnenberger * ``The result of converting a zero value with an
9416f1e2b38SJoerg Sonnenberger * explicit precision of zero is no characters.''
9426f1e2b38SJoerg Sonnenberger * -- ANSI X3J11
9436f1e2b38SJoerg Sonnenberger *
9446f1e2b38SJoerg Sonnenberger * ``The C Standard is clear enough as is. The call
9456f1e2b38SJoerg Sonnenberger * printf("%#.0o", 0) should print 0.''
9466f1e2b38SJoerg Sonnenberger * -- Defect Report #151
9476f1e2b38SJoerg Sonnenberger */
9486f1e2b38SJoerg Sonnenberger cp = buf + BUF;
9496f1e2b38SJoerg Sonnenberger if (flags & INTMAX_SIZE) {
9506f1e2b38SJoerg Sonnenberger if (ujval != 0 || prec != 0 ||
9516f1e2b38SJoerg Sonnenberger (flags & ALT && base == 8))
9526f1e2b38SJoerg Sonnenberger cp = __ujtoa(ujval, cp, base,
953e0f95098SPeter Avalos flags & ALT, xdigs);
9546f1e2b38SJoerg Sonnenberger } else {
9556f1e2b38SJoerg Sonnenberger if (ulval != 0 || prec != 0 ||
9566f1e2b38SJoerg Sonnenberger (flags & ALT && base == 8))
9576f1e2b38SJoerg Sonnenberger cp = __ultoa(ulval, cp, base,
958e0f95098SPeter Avalos flags & ALT, xdigs);
9596f1e2b38SJoerg Sonnenberger }
9606f1e2b38SJoerg Sonnenberger size = buf + BUF - cp;
9616f1e2b38SJoerg Sonnenberger if (size > BUF) /* should never happen */
9626f1e2b38SJoerg Sonnenberger abort();
963e0f95098SPeter Avalos if ((flags & GROUPING) && size != 0)
964*0d5acd74SJohn Marino size += grouping_init(&gs, size, locale);
9656f1e2b38SJoerg Sonnenberger break;
9666f1e2b38SJoerg Sonnenberger default: /* "%?" prints ?, unless ? is NUL */
9676f1e2b38SJoerg Sonnenberger if (ch == '\0')
9686f1e2b38SJoerg Sonnenberger goto done;
9696f1e2b38SJoerg Sonnenberger /* pretend it was %c with argument ch */
9706f1e2b38SJoerg Sonnenberger cp = buf;
9716f1e2b38SJoerg Sonnenberger *cp = ch;
9726f1e2b38SJoerg Sonnenberger size = 1;
9736f1e2b38SJoerg Sonnenberger sign = '\0';
9746f1e2b38SJoerg Sonnenberger break;
9756f1e2b38SJoerg Sonnenberger }
9766f1e2b38SJoerg Sonnenberger
9776f1e2b38SJoerg Sonnenberger /*
9786f1e2b38SJoerg Sonnenberger * All reasonable formats wind up here. At this point, `cp'
9796f1e2b38SJoerg Sonnenberger * points to a string which (if not flags&LADJUST) should be
9806f1e2b38SJoerg Sonnenberger * padded out to `width' places. If flags&ZEROPAD, it should
9816f1e2b38SJoerg Sonnenberger * first be prefixed by any sign or other prefix; otherwise,
9826f1e2b38SJoerg Sonnenberger * it should be blank padded before the prefix is emitted.
9836f1e2b38SJoerg Sonnenberger * After any left-hand padding and prefixing, emit zeroes
9846f1e2b38SJoerg Sonnenberger * required by a decimal [diouxX] precision, then print the
9856f1e2b38SJoerg Sonnenberger * string proper, then emit zeroes required by any leftover
9866f1e2b38SJoerg Sonnenberger * floating precision; finally, if LADJUST, pad with blanks.
9876f1e2b38SJoerg Sonnenberger *
9886f1e2b38SJoerg Sonnenberger * Compute actual size, so we know how much to pad.
9896f1e2b38SJoerg Sonnenberger * size excludes decimal prec; realsz includes it.
9906f1e2b38SJoerg Sonnenberger */
9916f1e2b38SJoerg Sonnenberger realsz = dprec > size ? dprec : size;
9926f1e2b38SJoerg Sonnenberger if (sign)
9936f1e2b38SJoerg Sonnenberger realsz++;
9946f1e2b38SJoerg Sonnenberger if (ox[1])
9956f1e2b38SJoerg Sonnenberger realsz += 2;
9966f1e2b38SJoerg Sonnenberger
9976f1e2b38SJoerg Sonnenberger prsize = width > realsz ? width : realsz;
9986f1e2b38SJoerg Sonnenberger if ((unsigned)ret + prsize > INT_MAX) {
9996f1e2b38SJoerg Sonnenberger ret = EOF;
1000*0d5acd74SJohn Marino errno = EOVERFLOW;
10016f1e2b38SJoerg Sonnenberger goto error;
10026f1e2b38SJoerg Sonnenberger }
10036f1e2b38SJoerg Sonnenberger
10046f1e2b38SJoerg Sonnenberger /* right-adjusting blank padding */
10056f1e2b38SJoerg Sonnenberger if ((flags & (LADJUST|ZEROPAD)) == 0)
10066f1e2b38SJoerg Sonnenberger PAD(width - realsz, blanks);
10076f1e2b38SJoerg Sonnenberger
10086f1e2b38SJoerg Sonnenberger /* prefix */
10096f1e2b38SJoerg Sonnenberger if (sign)
10106f1e2b38SJoerg Sonnenberger PRINT(&sign, 1);
10116f1e2b38SJoerg Sonnenberger
10126f1e2b38SJoerg Sonnenberger if (ox[1]) { /* ox[1] is either x, X, or \0 */
10136f1e2b38SJoerg Sonnenberger ox[0] = '0';
10146f1e2b38SJoerg Sonnenberger PRINT(ox, 2);
10156f1e2b38SJoerg Sonnenberger }
10166f1e2b38SJoerg Sonnenberger
10176f1e2b38SJoerg Sonnenberger /* right-adjusting zero padding */
10186f1e2b38SJoerg Sonnenberger if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
10196f1e2b38SJoerg Sonnenberger PAD(width - realsz, zeroes);
10206f1e2b38SJoerg Sonnenberger
10216f1e2b38SJoerg Sonnenberger /* the string or number proper */
10226f1e2b38SJoerg Sonnenberger #ifndef NO_FLOATING_POINT
10236f1e2b38SJoerg Sonnenberger if ((flags & FPT) == 0) {
1024e0f95098SPeter Avalos #endif
1025e0f95098SPeter Avalos /* leading zeroes from decimal precision */
1026e0f95098SPeter Avalos PAD(dprec - size, zeroes);
1027e0f95098SPeter Avalos if (gs.grouping) {
1028*0d5acd74SJohn Marino if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0)
1029e0f95098SPeter Avalos goto error;
1030e0f95098SPeter Avalos } else {
10316f1e2b38SJoerg Sonnenberger PRINT(cp, size);
1032e0f95098SPeter Avalos }
1033e0f95098SPeter Avalos #ifndef NO_FLOATING_POINT
10346f1e2b38SJoerg Sonnenberger } else { /* glue together f_p fragments */
10356f1e2b38SJoerg Sonnenberger if (!expchar) { /* %[fF] or sufficiently short %[gG] */
10366f1e2b38SJoerg Sonnenberger if (expt <= 0) {
10376f1e2b38SJoerg Sonnenberger PRINT(zeroes, 1);
10386f1e2b38SJoerg Sonnenberger if (prec || flags & ALT)
1039e0f95098SPeter Avalos PRINT(&decimal_point, 1);
10406f1e2b38SJoerg Sonnenberger PAD(-expt, zeroes);
10416f1e2b38SJoerg Sonnenberger /* already handled initial 0's */
10426f1e2b38SJoerg Sonnenberger prec += expt;
10436f1e2b38SJoerg Sonnenberger } else {
1044e0f95098SPeter Avalos if (gs.grouping) {
1045e0f95098SPeter Avalos n = grouping_print(&gs, &io,
1046*0d5acd74SJohn Marino cp, convbuf + ndig, locale);
1047e0f95098SPeter Avalos if (n < 0)
1048e0f95098SPeter Avalos goto error;
1049e0f95098SPeter Avalos cp += n;
1050e0f95098SPeter Avalos } else {
1051e0f95098SPeter Avalos PRINTANDPAD(cp, convbuf + ndig,
1052e0f95098SPeter Avalos expt, zeroes);
1053e0f95098SPeter Avalos cp += expt;
10546f1e2b38SJoerg Sonnenberger }
1055e0f95098SPeter Avalos if (prec || flags & ALT)
1056e0f95098SPeter Avalos PRINT(&decimal_point, 1);
10576f1e2b38SJoerg Sonnenberger }
10586f1e2b38SJoerg Sonnenberger PRINTANDPAD(cp, convbuf + ndig, prec, zeroes);
10596f1e2b38SJoerg Sonnenberger } else { /* %[eE] or sufficiently long %[gG] */
10606f1e2b38SJoerg Sonnenberger if (prec > 1 || flags & ALT) {
10616f1e2b38SJoerg Sonnenberger buf[0] = *cp++;
1062e0f95098SPeter Avalos buf[1] = decimal_point;
10636f1e2b38SJoerg Sonnenberger PRINT(buf, 2);
10646f1e2b38SJoerg Sonnenberger PRINT(cp, ndig-1);
10656f1e2b38SJoerg Sonnenberger PAD(prec - ndig, zeroes);
10666f1e2b38SJoerg Sonnenberger } else /* XeYYY */
10676f1e2b38SJoerg Sonnenberger PRINT(cp, 1);
10686f1e2b38SJoerg Sonnenberger PRINT(expstr, expsize);
10696f1e2b38SJoerg Sonnenberger }
10706f1e2b38SJoerg Sonnenberger }
10716f1e2b38SJoerg Sonnenberger #endif
10726f1e2b38SJoerg Sonnenberger /* left-adjusting padding (always blank) */
10736f1e2b38SJoerg Sonnenberger if (flags & LADJUST)
10746f1e2b38SJoerg Sonnenberger PAD(width - realsz, blanks);
10756f1e2b38SJoerg Sonnenberger
10766f1e2b38SJoerg Sonnenberger /* finally, adjust ret */
10776f1e2b38SJoerg Sonnenberger ret += prsize;
1078e0f95098SPeter Avalos
1079e0f95098SPeter Avalos FLUSH(); /* copy out the I/O vectors */
10806f1e2b38SJoerg Sonnenberger }
10816f1e2b38SJoerg Sonnenberger done:
1082e0f95098SPeter Avalos FLUSH();
10836f1e2b38SJoerg Sonnenberger error:
10846f1e2b38SJoerg Sonnenberger va_end(orgap);
10856f1e2b38SJoerg Sonnenberger if (convbuf != NULL)
10866f1e2b38SJoerg Sonnenberger free(convbuf);
10876f1e2b38SJoerg Sonnenberger if (__sferror(fp))
10886f1e2b38SJoerg Sonnenberger ret = EOF;
10896f1e2b38SJoerg Sonnenberger if ((argtable != NULL) && (argtable != statargtable))
10906f1e2b38SJoerg Sonnenberger free (argtable);
10916f1e2b38SJoerg Sonnenberger return (ret);
10926f1e2b38SJoerg Sonnenberger /* NOTREACHED */
10936f1e2b38SJoerg Sonnenberger }
1094