xref: /netbsd-src/lib/libc/stdio/vfwprintf.c (revision d9285aa4340c19817a4a02a67c373741aa3c6c6f)
1 /*	$NetBSD: vfwprintf.c,v 1.29 2012/03/21 14:20:47 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 1990, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Chris Torek.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
36 #if defined(LIBC_SCCS) && !defined(lint)
37 #if 0
38 static char sccsid[] = "@(#)vfprintf.c	8.1 (Berkeley) 6/4/93";
39 __FBSDID("$FreeBSD: src/lib/libc/stdio/vfwprintf.c,v 1.27 2007/01/09 00:28:08 imp Exp $");
40 #else
41 __RCSID("$NetBSD: vfwprintf.c,v 1.29 2012/03/21 14:20:47 christos Exp $");
42 #endif
43 #endif /* LIBC_SCCS and not lint */
44 
45 /*
46  * Actual {w,}printf innards.
47  */
48 
49 #include "namespace.h"
50 #include <sys/types.h>
51 
52 #include <assert.h>
53 #include <ctype.h>
54 #include <limits.h>
55 #include <locale.h>
56 #include <stdarg.h>
57 #include <stddef.h>
58 #include <stdint.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <errno.h>
63 #include <wchar.h>
64 #include <wctype.h>
65 
66 #include "reentrant.h"
67 #include "local.h"
68 #include "extern.h"
69 #include "fvwrite.h"
70 
71 #ifndef NARROW
72 #define MCHAR_T		char
73 #define CHAR_T		wchar_t
74 #define STRLEN(a)	wcslen(a)
75 #define MEMCHR(a, b, c)	wmemchr(a, b, c)
76 #define SCONV(a, b)	__mbsconv(a, b)
77 #define STRCONST(a)	L ## a
78 #define WDECL(a, b)	a ## w ## b
79 #define END_OF_FILE	WEOF
80 #define MULTI		0
81 #else
82 #define MCHAR_T		wchar_t
83 #define CHAR_T		char
84 #define STRLEN(a)	strlen(a)
85 #define MEMCHR(a, b, c)	memchr(a, b, c)
86 #define SCONV(a, b)	__wcsconv(a, b)
87 #define STRCONST(a)	a
88 #define WDECL(a, b)	a ## b
89 #define END_OF_FILE	EOF
90 #define MULTI		LONGINT
91 #endif
92 
93 union arg {
94 	int	intarg;
95 	u_int	uintarg;
96 	long	longarg;
97 	u_long	ulongarg;
98 	long long longlongarg;
99 	unsigned long long ulonglongarg;
100 	ptrdiff_t ptrdiffarg;
101 	ssize_t ssizearg;
102 	size_t	sizearg;
103 	intmax_t intmaxarg;
104 	uintmax_t uintmaxarg;
105 	void	*pvoidarg;
106 	char	*pchararg;
107 	signed char *pschararg;
108 	short	*pshortarg;
109 	int	*pintarg;
110 	long	*plongarg;
111 	long long *plonglongarg;
112 	ptrdiff_t *pptrdiffarg;
113 	size_t	*psizearg;
114 	intmax_t *pintmaxarg;
115 #ifndef NO_FLOATING_POINT
116 	double	doublearg;
117 	long double longdoublearg;
118 #endif
119 	wint_t	wintarg;
120 	wchar_t	*pwchararg;
121 };
122 
123 /*
124  * Type ids for argument type table.
125  */
126 enum typeid {
127 	T_UNUSED = 0, TP_SHORT, T_INT, T_U_INT, TP_INT,
128 	T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,
129 	T_PTRDIFFT, TP_PTRDIFFT, T_SSIZET, T_SIZET, TP_SIZET,
130 	T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
131 	T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
132 };
133 
134 static int	__sbprintf(FILE *, const CHAR_T *, va_list);
135 static CHAR_T	*__ujtoa(uintmax_t, CHAR_T *, int, int, const char *, int,
136 		    char, const char *);
137 static CHAR_T	*__ultoa(u_long, CHAR_T *, int, int, const char *, int,
138 		    char, const char *);
139 #ifndef NARROW
140 static CHAR_T	*__mbsconv(char *, int);
141 static wint_t	__xfputwc(CHAR_T, FILE *);
142 #else
143 static char	*__wcsconv(wchar_t *, int);
144 static int	__sprint(FILE *, struct __suio *);
145 #endif
146 static int	__find_arguments(const CHAR_T *, va_list, union arg **);
147 static int	__grow_type_table(size_t, enum typeid **, size_t *);
148 
149 /*
150  * Helper function for `fprintf to unbuffered unix file': creates a
151  * temporary buffer.  We only work on write-only files; this avoids
152  * worries about ungetc buffers and so forth.
153  */
154 static int
155 __sbprintf(FILE *fp, const CHAR_T *fmt, va_list ap)
156 {
157 	int ret;
158 	FILE fake;
159 	struct __sfileext fakeext;
160 	unsigned char buf[BUFSIZ];
161 
162 	_DIAGASSERT(fp != NULL);
163 	_DIAGASSERT(fmt != NULL);
164 
165 	_FILEEXT_SETUP(&fake, &fakeext);
166 	memset(WCIO_GET(&fake), 0, sizeof(struct wchar_io_data));
167 
168 	/* copy the important variables */
169 	fake._flags = fp->_flags & ~__SNBF;
170 	fake._file = fp->_file;
171 	fake._cookie = fp->_cookie;
172 	fake._write = fp->_write;
173 
174 	/* set up the buffer */
175 	fake._bf._base = fake._p = buf;
176 	fake._bf._size = fake._w = sizeof(buf);
177 	fake._lbfsize = 0;	/* not actually used, but Just In Case */
178 
179 	/* do the work, then copy any error status */
180 	ret = WDECL(__vf,printf_unlocked)(&fake, fmt, ap);
181 	if (ret >= 0 && fflush(&fake))
182 		ret = END_OF_FILE;
183 	if (fake._flags & __SERR)
184 		fp->_flags |= __SERR;
185 	return ret;
186 }
187 
188 #ifndef NARROW
189 /*
190  * Like __fputwc, but handles fake string (__SSTR) files properly.
191  * File must already be locked.
192  */
193 static wint_t
194 __xfputwc(wchar_t wc, FILE *fp)
195 {
196 	static const mbstate_t initial;
197 	mbstate_t mbs;
198 	char buf[MB_LEN_MAX];
199 	struct __suio uio;
200 	struct __siov iov;
201 	size_t len;
202 
203 	if ((fp->_flags & __SSTR) == 0)
204 		return __fputwc_unlock(wc, fp);
205 
206 	mbs = initial;
207 	if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) {
208 		fp->_flags |= __SERR;
209 		return END_OF_FILE;
210 	}
211 	uio.uio_iov = &iov;
212 	uio.uio_resid = len;
213 	uio.uio_iovcnt = 1;
214 	iov.iov_base = buf;
215 	iov.iov_len = len;
216 	return __sfvwrite(fp, &uio) != EOF ? (wint_t)wc : END_OF_FILE;
217 }
218 #else
219 /*
220  * Flush out all the vectors defined by the given uio,
221  * then reset it so that it can be reused.
222  */
223 static int
224 __sprint(FILE *fp, struct __suio *uio)
225 {
226 	int err;
227 
228 	_DIAGASSERT(fp != NULL);
229 	_DIAGASSERT(uio != NULL);
230 
231 	if (uio->uio_resid == 0) {
232 		uio->uio_iovcnt = 0;
233 		return 0;
234 	}
235 	err = __sfvwrite(fp, uio);
236 	uio->uio_resid = 0;
237 	uio->uio_iovcnt = 0;
238 	return err;
239 }
240 #endif
241 
242 /*
243  * Macros for converting digits to letters and vice versa
244  */
245 #define	to_digit(c)	((c) - '0')
246 #define is_digit(c)	((unsigned)to_digit(c) <= 9)
247 #define	to_char(n)	(CHAR_T)((n) + '0')
248 
249 /*
250  * Convert an unsigned long to ASCII for printf purposes, returning
251  * a pointer to the first character of the string representation.
252  * Octal numbers can be forced to have a leading zero; hex numbers
253  * use the given digits.
254  */
255 static CHAR_T *
256 __ultoa(u_long val, CHAR_T *endp, int base, int octzero, const char *xdigs,
257     int needgrp, char thousep, const char *grp)
258 {
259 	CHAR_T *cp = endp;
260 	long sval;
261 	int ndig;
262 
263 	/*
264 	 * Handle the three cases separately, in the hope of getting
265 	 * better/faster code.
266 	 */
267 	switch (base) {
268 	case 10:
269 		if (val < 10) {	/* many numbers are 1 digit */
270 			*--cp = to_char(val);
271 			return cp;
272 		}
273 		ndig = 0;
274 		/*
275 		 * On many machines, unsigned arithmetic is harder than
276 		 * signed arithmetic, so we do at most one unsigned mod and
277 		 * divide; this is sufficient to reduce the range of
278 		 * the incoming value to where signed arithmetic works.
279 		 */
280 		if (val > LONG_MAX) {
281 			*--cp = to_char(val % 10);
282 			ndig++;
283 			sval = val / 10;
284 		} else
285 			sval = val;
286 		do {
287 			*--cp = to_char(sval % 10);
288 			ndig++;
289 			/*
290 			 * If (*grp == CHAR_MAX) then no more grouping
291 			 * should be performed.
292 			 */
293 			if (needgrp && ndig == *grp
294 			    && (unsigned char)*grp != (unsigned char)CHAR_MAX
295 			    && sval > 9) {
296 				*--cp = thousep;
297 				ndig = 0;
298 				/*
299 				 * If (*(grp+1) == '\0') then we have to
300 				 * use *grp character (last grouping rule)
301 				 * for all next cases
302 				 */
303 				if (*(grp+1) != '\0')
304 					grp++;
305 			}
306 			sval /= 10;
307 		} while (sval != 0);
308 		break;
309 
310 	case 8:
311 		do {
312 			*--cp = to_char(val & 7);
313 			val >>= 3;
314 		} while (val);
315 		if (octzero && *cp != '0')
316 			*--cp = '0';
317 		break;
318 
319 	case 16:
320 		do {
321 			*--cp = xdigs[(size_t)val & 15];
322 			val >>= 4;
323 		} while (val);
324 		break;
325 
326 	default:			/* oops */
327 		abort();
328 	}
329 	return cp;
330 }
331 
332 /* Identical to __ultoa, but for intmax_t. */
333 static CHAR_T *
334 __ujtoa(uintmax_t val, CHAR_T *endp, int base, int octzero,
335     const char *xdigs, int needgrp, char thousep, const char *grp)
336 {
337 	CHAR_T *cp = endp;
338 	intmax_t sval;
339 	int ndig;
340 
341 	/* quick test for small values; __ultoa is typically much faster */
342 	/* (perhaps instead we should run until small, then call __ultoa?) */
343 	if (val <= ULONG_MAX)
344 		return __ultoa((u_long)val, endp, base, octzero, xdigs,
345 		    needgrp, thousep, grp);
346 	switch (base) {
347 	case 10:
348 		if (val < 10) {
349 			*--cp = to_char(val % 10);
350 			return cp;
351 		}
352 		ndig = 0;
353 		if (val > INTMAX_MAX) {
354 			*--cp = to_char(val % 10);
355 			ndig++;
356 			sval = val / 10;
357 		} else
358 			sval = val;
359 		do {
360 			*--cp = to_char(sval % 10);
361 			ndig++;
362 			/*
363 			 * If (*grp == CHAR_MAX) then no more grouping
364 			 * should be performed.
365 			 */
366 			if (needgrp
367 			    && (unsigned char)*grp != (unsigned char)CHAR_MAX
368 			    && ndig == *grp
369 			    && sval > 9) {
370 				*--cp = thousep;
371 				ndig = 0;
372 				/*
373 				 * If (*(grp+1) == '\0') then we have to
374 				 * use *grp character (last grouping rule)
375 				 * for all next cases
376 				 */
377 				if (*(grp+1) != '\0')
378 					grp++;
379 			}
380 			sval /= 10;
381 		} while (sval != 0);
382 		break;
383 
384 	case 8:
385 		do {
386 			*--cp = to_char(val & 7);
387 			val >>= 3;
388 		} while (val);
389 		if (octzero && *cp != '0')
390 			*--cp = '0';
391 		break;
392 
393 	case 16:
394 		do {
395 			*--cp = xdigs[(size_t)val & 15];
396 			val >>= 4;
397 		} while (val);
398 		break;
399 
400 	default:
401 		abort();
402 	}
403 	return cp;
404 }
405 
406 #ifndef NARROW
407 /*
408  * Convert a multibyte character string argument for the %s format to a wide
409  * string representation. ``prec'' specifies the maximum number of bytes
410  * to output. If ``prec'' is greater than or equal to zero, we can't assume
411  * that the multibyte char. string ends in a null character.
412  */
413 static wchar_t *
414 __mbsconv(char *mbsarg, int prec)
415 {
416 	static const mbstate_t initial;
417 	mbstate_t mbs;
418 	wchar_t *convbuf, *wcp;
419 	const char *p;
420 	size_t insize, nchars, nconv;
421 
422 	if (mbsarg == NULL)
423 		return NULL;
424 
425 	/*
426 	 * Supplied argument is a multibyte string; convert it to wide
427 	 * characters first.
428 	 */
429 	if (prec >= 0) {
430 		/*
431 		 * String is not guaranteed to be NUL-terminated. Find the
432 		 * number of characters to print.
433 		 */
434 		p = mbsarg;
435 		insize = nchars = nconv = 0;
436 		mbs = initial;
437 		while (nchars != (size_t)prec) {
438 			nconv = mbrlen(p, MB_CUR_MAX, &mbs);
439 			if (nconv == 0 || nconv == (size_t)-1 ||
440 			    nconv == (size_t)-2)
441 				break;
442 			p += nconv;
443 			nchars++;
444 			insize += nconv;
445 		}
446 		if (nconv == (size_t)-1 || nconv == (size_t)-2)
447 			return NULL;
448 	} else
449 		insize = strlen(mbsarg);
450 
451 	/*
452 	 * Allocate buffer for the result and perform the conversion,
453 	 * converting at most `size' bytes of the input multibyte string to
454 	 * wide characters for printing.
455 	 */
456 	convbuf = malloc((insize + 1) * sizeof(*convbuf));
457 	if (convbuf == NULL)
458 		return NULL;
459 	wcp = convbuf;
460 	p = mbsarg;
461 	mbs = initial;
462 	nconv = 0;
463 	while (insize != 0) {
464 		nconv = mbrtowc(wcp, p, insize, &mbs);
465 		if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2)
466 			break;
467 		wcp++;
468 		p += nconv;
469 		insize -= nconv;
470 	}
471 	if (nconv == (size_t)-1 || nconv == (size_t)-2) {
472 		free(convbuf);
473 		return NULL;
474 	}
475 	*wcp = L'\0';
476 
477 	return convbuf;
478 }
479 #else
480 /*
481  * Convert a wide-character string argument for the %ls format to a multibyte
482  * string representation. If not -1, prec specifies the maximum number of
483  * bytes to output, and also means that we can't assume that the wide-char.
484  * string ends is null-terminated.
485  */
486 static char *
487 __wcsconv(wchar_t *wcsarg, int prec)
488 {
489 	static const mbstate_t initial;
490 	mbstate_t mbs;
491 	char buf[MB_LEN_MAX];
492 	wchar_t *p;
493 	char *convbuf;
494 	size_t clen, nbytes;
495 
496 	/* Allocate space for the maximum number of bytes we could output. */
497 	if (prec < 0) {
498 		p = wcsarg;
499 		mbs = initial;
500 		nbytes = wcsrtombs(NULL, (void *)&p, 0, &mbs);
501 		if (nbytes == (size_t)-1)
502 			return NULL;
503 	} else {
504 		/*
505 		 * Optimisation: if the output precision is small enough,
506 		 * just allocate enough memory for the maximum instead of
507 		 * scanning the string.
508 		 */
509 		if (prec < 128)
510 			nbytes = prec;
511 		else {
512 			nbytes = 0;
513 			p = wcsarg;
514 			mbs = initial;
515 			for (;;) {
516 				clen = wcrtomb(buf, *p++, &mbs);
517 				if (clen == 0 || clen == (size_t)-1 ||
518 				    nbytes + clen > (size_t)prec)
519 					break;
520 				nbytes += clen;
521 			}
522 		}
523 	}
524 	if ((convbuf = malloc(nbytes + 1)) == NULL)
525 		return NULL;
526 
527 	/* Fill the output buffer. */
528 	p = wcsarg;
529 	mbs = initial;
530 	if ((nbytes = wcsrtombs(convbuf, (void *)&p,
531 	    nbytes, &mbs)) == (size_t)-1) {
532 		free(convbuf);
533 		return NULL;
534 	}
535 	convbuf[nbytes] = '\0';
536 	return convbuf;
537 }
538 #endif
539 
540 /*
541  * MT-safe version
542  */
543 int
544 WDECL(vf,printf)(FILE * __restrict fp, const CHAR_T * __restrict fmt0, va_list ap)
545 {
546 	int ret;
547 
548 	FLOCKFILE(fp);
549 	ret = WDECL(__vf,printf_unlocked)(fp, fmt0, ap);
550 	FUNLOCKFILE(fp);
551 	return ret;
552 }
553 
554 #ifndef NO_FLOATING_POINT
555 
556 #include <float.h>
557 #include <math.h>
558 #include "floatio.h"
559 
560 #define	DEFPREC		6
561 
562 static int exponent(CHAR_T *, int, int);
563 #ifndef WIDE_DOUBLE
564 static char *cvt(double, int, int, char *, int *, int, int *);
565 #endif
566 
567 #endif /* !NO_FLOATING_POINT */
568 
569 /*
570  * The size of the buffer we use as scratch space for integer
571  * conversions, among other things.  Technically, we would need the
572  * most space for base 10 conversions with thousands' grouping
573  * characters between each pair of digits.  100 bytes is a
574  * conservative overestimate even for a 128-bit uintmax_t.
575  */
576 #define	BUF	100
577 
578 #define STATIC_ARG_TBL_SIZE 8           /* Size of static argument table. */
579 
580 /*
581  * Flags used during conversion.
582  */
583 #define	ALT		0x001		/* alternate form */
584 #define	LADJUST		0x004		/* left adjustment */
585 #define	LONGDBL		0x008		/* long double */
586 #define	LONGINT		0x010		/* long integer */
587 #define	LLONGINT	0x020		/* long long integer */
588 #define	SHORTINT	0x040		/* short integer */
589 #define	ZEROPAD		0x080		/* zero (as opposed to blank) pad */
590 #define	FPT		0x100		/* Floating point number */
591 #define	GROUPING	0x200		/* use grouping ("'" flag) */
592 					/* C99 additional size modifiers: */
593 #define	SIZET		0x400		/* size_t */
594 #define	PTRDIFFT	0x800		/* ptrdiff_t */
595 #define	INTMAXT		0x1000		/* intmax_t */
596 #define	CHARINT		0x2000		/* print char using int format */
597 
598 /*
599  * Non-MT-safe version
600  */
601 int
602 WDECL(__vf,printf_unlocked)(FILE *fp, const CHAR_T *fmt0, va_list ap)
603 {
604 	CHAR_T *fmt;		/* format string */
605 	int ch;			/* character from fmt */
606 	int n, n2;		/* handy integer (short term usage) */
607 	CHAR_T *cp;		/* handy char pointer (short term usage) */
608 	int flags;		/* flags as above */
609 	int ret;		/* return value accumulator */
610 	int width;		/* width from format (%8d), or 0 */
611 	int prec;		/* precision from format; <0 for N/A */
612 	CHAR_T sign;		/* sign prefix (' ', '+', '-', or \0) */
613 	char thousands_sep;	/* locale specific thousands separator */
614 	const char *grouping;	/* locale specific numeric grouping rules */
615 #ifndef NO_FLOATING_POINT
616 	/*
617 	 * We can decompose the printed representation of floating
618 	 * point numbers into several parts, some of which may be empty:
619 	 *
620 	 * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
621 	 *    A       B     ---C---      D       E   F
622 	 *
623 	 * A:	'sign' holds this value if present; '\0' otherwise
624 	 * B:	ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
625 	 * C:	cp points to the string MMMNNN.  Leading and trailing
626 	 *	zeros are not in the string and must be added.
627 	 * D:	expchar holds this character; '\0' if no exponent, e.g. %f
628 	 * F:	at least two digits for decimal, at least one digit for hex
629 	 */
630 	char *decimal_point;	/* locale specific decimal point */
631 #ifdef WIDE_DOUBLE
632 	int signflag;		/* true if float is negative */
633 	union {			/* floating point arguments %[aAeEfFgG] */
634 		double dbl;
635 		long double ldbl;
636 	} fparg;
637 	char *dtoaend;		/* pointer to end of converted digits */
638 #else
639 	double _double;		/* double precision arguments %[eEfgG] */
640 	char softsign;		/* temporary negative sign for floats */
641 #endif
642 	char *dtoaresult;	/* buffer allocated by dtoa */
643 	int expt;		/* integer value of exponent */
644 	char expchar;		/* exponent character: [eEpP\0] */
645 	int expsize;		/* character count for expstr */
646 	int lead;		/* sig figs before decimal or group sep */
647 	int ndig;		/* actual number of digits returned by dtoa */
648 	CHAR_T expstr[MAXEXPDIG+2];	/* buffer for exponent string: e+ZZZ */
649 	int nseps;		/* number of group separators with ' */
650 	int nrepeats;		/* number of repeats of the last group */
651 #endif
652 	u_long	ulval;		/* integer arguments %[diouxX] */
653 	uintmax_t ujval;	/* %j, %ll, %q, %t, %z integers */
654 	int base;		/* base for [diouxX] conversion */
655 	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
656 	int realsz;		/* field size expanded by dprec, sign, etc */
657 	int size;		/* size of converted field or string */
658 	int prsize;             /* max size of printed field */
659 	const char *xdigs;	/* digits for %[xX] conversion */
660 #ifdef NARROW
661 #define NIOV 8
662 	struct __siov *iovp;	/* for PRINT macro */
663 	struct __suio uio;	/* output information: summary */
664 	struct __siov iov[NIOV];/* ... and individual io vectors */
665 #else
666 	int n3;
667 #endif
668 	CHAR_T buf[BUF];	/* buffer with space for digits of uintmax_t */
669 	CHAR_T ox[2];		/* space for 0x hex-prefix */
670 	union arg *argtable;	/* args, built due to positional arg */
671 	union arg statargtable [STATIC_ARG_TBL_SIZE];
672 	int nextarg;		/* 1-based argument index */
673 	va_list orgap;		/* original argument pointer */
674 	CHAR_T *convbuf;	/* multibyte to wide conversion result */
675 
676 	/*
677 	 * Choose PADSIZE to trade efficiency vs. size.  If larger printf
678 	 * fields occur frequently, increase PADSIZE and make the initialisers
679 	 * below longer.
680 	 */
681 #define	PADSIZE	16		/* pad chunk size */
682 	static CHAR_T blanks[PADSIZE] =
683 	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
684 	static CHAR_T zeroes[PADSIZE] =
685 	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
686 
687 	static const char xdigs_lower[16] = "0123456789abcdef";
688 	static const char xdigs_upper[16] = "0123456789ABCDEF";
689 
690 	/*
691 	 * BEWARE, these `goto error' on error, PRINT uses `n2' and
692 	 * PAD uses `n'.
693 	 */
694 #ifndef NARROW
695 #define	PRINT(ptr, len)	do {			\
696 	for (n3 = 0; n3 < (len); n3++)		\
697 		__xfputwc((ptr)[n3], fp);	\
698 } while (/*CONSTCOND*/0)
699 #define FLUSH()
700 #else
701 #define	PRINT(ptr, len) do { \
702 	iovp->iov_base = __UNCONST(ptr); \
703 	iovp->iov_len = (len); \
704 	uio.uio_resid += (len); \
705 	iovp++; \
706 	if (++uio.uio_iovcnt >= NIOV) { \
707 		if (__sprint(fp, &uio)) \
708 			goto error; \
709 		iovp = iov; \
710 	} \
711 } while (/*CONSTCOND*/0)
712 #define	FLUSH() do { \
713 	if (uio.uio_resid && __sprint(fp, &uio)) \
714 		goto error; \
715 	uio.uio_iovcnt = 0; \
716 	iovp = iov; \
717 } while (/*CONSTCOND*/0)
718 #endif /* NARROW */
719 
720 #define	PAD(howmany, with)	do {		\
721 	if ((n = (howmany)) > 0) {		\
722 		while (n > PADSIZE) {		\
723 			PRINT(with, PADSIZE);	\
724 			n -= PADSIZE;		\
725 		}				\
726 		PRINT(with, n);			\
727 	}					\
728 } while (/*CONSTCOND*/0)
729 #define	PRINTANDPAD(p, ep, len, with) do {	\
730 	ptrdiff_t td = (ep) - (p);		\
731 	_DIAGASSERT(__type_fit(int, td));	\
732 	n2 = (int)td;       			\
733 	if (n2 > (len))				\
734 		n2 = (len);			\
735 	if (n2 > 0)				\
736 		PRINT((p), n2);			\
737 	PAD((len) - (n2 > 0 ? n2 : 0), (with));	\
738 } while(/*CONSTCOND*/0)
739 
740 	/*
741 	 * Get the argument indexed by nextarg.   If the argument table is
742 	 * built, use it to get the argument.  If its not, get the next
743 	 * argument (and arguments must be gotten sequentially).
744 	 */
745 #define GETARG(type) \
746 	((/*CONSTCOND*/argtable != NULL) ? *((type*)(void*)(&argtable[nextarg++])) : \
747 	    (nextarg++, va_arg(ap, type)))
748 
749 	/*
750 	 * To extend shorts properly, we need both signed and unsigned
751 	 * argument extraction methods.
752 	 */
753 #define	SARG() \
754 	(flags&LONGINT ? GETARG(long) : \
755 	    flags&SHORTINT ? (long)(short)GETARG(int) : \
756 	    flags&CHARINT ? (long)(signed char)GETARG(int) : \
757 	    (long)GETARG(int))
758 #define	UARG() \
759 	(flags&LONGINT ? GETARG(u_long) : \
760 	    flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
761 	    flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
762 	    (u_long)GETARG(u_int))
763 #define	INTMAX_SIZE	(INTMAXT|SIZET|PTRDIFFT|LLONGINT)
764 #define SJARG() \
765 	(flags&INTMAXT ? GETARG(intmax_t) : \
766 	    flags&SIZET ? (intmax_t)GETARG(ssize_t) : \
767 	    flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
768 	    (intmax_t)GETARG(long long))
769 #define	UJARG() \
770 	(flags&INTMAXT ? GETARG(uintmax_t) : \
771 	    flags&SIZET ? (uintmax_t)GETARG(size_t) : \
772 	    flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
773 	    (uintmax_t)GETARG(unsigned long long))
774 
775 	/*
776 	 * Get * arguments, including the form *nn$.  Preserve the nextarg
777 	 * that the argument can be gotten once the type is determined.
778 	 */
779 #define GETASTER(val) \
780 	n2 = 0; \
781 	cp = fmt; \
782 	while (is_digit(*cp)) { \
783 		n2 = 10 * n2 + to_digit(*cp); \
784 		cp++; \
785 	} \
786 	if (*cp == '$') { \
787 		int hold = nextarg; \
788 		if (argtable == NULL) { \
789 			argtable = statargtable; \
790 			if (__find_arguments(fmt0, orgap, &argtable) == -1) \
791 				goto oomem; \
792 		} \
793 		nextarg = n2; \
794 		val = GETARG (int); \
795 		nextarg = hold; \
796 		fmt = ++cp; \
797 	} else { \
798 		val = GETARG (int); \
799 	}
800 
801 	_DIAGASSERT(fp != NULL);
802 	_DIAGASSERT(fmt0 != NULL);
803 
804 	_SET_ORIENTATION(fp, -1);
805 
806 	ndig = -1;	/* XXX gcc */
807 
808 	thousands_sep = '\0';
809 	grouping = NULL;
810 #ifndef NO_FLOATING_POINT
811 	decimal_point = localeconv()->decimal_point;
812 	expsize = 0;		/* XXXGCC -Wuninitialized [sh3,m68000] */
813 #endif
814 	convbuf = NULL;
815 	/* sorry, f{w,}printf(read_only_file, L"") returns {W,}EOF, not 0 */
816 	if (cantwrite(fp)) {
817 		errno = EBADF;
818 		return END_OF_FILE;
819 	}
820 
821 	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
822 	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
823 	    __sfileno(fp) != -1)
824 		return __sbprintf(fp, fmt0, ap);
825 
826 	fmt = (CHAR_T *)__UNCONST(fmt0);
827 	argtable = NULL;
828 	nextarg = 1;
829 	va_copy(orgap, ap);
830 #ifdef NARROW
831 	uio.uio_iov = iovp = iov;
832 	uio.uio_resid = 0;
833 	uio.uio_iovcnt = 0;
834 #endif
835 	ret = 0;
836 
837 	/*
838 	 * Scan the format for conversions (`%' character).
839 	 */
840 	for (;;) {
841 		const CHAR_T *result;
842 
843 		for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
844 			continue;
845 		_DIAGASSERT(__type_fit(int, fmt - cp));
846 		if ((n = (int)(fmt - cp)) != 0) {
847 			if ((unsigned)ret + n > INT_MAX) {
848 				ret = END_OF_FILE;
849 				goto error;
850 			}
851 			PRINT(cp, n);
852 			ret += n;
853 		}
854 		if (ch == '\0')
855 			goto done;
856 		fmt++;		/* skip over '%' */
857 
858 		flags = 0;
859 		dprec = 0;
860 		width = 0;
861 		prec = -1;
862 		sign = '\0';
863 		ox[1] = '\0';
864 		expchar = '\0';
865 		lead = 0;
866 		nseps = nrepeats = 0;
867 		ulval = 0;
868 		ujval = 0;
869 		xdigs = NULL;
870 
871 rflag:		ch = *fmt++;
872 reswitch:	switch (ch) {
873 		case ' ':
874 			/*-
875 			 * ``If the space and + flags both appear, the space
876 			 * flag will be ignored.''
877 			 *	-- ANSI X3J11
878 			 */
879 			if (!sign)
880 				sign = ' ';
881 			goto rflag;
882 		case '#':
883 			flags |= ALT;
884 			goto rflag;
885 		case '*':
886 			/*-
887 			 * ``A negative field width argument is taken as a
888 			 * - flag followed by a positive field width.''
889 			 *	-- ANSI X3J11
890 			 * They don't exclude field widths read from args.
891 			 */
892 			GETASTER (width);
893 			if (width >= 0)
894 				goto rflag;
895 			width = -width;
896 			/* FALLTHROUGH */
897 		case '-':
898 			flags |= LADJUST;
899 			goto rflag;
900 		case '+':
901 			sign = '+';
902 			goto rflag;
903 		case '\'':
904 			flags |= GROUPING;
905 			thousands_sep = *(localeconv()->thousands_sep);
906 			grouping = localeconv()->grouping;
907 			/* If the locale doesn't define the above, use sane
908 			 * defaults - otherwise silly things happen! */
909 			if (thousands_sep == 0)
910 				thousands_sep = ',';
911 			if (!grouping || !*grouping)
912 				grouping = "\3";
913 			goto rflag;
914 		case '.':
915 			if ((ch = *fmt++) == '*') {
916 				GETASTER (prec);
917 				goto rflag;
918 			}
919 			prec = 0;
920 			while (is_digit(ch)) {
921 				prec = 10 * prec + to_digit(ch);
922 				ch = *fmt++;
923 			}
924 			goto reswitch;
925 		case '0':
926 			/*-
927 			 * ``Note that 0 is taken as a flag, not as the
928 			 * beginning of a field width.''
929 			 *	-- ANSI X3J11
930 			 */
931 			flags |= ZEROPAD;
932 			goto rflag;
933 		case '1': case '2': case '3': case '4':
934 		case '5': case '6': case '7': case '8': case '9':
935 			n = 0;
936 			do {
937 				n = 10 * n + to_digit(ch);
938 				ch = *fmt++;
939 			} while (is_digit(ch));
940 			if (ch == '$') {
941 				nextarg = n;
942 				if (argtable == NULL) {
943 					argtable = statargtable;
944 					if (__find_arguments(fmt0, orgap,
945 					    &argtable) == -1)
946 						goto oomem;
947 				}
948 				goto rflag;
949 			}
950 			width = n;
951 			goto reswitch;
952 #ifndef NO_FLOATING_POINT
953 		case 'L':
954 			flags |= LONGDBL;
955 			goto rflag;
956 #endif
957 		case 'h':
958 			if (flags & SHORTINT) {
959 				flags &= ~SHORTINT;
960 				flags |= CHARINT;
961 			} else
962 				flags |= SHORTINT;
963 			goto rflag;
964 		case 'j':
965 			flags |= INTMAXT;
966 			goto rflag;
967 		case 'l':
968 			if (flags & LONGINT) {
969 				flags &= ~LONGINT;
970 				flags |= LLONGINT;
971 			} else
972 				flags |= LONGINT;
973 			goto rflag;
974 		case 'q':
975 			flags |= LLONGINT;	/* not necessarily */
976 			goto rflag;
977 		case 't':
978 			flags |= PTRDIFFT;
979 			goto rflag;
980 		case 'z':
981 			flags |= SIZET;
982 			goto rflag;
983 		case 'C':
984 			flags |= LONGINT;
985 			/*FALLTHROUGH*/
986 		case 'c':
987 #ifdef NARROW
988 			if (flags & LONGINT) {
989 				static const mbstate_t initial;
990 				mbstate_t mbs;
991 				size_t mbseqlen;
992 
993 				mbs = initial;
994 				mbseqlen = wcrtomb(buf,
995 				    (wchar_t)GETARG(wint_t), &mbs);
996 				if (mbseqlen == (size_t)-1) {
997 					fp->_flags |= __SERR;
998 					goto error;
999 				}
1000 				size = (int)mbseqlen;
1001 			} else {
1002 				*buf = GETARG(int);
1003 				size = 1;
1004 			}
1005 #else
1006 			if (flags & LONGINT)
1007 				*buf = (wchar_t)GETARG(wint_t);
1008 			else
1009 				*buf = (wchar_t)btowc(GETARG(int));
1010 			size = 1;
1011 #endif
1012 			result = buf;
1013 			sign = '\0';
1014 			break;
1015 		case 'D':
1016 			flags |= LONGINT;
1017 			/*FALLTHROUGH*/
1018 		case 'd':
1019 		case 'i':
1020 			if (flags & INTMAX_SIZE) {
1021 				ujval = SJARG();
1022 				if ((intmax_t)ujval < 0) {
1023 					ujval = -ujval;
1024 					sign = '-';
1025 				}
1026 			} else {
1027 				ulval = SARG();
1028 				if ((long)ulval < 0) {
1029 					ulval = -ulval;
1030 					sign = '-';
1031 				}
1032 			}
1033 			base = 10;
1034 			goto number;
1035 #ifndef NO_FLOATING_POINT
1036 #ifdef WIDE_DOUBLE
1037 		case 'a':
1038 		case 'A':
1039 			if (ch == 'a') {
1040 				ox[1] = 'x';
1041 				xdigs = xdigs_lower;
1042 				expchar = 'p';
1043 			} else {
1044 				ox[1] = 'X';
1045 				xdigs = xdigs_upper;
1046 				expchar = 'P';
1047 			}
1048 			if (prec >= 0)
1049 				prec++;
1050 			if (flags & LONGDBL) {
1051 				fparg.ldbl = GETARG(long double);
1052 				dtoaresult =
1053 				    __hldtoa(fparg.ldbl, xdigs, prec,
1054 				        &expt, &signflag, &dtoaend);
1055 			} else {
1056 				fparg.dbl = GETARG(double);
1057 				dtoaresult =
1058 				    __hdtoa(fparg.dbl, xdigs, prec,
1059 				        &expt, &signflag, &dtoaend);
1060 			}
1061 			if (dtoaresult == NULL)
1062 				goto oomem;
1063 
1064 			if (prec < 0) {
1065 				_DIAGASSERT(__type_fit(int,
1066 				    dtoaend - dtoaresult));
1067 				prec = (int)(dtoaend - dtoaresult);
1068 			}
1069 			if (expt == INT_MAX)
1070 				ox[1] = '\0';
1071 			_DIAGASSERT(__type_fit(int, dtoaend - dtoaresult));
1072 			ndig = (int)(dtoaend - dtoaresult);
1073 			if (convbuf != NULL)
1074 				free(convbuf);
1075 #ifndef NARROW
1076 			result = convbuf = __mbsconv(dtoaresult, -1);
1077 #else
1078 			/*XXX inefficient*/
1079 			result = convbuf = strdup(dtoaresult);
1080 #endif
1081 			if (result == NULL)
1082 				goto oomem;
1083 			__freedtoa(dtoaresult);
1084 			goto fp_common;
1085 		case 'e':
1086 		case 'E':
1087 			expchar = ch;
1088 			if (prec < 0)	/* account for digit before decpt */
1089 				prec = DEFPREC + 1;
1090 			else
1091 				prec++;
1092 			goto fp_begin;
1093 		case 'f':
1094 		case 'F':
1095 			expchar = '\0';
1096 			goto fp_begin;
1097 		case 'g':
1098 		case 'G':
1099 			expchar = ch - ('g' - 'e');
1100 			if (prec == 0)
1101 				prec = 1;
1102 fp_begin:
1103 			if (prec < 0)
1104 				prec = DEFPREC;
1105 			if (flags & LONGDBL) {
1106 				fparg.ldbl = GETARG(long double);
1107 				dtoaresult =
1108 				    __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
1109 				    &expt, &signflag, &dtoaend);
1110 			} else {
1111 				fparg.dbl = GETARG(double);
1112 				dtoaresult =
1113 				    __dtoa(fparg.dbl, expchar ? 2 : 3, prec,
1114 				    &expt, &signflag, &dtoaend);
1115 				if (expt == 9999)
1116 					expt = INT_MAX;
1117 			}
1118 			if (dtoaresult == NULL)
1119 				goto oomem;
1120 			_DIAGASSERT(__type_fit(int, dtoaend - dtoaresult));
1121 			ndig = (int)(dtoaend - dtoaresult);
1122 			if (convbuf != NULL)
1123 				free(convbuf);
1124 #ifndef NARROW
1125 			result = convbuf = __mbsconv(dtoaresult, -1);
1126 #else
1127 			/*XXX inefficient*/
1128 			result = convbuf = strdup(dtoaresult);
1129 #endif
1130 			if (result == NULL)
1131 				goto oomem;
1132 			__freedtoa(dtoaresult);
1133 fp_common:
1134 			if (signflag)
1135 				sign = '-';
1136 			if (expt == INT_MAX) {	/* inf or nan */
1137 				if (*result == 'N') {
1138 					result = (ch >= 'a') ? STRCONST("nan") :
1139 					    STRCONST("NAN");
1140 					sign = '\0';
1141 				} else
1142 					result = (ch >= 'a') ? STRCONST("inf") :
1143 					    STRCONST("INF");
1144 				size = 3;
1145 				flags &= ~ZEROPAD;
1146 				break;
1147 			}
1148 #else
1149 		case 'e':
1150 		case 'E':
1151 		case 'f':
1152 		case 'F':
1153 		case 'g':
1154 		case 'G':
1155 			if (prec == -1) {
1156 				prec = DEFPREC;
1157 			} else if ((ch == 'g' || ch == 'G') && prec == 0) {
1158 				prec = 1;
1159 			}
1160 
1161 			if (flags & LONGDBL) {
1162 				_double = (double) GETARG(long double);
1163 			} else {
1164 				_double = GETARG(double);
1165 			}
1166 
1167 			/* do this before tricky precision changes */
1168 			if (isinf(_double)) {
1169 				if (_double < 0)
1170 					sign = '-';
1171 				if (ch == 'E' || ch == 'F' || ch == 'G')
1172 					result = STRCONST("INF");
1173 				else
1174 					result = STRCONST("inf");
1175 				size = 3;
1176 				flags &= ~ZEROPAD;
1177 				break;
1178 			}
1179 			if (isnan(_double)) {
1180 				if (ch == 'E' || ch == 'F' || ch == 'G')
1181 					result = STRCONST("NAN");
1182 				else
1183 					result = STRCONST("nan");
1184 				size = 3;
1185 				flags &= ~ZEROPAD;
1186 				break;
1187 			}
1188 
1189 			flags |= FPT;
1190 			dtoaresult = cvt(_double, prec, flags, &softsign,
1191 			    &expt, ch, &ndig);
1192 			if (dtoaresult == NULL)
1193 				goto oomem;
1194 			if (convbuf != NULL)
1195 				free(convbuf);
1196 #ifndef NARROW
1197 			result = convbuf = __mbsconv(dtoaresult, -1);
1198 #else
1199 			/*XXX inefficient*/
1200 			result = convbuf = strdup(dtoaresult);
1201 #endif
1202 			if (result == NULL)
1203 				goto oomem;
1204 			__freedtoa(dtoaresult);
1205 			if (softsign)
1206 				sign = '-';
1207 #endif
1208 			flags |= FPT;
1209 			if (ch == 'g' || ch == 'G') {
1210 				if (expt > -4 && expt <= prec) {
1211 					/* Make %[gG] smell like %[fF] */
1212 					expchar = '\0';
1213 					if (flags & ALT)
1214 						prec -= expt;
1215 					else
1216 						prec = ndig - expt;
1217 					if (prec < 0)
1218 						prec = 0;
1219 				} else {
1220 					/*
1221 					 * Make %[gG] smell like %[eE], but
1222 					 * trim trailing zeroes if no # flag.
1223 					 */
1224 					if (!(flags & ALT))
1225 						prec = ndig;
1226 				}
1227 			}
1228 			if (expchar) {
1229 				expsize = exponent(expstr, expt - 1, expchar);
1230 				size = expsize + prec;
1231 				if (prec > 1 || flags & ALT)
1232 					++size;
1233 			} else {
1234 				/* space for digits before decimal point */
1235 				if (expt > 0)
1236 					size = expt;
1237 				else	/* "0" */
1238 					size = 1;
1239 				/* space for decimal pt and following digits */
1240 				if (prec || flags & ALT)
1241 					size += prec + 1;
1242 				if (grouping && expt > 0) {
1243 					/* space for thousands' grouping */
1244 					nseps = nrepeats = 0;
1245 					lead = expt;
1246 					while ((unsigned char)*grouping
1247 					    != (unsigned char)CHAR_MAX) {
1248 						if (lead <= *grouping)
1249 							break;
1250 						lead -= *grouping;
1251 						if (*(grouping+1)) {
1252 							nseps++;
1253 							grouping++;
1254 						} else
1255 							nrepeats++;
1256 					}
1257 					size += nseps + nrepeats;
1258 				} else
1259 					lead = expt;
1260 			}
1261 			break;
1262 #endif /* !NO_FLOATING_POINT */
1263 		case 'n':
1264 			/*
1265 			 * Assignment-like behavior is specified if the
1266 			 * value overflows or is otherwise unrepresentable.
1267 			 * C99 says to use `signed char' for %hhn conversions.
1268 			 */
1269 			if (flags & LLONGINT)
1270 				*GETARG(long long *) = ret;
1271 			else if (flags & SIZET)
1272 				*GETARG(ssize_t *) = (ssize_t)ret;
1273 			else if (flags & PTRDIFFT)
1274 				*GETARG(ptrdiff_t *) = ret;
1275 			else if (flags & INTMAXT)
1276 				*GETARG(intmax_t *) = ret;
1277 			else if (flags & LONGINT)
1278 				*GETARG(long *) = ret;
1279 			else if (flags & SHORTINT)
1280 				*GETARG(short *) = ret;
1281 			else if (flags & CHARINT)
1282 				*GETARG(signed char *) = ret;
1283 			else
1284 				*GETARG(int *) = ret;
1285 			continue;	/* no output */
1286 		case 'O':
1287 			flags |= LONGINT;
1288 			/*FALLTHROUGH*/
1289 		case 'o':
1290 			if (flags & INTMAX_SIZE)
1291 				ujval = UJARG();
1292 			else
1293 				ulval = UARG();
1294 			base = 8;
1295 			goto nosign;
1296 		case 'p':
1297 			/*-
1298 			 * ``The argument shall be a pointer to void.  The
1299 			 * value of the pointer is converted to a sequence
1300 			 * of printable characters, in an implementation-
1301 			 * defined manner.''
1302 			 *	-- ANSI X3J11
1303 			 */
1304 			ujval = (uintmax_t)(uintptr_t)GETARG(void *);
1305 			base = 16;
1306 			xdigs = xdigs_lower;
1307 			flags = flags | INTMAXT;
1308 			ox[1] = 'x';
1309 			goto nosign;
1310 		case 'S':
1311 			flags |= LONGINT;
1312 			/*FALLTHROUGH*/
1313 		case 's':
1314 			if ((flags & LONGINT) != MULTI) {
1315 				if ((result = GETARG(CHAR_T *)) == NULL)
1316 					result = STRCONST("(null)");
1317 			} else {
1318 				MCHAR_T *mc;
1319 
1320 				if (convbuf != NULL)
1321 					free(convbuf);
1322 				if ((mc = GETARG(MCHAR_T *)) == NULL)
1323 					result = STRCONST("(null)");
1324 				else {
1325 					convbuf = SCONV(mc, prec);
1326 					if (convbuf == NULL) {
1327 						fp->_flags |= __SERR;
1328 						goto error;
1329 					}
1330 					result = convbuf;
1331 				}
1332 			}
1333 
1334 			if (prec >= 0) {
1335 				/*
1336 				 * can't use STRLEN; can only look for the
1337 				 * NUL in the first `prec' characters, and
1338 				 * STRLEN() will go further.
1339 				 */
1340 				CHAR_T *p = MEMCHR(result, 0, (size_t)prec);
1341 
1342 				if (p != NULL) {
1343 					_DIAGASSERT(__type_fit(int,
1344 					    p - result));
1345 					size = (int)(p - result);
1346 					if (size > prec)
1347 						size = prec;
1348 				} else
1349 					size = prec;
1350 			} else {
1351 				size_t rlen = STRLEN(result);
1352 				_DIAGASSERT(__type_fit(int, rlen));
1353 				size = (int)rlen;
1354 			}
1355 			sign = '\0';
1356 			break;
1357 		case 'U':
1358 			flags |= LONGINT;
1359 			/*FALLTHROUGH*/
1360 		case 'u':
1361 			if (flags & INTMAX_SIZE)
1362 				ujval = UJARG();
1363 			else
1364 				ulval = UARG();
1365 			base = 10;
1366 			goto nosign;
1367 		case 'X':
1368 			xdigs = xdigs_upper;
1369 			goto hex;
1370 		case 'x':
1371 			xdigs = xdigs_lower;
1372 hex:
1373 			if (flags & INTMAX_SIZE)
1374 				ujval = UJARG();
1375 			else
1376 				ulval = UARG();
1377 			base = 16;
1378 			/* leading 0x/X only if non-zero */
1379 			if (flags & ALT &&
1380 			    (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
1381 				ox[1] = ch;
1382 
1383 			flags &= ~GROUPING;
1384 			/* unsigned conversions */
1385 nosign:			sign = '\0';
1386 			/*-
1387 			 * ``... diouXx conversions ... if a precision is
1388 			 * specified, the 0 flag will be ignored.''
1389 			 *	-- ANSI X3J11
1390 			 */
1391 number:			if ((dprec = prec) >= 0)
1392 				flags &= ~ZEROPAD;
1393 
1394 			/*-
1395 			 * ``The result of converting a zero value with an
1396 			 * explicit precision of zero is no characters.''
1397 			 *	-- ANSI X3J11
1398 			 *
1399 			 * ``The C Standard is clear enough as is.  The call
1400 			 * printf("%#.0o", 0) should print 0.''
1401 			 *	-- Defect Report #151
1402 			 */
1403 			result = cp = buf + BUF;
1404 			if (flags & INTMAX_SIZE) {
1405 				if (ujval != 0 || prec != 0 ||
1406 				    (flags & ALT && base == 8))
1407 					result = __ujtoa(ujval, cp, base,
1408 					    flags & ALT, xdigs,
1409 					    flags & GROUPING, thousands_sep,
1410 					    grouping);
1411 			} else {
1412 				if (ulval != 0 || prec != 0 ||
1413 				    (flags & ALT && base == 8))
1414 					result = __ultoa(ulval, cp, base,
1415 					    flags & ALT, xdigs,
1416 					    flags & GROUPING, thousands_sep,
1417 					    grouping);
1418 			}
1419 			_DIAGASSERT(__type_fit(int, buf + BUF - result));
1420 			size = (int)(buf + BUF - result);
1421 			if (size > BUF)	/* should never happen */
1422 				abort();
1423 			break;
1424 		default:	/* "%?" prints ?, unless ? is NUL */
1425 			if (ch == '\0')
1426 				goto done;
1427 			/* pretend it was %c with argument ch */
1428 			*buf = ch;
1429 			result = buf;
1430 			size = 1;
1431 			sign = '\0';
1432 			break;
1433 		}
1434 
1435 		/*
1436 		 * All reasonable formats wind up here.  At this point, `result'
1437 		 * points to a string which (if not flags&LADJUST) should be
1438 		 * padded out to `width' places.  If flags&ZEROPAD, it should
1439 		 * first be prefixed by any sign or other prefix; otherwise,
1440 		 * it should be blank padded before the prefix is emitted.
1441 		 * After any left-hand padding and prefixing, emit zeroes
1442 		 * required by a decimal [diouxX] precision, then print the
1443 		 * string proper, then emit zeroes required by any leftover
1444 		 * floating precision; finally, if LADJUST, pad with blanks.
1445 		 *
1446 		 * Compute actual size, so we know how much to pad.
1447 		 * size excludes decimal prec; realsz includes it.
1448 		 */
1449 		realsz = dprec > size ? dprec : size;
1450 		if (sign)
1451 			realsz++;
1452 		if (ox[1])
1453 			realsz += 2;
1454 
1455 		prsize = width > realsz ? width : realsz;
1456 		if ((unsigned)ret + prsize > INT_MAX) {
1457 			ret = END_OF_FILE;
1458 			goto error;
1459 		}
1460 
1461 		/* right-adjusting blank padding */
1462 		if ((flags & (LADJUST|ZEROPAD)) == 0)
1463 			PAD(width - realsz, blanks);
1464 
1465 		/* prefix */
1466 		if (sign)
1467 			PRINT(&sign, 1);
1468 
1469 		if (ox[1]) {	/* ox[1] is either x, X, or \0 */
1470 			ox[0] = '0';
1471 			PRINT(ox, 2);
1472 		}
1473 
1474 		/* right-adjusting zero padding */
1475 		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
1476 			PAD(width - realsz, zeroes);
1477 
1478 		/* leading zeroes from decimal precision */
1479 		PAD(dprec - size, zeroes);
1480 
1481 		/* the string or number proper */
1482 #ifndef NO_FLOATING_POINT
1483 		if ((flags & FPT) == 0) {
1484 			PRINT(result, size);
1485 		} else {	/* glue together f_p fragments */
1486 			if (!expchar) {	/* %[fF] or sufficiently short %[gG] */
1487 				if (expt <= 0) {
1488 					PRINT(zeroes, 1);
1489 					if (prec || flags & ALT)
1490 						PRINT(decimal_point, 1);
1491 					PAD(-expt, zeroes);
1492 					/* already handled initial 0's */
1493 					prec += expt;
1494 				} else {
1495 					PRINTANDPAD(result, convbuf + ndig,
1496 					    lead, zeroes);
1497 					result += lead;
1498 					if (grouping) {
1499 						while (nseps>0 || nrepeats>0) {
1500 							if (nrepeats > 0)
1501 								nrepeats--;
1502 							else {
1503 								grouping--;
1504 								nseps--;
1505 							}
1506 							PRINT(&thousands_sep,
1507 							    1);
1508 							PRINTANDPAD(result,
1509 							    convbuf + ndig,
1510 							    *grouping, zeroes);
1511 							result += *grouping;
1512 						}
1513 						if (result > convbuf + ndig)
1514 							result = convbuf + ndig;
1515 					}
1516 					if (prec || flags & ALT) {
1517 						buf[0] = *decimal_point;
1518 						PRINT(buf, 1);
1519 					}
1520 				}
1521 				PRINTANDPAD(result, convbuf + ndig, prec,
1522 				    zeroes);
1523 			} else {	/* %[eE] or sufficiently long %[gG] */
1524 				if (prec > 1 || flags & ALT) {
1525 					buf[0] = *result++;
1526 					buf[1] = *decimal_point;
1527 					PRINT(buf, 2);
1528 					PRINT(result, ndig-1);
1529 					PAD(prec - ndig, zeroes);
1530 				} else	/* XeYYY */
1531 					PRINT(result, 1);
1532 				PRINT(expstr, expsize);
1533 			}
1534 		}
1535 #else
1536 		PRINT(result, size);
1537 #endif
1538 		/* left-adjusting padding (always blank) */
1539 		if (flags & LADJUST)
1540 			PAD(width - realsz, blanks);
1541 
1542 		/* finally, adjust ret */
1543 		ret += prsize;
1544 		FLUSH();
1545 	}
1546 done:
1547 	FLUSH();
1548 error:
1549 	va_end(orgap);
1550 	if (convbuf != NULL)
1551 		free(convbuf);
1552 	if (__sferror(fp))
1553 		ret = END_OF_FILE;
1554 	if ((argtable != NULL) && (argtable != statargtable))
1555 		free (argtable);
1556 	return ret;
1557 	/* NOTREACHED */
1558 oomem:
1559 	errno = ENOMEM;
1560 	ret = END_OF_FILE;
1561 	goto error;
1562 }
1563 
1564 /*
1565  * Find all arguments when a positional parameter is encountered.  Returns a
1566  * table, indexed by argument number, of pointers to each arguments.  The
1567  * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
1568  * It will be replaces with a malloc-ed one if it overflows.
1569  */
1570 static int
1571 __find_arguments(const CHAR_T *fmt0, va_list ap, union arg **argtable)
1572 {
1573 	CHAR_T *fmt;		/* format string */
1574 	int ch;			/* character from fmt */
1575 	size_t n, n2;		/* handy index (short term usage) */
1576 	CHAR_T *cp;		/* handy char pointer (short term usage) */
1577 	int flags;		/* flags as above */
1578 	enum typeid *typetable; /* table of types */
1579 	enum typeid stattypetable [STATIC_ARG_TBL_SIZE];
1580 	size_t tablesize;	/* current size of type table */
1581 	size_t tablemax;	/* largest used index in table */
1582 	size_t nextarg;		/* 1-based argument index */
1583 	size_t nitems;		/* number of items we picked from the stack */
1584 
1585 	/*
1586 	 * Add an argument type to the table, expanding if necessary.
1587 	 * Check for overflow.
1588 	 */
1589 #define ADDTYPE(type) \
1590 	do { \
1591 		if (nextarg > SIZE_MAX / sizeof(**argtable)) { \
1592 			if (typetable != stattypetable) \
1593 				free(typetable); \
1594 			return -1; \
1595 		} \
1596 		if (nextarg >= tablesize) \
1597 			if (__grow_type_table(nextarg, &typetable, \
1598 			    &tablesize) == -1) \
1599 				return -1; \
1600 		if (nextarg > tablemax) \
1601 			tablemax = nextarg; \
1602 		typetable[nextarg++] = type; \
1603 		nitems++; \
1604 	} while (/*CONSTCOND*/0)
1605 
1606 #define	ADDSARG() \
1607 	do { \
1608 		if (flags & INTMAXT)  \
1609 			ADDTYPE(T_INTMAXT); \
1610 		else if (flags & SIZET)  \
1611 			ADDTYPE(T_SSIZET); \
1612 		else if (flags & PTRDIFFT) \
1613 			ADDTYPE(T_PTRDIFFT); \
1614 		else if (flags & LLONGINT) \
1615 			ADDTYPE(T_LLONG); \
1616 		else if (flags & LONGINT) \
1617 			ADDTYPE(T_LONG); \
1618 		else \
1619 			ADDTYPE(T_INT); \
1620 	} while (/*CONSTCOND*/0)
1621 
1622 #define	ADDUARG() \
1623 	do { \
1624 		if (flags & INTMAXT)  \
1625 			ADDTYPE(T_UINTMAXT); \
1626 		else if (flags & SIZET)  \
1627 			ADDTYPE(T_SIZET); \
1628 		else if (flags & PTRDIFFT) \
1629 			ADDTYPE(T_PTRDIFFT); \
1630 		else if (flags & LLONGINT) \
1631 			ADDTYPE(T_U_LLONG); \
1632 		else if (flags & LONGINT) \
1633 			ADDTYPE(T_U_LONG); \
1634 		else \
1635 			ADDTYPE(T_U_INT); \
1636 	} while (/*CONSTCOND*/0)
1637 	/*
1638 	 * Add * arguments to the type array.
1639 	 */
1640 #define ADDASTER() \
1641 	n2 = 0; \
1642 	cp = fmt; \
1643 	while (is_digit(*cp)) { \
1644 		n2 = 10 * n2 + to_digit(*cp); \
1645 		cp++; \
1646 	} \
1647 	if (*cp == '$') { \
1648 		size_t hold = nextarg; \
1649 		nextarg = n2; \
1650 		ADDTYPE(T_INT); \
1651 		nextarg = hold; \
1652 		fmt = ++cp; \
1653 	} else { \
1654 		ADDTYPE(T_INT); \
1655 	}
1656 	fmt = (CHAR_T *)__UNCONST(fmt0);
1657 	memset(stattypetable, 0, sizeof(stattypetable));
1658 	typetable = stattypetable;
1659 	tablesize = STATIC_ARG_TBL_SIZE;
1660 	tablemax = 0;
1661 	nextarg = 1;
1662 	nitems = 1;
1663 
1664 	/*
1665 	 * Scan the format for conversions (`%' character).
1666 	 */
1667 	for (;;) {
1668 		for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
1669 			/* void */;
1670 		if (ch == '\0')
1671 			goto done;
1672 		fmt++;		/* skip over '%' */
1673 
1674 		flags = 0;
1675 
1676 rflag:		ch = *fmt++;
1677 reswitch:	switch (ch) {
1678 		case ' ':
1679 		case '#':
1680 			goto rflag;
1681 		case '*':
1682 			ADDASTER ();
1683 			goto rflag;
1684 		case '-':
1685 		case '+':
1686 		case '\'':
1687 			goto rflag;
1688 		case '.':
1689 			if ((ch = *fmt++) == '*') {
1690 				ADDASTER ();
1691 				goto rflag;
1692 			}
1693 			while (is_digit(ch)) {
1694 				ch = *fmt++;
1695 			}
1696 			goto reswitch;
1697 		case '0':
1698 			goto rflag;
1699 		case '1': case '2': case '3': case '4':
1700 		case '5': case '6': case '7': case '8': case '9':
1701 			n = 0;
1702 			do {
1703 				n = 10 * n + to_digit(ch);
1704 				ch = *fmt++;
1705 			} while (is_digit(ch));
1706 			if (ch == '$') {
1707 				nextarg = n;
1708 				goto rflag;
1709 			}
1710 			goto reswitch;
1711 #ifndef NO_FLOATING_POINT
1712 		case 'L':
1713 			flags |= LONGDBL;
1714 			goto rflag;
1715 #endif
1716 		case 'h':
1717 			if (flags & SHORTINT) {
1718 				flags &= ~SHORTINT;
1719 				flags |= CHARINT;
1720 			} else
1721 				flags |= SHORTINT;
1722 			goto rflag;
1723 		case 'j':
1724 			flags |= INTMAXT;
1725 			goto rflag;
1726 		case 'l':
1727 			if (flags & LONGINT) {
1728 				flags &= ~LONGINT;
1729 				flags |= LLONGINT;
1730 			} else
1731 				flags |= LONGINT;
1732 			goto rflag;
1733 		case 'q':
1734 			flags |= LLONGINT;	/* not necessarily */
1735 			goto rflag;
1736 		case 't':
1737 			flags |= PTRDIFFT;
1738 			goto rflag;
1739 		case 'z':
1740 			flags |= SIZET;
1741 			goto rflag;
1742 		case 'C':
1743 			flags |= LONGINT;
1744 			/*FALLTHROUGH*/
1745 		case 'c':
1746 			if (flags & LONGINT)
1747 				ADDTYPE(T_WINT);
1748 			else
1749 				ADDTYPE(T_INT);
1750 			break;
1751 		case 'D':
1752 			flags |= LONGINT;
1753 			/*FALLTHROUGH*/
1754 		case 'd':
1755 		case 'i':
1756 			ADDSARG();
1757 			break;
1758 #ifndef NO_FLOATING_POINT
1759 		case 'a':
1760 		case 'A':
1761 		case 'e':
1762 		case 'E':
1763 		case 'f':
1764 		case 'g':
1765 		case 'G':
1766 			if (flags & LONGDBL)
1767 				ADDTYPE(T_LONG_DOUBLE);
1768 			else
1769 				ADDTYPE(T_DOUBLE);
1770 			break;
1771 #endif /* !NO_FLOATING_POINT */
1772 		case 'n':
1773 			if (flags & INTMAXT)
1774 				ADDTYPE(TP_INTMAXT);
1775 			else if (flags & PTRDIFFT)
1776 				ADDTYPE(TP_PTRDIFFT);
1777 			else if (flags & SIZET)
1778 				ADDTYPE(TP_SIZET);
1779 			else if (flags & LLONGINT)
1780 				ADDTYPE(TP_LLONG);
1781 			else if (flags & LONGINT)
1782 				ADDTYPE(TP_LONG);
1783 			else if (flags & SHORTINT)
1784 				ADDTYPE(TP_SHORT);
1785 			else if (flags & CHARINT)
1786 				ADDTYPE(TP_SCHAR);
1787 			else
1788 				ADDTYPE(TP_INT);
1789 			continue;	/* no output */
1790 		case 'O':
1791 			flags |= LONGINT;
1792 			/*FALLTHROUGH*/
1793 		case 'o':
1794 			ADDUARG();
1795 			break;
1796 		case 'p':
1797 			ADDTYPE(TP_VOID);
1798 			break;
1799 		case 'S':
1800 			flags |= LONGINT;
1801 			/*FALLTHROUGH*/
1802 		case 's':
1803 			if (flags & LONGINT)
1804 				ADDTYPE(TP_WCHAR);
1805 			else
1806 				ADDTYPE(TP_CHAR);
1807 			break;
1808 		case 'U':
1809 			flags |= LONGINT;
1810 			/*FALLTHROUGH*/
1811 		case 'u':
1812 		case 'X':
1813 		case 'x':
1814 			ADDUARG();
1815 			break;
1816 		default:	/* "%?" prints ?, unless ? is NUL */
1817 			if (ch == '\0')
1818 				goto done;
1819 			break;
1820 		}
1821 	}
1822 done:
1823 	/*
1824 	 * nitems contains the number of arguments we picked from the stack.
1825 	 * If tablemax is larger, this means that some positional argument,
1826 	 * tried to pick an argument the number of arguments possibly supplied.
1827 	 * Since positional arguments are typically used to swap the order of
1828 	 * the printf arguments and not to pick random arguments from strange
1829 	 * positions in the stack, we assume that if the positional argument
1830 	 * is trying to pick beyond the end of arguments, then this is wrong.
1831 	 * Alternatively we could find a way to figure out when va_arg() runs
1832 	 * out, but how to do that?
1833 	 */
1834 	if (nitems < tablemax) {
1835 		if (typetable != stattypetable)
1836 			free(typetable);
1837 		return -1;
1838 	}
1839 	/*
1840 	 * Build the argument table.
1841 	 */
1842 	if (tablemax >= STATIC_ARG_TBL_SIZE) {
1843 		*argtable = malloc(sizeof(**argtable) * (tablemax + 1));
1844 		if (*argtable == NULL) {
1845 			free(typetable);
1846 			return -1;
1847 		}
1848 	}
1849 
1850 	(*argtable) [0].intarg = 0;
1851 	for (n = 1; n <= tablemax; n++) {
1852 		switch (typetable [n]) {
1853 		    case T_UNUSED: /* whoops! */
1854 			(*argtable) [n].intarg = va_arg (ap, int);
1855 			break;
1856 		    case TP_SCHAR:
1857 			(*argtable) [n].pschararg = va_arg (ap, signed char *);
1858 			break;
1859 		    case TP_SHORT:
1860 			(*argtable) [n].pshortarg = va_arg (ap, short *);
1861 			break;
1862 		    case T_INT:
1863 			(*argtable) [n].intarg = va_arg (ap, int);
1864 			break;
1865 		    case T_U_INT:
1866 			(*argtable) [n].uintarg = va_arg (ap, unsigned int);
1867 			break;
1868 		    case TP_INT:
1869 			(*argtable) [n].pintarg = va_arg (ap, int *);
1870 			break;
1871 		    case T_LONG:
1872 			(*argtable) [n].longarg = va_arg (ap, long);
1873 			break;
1874 		    case T_U_LONG:
1875 			(*argtable) [n].ulongarg = va_arg (ap, unsigned long);
1876 			break;
1877 		    case TP_LONG:
1878 			(*argtable) [n].plongarg = va_arg (ap, long *);
1879 			break;
1880 		    case T_LLONG:
1881 			(*argtable) [n].longlongarg = va_arg (ap, long long);
1882 			break;
1883 		    case T_U_LLONG:
1884 			(*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
1885 			break;
1886 		    case TP_LLONG:
1887 			(*argtable) [n].plonglongarg = va_arg (ap, long long *);
1888 			break;
1889 		    case T_PTRDIFFT:
1890 			(*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
1891 			break;
1892 		    case TP_PTRDIFFT:
1893 			(*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
1894 			break;
1895 		    case T_SSIZET:
1896 			(*argtable) [n].ssizearg = va_arg (ap, ssize_t);
1897 			break;
1898 		    case T_SIZET:
1899 			(*argtable) [n].sizearg = va_arg (ap, size_t);
1900 			break;
1901 		    case TP_SIZET:
1902 			(*argtable) [n].psizearg = va_arg (ap, size_t *);
1903 			break;
1904 		    case T_INTMAXT:
1905 			(*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
1906 			break;
1907 		    case T_UINTMAXT:
1908 			(*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
1909 			break;
1910 		    case TP_INTMAXT:
1911 			(*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
1912 			break;
1913 		    case T_DOUBLE:
1914 #ifndef NO_FLOATING_POINT
1915 			(*argtable) [n].doublearg = va_arg (ap, double);
1916 #endif
1917 			break;
1918 		    case T_LONG_DOUBLE:
1919 #ifndef NO_FLOATING_POINT
1920 			(*argtable) [n].longdoublearg = va_arg (ap, long double);
1921 #endif
1922 			break;
1923 		    case TP_CHAR:
1924 			(*argtable) [n].pchararg = va_arg (ap, char *);
1925 			break;
1926 		    case TP_VOID:
1927 			(*argtable) [n].pvoidarg = va_arg (ap, void *);
1928 			break;
1929 		    case T_WINT:
1930 			(*argtable) [n].wintarg = va_arg (ap, wint_t);
1931 			break;
1932 		    case TP_WCHAR:
1933 			(*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
1934 			break;
1935 		}
1936 	}
1937 
1938 	if (typetable != stattypetable)
1939 		free (typetable);
1940 	return 0;
1941 }
1942 
1943 /*
1944  * Increase the size of the type table.
1945  */
1946 static int
1947 __grow_type_table (size_t nextarg, enum typeid **typetable, size_t *tablesize)
1948 {
1949 	enum typeid *const oldtable = *typetable;
1950 	const size_t oldsize = *tablesize;
1951 	enum typeid *newtable;
1952 	size_t newsize = oldsize * 2;
1953 
1954 	if (newsize < nextarg + 1)
1955 		newsize = nextarg + 1;
1956 	if (oldsize == STATIC_ARG_TBL_SIZE) {
1957 		if ((newtable = malloc(newsize * sizeof(*newtable))) == NULL)
1958 			return -1;
1959 		memcpy(newtable, oldtable, oldsize * sizeof(*newtable));
1960 	} else {
1961 		newtable = realloc(oldtable, newsize * sizeof(*newtable));
1962 		if (newtable == NULL) {
1963 			free(oldtable);
1964 			return -1;
1965 		}
1966 	}
1967 	memset(&newtable[oldsize], 0, (newsize - oldsize) * sizeof(*newtable));
1968 
1969 	*typetable = newtable;
1970 	*tablesize = newsize;
1971 	return 0;
1972 }
1973 
1974 
1975 #ifndef NO_FLOATING_POINT
1976 #ifndef WIDE_DOUBLE
1977 static char *
1978 cvt(double value, int ndigits, int flags, char *sign, int *decpt, int ch,
1979     int *length)
1980 {
1981 	int mode, dsgn;
1982 	char *digits, *bp, *rve;
1983 
1984 	_DIAGASSERT(decpt != NULL);
1985 	_DIAGASSERT(length != NULL);
1986 	_DIAGASSERT(sign != NULL);
1987 
1988 	if (ch == 'f') {
1989 		mode = 3;		/* ndigits after the decimal point */
1990 	} else {
1991 		/* To obtain ndigits after the decimal point for the 'e'
1992 		 * and 'E' formats, round to ndigits + 1 significant
1993 		 * figures.
1994 		 */
1995 		if (ch == 'e' || ch == 'E') {
1996 			ndigits++;
1997 		}
1998 		mode = 2;		/* ndigits significant digits */
1999 	}
2000 
2001 	digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
2002 	if (digits == NULL)
2003 		return NULL;
2004 	if (dsgn) {
2005 		value = -value;
2006 		*sign = '-';
2007 	} else
2008 		*sign = '\000';
2009 	if ((ch != 'g' && ch != 'G') || flags & ALT) {	/* Print trailing zeros */
2010 		bp = digits + ndigits;
2011 		if (ch == 'f') {
2012 			if (*digits == '0' && value)
2013 				*decpt = -ndigits + 1;
2014 			bp += *decpt;
2015 		}
2016 		if (value == 0)	/* kludge for __dtoa irregularity */
2017 			rve = bp;
2018 		while (rve < bp)
2019 			*rve++ = '0';
2020 	}
2021 	*length = rve - digits;
2022 	return digits;
2023 }
2024 #endif
2025 
2026 static int
2027 exponent(CHAR_T *p0, int expo, int fmtch)
2028 {
2029 	CHAR_T *p, *t;
2030 	CHAR_T expbuf[MAXEXPDIG];
2031 
2032 	p = p0;
2033 	*p++ = fmtch;
2034 	if (expo < 0) {
2035 		expo = -expo;
2036 		*p++ = '-';
2037 	}
2038 	else
2039 		*p++ = '+';
2040 	t = expbuf + MAXEXPDIG;
2041 	if (expo > 9) {
2042 		do {
2043 			*--t = to_char(expo % 10);
2044 		} while ((expo /= 10) > 9);
2045 		*--t = to_char(expo);
2046 		for (; t < expbuf + MAXEXPDIG; *p++ = *t++);
2047 	}
2048 	else {
2049 		/*
2050 		 * Exponents for decimal floating point conversions
2051 		 * (%[eEgG]) must be at least two characters long,
2052 		 * whereas exponents for hexadecimal conversions can
2053 		 * be only one character long.
2054 		 */
2055 		if (fmtch == 'e' || fmtch == 'E')
2056 			*p++ = '0';
2057 		*p++ = to_char(expo);
2058 	}
2059 	_DIAGASSERT(__type_fit(int, p - p0));
2060 	return (int)(p - p0);
2061 }
2062 #endif /* !NO_FLOATING_POINT */
2063