Home | History | Annotate | Line # | Download | only in stdio
vfprintf.c revision 1.58
      1  1.58       dsl #if 0
      2  1.58       dsl /* Contains my POSITIONAL_PARAMS code */
      3  1.58       dsl /*	$NetBSD: vfprintf.c,v 1.58 2009/10/14 21:25:52 dsl Exp $	*/
      4  1.58       dsl 
      5  1.58       dsl /*-
      6  1.58       dsl  * Copyright (c) 1990 The Regents of the University of California.
      7  1.58       dsl  * All rights reserved.
      8  1.58       dsl  *
      9  1.58       dsl  * This code is derived from software contributed to Berkeley by
     10  1.58       dsl  * Chris Torek.
     11  1.58       dsl  *
     12  1.58       dsl  * Redistribution and use in source and binary forms, with or without
     13  1.58       dsl  * modification, are permitted provided that the following conditions
     14  1.58       dsl  * are met:
     15  1.58       dsl  * 1. Redistributions of source code must retain the above copyright
     16  1.58       dsl  *    notice, this list of conditions and the following disclaimer.
     17  1.58       dsl  * 2. Redistributions in binary form must reproduce the above copyright
     18  1.58       dsl  *    notice, this list of conditions and the following disclaimer in the
     19  1.58       dsl  *    documentation and/or other materials provided with the distribution.
     20  1.58       dsl  * 3. Neither the name of the University nor the names of its contributors
     21  1.58       dsl  *    may be used to endorse or promote products derived from this software
     22  1.58       dsl  *    without specific prior written permission.
     23  1.58       dsl  *
     24  1.58       dsl  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  1.58       dsl  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  1.58       dsl  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  1.58       dsl  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  1.58       dsl  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  1.58       dsl  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  1.58       dsl  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  1.58       dsl  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  1.58       dsl  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  1.58       dsl  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  1.58       dsl  * SUCH DAMAGE.
     35  1.58       dsl  */
     36  1.58       dsl 
     37  1.58       dsl #include <sys/cdefs.h>
     38  1.58       dsl #if defined(LIBC_SCCS) && !defined(lint)
     39  1.58       dsl #if 0
     40  1.58       dsl static char *sccsid = "@(#)vfprintf.c	5.50 (Berkeley) 12/16/92";
     41  1.58       dsl #else
     42  1.58       dsl __RCSID("$NetBSD: vfprintf.c,v 1.58 2009/10/14 21:25:52 dsl Exp $");
     43  1.58       dsl #endif
     44  1.58       dsl #endif /* LIBC_SCCS and not lint */
     45  1.58       dsl 
     46  1.58       dsl /*
     47  1.58       dsl  * Actual printf innards.
     48  1.58       dsl  *
     49  1.58       dsl  * This code is large and complicated...
     50  1.58       dsl  */
     51  1.58       dsl 
     52  1.58       dsl #include "namespace.h"
     53  1.58       dsl #include <sys/types.h>
     54  1.58       dsl 
     55  1.58       dsl #include <assert.h>
     56  1.58       dsl #include <errno.h>
     57  1.58       dsl #include <stdarg.h>
     58  1.58       dsl #include <stddef.h>
     59  1.58       dsl #include <stdint.h>
     60  1.58       dsl #include <stdio.h>
     61  1.58       dsl #include <stdlib.h>
     62  1.58       dsl #include <string.h>
     63  1.58       dsl #include <wchar.h>
     64  1.58       dsl 
     65  1.58       dsl #include "reentrant.h"
     66  1.58       dsl #include "local.h"
     67  1.58       dsl #include "fvwrite.h"
     68  1.58       dsl #include "extern.h"
     69  1.58       dsl 
     70  1.58       dsl #ifdef FLOATING_POINT
     71  1.58       dsl #define POSITIONAL_PARAMS
     72  1.58       dsl #endif
     73  1.58       dsl 
     74  1.58       dsl static int __sprint __P((FILE *, struct __suio *));
     75  1.58       dsl static int __sbprintf __P((FILE *, const char *, va_list))
     76  1.58       dsl      __attribute__((__format__(__printf__, 2, 0)));
     77  1.58       dsl #ifdef POSITIONAL_PARAMS
     78  1.58       dsl #define NL_ARGMAX	9	/* minimum required by IEEE Std 1003.1-2001 */
     79  1.58       dsl 
     80  1.58       dsl union parg {
     81  1.58       dsl 	int		flags;
     82  1.58       dsl 	uintmax_t	_uintmax;
     83  1.58       dsl 	void		*_pointer;
     84  1.58       dsl 	double		_double;
     85  1.58       dsl };
     86  1.58       dsl static void set_printf_args(union parg *, const char *, _BSD_VA_LIST_);
     87  1.58       dsl #endif
     88  1.58       dsl 
     89  1.58       dsl /*
     90  1.58       dsl  * Flush out all the vectors defined by the given uio,
     91  1.58       dsl  * then reset it so that it can be reused.
     92  1.58       dsl  */
     93  1.58       dsl /* NB: async-signal-safe when fp->_flags & __SAFE */
     94  1.58       dsl static int
     95  1.58       dsl __sprint(fp, uio)
     96  1.58       dsl 	FILE *fp;
     97  1.58       dsl 	struct __suio *uio;
     98  1.58       dsl {
     99  1.58       dsl 	int err;
    100  1.58       dsl 
    101  1.58       dsl 	_DIAGASSERT(fp != NULL);
    102  1.58       dsl 	_DIAGASSERT(uio != NULL);
    103  1.58       dsl 
    104  1.58       dsl 	if (uio->uio_resid == 0) {
    105  1.58       dsl 		uio->uio_iovcnt = 0;
    106  1.58       dsl 		return (0);
    107  1.58       dsl 	}
    108  1.58       dsl 	err = __sfvwrite(fp, uio);
    109  1.58       dsl 	uio->uio_resid = 0;
    110  1.58       dsl 	uio->uio_iovcnt = 0;
    111  1.58       dsl 	return (err);
    112  1.58       dsl }
    113  1.58       dsl 
    114  1.58       dsl /*
    115  1.58       dsl  * Helper function for `fprintf to unbuffered unix file': creates a
    116  1.58       dsl  * temporary buffer.  We only work on write-only files; this avoids
    117  1.58       dsl  * worries about ungetc buffers and so forth.
    118  1.58       dsl  */
    119  1.58       dsl static int
    120  1.58       dsl __sbprintf(fp, fmt, ap)
    121  1.58       dsl 	FILE *fp;
    122  1.58       dsl 	const char *fmt;
    123  1.58       dsl 	va_list ap;
    124  1.58       dsl {
    125  1.58       dsl 	int ret;
    126  1.58       dsl 	FILE fake;
    127  1.58       dsl 	struct __sfileext fakeext;
    128  1.58       dsl 	unsigned char buf[BUFSIZ];
    129  1.58       dsl 
    130  1.58       dsl 	_DIAGASSERT(fp != NULL);
    131  1.58       dsl 	_DIAGASSERT(fmt != NULL);
    132  1.58       dsl 
    133  1.58       dsl 	_FILEEXT_SETUP(&fake, &fakeext);
    134  1.58       dsl 
    135  1.58       dsl 	/* copy the important variables */
    136  1.58       dsl 	fake._flags = fp->_flags & ~__SNBF;
    137  1.58       dsl 	fake._file = fp->_file;
    138  1.58       dsl 	fake._cookie = fp->_cookie;
    139  1.58       dsl 	fake._write = fp->_write;
    140  1.58       dsl 
    141  1.58       dsl 	/* set up the buffer */
    142  1.58       dsl 	fake._bf._base = fake._p = buf;
    143  1.58       dsl 	fake._bf._size = fake._w = sizeof(buf);
    144  1.58       dsl 	fake._lbfsize = 0;	/* not actually used, but Just In Case */
    145  1.58       dsl 
    146  1.58       dsl 	/* do the work, then copy any error status */
    147  1.58       dsl 	ret = vfprintf(&fake, fmt, ap);
    148  1.58       dsl 	if (ret >= 0 && fflush(&fake))
    149  1.58       dsl 		ret = -1;
    150  1.58       dsl 	if (fake._flags & __SERR)
    151  1.58       dsl 		fp->_flags |= __SERR;
    152  1.58       dsl 	return (ret);
    153  1.58       dsl }
    154  1.58       dsl 
    155  1.58       dsl 
    156  1.58       dsl #ifndef NO_FLOATING_POINT
    157  1.58       dsl #include <locale.h>
    158  1.58       dsl #include <math.h>
    159  1.58       dsl #include "floatio.h"
    160  1.58       dsl 
    161  1.58       dsl #define	BUF		(MAXEXP+MAXFRACT+1)	/* + decimal point */
    162  1.58       dsl #define	DEFPREC		6
    163  1.58       dsl 
    164  1.58       dsl static char *cvt __P((double, int, int, char *, int *, int, int *));
    165  1.58       dsl static int exponent __P((char *, int, int));
    166  1.58       dsl 
    167  1.58       dsl #else /* FLOATING_POINT */
    168  1.58       dsl 
    169  1.58       dsl #define	BUF		40
    170  1.58       dsl 
    171  1.58       dsl #endif /* NO_FLOATING_POINT */
    172  1.58       dsl 
    173  1.58       dsl /*
    174  1.58       dsl  * Macros for converting digits to letters and vice versa
    175  1.58       dsl  */
    176  1.58       dsl #define	to_digit(c)	((c) - '0')
    177  1.58       dsl #define is_digit(c)	((unsigned)to_digit(c) <= 9)
    178  1.58       dsl #define	to_char(n)	((char)((n) + '0'))
    179  1.58       dsl 
    180  1.58       dsl /*
    181  1.58       dsl  * Flags used during conversion.
    182  1.58       dsl  */
    183  1.58       dsl #define	ALT		0x001		/* alternate form */
    184  1.58       dsl #define	HEXPREFIX	0x002		/* add 0x or 0X prefix */
    185  1.58       dsl #define	LADJUST		0x004		/* left adjustment */
    186  1.58       dsl #define	LONGDBL		0x008		/* long double; unimplemented */
    187  1.58       dsl #define	LONGINT		0x010		/* long integer */
    188  1.58       dsl #define	QUADINT		0x020		/* quad integer */
    189  1.58       dsl #define	SHORTINT	0x040		/* short integer */
    190  1.58       dsl #define	MAXINT		0x080		/* (unsigned) intmax_t */
    191  1.58       dsl #define	PTRINT		0x100		/* (unsigned) ptrdiff_t */
    192  1.58       dsl #define	SIZEINT		0x200		/* (signed) size_t */
    193  1.58       dsl #define	ZEROPAD		0x400		/* zero (as opposed to blank) pad */
    194  1.58       dsl #define FPT		0x800		/* Floating point number */
    195  1.58       dsl #ifdef POSITIONAL_PARAMS
    196  1.58       dsl #define POINTER		0x10000		/* Pointer to something */
    197  1.58       dsl #define SIGNED		0x20000		/* signed value */
    198  1.58       dsl #define CHARINT		0x40000		/* move above when %hhd implemented */
    199  1.58       dsl #endif
    200  1.58       dsl 
    201  1.58       dsl int
    202  1.58       dsl vfprintf(fp, fmt0, ap)
    203  1.58       dsl 	FILE *fp;
    204  1.58       dsl 	const char *fmt0;
    205  1.58       dsl 	_BSD_VA_LIST_ ap;
    206  1.58       dsl {
    207  1.58       dsl 	int ret;
    208  1.58       dsl 
    209  1.58       dsl 	FLOCKFILE(fp);
    210  1.58       dsl 	ret = __vfprintf_unlocked(fp, fmt0, ap);
    211  1.58       dsl 	FUNLOCKFILE(fp);
    212  1.58       dsl 
    213  1.58       dsl 	return ret;
    214  1.58       dsl }
    215  1.58       dsl 
    216  1.58       dsl 
    217  1.58       dsl 
    218  1.58       dsl /* NB: async-signal-safe when fp->_flags & __SAFE */
    219  1.58       dsl int
    220  1.58       dsl __vfprintf_unlocked(fp, fmt0, ap)
    221  1.58       dsl 	FILE *fp;
    222  1.58       dsl 	const char *fmt0;
    223  1.58       dsl 	_BSD_VA_LIST_ ap;
    224  1.58       dsl {
    225  1.58       dsl 	const char *fmt;/* format string */
    226  1.58       dsl 	int ch;	/* character from fmt */
    227  1.58       dsl 	int n, m;	/* handy integers (short term usage) */
    228  1.58       dsl 	const char *cp;	/* handy char pointer (short term usage) */
    229  1.58       dsl 	char *bp;	/* handy char pointer (short term usage) */
    230  1.58       dsl 	struct __siov *iovp;/* for PRINT macro */
    231  1.58       dsl 	int flags;	/* flags as above */
    232  1.58       dsl 	int ret;		/* return value accumulator */
    233  1.58       dsl 	int width;		/* width from format (%8d), or 0 */
    234  1.58       dsl 	int prec;		/* precision from format (%.3d), or -1 */
    235  1.58       dsl 	char sign;		/* sign prefix (' ', '+', '-', or \0) */
    236  1.58       dsl 	wchar_t wc;
    237  1.58       dsl 	mbstate_t ps;
    238  1.58       dsl #ifndef NO_FLOATING_POINT
    239  1.58       dsl 	char *decimal_point = NULL;
    240  1.58       dsl 	char softsign;		/* temporary negative sign for floats */
    241  1.58       dsl 	double _double;		/* double precision arguments %[eEfgG] */
    242  1.58       dsl 	int expt;		/* integer value of exponent */
    243  1.58       dsl 	int expsize = 0;	/* character count for expstr */
    244  1.58       dsl 	int ndig;		/* actual number of digits returned by cvt */
    245  1.58       dsl 	char expstr[7];		/* buffer for exponent string */
    246  1.58       dsl 	char *dtoaresult = NULL;
    247  1.58       dsl #endif
    248  1.58       dsl 
    249  1.58       dsl #ifdef __GNUC__			/* gcc has builtin quad type (long long) SOS */
    250  1.58       dsl #define	quad_t	  long long
    251  1.58       dsl #define	u_quad_t  unsigned long long
    252  1.58       dsl #endif
    253  1.58       dsl 
    254  1.58       dsl #define	INTMAX_T	intmax_t
    255  1.58       dsl #define	UINTMAX_T	uintmax_t
    256  1.58       dsl 
    257  1.58       dsl 	UINTMAX_T _uintmax;	/* integer arguments %[diouxX] */
    258  1.58       dsl 	enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
    259  1.58       dsl 	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
    260  1.58       dsl 	int realsz;		/* field size expanded by dprec */
    261  1.58       dsl 	int size;		/* size of converted field or string */
    262  1.58       dsl 	const char *xdigs = NULL;/* digits for [xX] conversion */
    263  1.58       dsl #define NIOV 8
    264  1.58       dsl 	struct __suio uio;	/* output information: summary */
    265  1.58       dsl 	struct __siov iov[NIOV];/* ... and individual io vectors */
    266  1.58       dsl 	char buf[BUF];		/* space for %c, %[diouxX], %[eEfgG] */
    267  1.58       dsl 	char ox[2];		/* space for 0x hex-prefix */
    268  1.58       dsl 
    269  1.58       dsl 	/*
    270  1.58       dsl 	 * Choose PADSIZE to trade efficiency vs. size.  If larger printf
    271  1.58       dsl 	 * fields occur frequently, increase PADSIZE and make the initialisers
    272  1.58       dsl 	 * below longer.
    273  1.58       dsl 	 */
    274  1.58       dsl #define	PADSIZE	16		/* pad chunk size */
    275  1.58       dsl 	static const char blanks[PADSIZE] =
    276  1.58       dsl 	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
    277  1.58       dsl 	static const char zeroes[PADSIZE] =
    278  1.58       dsl 	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
    279  1.58       dsl #ifdef POSITIONAL_PARAMS	/* %n$... */
    280  1.58       dsl 	union parg parg[1 + NL_ARGMAX];
    281  1.58       dsl 	int positional = 0;
    282  1.58       dsl 	int argnum = 0;
    283  1.58       dsl 
    284  1.58       dsl 	memset(&parg, 0, sizeof parg);
    285  1.58       dsl #endif
    286  1.58       dsl 
    287  1.58       dsl 	/*
    288  1.58       dsl 	 * BEWARE, these `goto error' on error, and PAD uses `n'.
    289  1.58       dsl 	 */
    290  1.58       dsl #define	PRINT(ptr, len) do { \
    291  1.58       dsl 	iovp->iov_base = __UNCONST(ptr); \
    292  1.58       dsl 	iovp->iov_len = (len); \
    293  1.58       dsl 	uio.uio_resid += (len); \
    294  1.58       dsl 	iovp++; \
    295  1.58       dsl 	if (++uio.uio_iovcnt >= NIOV) { \
    296  1.58       dsl 		if (__sprint(fp, &uio)) \
    297  1.58       dsl 			goto error; \
    298  1.58       dsl 		iovp = iov; \
    299  1.58       dsl 	} \
    300  1.58       dsl } while (/*CONSTCOND*/0)
    301  1.58       dsl 
    302  1.58       dsl #define	PAD(howmany, with) do { \
    303  1.58       dsl 	if ((n = (howmany)) > 0) { \
    304  1.58       dsl 		while (n > PADSIZE) { \
    305  1.58       dsl 			PRINT(with, PADSIZE); \
    306  1.58       dsl 			n -= PADSIZE; \
    307  1.58       dsl 		} \
    308  1.58       dsl 		PRINT(with, n); \
    309  1.58       dsl 	} \
    310  1.58       dsl } while (/*CONSTCOND*/0)
    311  1.58       dsl 
    312  1.58       dsl #define	FLUSH() do { \
    313  1.58       dsl 	if (uio.uio_resid && __sprint(fp, &uio)) \
    314  1.58       dsl 		goto error; \
    315  1.58       dsl 	uio.uio_iovcnt = 0; \
    316  1.58       dsl 	iovp = iov; \
    317  1.58       dsl } while (/*CONSTCOND*/0)
    318  1.58       dsl 
    319  1.58       dsl 	/*
    320  1.58       dsl 	 * To extend shorts properly, we need both signed and unsigned
    321  1.58       dsl 	 * argument extraction methods.
    322  1.58       dsl 	 */
    323  1.58       dsl #define	SARG(flags, ap) \
    324  1.58       dsl 	(flags&MAXINT ? va_arg(ap, intmax_t) : \
    325  1.58       dsl 	    flags&PTRINT ? va_arg(ap, ptrdiff_t) : \
    326  1.58       dsl 	    flags&SIZEINT ? va_arg(ap, ssize_t) : /* XXX */ \
    327  1.58       dsl 	    flags&QUADINT ? va_arg(ap, quad_t) : \
    328  1.58       dsl 	    flags&LONGINT ? va_arg(ap, long) : \
    329  1.58       dsl 	    flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
    330  1.58       dsl 	    (long)va_arg(ap, int))
    331  1.58       dsl #define	UARG(flags, ap) \
    332  1.58       dsl 	(flags&MAXINT ? va_arg(ap, uintmax_t) : \
    333  1.58       dsl 	    flags&PTRINT ? va_arg(ap, uintptr_t) : /* XXX */ \
    334  1.58       dsl 	    flags&SIZEINT ? va_arg(ap, size_t) : \
    335  1.58       dsl 	    flags&QUADINT ? va_arg(ap, u_quad_t) : \
    336  1.58       dsl 	    flags&LONGINT ? va_arg(ap, u_long) : \
    337  1.58       dsl 	    flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
    338  1.58       dsl 	    (u_long)va_arg(ap, u_int))
    339  1.58       dsl 
    340  1.58       dsl 	_DIAGASSERT(fp != NULL);
    341  1.58       dsl 	_DIAGASSERT(fmt0 != NULL);
    342  1.58       dsl 
    343  1.58       dsl 	_SET_ORIENTATION(fp, -1);
    344  1.58       dsl 
    345  1.58       dsl 	/* sorry, fprintf(read_only_file, "") returns -1, not 0 */
    346  1.58       dsl 	if (cantwrite(fp)) {
    347  1.58       dsl 		errno = EBADF;
    348  1.58       dsl 		return (-1);
    349  1.58       dsl 	}
    350  1.58       dsl 
    351  1.58       dsl 	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
    352  1.58       dsl 	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
    353  1.58       dsl 	    fp->_file >= 0) {
    354  1.58       dsl 		ret = __sbprintf(fp, fmt0, ap);
    355  1.58       dsl 		return (ret);
    356  1.58       dsl 	}
    357  1.58       dsl 
    358  1.58       dsl 	fmt = fmt0;
    359  1.58       dsl 	uio.uio_iov = iovp = iov;
    360  1.58       dsl 	uio.uio_resid = 0;
    361  1.58       dsl 	uio.uio_iovcnt = 0;
    362  1.58       dsl 	ret = 0;
    363  1.58       dsl 
    364  1.58       dsl 	memset(&ps, 0, sizeof(ps));
    365  1.58       dsl 
    366  1.58       dsl 	/*
    367  1.58       dsl 	 * Scan the format for conversions (`%' character).
    368  1.58       dsl 	 */
    369  1.58       dsl 	for (;;) {
    370  1.58       dsl 		cp = fmt;
    371  1.58       dsl 		if (fp->_flags & __SAFE) {
    372  1.58       dsl 			for (; *fmt && *fmt != '%'; fmt++)
    373  1.58       dsl 				continue;
    374  1.58       dsl 			n = *fmt == '%';
    375  1.58       dsl 		} else {
    376  1.58       dsl 			while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
    377  1.58       dsl 				fmt += n;
    378  1.58       dsl 				if (wc == '%') {
    379  1.58       dsl 					fmt--;
    380  1.58       dsl 					break;
    381  1.58       dsl 				}
    382  1.58       dsl 			}
    383  1.58       dsl 		}
    384  1.58       dsl 		if ((m = fmt - cp) != 0) {
    385  1.58       dsl 			PRINT(cp, m);
    386  1.58       dsl 			ret += m;
    387  1.58       dsl 		}
    388  1.58       dsl 		if (n <= 0)
    389  1.58       dsl 			goto done;
    390  1.58       dsl 		fmt0 = fmt;	/* save pointer to the '%' */
    391  1.58       dsl 		fmt++;		/* skip over '%' */
    392  1.58       dsl 
    393  1.58       dsl 		flags = 0;
    394  1.58       dsl 		dprec = 0;
    395  1.58       dsl 		width = 0;
    396  1.58       dsl 		prec = -1;
    397  1.58       dsl 		sign = '\0';
    398  1.58       dsl 
    399  1.58       dsl #ifdef POSITIONAL_PARAMS
    400  1.58       dsl 		ch = *fmt;
    401  1.58       dsl 		if (is_digit(ch) && fmt[1] == '$' && positional >= 0) {
    402  1.58       dsl 			fmt += 2;
    403  1.58       dsl 			if (positional == 0) {
    404  1.58       dsl 				set_printf_args(parg, fmt0, ap);
    405  1.58       dsl 				positional = 1;
    406  1.58       dsl 			}
    407  1.58       dsl 			argnum = to_digit(ch);
    408  1.58       dsl 		}
    409  1.58       dsl #endif
    410  1.58       dsl 
    411  1.58       dsl 
    412  1.58       dsl rflag:		ch = *fmt++;
    413  1.58       dsl reswitch:	switch (ch) {
    414  1.58       dsl 		case ' ':
    415  1.58       dsl 			/*
    416  1.58       dsl 			 * ``If the space and + flags both appear, the space
    417  1.58       dsl 			 * flag will be ignored.''
    418  1.58       dsl 			 *	-- ANSI X3J11
    419  1.58       dsl 			 */
    420  1.58       dsl 			if (!sign)
    421  1.58       dsl 				sign = ' ';
    422  1.58       dsl 			goto rflag;
    423  1.58       dsl 		case '#':
    424  1.58       dsl 			flags |= ALT;
    425  1.58       dsl 			goto rflag;
    426  1.58       dsl 		case '*':
    427  1.58       dsl #ifdef POSITIONAL_PARAMS
    428  1.58       dsl 			if (positional > 0) {
    429  1.58       dsl 				ch = *fmt++;
    430  1.58       dsl 				if (!is_digit(ch))
    431  1.58       dsl 					goto invalid;
    432  1.58       dsl 				n = to_digit(ch);
    433  1.58       dsl 				ch = *fmt++;
    434  1.58       dsl 				if (n == 0 || ch != '$')
    435  1.58       dsl 					goto invalid;
    436  1.58       dsl 				width = (int)parg[n]._uintmax;
    437  1.58       dsl 			} else
    438  1.58       dsl #endif
    439  1.58       dsl 			width = va_arg(ap, int);
    440  1.58       dsl 			/*
    441  1.58       dsl 			 * ``A negative field width argument is taken as a
    442  1.58       dsl 			 * - flag followed by a positive field width.''
    443  1.58       dsl 			 *	-- ANSI X3J11
    444  1.58       dsl 			 * They don't exclude field widths read from args.
    445  1.58       dsl 			 */
    446  1.58       dsl 			if (width >= 0)
    447  1.58       dsl 				goto rflag;
    448  1.58       dsl 			width = -width;
    449  1.58       dsl 			/* FALLTHROUGH */
    450  1.58       dsl 		case '-':
    451  1.58       dsl 			flags |= LADJUST;
    452  1.58       dsl 			goto rflag;
    453  1.58       dsl 		case '+':
    454  1.58       dsl 			sign = '+';
    455  1.58       dsl 			goto rflag;
    456  1.58       dsl 		case '.':
    457  1.58       dsl 			if ((ch = *fmt++) == '*') {
    458  1.58       dsl #ifdef POSITIONAL_PARAMS
    459  1.58       dsl 				if (positional > 0) {
    460  1.58       dsl 					ch = *fmt++;
    461  1.58       dsl 					if (!is_digit(ch))
    462  1.58       dsl 						goto invalid;
    463  1.58       dsl 					n = to_digit(ch);
    464  1.58       dsl 					ch = *fmt++;
    465  1.58       dsl 					if (n == 0 || ch != '$')
    466  1.58       dsl 						goto invalid;
    467  1.58       dsl 					n = (int)parg[n]._uintmax;
    468  1.58       dsl 				} else
    469  1.58       dsl #endif
    470  1.58       dsl 				n = va_arg(ap, int);
    471  1.58       dsl 				prec = n < 0 ? -1 : n;
    472  1.58       dsl 				goto rflag;
    473  1.58       dsl 			}
    474  1.58       dsl 			n = 0;
    475  1.58       dsl 			while (is_digit(ch)) {
    476  1.58       dsl 				n = 10 * n + to_digit(ch);
    477  1.58       dsl 				ch = *fmt++;
    478  1.58       dsl 			}
    479  1.58       dsl 			prec = n < 0 ? -1 : n;
    480  1.58       dsl 			goto reswitch;
    481  1.58       dsl 		case '0':
    482  1.58       dsl 			/*
    483  1.58       dsl 			 * ``Note that 0 is taken as a flag, not as the
    484  1.58       dsl 			 * beginning of a field width.''
    485  1.58       dsl 			 *	-- ANSI X3J11
    486  1.58       dsl 			 */
    487  1.58       dsl 			flags |= ZEROPAD;
    488  1.58       dsl 			goto rflag;
    489  1.58       dsl 		case '1': case '2': case '3': case '4':
    490  1.58       dsl 		case '5': case '6': case '7': case '8': case '9':
    491  1.58       dsl 			n = 0;
    492  1.58       dsl 			do {
    493  1.58       dsl 				n = 10 * n + to_digit(ch);
    494  1.58       dsl 				ch = *fmt++;
    495  1.58       dsl 			} while (is_digit(ch));
    496  1.58       dsl 			width = n;
    497  1.58       dsl 			goto reswitch;
    498  1.58       dsl #ifndef NO_FLOATING_POINT
    499  1.58       dsl 		case 'L':
    500  1.58       dsl 			flags |= LONGDBL;
    501  1.58       dsl 			goto rflag;
    502  1.58       dsl #endif
    503  1.58       dsl 		case 'h':
    504  1.58       dsl 			flags |= SHORTINT;
    505  1.58       dsl 			goto rflag;
    506  1.58       dsl 		case 'j':
    507  1.58       dsl 			flags |= MAXINT;
    508  1.58       dsl 			goto rflag;
    509  1.58       dsl 		case 'l':
    510  1.58       dsl 			if (*fmt == 'l') {
    511  1.58       dsl 				fmt++;
    512  1.58       dsl 				flags |= QUADINT;
    513  1.58       dsl 			} else {
    514  1.58       dsl 				flags |= LONGINT;
    515  1.58       dsl 			}
    516  1.58       dsl 			goto rflag;
    517  1.58       dsl 		case 'q':
    518  1.58       dsl 			flags |= QUADINT;
    519  1.58       dsl 			goto rflag;
    520  1.58       dsl 		case 't':
    521  1.58       dsl 			flags |= PTRINT;
    522  1.58       dsl 			goto rflag;
    523  1.58       dsl 		case 'z':
    524  1.58       dsl 			flags |= SIZEINT;
    525  1.58       dsl 			goto rflag;
    526  1.58       dsl 		case 'c':
    527  1.58       dsl #ifdef POSITIONAL_PARAMS
    528  1.58       dsl 			if (positional > 0)
    529  1.58       dsl 				*buf = (int)parg[argnum]._uintmax;
    530  1.58       dsl 			else
    531  1.58       dsl #endif
    532  1.58       dsl 			*buf = va_arg(ap, int);
    533  1.58       dsl 			cp = buf;
    534  1.58       dsl 			size = 1;
    535  1.58       dsl 			sign = '\0';
    536  1.58       dsl 			break;
    537  1.58       dsl 		case 'D':
    538  1.58       dsl 			flags |= LONGINT;
    539  1.58       dsl 			/*FALLTHROUGH*/
    540  1.58       dsl 		case 'd':
    541  1.58       dsl 		case 'i':
    542  1.58       dsl #ifdef POSITIONAL_PARAMS
    543  1.58       dsl 			if (positional > 0)
    544  1.58       dsl 				_uintmax = parg[argnum]._uintmax;
    545  1.58       dsl 			else
    546  1.58       dsl #endif
    547  1.58       dsl 			_uintmax = SARG(flags, ap);
    548  1.58       dsl 			if ((intmax_t)_uintmax < 0) {
    549  1.58       dsl 				_uintmax = -_uintmax;
    550  1.58       dsl 				sign = '-';
    551  1.58       dsl 			}
    552  1.58       dsl 			base = DEC;
    553  1.58       dsl 			goto number;
    554  1.58       dsl #ifndef NO_FLOATING_POINT
    555  1.58       dsl 		case 'e':
    556  1.58       dsl 		case 'E':
    557  1.58       dsl 		case 'f':
    558  1.58       dsl 		case 'F':
    559  1.58       dsl 		case 'g':
    560  1.58       dsl 		case 'G':
    561  1.58       dsl 			if (prec == -1) {
    562  1.58       dsl 				prec = DEFPREC;
    563  1.58       dsl 			} else if ((ch == 'g' || ch == 'G') && prec == 0) {
    564  1.58       dsl 				prec = 1;
    565  1.58       dsl 			}
    566  1.58       dsl 
    567  1.58       dsl #ifdef POSITIONAL_PARAMS
    568  1.58       dsl 			if (positional > 0)
    569  1.58       dsl 				_double = parg[argnum]._double;
    570  1.58       dsl 			else
    571  1.58       dsl #endif
    572  1.58       dsl 			if (flags & LONGDBL) {
    573  1.58       dsl 				_double = (double) va_arg(ap, long double);
    574  1.58       dsl 			} else {
    575  1.58       dsl 				_double = va_arg(ap, double);
    576  1.58       dsl 			}
    577  1.58       dsl 
    578  1.58       dsl 			/* do this before tricky precision changes */
    579  1.58       dsl 			if (isinf(_double)) {
    580  1.58       dsl 				if (_double < 0)
    581  1.58       dsl 					sign = '-';
    582  1.58       dsl 				if (ch == 'E' || ch == 'F' || ch == 'G')
    583  1.58       dsl 					cp = "INF";
    584  1.58       dsl 				else
    585  1.58       dsl 					cp = "inf";
    586  1.58       dsl 				size = 3;
    587  1.58       dsl 				break;
    588  1.58       dsl 			}
    589  1.58       dsl 			if (isnan(_double)) {
    590  1.58       dsl 				if (ch == 'E' || ch == 'F' || ch == 'G')
    591  1.58       dsl 					cp = "NAN";
    592  1.58       dsl 				else
    593  1.58       dsl 					cp = "nan";
    594  1.58       dsl 				size = 3;
    595  1.58       dsl 				break;
    596  1.58       dsl 			}
    597  1.58       dsl 			if (fp->_flags & __SAFE) {
    598  1.58       dsl 				if (ch == 'E' || ch == 'F' || ch == 'G')
    599  1.58       dsl 					cp = "UNK";
    600  1.58       dsl 				else
    601  1.58       dsl 					cp = "unk";
    602  1.58       dsl 				size = 3;
    603  1.58       dsl 				break;
    604  1.58       dsl 			}
    605  1.58       dsl 
    606  1.58       dsl 			flags |= FPT;
    607  1.58       dsl 			if (dtoaresult)
    608  1.58       dsl 				__freedtoa(dtoaresult);
    609  1.58       dsl 			cp = dtoaresult = cvt(_double, prec, flags, &softsign,
    610  1.58       dsl 				&expt, ch, &ndig);
    611  1.58       dsl 			if (ch == 'g' || ch == 'G') {
    612  1.58       dsl 				if (expt <= -4 || expt > prec)
    613  1.58       dsl 					ch = (ch == 'g') ? 'e' : 'E';
    614  1.58       dsl 				else
    615  1.58       dsl 					ch = 'g';
    616  1.58       dsl 			}
    617  1.58       dsl 			if (ch == 'e' || ch == 'E') {
    618  1.58       dsl 				--expt;
    619  1.58       dsl 				expsize = exponent(expstr, expt, ch);
    620  1.58       dsl 				size = expsize + ndig;
    621  1.58       dsl 				if (ndig > 1 || flags & ALT)
    622  1.58       dsl 					++size;
    623  1.58       dsl 			} else if (ch == 'f' || ch == 'F') {
    624  1.58       dsl 				if (expt > 0) {
    625  1.58       dsl 					size = expt;
    626  1.58       dsl 					if (prec || flags & ALT)
    627  1.58       dsl 						size += prec + 1;
    628  1.58       dsl 				} else	/* "0.X" */
    629  1.58       dsl 					size = prec + 2;
    630  1.58       dsl 			} else if (expt >= ndig) {	/* fixed g fmt */
    631  1.58       dsl 				size = expt;
    632  1.58       dsl 				if (flags & ALT)
    633  1.58       dsl 					++size;
    634  1.58       dsl 			} else
    635  1.58       dsl 				size = ndig + (expt > 0 ?
    636  1.58       dsl 					1 : 2 - expt);
    637  1.58       dsl 
    638  1.58       dsl 			if (softsign)
    639  1.58       dsl 				sign = '-';
    640  1.58       dsl 			break;
    641  1.58       dsl #endif /* NO_FLOATING_POINT */
    642  1.58       dsl 		case 'n':
    643  1.58       dsl #ifdef POSITIONAL_PARAMS
    644  1.58       dsl 			if (positional > 0)
    645  1.58       dsl 				/*
    646  1.58       dsl 				 * This could be implemented, but it stinks
    647  1.58       dsl 				 * of a security risk.
    648  1.58       dsl 				 */
    649  1.58       dsl 				PRINT("(%n unassigned)", 15);
    650  1.58       dsl 			else
    651  1.58       dsl #endif
    652  1.58       dsl 			if (flags & MAXINT)
    653  1.58       dsl 				*va_arg(ap, intmax_t *) = ret;
    654  1.58       dsl 			else if (flags & PTRINT)
    655  1.58       dsl 				*va_arg(ap, ptrdiff_t *) = ret;
    656  1.58       dsl 			else if (flags & SIZEINT)
    657  1.58       dsl 				*va_arg(ap, ssize_t *) = ret;	/* XXX */
    658  1.58       dsl 			else if (flags & QUADINT)
    659  1.58       dsl 				*va_arg(ap, quad_t *) = ret;
    660  1.58       dsl 			else if (flags & LONGINT)
    661  1.58       dsl 				*va_arg(ap, long *) = ret;
    662  1.58       dsl 			else if (flags & SHORTINT)
    663  1.58       dsl 				*va_arg(ap, short *) = ret;
    664  1.58       dsl 			else
    665  1.58       dsl 				*va_arg(ap, int *) = ret;
    666  1.58       dsl 			continue;	/* no output */
    667  1.58       dsl 		case 'O':
    668  1.58       dsl 			flags |= LONGINT;
    669  1.58       dsl 			/*FALLTHROUGH*/
    670  1.58       dsl 		case 'o':
    671  1.58       dsl #ifdef POSITIONAL_PARAMS
    672  1.58       dsl 			if (positional > 0)
    673  1.58       dsl 				_uintmax = parg[argnum]._uintmax;
    674  1.58       dsl 			else
    675  1.58       dsl #endif
    676  1.58       dsl 			_uintmax = UARG(flags, ap);
    677  1.58       dsl 			base = OCT;
    678  1.58       dsl 			goto nosign;
    679  1.58       dsl 		case 'p':
    680  1.58       dsl 			/*
    681  1.58       dsl 			 * ``The argument shall be a pointer to void.  The
    682  1.58       dsl 			 * value of the pointer is converted to a sequence
    683  1.58       dsl 			 * of printable characters, in an implementation-
    684  1.58       dsl 			 * defined manner.''
    685  1.58       dsl 			 *	-- ANSI X3J11
    686  1.58       dsl 			 */
    687  1.58       dsl #ifdef POSITIONAL_PARAMS
    688  1.58       dsl 			if (positional > 0)
    689  1.58       dsl 				_uintmax = (uintptr_t)parg[argnum]._pointer;
    690  1.58       dsl 			else
    691  1.58       dsl #endif
    692  1.58       dsl 			/* NOSTRICT */
    693  1.58       dsl 			_uintmax = (uintptr_t)va_arg(ap, void *);
    694  1.58       dsl 			base = HEX;
    695  1.58       dsl 			xdigs = "0123456789abcdef";
    696  1.58       dsl 			flags |= HEXPREFIX;
    697  1.58       dsl 			ch = 'x';
    698  1.58       dsl 			goto nosign;
    699  1.58       dsl 		case 's':
    700  1.58       dsl #ifdef POSITIONAL_PARAMS
    701  1.58       dsl 			if (positional > 0)
    702  1.58       dsl 				cp = parg[argnum]._pointer;
    703  1.58       dsl 			else
    704  1.58       dsl #endif
    705  1.58       dsl 			cp = va_arg(ap, char *);
    706  1.58       dsl 			if (cp == NULL)
    707  1.58       dsl 				cp = "(null)";
    708  1.58       dsl 			if (prec >= 0) {
    709  1.58       dsl 				/*
    710  1.58       dsl 				 * can't use strlen; can only look for the
    711  1.58       dsl 				 * NUL in the first `prec' characters, and
    712  1.58       dsl 				 * strlen() will go further.
    713  1.58       dsl 				 */
    714  1.58       dsl 				char *p = memchr(cp, 0, (size_t)prec);
    715  1.58       dsl 
    716  1.58       dsl 				if (p != NULL) {
    717  1.58       dsl 					size = p - cp;
    718  1.58       dsl 					if (size > prec)
    719  1.58       dsl 						size = prec;
    720  1.58       dsl 				} else
    721  1.58       dsl 					size = prec;
    722  1.58       dsl 			} else
    723  1.58       dsl 				size = strlen(cp);
    724  1.58       dsl 			sign = '\0';
    725  1.58       dsl 			break;
    726  1.58       dsl 		case 'U':
    727  1.58       dsl 			flags |= LONGINT;
    728  1.58       dsl 			/*FALLTHROUGH*/
    729  1.58       dsl 		case 'u':
    730  1.58       dsl #ifdef POSITIONAL_PARAMS
    731  1.58       dsl 			if (positional > 0)
    732  1.58       dsl 				_uintmax = parg[argnum]._uintmax;
    733  1.58       dsl 			else
    734  1.58       dsl #endif
    735  1.58       dsl 			_uintmax = UARG(flags, ap);
    736  1.58       dsl 			base = DEC;
    737  1.58       dsl 			goto nosign;
    738  1.58       dsl 		case 'X':
    739  1.58       dsl 			xdigs = "0123456789ABCDEF";
    740  1.58       dsl 			goto hex;
    741  1.58       dsl 		case 'x':
    742  1.58       dsl 			xdigs = "0123456789abcdef";
    743  1.58       dsl hex:
    744  1.58       dsl #ifdef POSITIONAL_PARAMS
    745  1.58       dsl 			if (positional > 0)
    746  1.58       dsl 				_uintmax = parg[argnum]._uintmax;
    747  1.58       dsl 			else
    748  1.58       dsl #endif
    749  1.58       dsl 			_uintmax = UARG(flags, ap);
    750  1.58       dsl 			base = HEX;
    751  1.58       dsl 			/* leading 0x/X only if non-zero */
    752  1.58       dsl 			if (flags & ALT && _uintmax != 0)
    753  1.58       dsl 				flags |= HEXPREFIX;
    754  1.58       dsl 
    755  1.58       dsl 			/* unsigned conversions */
    756  1.58       dsl nosign:			sign = '\0';
    757  1.58       dsl 			/*
    758  1.58       dsl 			 * ``... diouXx conversions ... if a precision is
    759  1.58       dsl 			 * specified, the 0 flag will be ignored.''
    760  1.58       dsl 			 *	-- ANSI X3J11
    761  1.58       dsl 			 */
    762  1.58       dsl number:			if ((dprec = prec) >= 0)
    763  1.58       dsl 				flags &= ~ZEROPAD;
    764  1.58       dsl 
    765  1.58       dsl 			/*
    766  1.58       dsl 			 * ``The result of converting a zero value with an
    767  1.58       dsl 			 * explicit precision of zero is no characters.''
    768  1.58       dsl 			 *	-- ANSI X3J11
    769  1.58       dsl 			 */
    770  1.58       dsl 			bp = buf + BUF;
    771  1.58       dsl 			if (_uintmax != 0 || prec != 0) {
    772  1.58       dsl 				/*
    773  1.58       dsl 				 * Unsigned mod is hard, and unsigned mod
    774  1.58       dsl 				 * by a constant is easier than that by
    775  1.58       dsl 				 * a variable; hence this switch.
    776  1.58       dsl 				 */
    777  1.58       dsl 				switch (base) {
    778  1.58       dsl 				case OCT:
    779  1.58       dsl 					do {
    780  1.58       dsl 						*--bp = to_char(_uintmax & 7);
    781  1.58       dsl 						_uintmax >>= 3;
    782  1.58       dsl 					} while (_uintmax);
    783  1.58       dsl 					/* handle octal leading 0 */
    784  1.58       dsl 					if (flags & ALT && *bp != '0')
    785  1.58       dsl 						*--bp = '0';
    786  1.58       dsl 					break;
    787  1.58       dsl 
    788  1.58       dsl 				case DEC:
    789  1.58       dsl 					/* many numbers are 1 digit */
    790  1.58       dsl 					while (_uintmax >= 10) {
    791  1.58       dsl 						*--bp = to_char(_uintmax % 10);
    792  1.58       dsl 						_uintmax /= 10;
    793  1.58       dsl 					}
    794  1.58       dsl 					*--bp = to_char(_uintmax);
    795  1.58       dsl 					break;
    796  1.58       dsl 
    797  1.58       dsl 				case HEX:
    798  1.58       dsl 					do {
    799  1.58       dsl 						*--bp = xdigs[(size_t)
    800  1.58       dsl 						    (_uintmax & 15)];
    801  1.58       dsl 						_uintmax >>= 4;
    802  1.58       dsl 					} while (_uintmax);
    803  1.58       dsl 					break;
    804  1.58       dsl 
    805  1.58       dsl 				default:
    806  1.58       dsl 					cp = "bug in vfprintf: bad base";
    807  1.58       dsl 					size = strlen(cp);
    808  1.58       dsl 					goto skipsize;
    809  1.58       dsl 				}
    810  1.58       dsl 			}
    811  1.58       dsl 			cp = bp;
    812  1.58       dsl 			size = buf + BUF - bp;
    813  1.58       dsl 		skipsize:
    814  1.58       dsl 			break;
    815  1.58       dsl 		default:	/* "%?" prints ?, unless ? is NUL */
    816  1.58       dsl invalid:
    817  1.58       dsl 			if (ch == '\0')
    818  1.58       dsl 				goto done;
    819  1.58       dsl 			/* Back up so we output all of the errorous format */
    820  1.58       dsl 			fmt = fmt0 + 1;
    821  1.58       dsl 			/* FALLTHROUGH */
    822  1.58       dsl 		case '%':
    823  1.58       dsl 			if (fmt != fmt0 + 2)
    824  1.58       dsl 				goto invalid;
    825  1.58       dsl 			/* Output a single '%' */
    826  1.58       dsl 			*buf = '%';
    827  1.58       dsl 			cp = buf;
    828  1.58       dsl 			size = 1;
    829  1.58       dsl 			sign = '\0';
    830  1.58       dsl 			width = 0;
    831  1.58       dsl 			prec = -1;
    832  1.58       dsl #ifdef POSITIONAL_PARAMS
    833  1.58       dsl 			argnum = 1;
    834  1.58       dsl #endif
    835  1.58       dsl 			break;
    836  1.58       dsl 		}
    837  1.58       dsl 
    838  1.58       dsl #ifdef POSITIONAL_PARAMS
    839  1.58       dsl 		if (argnum == 0) {
    840  1.58       dsl 			if (positional == 0)
    841  1.58       dsl 				positional = -1;
    842  1.58       dsl 			if (positional > 0)
    843  1.58       dsl 				goto invalid;
    844  1.58       dsl 		}
    845  1.58       dsl 		argnum = 0;
    846  1.58       dsl #endif
    847  1.58       dsl 
    848  1.58       dsl 		/*
    849  1.58       dsl 		 * All reasonable formats wind up here.  At this point, `cp'
    850  1.58       dsl 		 * points to a string which (if not flags&LADJUST) should be
    851  1.58       dsl 		 * padded out to `width' places.  If flags&ZEROPAD, it should
    852  1.58       dsl 		 * first be prefixed by any sign or other prefix; otherwise,
    853  1.58       dsl 		 * it should be blank padded before the prefix is emitted.
    854  1.58       dsl 		 * After any left-hand padding and prefixing, emit zeroes
    855  1.58       dsl 		 * required by a decimal [diouxX] precision, then print the
    856  1.58       dsl 		 * string proper, then emit zeroes required by any leftover
    857  1.58       dsl 		 * floating precision; finally, if LADJUST, pad with blanks.
    858  1.58       dsl 		 *
    859  1.58       dsl 		 * Compute actual size, so we know how much to pad.
    860  1.58       dsl 		 * size excludes decimal prec; realsz includes it.
    861  1.58       dsl 		 */
    862  1.58       dsl 		realsz = dprec > size ? dprec : size;
    863  1.58       dsl 		if (sign)
    864  1.58       dsl 			realsz++;
    865  1.58       dsl 		else if (flags & HEXPREFIX)
    866  1.58       dsl 			realsz+= 2;
    867  1.58       dsl 
    868  1.58       dsl 		/* right-adjusting blank padding */
    869  1.58       dsl 		if ((flags & (LADJUST|ZEROPAD)) == 0)
    870  1.58       dsl 			PAD(width - realsz, blanks);
    871  1.58       dsl 
    872  1.58       dsl 		/* prefix */
    873  1.58       dsl 		if (sign) {
    874  1.58       dsl 			PRINT(&sign, 1);
    875  1.58       dsl 		} else if (flags & HEXPREFIX) {
    876  1.58       dsl 			ox[0] = '0';
    877  1.58       dsl 			ox[1] = ch;
    878  1.58       dsl 			PRINT(ox, 2);
    879  1.58       dsl 		}
    880  1.58       dsl 
    881  1.58       dsl 		/* right-adjusting zero padding */
    882  1.58       dsl 		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
    883  1.58       dsl 			PAD(width - realsz, zeroes);
    884  1.58       dsl 
    885  1.58       dsl 		/* leading zeroes from decimal precision */
    886  1.58       dsl 		PAD(dprec - size, zeroes);
    887  1.58       dsl 
    888  1.58       dsl 		/* the string or number proper */
    889  1.58       dsl #ifndef NO_FLOATING_POINT
    890  1.58       dsl 		if ((flags & FPT) == 0) {
    891  1.58       dsl 			PRINT(cp, size);
    892  1.58       dsl 		} else {	/* glue together f_p fragments */
    893  1.58       dsl 			if (ch >= 'f') {	/* 'f' or 'g' */
    894  1.58       dsl 				if (decimal_point == NULL)
    895  1.58       dsl 					decimal_point =
    896  1.58       dsl 					    localeconv()->decimal_point;
    897  1.58       dsl 				if (_double == 0) {
    898  1.58       dsl 					/* kludge for __dtoa irregularity */
    899  1.58       dsl 					PRINT("0", 1);
    900  1.58       dsl 					if (expt < ndig || (flags & ALT) != 0) {
    901  1.58       dsl 						PRINT(decimal_point, 1);
    902  1.58       dsl 						PAD(ndig - 1, zeroes);
    903  1.58       dsl 					}
    904  1.58       dsl 				} else if (expt <= 0) {
    905  1.58       dsl 					PRINT("0", 1);
    906  1.58       dsl 					PRINT(decimal_point, 1);
    907  1.58       dsl 					PAD(-expt, zeroes);
    908  1.58       dsl 					PRINT(cp, ndig);
    909  1.58       dsl 				} else if (expt >= ndig) {
    910  1.58       dsl 					PRINT(cp, ndig);
    911  1.58       dsl 					PAD(expt - ndig, zeroes);
    912  1.58       dsl 					if (flags & ALT)
    913  1.58       dsl 						PRINT(".", 1);
    914  1.58       dsl 				} else {
    915  1.58       dsl 					PRINT(cp, expt);
    916  1.58       dsl 					cp += expt;
    917  1.58       dsl 					PRINT(".", 1);
    918  1.58       dsl 					PRINT(cp, ndig-expt);
    919  1.58       dsl 				}
    920  1.58       dsl 			} else {	/* 'e' or 'E' */
    921  1.58       dsl 				if (ndig > 1 || flags & ALT) {
    922  1.58       dsl 					ox[0] = *cp++;
    923  1.58       dsl 					ox[1] = '.';
    924  1.58       dsl 					PRINT(ox, 2);
    925  1.58       dsl 					if (_double) {
    926  1.58       dsl 						PRINT(cp, ndig-1);
    927  1.58       dsl 					} else	/* 0.[0..] */
    928  1.58       dsl 						/* __dtoa irregularity */
    929  1.58       dsl 						PAD(ndig - 1, zeroes);
    930  1.58       dsl 				} else	/* XeYYY */
    931  1.58       dsl 					PRINT(cp, 1);
    932  1.58       dsl 				PRINT(expstr, expsize);
    933  1.58       dsl 			}
    934  1.58       dsl 		}
    935  1.58       dsl #else
    936  1.58       dsl 		PRINT(cp, size);
    937  1.58       dsl #endif
    938  1.58       dsl 		/* left-adjusting padding (always blank) */
    939  1.58       dsl 		if (flags & LADJUST)
    940  1.58       dsl 			PAD(width - realsz, blanks);
    941  1.58       dsl 
    942  1.58       dsl 		/* finally, adjust ret */
    943  1.58       dsl 		ret += width > realsz ? width : realsz;
    944  1.58       dsl 
    945  1.58       dsl 		FLUSH();	/* copy out the I/O vectors */
    946  1.58       dsl 	}
    947  1.58       dsl done:
    948  1.58       dsl 	FLUSH();
    949  1.58       dsl error:
    950  1.58       dsl #ifndef NO_FLOATING_POINT
    951  1.58       dsl 	if (dtoaresult)
    952  1.58       dsl 		__freedtoa(dtoaresult);
    953  1.58       dsl #endif
    954  1.58       dsl 	if (__sferror(fp))
    955  1.58       dsl 		ret = -1;
    956  1.58       dsl 	return (ret);
    957  1.58       dsl }
    958  1.58       dsl 
    959  1.58       dsl #ifndef NO_FLOATING_POINT
    960  1.58       dsl 
    961  1.58       dsl static char *
    962  1.58       dsl cvt(value, ndigits, flags, sign, decpt, ch, length)
    963  1.58       dsl 	double value;
    964  1.58       dsl 	int ndigits, flags, *decpt, ch, *length;
    965  1.58       dsl 	char *sign;
    966  1.58       dsl {
    967  1.58       dsl 	int mode, dsgn;
    968  1.58       dsl 	char *digits, *bp, *rve;
    969  1.58       dsl 
    970  1.58       dsl 	_DIAGASSERT(decpt != NULL);
    971  1.58       dsl 	_DIAGASSERT(length != NULL);
    972  1.58       dsl 	_DIAGASSERT(sign != NULL);
    973  1.58       dsl 
    974  1.58       dsl 	if (ch == 'f') {
    975  1.58       dsl 		mode = 3;		/* ndigits after the decimal point */
    976  1.58       dsl 	} else {
    977  1.58       dsl 		/* To obtain ndigits after the decimal point for the 'e'
    978  1.58       dsl 		 * and 'E' formats, round to ndigits + 1 significant
    979  1.58       dsl 		 * figures.
    980  1.58       dsl 		 */
    981  1.58       dsl 		if (ch == 'e' || ch == 'E') {
    982  1.58       dsl 			ndigits++;
    983  1.58       dsl 		}
    984  1.58       dsl 		mode = 2;		/* ndigits significant digits */
    985  1.58       dsl 	}
    986  1.58       dsl 
    987  1.58       dsl 	digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
    988  1.58       dsl 	if (dsgn) {
    989  1.58       dsl 		value = -value;
    990  1.58       dsl 		*sign = '-';
    991  1.58       dsl 	} else
    992  1.58       dsl 		*sign = '\000';
    993  1.58       dsl 	if ((ch != 'g' && ch != 'G') || flags & ALT) {	/* Print trailing zeros */
    994  1.58       dsl 		bp = digits + ndigits;
    995  1.58       dsl 		if (ch == 'f') {
    996  1.58       dsl 			if (*digits == '0' && value)
    997  1.58       dsl 				*decpt = -ndigits + 1;
    998  1.58       dsl 			bp += *decpt;
    999  1.58       dsl 		}
   1000  1.58       dsl 		if (value == 0)	/* kludge for __dtoa irregularity */
   1001  1.58       dsl 			rve = bp;
   1002  1.58       dsl 		while (rve < bp)
   1003  1.58       dsl 			*rve++ = '0';
   1004  1.58       dsl 	}
   1005  1.58       dsl 	*length = rve - digits;
   1006  1.58       dsl 	return (digits);
   1007  1.58       dsl }
   1008  1.58       dsl 
   1009  1.58       dsl static int
   1010  1.58       dsl exponent(p0, expon, fmtch)
   1011  1.58       dsl 	char *p0;
   1012  1.58       dsl 	int expon, fmtch;
   1013  1.58       dsl {
   1014  1.58       dsl 	char *p, *t;
   1015  1.58       dsl 	char expbuf[MAXEXP];
   1016  1.58       dsl 
   1017  1.58       dsl 	_DIAGASSERT(p0 != NULL);
   1018  1.58       dsl 
   1019  1.58       dsl 	p = p0;
   1020  1.58       dsl 	*p++ = fmtch;
   1021  1.58       dsl 	if (expon < 0) {
   1022  1.58       dsl 		expon = -expon;
   1023  1.58       dsl 		*p++ = '-';
   1024  1.58       dsl 	}
   1025  1.58       dsl 	else
   1026  1.58       dsl 		*p++ = '+';
   1027  1.58       dsl 	t = expbuf + MAXEXP;
   1028  1.58       dsl 	if (expon > 9) {
   1029  1.58       dsl 		do {
   1030  1.58       dsl 			*--t = to_char(expon % 10);
   1031  1.58       dsl 		} while ((expon /= 10) > 9);
   1032  1.58       dsl 		*--t = to_char(expon);
   1033  1.58       dsl 		for (; t < expbuf + MAXEXP; *p++ = *t++);
   1034  1.58       dsl 	}
   1035  1.58       dsl 	else {
   1036  1.58       dsl 		*p++ = '0';
   1037  1.58       dsl 		*p++ = to_char(expon);
   1038  1.58       dsl 	}
   1039  1.58       dsl 	return (p - p0);
   1040  1.58       dsl }
   1041  1.58       dsl #endif /* NO_FLOATING_POINT */
   1042  1.58       dsl 
   1043  1.58       dsl #ifdef POSITIONAL_PARAMS
   1044  1.58       dsl static void parse_fmt(union parg *, const char *);
   1045  1.58       dsl 
   1046  1.58       dsl static void
   1047  1.58       dsl set_printf_args(union parg *arg, const char *fmt, _BSD_VA_LIST_ ap)
   1048  1.58       dsl {
   1049  1.58       dsl 	int flags;
   1050  1.58       dsl 	int i;
   1051  1.58       dsl 
   1052  1.58       dsl 	/*
   1053  1.58       dsl 	 * In order to set ap so that the n'th argument can be picked next
   1054  1.58       dsl 	 * we have to know the type of all the arguments.
   1055  1.58       dsl 	 */
   1056  1.58       dsl 	parse_fmt(arg, fmt);
   1057  1.58       dsl 
   1058  1.58       dsl 	/* Now walk ap along the arguments saving the values */
   1059  1.58       dsl 	for (i = 1; i <= NL_ARGMAX; i++) {
   1060  1.58       dsl 		flags = arg[i].flags;
   1061  1.58       dsl 		if (flags == 0)
   1062  1.58       dsl 			/* arg not used in format */
   1063  1.58       dsl 			break;
   1064  1.58       dsl 		if (flags & POINTER) {
   1065  1.58       dsl 			if (flags & CHARINT)
   1066  1.58       dsl 				arg[i]._pointer = va_arg(ap, char *);
   1067  1.58       dsl 			else
   1068  1.58       dsl 				arg[i]._pointer = va_arg(ap, void *);
   1069  1.58       dsl 			continue;
   1070  1.58       dsl 		}
   1071  1.58       dsl 		if (flags & FPT) {
   1072  1.58       dsl 			if (flags & LONGDBL)
   1073  1.58       dsl 				arg[i]._double = va_arg(ap, long double);
   1074  1.58       dsl 			else
   1075  1.58       dsl 				arg[i]._double = va_arg(ap, double);
   1076  1.58       dsl 			continue;
   1077  1.58       dsl 		}
   1078  1.58       dsl 		if (flags & SIGNED)
   1079  1.58       dsl 			arg[i]._uintmax = SARG(flags, ap);
   1080  1.58       dsl 		else
   1081  1.58       dsl 			arg[i]._uintmax = UARG(flags, ap);
   1082  1.58       dsl 	}
   1083  1.58       dsl 	return;
   1084  1.58       dsl }
   1085  1.58       dsl 
   1086  1.58       dsl static void
   1087  1.58       dsl parse_fmt(union parg *arg, const char *fmt)
   1088  1.58       dsl {
   1089  1.58       dsl 	int argnum;
   1090  1.58       dsl 	int flags;
   1091  1.58       dsl 	int n;
   1092  1.58       dsl 	char ch;
   1093  1.58       dsl 	wchar_t wc;
   1094  1.58       dsl 	mbstate_t ps;
   1095  1.58       dsl 
   1096  1.58       dsl 	mbrtowc(NULL, NULL, 0, &ps);
   1097  1.58       dsl 
   1098  1.58       dsl 	for (;;) {
   1099  1.58       dsl 		do {
   1100  1.58       dsl 			n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps);
   1101  1.58       dsl 			if (n <= 0)
   1102  1.58       dsl 				return;
   1103  1.58       dsl 			fmt += n;
   1104  1.58       dsl 		} while (wc != '%');
   1105  1.58       dsl 		/* Positional formats all start "%n$" */
   1106  1.58       dsl 		ch = *fmt++;
   1107  1.58       dsl 		if (ch < '1' || ch > '9' || *fmt != '$')
   1108  1.58       dsl 			continue;
   1109  1.58       dsl 		fmt++;
   1110  1.58       dsl 		argnum = to_digit(ch);
   1111  1.58       dsl 		flags = ALT;	/* something non-zero that doesn't matter */
   1112  1.58       dsl 		for (;;) {
   1113  1.58       dsl 			ch = *fmt++;
   1114  1.58       dsl 			switch (ch) {
   1115  1.58       dsl 			case ' ':	continue;
   1116  1.58       dsl 			case '#':	continue;
   1117  1.58       dsl 			case '-':	continue;
   1118  1.58       dsl 			case '+':	continue;
   1119  1.58       dsl 			case '*':	continue;
   1120  1.58       dsl 			case '0':	continue;
   1121  1.58       dsl 			case '.':	continue;
   1122  1.58       dsl 			case 'h':	flags |= SHORTINT;	continue;
   1123  1.58       dsl 			case 'j':	flags |= MAXINT;	continue;
   1124  1.58       dsl #ifdef FLOATING_POINT
   1125  1.58       dsl 			case 'L':	flags |= LONGDBL;	continue;
   1126  1.58       dsl #endif
   1127  1.58       dsl 			case 'q':	flags |= QUADINT;	continue;
   1128  1.58       dsl 			case 't':	flags |= PTRINT;	continue;
   1129  1.58       dsl 			case 'z':	flags |= SIZEINT;	continue;
   1130  1.58       dsl 			case 'l':
   1131  1.58       dsl 				if (fmt[0] == 'l') {
   1132  1.58       dsl 					fmt++;
   1133  1.58       dsl 					flags |= QUADINT;
   1134  1.58       dsl 				} else
   1135  1.58       dsl 					flags |= LONGINT;
   1136  1.58       dsl 				continue;
   1137  1.58       dsl 			case '1': case '2': case '3': case '4':
   1138  1.58       dsl 			case '5': case '6': case '7': case '8': case '9':
   1139  1.58       dsl 				if (*fmt == '$') {
   1140  1.58       dsl 					fmt++;
   1141  1.58       dsl 					arg[to_digit(ch)].flags = SIGNED;
   1142  1.58       dsl 				}
   1143  1.58       dsl 				continue;
   1144  1.58       dsl 			case 'D':
   1145  1.58       dsl 				flags |= LONGINT | SIGNED;
   1146  1.58       dsl 				break;
   1147  1.58       dsl 			case 'O': case 'U':
   1148  1.58       dsl 				flags |= LONGINT;
   1149  1.58       dsl 				break;
   1150  1.58       dsl 			case 'd': case 'i':
   1151  1.58       dsl 				flags |= SIGNED;
   1152  1.58       dsl 				break;
   1153  1.58       dsl 			case 'c': case 'o': case 'u': case 'X': case 'x':
   1154  1.58       dsl 				break;
   1155  1.58       dsl #ifdef FLOATING_POINT
   1156  1.58       dsl 			case 'e': case 'f': case 'g':
   1157  1.58       dsl 			case 'E': case 'F': case 'G':
   1158  1.58       dsl 				flags |= FPT;
   1159  1.58       dsl 				break;
   1160  1.58       dsl #endif /* FLOATING_POINT */
   1161  1.58       dsl 			case 's':
   1162  1.58       dsl 				flags |= CHARINT | POINTER;
   1163  1.58       dsl 				break;
   1164  1.58       dsl 			case 'n': case 'p':
   1165  1.58       dsl 				flags |= POINTER;
   1166  1.58       dsl 				break;
   1167  1.58       dsl 			default:
   1168  1.58       dsl 				/* Unexpected end of format */
   1169  1.58       dsl 				if (ch == 0)
   1170  1.58       dsl 					return;
   1171  1.58       dsl 				ch = 0;
   1172  1.58       dsl 				break;
   1173  1.58       dsl 			}
   1174  1.58       dsl 			if (argnum != 0)
   1175  1.58       dsl 				arg[argnum].flags = flags;
   1176  1.58       dsl 			break;
   1177  1.58       dsl 		}
   1178  1.58       dsl 	}
   1179  1.58       dsl }
   1180  1.58       dsl #endif
   1181  1.58       dsl #endif
   1182  1.57  christos #define NARROW
   1183  1.57  christos #include "vfwprintf.c"
   1184