xref: /dragonfly/lib/libc/stdio/vfwprintf.c (revision 0d5acd74)
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