vfprintf.c revision 14727
191174Stmm/*-
291174Stmm * Copyright (c) 1990, 1993
391174Stmm *	The Regents of the University of California.  All rights reserved.
491174Stmm *
591174Stmm * This code is derived from software contributed to Berkeley by
691174Stmm * Chris Torek.
791174Stmm *
891174Stmm * Redistribution and use in source and binary forms, with or without
991174Stmm * modification, are permitted provided that the following conditions
1091174Stmm * are met:
1191174Stmm * 1. Redistributions of source code must retain the above copyright
1291174Stmm *    notice, this list of conditions and the following disclaimer.
1391174Stmm * 2. Redistributions in binary form must reproduce the above copyright
1491174Stmm *    notice, this list of conditions and the following disclaimer in the
1591174Stmm *    documentation and/or other materials provided with the distribution.
1691174Stmm * 3. All advertising materials mentioning features or use of this software
1791174Stmm *    must display the following acknowledgement:
1891174Stmm *	This product includes software developed by the University of
1991174Stmm *	California, Berkeley and its contributors.
2091174Stmm * 4. Neither the name of the University nor the names of its contributors
2191174Stmm *    may be used to endorse or promote products derived from this software
2291174Stmm *    without specific prior written permission.
2391174Stmm *
2491174Stmm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2591174Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2691174Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2791174Stmm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2891174Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2991174Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3091174Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3191174Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3291174Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3391174Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3491174Stmm * SUCH DAMAGE.
3591174Stmm */
3691174Stmm
3791174Stmm#if defined(LIBC_SCCS) && !defined(lint)
3891174Stmmstatic char sccsid[] = "@(#)vfprintf.c	8.1 (Berkeley) 6/4/93";
3991174Stmm#endif /* LIBC_SCCS and not lint */
4091174Stmm
4191174Stmm/*
4291174Stmm * Actual printf innards.
4392986Sobrien *
4491174Stmm * This code is large and complicated...
4591174Stmm */
4692986Sobrien
4792986Sobrien#include <sys/types.h>
4892986Sobrien
4991174Stmm#include <limits.h>
5091174Stmm#include <stdio.h>
5191174Stmm#include <stdlib.h>
5291174Stmm#include <string.h>
5391174Stmm
5491174Stmm#if __STDC__
5591174Stmm#include <stdarg.h>
5691174Stmm#else
5791174Stmm#include <varargs.h>
5891174Stmm#endif
5991174Stmm
6091174Stmm#include "local.h"
6191174Stmm#include "fvwrite.h"
6291174Stmm#ifdef _THREAD_SAFE
6391174Stmm#include <pthread.h>
6491174Stmm#include "pthread_private.h"
6591174Stmm#endif
6691174Stmm
6791174Stmm/* Define FLOATING_POINT to get floating point. */
6891174Stmm#define	FLOATING_POINT
6991174Stmm
7091174Stmm/*
7191174Stmm * Flush out all the vectors defined by the given uio,
7291174Stmm * then reset it so that it can be reused.
7391174Stmm */
7491174Stmmstatic int
7591174Stmm__sprint(fp, uio)
7691174Stmm	FILE *fp;
7791174Stmm	register struct __suio *uio;
7891174Stmm{
7991174Stmm	register int err;
8091174Stmm
8191174Stmm	if (uio->uio_resid == 0) {
8291174Stmm		uio->uio_iovcnt = 0;
8391174Stmm		return (0);
8491174Stmm	}
8591174Stmm	err = __sfvwrite(fp, uio);
8691174Stmm	uio->uio_resid = 0;
8791174Stmm	uio->uio_iovcnt = 0;
8891174Stmm	return (err);
8991174Stmm}
9092889Sobrien
9192889Sobrien/*
9291174Stmm * Helper function for `fprintf to unbuffered unix file': creates a
9391174Stmm * temporary buffer.  We only work on write-only files; this avoids
9491174Stmm * worries about ungetc buffers and so forth.
9591174Stmm */
9691174Stmmstatic int
9791174Stmm__sbprintf(fp, fmt, ap)
9891174Stmm	register FILE *fp;
9991174Stmm	const char *fmt;
10091174Stmm	va_list ap;
10191174Stmm{
10291174Stmm	int ret;
10391174Stmm	FILE fake;
10491174Stmm	unsigned char buf[BUFSIZ];
10591174Stmm
10691174Stmm	/* copy the important variables */
10791174Stmm	fake._flags = fp->_flags & ~__SNBF;
10891174Stmm	fake._file = fp->_file;
10991174Stmm	fake._cookie = fp->_cookie;
11091174Stmm	fake._write = fp->_write;
11191174Stmm
11291174Stmm	/* set up the buffer */
11391174Stmm	fake._bf._base = fake._p = buf;
11491174Stmm	fake._bf._size = fake._w = sizeof(buf);
11591174Stmm	fake._lbfsize = 0;	/* not actually used, but Just In Case */
11692889Sobrien
11792889Sobrien	/* do the work, then copy any error status */
11891174Stmm	ret = vfprintf(&fake, fmt, ap);
11991174Stmm	if (ret >= 0 && fflush(&fake))
12091174Stmm		ret = EOF;
12191174Stmm	if (fake._flags & __SERR)
12291174Stmm		fp->_flags |= __SERR;
12391174Stmm	return (ret);
12491174Stmm}
12591174Stmm
12691174Stmm/*
12791174Stmm * Macros for converting digits to letters and vice versa
12891174Stmm */
12991174Stmm#define	to_digit(c)	((c) - '0')
13091174Stmm#define is_digit(c)	((unsigned)to_digit(c) <= 9)
13191174Stmm#define	to_char(n)	((n) + '0')
13291174Stmm
13391174Stmm/*
13491174Stmm * Convert an unsigned long to ASCII for printf purposes, returning
13591174Stmm * a pointer to the first character of the string representation.
13691174Stmm * Octal numbers can be forced to have a leading zero; hex numbers
13791174Stmm * use the given digits.
13891174Stmm */
13991174Stmmstatic char *
14091174Stmm__ultoa(val, endp, base, octzero, xdigs)
14191174Stmm	register u_long val;
14291174Stmm	char *endp;
14391174Stmm	int base, octzero;
14491174Stmm	char *xdigs;
14591174Stmm{
14691174Stmm	register char *cp = endp;
14791174Stmm	register long sval;
14891174Stmm
14991174Stmm	/*
15091174Stmm	 * Handle the three cases separately, in the hope of getting
15191174Stmm	 * better/faster code.
15291174Stmm	 */
15391174Stmm	switch (base) {
15491174Stmm	case 10:
15591174Stmm		if (val < 10) {	/* many numbers are 1 digit */
15691174Stmm			*--cp = to_char(val);
15791174Stmm			return (cp);
15891174Stmm		}
15991174Stmm		/*
16091174Stmm		 * On many machines, unsigned arithmetic is harder than
16191174Stmm		 * signed arithmetic, so we do at most one unsigned mod and
16291174Stmm		 * divide; this is sufficient to reduce the range of
16391174Stmm		 * the incoming value to where signed arithmetic works.
16491174Stmm		 */
16591174Stmm		if (val > LONG_MAX) {
16691174Stmm			*--cp = to_char(val % 10);
16791174Stmm			sval = val / 10;
16891174Stmm		} else
16991174Stmm			sval = val;
17091174Stmm		do {
17191174Stmm			*--cp = to_char(sval % 10);
17291174Stmm			sval /= 10;
17391174Stmm		} while (sval != 0);
17491174Stmm		break;
17591174Stmm
17691174Stmm	case 8:
17792889Sobrien		do {
17892889Sobrien			*--cp = to_char(val & 7);
17991174Stmm			val >>= 3;
18092889Sobrien		} while (val);
18192889Sobrien		if (octzero && *cp != '0')
18291174Stmm			*--cp = '0';
18391174Stmm		break;
18491174Stmm
18591174Stmm	case 16:
18691174Stmm		do {
18791174Stmm			*--cp = xdigs[val & 15];
18891174Stmm			val >>= 4;
18991174Stmm		} while (val);
19091174Stmm		break;
19191174Stmm
19291174Stmm	default:			/* oops */
19391174Stmm		abort();
19491174Stmm	}
19591174Stmm	return (cp);
19691174Stmm}
19792889Sobrien
19892889Sobrien/* Identical to __ultoa, but for quads. */
19991174Stmmstatic char *
20092889Sobrien__uqtoa(val, endp, base, octzero, xdigs)
20192889Sobrien	register u_quad_t val;
20291174Stmm	char *endp;
20391174Stmm	int base, octzero;
20491174Stmm	char *xdigs;
20591174Stmm{
20691174Stmm	register char *cp = endp;
20791174Stmm	register quad_t sval;
20891174Stmm
20991174Stmm	/* quick test for small values; __ultoa is typically much faster */
21091174Stmm	/* (perhaps instead we should run until small, then call __ultoa?) */
21191174Stmm	if (val <= ULONG_MAX)
21291174Stmm		return (__ultoa((u_long)val, endp, base, octzero, xdigs));
21391174Stmm	switch (base) {
21491174Stmm	case 10:
21591174Stmm		if (val < 10) {
21691174Stmm			*--cp = to_char(val % 10);
21791174Stmm			return (cp);
21892889Sobrien		}
21992889Sobrien		if (val > QUAD_MAX) {
22091174Stmm			*--cp = to_char(val % 10);
22192889Sobrien			sval = val / 10;
22292889Sobrien		} else
22391174Stmm			sval = val;
22491174Stmm		do {
22591174Stmm			*--cp = to_char(sval % 10);
22691174Stmm			sval /= 10;
22791174Stmm		} while (sval != 0);
22891174Stmm		break;
22991174Stmm
23091174Stmm	case 8:
23191174Stmm		do {
23291174Stmm			*--cp = to_char(val & 7);
23391174Stmm			val >>= 3;
23491174Stmm		} while (val);
23591174Stmm		if (octzero && *cp != '0')
23691174Stmm			*--cp = '0';
23791174Stmm		break;
23891174Stmm
23992889Sobrien	case 16:
24091174Stmm		do {
24191174Stmm			*--cp = xdigs[val & 15];
24291174Stmm			val >>= 4;
24391174Stmm		} while (val);
24491174Stmm		break;
24591174Stmm
24691174Stmm	default:
24791174Stmm		abort();
24891174Stmm	}
24991174Stmm	return (cp);
25091174Stmm}
25191174Stmm
25291174Stmm#ifdef FLOATING_POINT
25391174Stmm#include <math.h>
25491174Stmm#include "floatio.h"
25591174Stmm
25691174Stmm#define	BUF		(MAXEXP+MAXFRACT+1)	/* + decimal point */
25791174Stmm#define	DEFPREC		6
25891174Stmm
25991174Stmmstatic char *cvt __P((double, int, int, char *, int *, int, int *));
26091174Stmmstatic int exponent __P((char *, int, int));
26191174Stmm
26291174Stmm#else /* no FLOATING_POINT */
26391174Stmm
26491174Stmm#define	BUF		68
26591174Stmm
26691174Stmm#endif /* FLOATING_POINT */
26791174Stmm
26891174Stmm
26991174Stmm/*
27091174Stmm * Flags used during conversion.
27191174Stmm */
27291174Stmm#define	ALT		0x001		/* alternate form */
27391174Stmm#define	HEXPREFIX	0x002		/* add 0x or 0X prefix */
27491174Stmm#define	LADJUST		0x004		/* left adjustment */
27591174Stmm#define	LONGDBL		0x008		/* long double; unimplemented */
27691174Stmm#define	LONGINT		0x010		/* long integer */
27791174Stmm#define	QUADINT		0x020		/* quad integer */
27891174Stmm#define	SHORTINT	0x040		/* short integer */
27991174Stmm#define	ZEROPAD		0x080		/* zero (as opposed to blank) pad */
28091174Stmm#define FPT		0x100		/* Floating point number */
28191174Stmmint
28291174Stmmvfprintf(fp, fmt0, ap)
28391174Stmm	FILE *fp;
28491174Stmm	const char *fmt0;
28591174Stmm	va_list ap;
28691174Stmm{
28791174Stmm	register char *fmt;	/* format string */
28891174Stmm	register int ch;	/* character from fmt */
28991174Stmm	register int n;		/* handy integer (short term usage) */
29091174Stmm	register char *cp;	/* handy char pointer (short term usage) */
29191174Stmm	register struct __siov *iovp;/* for PRINT macro */
29291174Stmm	register int flags;	/* flags as above */
29391174Stmm	int ret;		/* return value accumulator */
29491174Stmm	int width;		/* width from format (%8d), or 0 */
29591174Stmm	int prec;		/* precision from format (%.3d), or -1 */
29691174Stmm	char sign;		/* sign prefix (' ', '+', '-', or \0) */
29791174Stmm#ifdef FLOATING_POINT
29891174Stmm	char softsign;		/* temporary negative sign for floats */
29991174Stmm	double _double;		/* double precision arguments %[eEfgG] */
30091174Stmm	int expt;		/* integer value of exponent */
30191174Stmm	int expsize;		/* character count for expstr */
30291174Stmm	int ndig;		/* actual number of digits returned by cvt */
30391174Stmm	char expstr[7];		/* buffer for exponent string */
30491174Stmm#endif
30591174Stmm	u_long	ulval;		/* integer arguments %[diouxX] */
306	u_quad_t uqval;		/* %q integers */
307	int base;		/* base for [diouxX] conversion */
308	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
309	int realsz;		/* field size expanded by dprec, sign, etc */
310	int size;		/* size of converted field or string */
311	char *xdigs;		/* digits for [xX] conversion */
312#define NIOV 8
313	struct __suio uio;	/* output information: summary */
314	struct __siov iov[NIOV];/* ... and individual io vectors */
315	char buf[BUF];		/* space for %c, %[diouxX], %[eEfgG] */
316	char ox[2];		/* space for 0x hex-prefix */
317
318	/*
319	 * Choose PADSIZE to trade efficiency vs. size.  If larger printf
320	 * fields occur frequently, increase PADSIZE and make the initialisers
321	 * below longer.
322	 */
323#define	PADSIZE	16		/* pad chunk size */
324	static char blanks[PADSIZE] =
325	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
326	static char zeroes[PADSIZE] =
327	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
328
329	/*
330	 * BEWARE, these `goto error' on error, and PAD uses `n'.
331	 */
332#define	PRINT(ptr, len) { \
333	iovp->iov_base = (ptr); \
334	iovp->iov_len = (len); \
335	uio.uio_resid += (len); \
336	iovp++; \
337	if (++uio.uio_iovcnt >= NIOV) { \
338		if (__sprint(fp, &uio)) \
339			goto error; \
340		iovp = iov; \
341	} \
342}
343#define	PAD(howmany, with) { \
344	if ((n = (howmany)) > 0) { \
345		while (n > PADSIZE) { \
346			PRINT(with, PADSIZE); \
347			n -= PADSIZE; \
348		} \
349		PRINT(with, n); \
350	} \
351}
352#define	FLUSH() { \
353	if (uio.uio_resid && __sprint(fp, &uio)) \
354		goto error; \
355	uio.uio_iovcnt = 0; \
356	iovp = iov; \
357}
358
359	/*
360	 * To extend shorts properly, we need both signed and unsigned
361	 * argument extraction methods.
362	 */
363#define	SARG() \
364	(flags&LONGINT ? va_arg(ap, long) : \
365	    flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
366	    (long)va_arg(ap, int))
367#define	UARG() \
368	(flags&LONGINT ? va_arg(ap, u_long) : \
369	    flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
370	    (u_long)va_arg(ap, u_int))
371
372#ifdef _THREAD_SAFE
373	_thread_flockfile(fp,__FILE__,__LINE__);
374#endif
375	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
376	if (cantwrite(fp)) {
377#ifdef _THREAD_SAFE
378		_thread_funlockfile(fp);
379#endif
380		return (EOF);
381	}
382
383	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
384	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
385	    fp->_file >= 0) {
386#ifdef _THREAD_SAFE
387		_thread_funlockfile(fp);
388#endif
389		return (__sbprintf(fp, fmt0, ap));
390	}
391
392	fmt = (char *)fmt0;
393	uio.uio_iov = iovp = iov;
394	uio.uio_resid = 0;
395	uio.uio_iovcnt = 0;
396	ret = 0;
397
398	/*
399	 * Scan the format for conversions (`%' character).
400	 */
401	for (;;) {
402		for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
403			/* void */;
404		if ((n = fmt - cp) != 0) {
405			PRINT(cp, n);
406			ret += n;
407		}
408		if (ch == '\0')
409			goto done;
410		fmt++;		/* skip over '%' */
411
412		flags = 0;
413		dprec = 0;
414		width = 0;
415		prec = -1;
416		sign = '\0';
417
418rflag:		ch = *fmt++;
419reswitch:	switch (ch) {
420		case ' ':
421			/*
422			 * ``If the space and + flags both appear, the space
423			 * flag will be ignored.''
424			 *	-- ANSI X3J11
425			 */
426			if (!sign)
427				sign = ' ';
428			goto rflag;
429		case '#':
430			flags |= ALT;
431			goto rflag;
432		case '*':
433			/*
434			 * ``A negative field width argument is taken as a
435			 * - flag followed by a positive field width.''
436			 *	-- ANSI X3J11
437			 * They don't exclude field widths read from args.
438			 */
439			if ((width = va_arg(ap, int)) >= 0)
440				goto rflag;
441			width = -width;
442			/* FALLTHROUGH */
443		case '-':
444			flags |= LADJUST;
445			goto rflag;
446		case '+':
447			sign = '+';
448			goto rflag;
449		case '.':
450			if ((ch = *fmt++) == '*') {
451				n = va_arg(ap, int);
452				prec = n < 0 ? -1 : n;
453				goto rflag;
454			}
455			n = 0;
456			while (is_digit(ch)) {
457				n = 10 * n + to_digit(ch);
458				ch = *fmt++;
459			}
460			prec = n < 0 ? -1 : n;
461			goto reswitch;
462		case '0':
463			/*
464			 * ``Note that 0 is taken as a flag, not as the
465			 * beginning of a field width.''
466			 *	-- ANSI X3J11
467			 */
468			flags |= ZEROPAD;
469			goto rflag;
470		case '1': case '2': case '3': case '4':
471		case '5': case '6': case '7': case '8': case '9':
472			n = 0;
473			do {
474				n = 10 * n + to_digit(ch);
475				ch = *fmt++;
476			} while (is_digit(ch));
477			width = n;
478			goto reswitch;
479#ifdef FLOATING_POINT
480		case 'L':
481			flags |= LONGDBL;
482			goto rflag;
483#endif
484		case 'h':
485			flags |= SHORTINT;
486			goto rflag;
487		case 'l':
488			flags |= LONGINT;
489			goto rflag;
490		case 'q':
491			flags |= QUADINT;
492			goto rflag;
493		case 'c':
494			*(cp = buf) = va_arg(ap, int);
495			size = 1;
496			sign = '\0';
497			break;
498		case 'D':
499			flags |= LONGINT;
500			/*FALLTHROUGH*/
501		case 'd':
502		case 'i':
503			if (flags & QUADINT) {
504				uqval = va_arg(ap, quad_t);
505				if ((quad_t)uqval < 0) {
506					uqval = -uqval;
507					sign = '-';
508				}
509			} else {
510				ulval = SARG();
511				if ((long)ulval < 0) {
512					ulval = -ulval;
513					sign = '-';
514				}
515			}
516			base = 10;
517			goto number;
518#ifdef FLOATING_POINT
519		case 'e':
520		case 'E':
521		case 'f':
522			goto fp_begin;
523		case 'g':
524		case 'G':
525			if (prec == 0)
526				prec = 1;
527fp_begin:		if (prec == -1)
528				prec = DEFPREC;
529			if (flags & LONGDBL)
530				_double = (double)va_arg(ap, long double);
531			else
532				_double = va_arg(ap, double);
533			/* do this before tricky precision changes */
534			if (isinf(_double)) {
535				if (_double < 0)
536					sign = '-';
537				cp = "Inf";
538				size = 3;
539				break;
540			}
541			if (isnan(_double)) {
542				cp = "NaN";
543				size = 3;
544				break;
545			}
546			flags |= FPT;
547			cp = cvt(_double, prec, flags, &softsign,
548				&expt, ch, &ndig);
549			if (ch == 'g' || ch == 'G') {
550				if (expt <= -4 || expt > prec)
551					ch = (ch == 'g') ? 'e' : 'E';
552				else
553					ch = 'g';
554			}
555			if (ch <= 'e') {	/* 'e' or 'E' fmt */
556				--expt;
557				expsize = exponent(expstr, expt, ch);
558				size = expsize + ndig;
559				if (ndig > 1 || flags & ALT)
560					++size;
561			} else if (ch == 'f') {		/* f fmt */
562				if (expt > 0) {
563					size = expt;
564					if (prec || flags & ALT)
565						size += prec + 1;
566				} else	/* "0.X" */
567					size = prec + 2;
568			} else if (expt >= ndig) {	/* fixed g fmt */
569				size = expt;
570				if (flags & ALT)
571					++size;
572			} else
573				size = ndig + (expt > 0 ?
574					1 : 2 - expt);
575
576			if (softsign)
577				sign = '-';
578			break;
579#endif /* FLOATING_POINT */
580		case 'n':
581			if (flags & QUADINT)
582				*va_arg(ap, quad_t *) = ret;
583			else if (flags & LONGINT)
584				*va_arg(ap, long *) = ret;
585			else if (flags & SHORTINT)
586				*va_arg(ap, short *) = ret;
587			else
588				*va_arg(ap, int *) = ret;
589			continue;	/* no output */
590		case 'O':
591			flags |= LONGINT;
592			/*FALLTHROUGH*/
593		case 'o':
594			if (flags & QUADINT)
595				uqval = va_arg(ap, u_quad_t);
596			else
597				ulval = UARG();
598			base = 8;
599			goto nosign;
600		case 'p':
601			/*
602			 * ``The argument shall be a pointer to void.  The
603			 * value of the pointer is converted to a sequence
604			 * of printable characters, in an implementation-
605			 * defined manner.''
606			 *	-- ANSI X3J11
607			 */
608			ulval = (u_long)va_arg(ap, void *);
609			base = 16;
610			xdigs = "0123456789abcdef";
611			flags = (flags & ~QUADINT) | HEXPREFIX;
612			ch = 'x';
613			goto nosign;
614		case 's':
615			if ((cp = va_arg(ap, char *)) == NULL)
616				cp = "(null)";
617			if (prec >= 0) {
618				/*
619				 * can't use strlen; can only look for the
620				 * NUL in the first `prec' characters, and
621				 * strlen() will go further.
622				 */
623				char *p = memchr(cp, 0, prec);
624
625				if (p != NULL) {
626					size = p - cp;
627					if (size > prec)
628						size = prec;
629				} else
630					size = prec;
631			} else
632				size = strlen(cp);
633			sign = '\0';
634			break;
635		case 'U':
636			flags |= LONGINT;
637			/*FALLTHROUGH*/
638		case 'u':
639			if (flags & QUADINT)
640				uqval = va_arg(ap, u_quad_t);
641			else
642				ulval = UARG();
643			base = 10;
644			goto nosign;
645		case 'X':
646			xdigs = "0123456789ABCDEF";
647			goto hex;
648		case 'x':
649			xdigs = "0123456789abcdef";
650hex:			if (flags & QUADINT)
651				uqval = va_arg(ap, u_quad_t);
652			else
653				ulval = UARG();
654			base = 16;
655			/* leading 0x/X only if non-zero */
656			if (flags & ALT &&
657			    (flags & QUADINT ? uqval != 0 : ulval != 0))
658				flags |= HEXPREFIX;
659
660			/* unsigned conversions */
661nosign:			sign = '\0';
662			/*
663			 * ``... diouXx conversions ... if a precision is
664			 * specified, the 0 flag will be ignored.''
665			 *	-- ANSI X3J11
666			 */
667number:			if ((dprec = prec) >= 0)
668				flags &= ~ZEROPAD;
669
670			/*
671			 * ``The result of converting a zero value with an
672			 * explicit precision of zero is no characters.''
673			 *	-- ANSI X3J11
674			 */
675			cp = buf + BUF;
676			if (flags & QUADINT) {
677				if (uqval != 0 || prec != 0)
678					cp = __uqtoa(uqval, cp, base,
679					    flags & ALT, xdigs);
680			} else {
681				if (ulval != 0 || prec != 0)
682					cp = __ultoa(ulval, cp, base,
683					    flags & ALT, xdigs);
684			}
685			size = buf + BUF - cp;
686			break;
687		default:	/* "%?" prints ?, unless ? is NUL */
688			if (ch == '\0')
689				goto done;
690			/* pretend it was %c with argument ch */
691			cp = buf;
692			*cp = ch;
693			size = 1;
694			sign = '\0';
695			break;
696		}
697
698		/*
699		 * All reasonable formats wind up here.  At this point, `cp'
700		 * points to a string which (if not flags&LADJUST) should be
701		 * padded out to `width' places.  If flags&ZEROPAD, it should
702		 * first be prefixed by any sign or other prefix; otherwise,
703		 * it should be blank padded before the prefix is emitted.
704		 * After any left-hand padding and prefixing, emit zeroes
705		 * required by a decimal [diouxX] precision, then print the
706		 * string proper, then emit zeroes required by any leftover
707		 * floating precision; finally, if LADJUST, pad with blanks.
708		 *
709		 * Compute actual size, so we know how much to pad.
710		 * size excludes decimal prec; realsz includes it.
711		 */
712		realsz = dprec > size ? dprec : size;
713		if (sign)
714			realsz++;
715		else if (flags & HEXPREFIX)
716			realsz += 2;
717
718		/* right-adjusting blank padding */
719		if ((flags & (LADJUST|ZEROPAD)) == 0)
720			PAD(width - realsz, blanks);
721
722		/* prefix */
723		if (sign) {
724			PRINT(&sign, 1);
725		} else if (flags & HEXPREFIX) {
726			ox[0] = '0';
727			ox[1] = ch;
728			PRINT(ox, 2);
729		}
730
731		/* right-adjusting zero padding */
732		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
733			PAD(width - realsz, zeroes);
734
735		/* leading zeroes from decimal precision */
736		PAD(dprec - size, zeroes);
737
738		/* the string or number proper */
739#ifdef FLOATING_POINT
740		if ((flags & FPT) == 0) {
741			PRINT(cp, size);
742		} else {	/* glue together f_p fragments */
743			if (ch >= 'f') {	/* 'f' or 'g' */
744				if (_double == 0) {
745					/* kludge for __dtoa irregularity */
746					if (expt >= ndig &&
747					    (flags & ALT) == 0) {
748						PRINT("0", 1);
749					} else {
750						PRINT("0.", 2);
751						PAD(ndig - 1, zeroes);
752					}
753				} else if (expt <= 0) {
754					PRINT("0.", 2);
755					PAD(-expt, zeroes);
756					PRINT(cp, ndig);
757				} else if (expt >= ndig) {
758					PRINT(cp, ndig);
759					PAD(expt - ndig, zeroes);
760					if (flags & ALT)
761						PRINT(".", 1);
762				} else {
763					PRINT(cp, expt);
764					cp += expt;
765					PRINT(".", 1);
766					PRINT(cp, ndig-expt);
767				}
768			} else {	/* 'e' or 'E' */
769				if (ndig > 1 || flags & ALT) {
770					ox[0] = *cp++;
771					ox[1] = '.';
772					PRINT(ox, 2);
773					if (_double) {
774						PRINT(cp, ndig-1);
775					} else	/* 0.[0..] */
776						/* __dtoa irregularity */
777						PAD(ndig - 1, zeroes);
778				} else	/* XeYYY */
779					PRINT(cp, 1);
780				PRINT(expstr, expsize);
781			}
782		}
783#else
784		PRINT(cp, size);
785#endif
786		/* left-adjusting padding (always blank) */
787		if (flags & LADJUST)
788			PAD(width - realsz, blanks);
789
790		/* finally, adjust ret */
791		ret += width > realsz ? width : realsz;
792
793		FLUSH();	/* copy out the I/O vectors */
794	}
795done:
796	FLUSH();
797error:
798	if (__sferror(fp))
799		ret = EOF;
800#ifdef _THREAD_SAFE
801	_thread_funlockfile(fp);
802#endif
803	return (ret);
804	/* NOTREACHED */
805}
806
807#ifdef FLOATING_POINT
808
809extern char *__dtoa __P((double, int, int, int *, int *, char **));
810
811static char *
812cvt(value, ndigits, flags, sign, decpt, ch, length)
813	double value;
814	int ndigits, flags, *decpt, ch, *length;
815	char *sign;
816{
817	int mode, dsgn;
818	char *digits, *bp, *rve;
819
820	if (ch == 'f')
821		mode = 3;		/* ndigits after the decimal point */
822	else {
823		/*
824		 * To obtain ndigits after the decimal point for the 'e'
825		 * and 'E' formats, round to ndigits + 1 significant
826		 * figures.
827		 */
828		if (ch == 'e' || ch == 'E')
829			ndigits++;
830		mode = 2;		/* ndigits significant digits */
831	}
832	if (value < 0) {
833		value = -value;
834		*sign = '-';
835	} else
836		*sign = '\000';
837	digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
838	if ((ch != 'g' && ch != 'G') || flags & ALT) {
839		/* print trailing zeros */
840		bp = digits + ndigits;
841		if (ch == 'f') {
842			if (*digits == '0' && value)
843				*decpt = -ndigits + 1;
844			bp += *decpt;
845		}
846		if (value == 0)	/* kludge for __dtoa irregularity */
847			rve = bp;
848		while (rve < bp)
849			*rve++ = '0';
850	}
851	*length = rve - digits;
852	return (digits);
853}
854
855static int
856exponent(p0, exp, fmtch)
857	char *p0;
858	int exp, fmtch;
859{
860	register char *p, *t;
861	char expbuf[MAXEXP];
862
863	p = p0;
864	*p++ = fmtch;
865	if (exp < 0) {
866		exp = -exp;
867		*p++ = '-';
868	}
869	else
870		*p++ = '+';
871	t = expbuf + MAXEXP;
872	if (exp > 9) {
873		do {
874			*--t = to_char(exp % 10);
875		} while ((exp /= 10) > 9);
876		*--t = to_char(exp);
877		for (; t < expbuf + MAXEXP; *p++ = *t++);
878	}
879	else {
880		*p++ = '0';
881		*p++ = to_char(exp);
882	}
883	return (p - p0);
884}
885#endif /* FLOATING_POINT */
886