summaryrefslogtreecommitdiff
path: root/lib/libc/stdio/vfprintf.c
diff options
context:
space:
mode:
authordsl <dsl@NetBSD.org>2009-10-15 06:19:35 +0000
committerdsl <dsl@NetBSD.org>2009-10-15 06:19:35 +0000
commit40f437887dff10be118e248ed59ea71966d6825b (patch)
treea84f755f26e39e4cacb2ae3eec2eab22cefd4f38 /lib/libc/stdio/vfprintf.c
parente91a07076b7d3a861641ac5068acea8b97b1395e (diff)
Reverse previous, committed by mistake.
Diffstat (limited to 'lib/libc/stdio/vfprintf.c')
-rw-r--r--lib/libc/stdio/vfprintf.c1181
1 files changed, 0 insertions, 1181 deletions
diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c
index 2e62aed9457..ae11e256f3b 100644
--- a/lib/libc/stdio/vfprintf.c
+++ b/lib/libc/stdio/vfprintf.c
@@ -1,1183 +1,2 @@
-#if 0
-/* Contains my POSITIONAL_PARAMS code */
-/* $NetBSD: vfprintf.c,v 1.58 2009/10/14 21:25:52 dsl Exp $ */
-
-/*-
- * Copyright (c) 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char *sccsid = "@(#)vfprintf.c 5.50 (Berkeley) 12/16/92";
-#else
-__RCSID("$NetBSD: vfprintf.c,v 1.58 2009/10/14 21:25:52 dsl Exp $");
-#endif
-#endif /* LIBC_SCCS and not lint */
-
-/*
- * Actual printf innards.
- *
- * This code is large and complicated...
- */
-
-#include "namespace.h"
-#include <sys/types.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
-
-#include "reentrant.h"
-#include "local.h"
-#include "fvwrite.h"
-#include "extern.h"
-
-#ifdef FLOATING_POINT
-#define POSITIONAL_PARAMS
-#endif
-
-static int __sprint __P((FILE *, struct __suio *));
-static int __sbprintf __P((FILE *, const char *, va_list))
- __attribute__((__format__(__printf__, 2, 0)));
-#ifdef POSITIONAL_PARAMS
-#define NL_ARGMAX 9 /* minimum required by IEEE Std 1003.1-2001 */
-
-union parg {
- int flags;
- uintmax_t _uintmax;
- void *_pointer;
- double _double;
-};
-static void set_printf_args(union parg *, const char *, _BSD_VA_LIST_);
-#endif
-
-/*
- * Flush out all the vectors defined by the given uio,
- * then reset it so that it can be reused.
- */
-/* NB: async-signal-safe when fp->_flags & __SAFE */
-static int
-__sprint(fp, uio)
- FILE *fp;
- struct __suio *uio;
-{
- int err;
-
- _DIAGASSERT(fp != NULL);
- _DIAGASSERT(uio != NULL);
-
- if (uio->uio_resid == 0) {
- uio->uio_iovcnt = 0;
- return (0);
- }
- err = __sfvwrite(fp, uio);
- uio->uio_resid = 0;
- uio->uio_iovcnt = 0;
- return (err);
-}
-
-/*
- * Helper function for `fprintf to unbuffered unix file': creates a
- * temporary buffer. We only work on write-only files; this avoids
- * worries about ungetc buffers and so forth.
- */
-static int
-__sbprintf(fp, fmt, ap)
- FILE *fp;
- const char *fmt;
- va_list ap;
-{
- int ret;
- FILE fake;
- struct __sfileext fakeext;
- unsigned char buf[BUFSIZ];
-
- _DIAGASSERT(fp != NULL);
- _DIAGASSERT(fmt != NULL);
-
- _FILEEXT_SETUP(&fake, &fakeext);
-
- /* copy the important variables */
- fake._flags = fp->_flags & ~__SNBF;
- fake._file = fp->_file;
- fake._cookie = fp->_cookie;
- fake._write = fp->_write;
-
- /* set up the buffer */
- fake._bf._base = fake._p = buf;
- fake._bf._size = fake._w = sizeof(buf);
- fake._lbfsize = 0; /* not actually used, but Just In Case */
-
- /* do the work, then copy any error status */
- ret = vfprintf(&fake, fmt, ap);
- if (ret >= 0 && fflush(&fake))
- ret = -1;
- if (fake._flags & __SERR)
- fp->_flags |= __SERR;
- return (ret);
-}
-
-
-#ifndef NO_FLOATING_POINT
-#include <locale.h>
-#include <math.h>
-#include "floatio.h"
-
-#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
-#define DEFPREC 6
-
-static char *cvt __P((double, int, int, char *, int *, int, int *));
-static int exponent __P((char *, int, int));
-
-#else /* FLOATING_POINT */
-
-#define BUF 40
-
-#endif /* NO_FLOATING_POINT */
-
-/*
- * Macros for converting digits to letters and vice versa
- */
-#define to_digit(c) ((c) - '0')
-#define is_digit(c) ((unsigned)to_digit(c) <= 9)
-#define to_char(n) ((char)((n) + '0'))
-
-/*
- * Flags used during conversion.
- */
-#define ALT 0x001 /* alternate form */
-#define HEXPREFIX 0x002 /* add 0x or 0X prefix */
-#define LADJUST 0x004 /* left adjustment */
-#define LONGDBL 0x008 /* long double; unimplemented */
-#define LONGINT 0x010 /* long integer */
-#define QUADINT 0x020 /* quad integer */
-#define SHORTINT 0x040 /* short integer */
-#define MAXINT 0x080 /* (unsigned) intmax_t */
-#define PTRINT 0x100 /* (unsigned) ptrdiff_t */
-#define SIZEINT 0x200 /* (signed) size_t */
-#define ZEROPAD 0x400 /* zero (as opposed to blank) pad */
-#define FPT 0x800 /* Floating point number */
-#ifdef POSITIONAL_PARAMS
-#define POINTER 0x10000 /* Pointer to something */
-#define SIGNED 0x20000 /* signed value */
-#define CHARINT 0x40000 /* move above when %hhd implemented */
-#endif
-
-int
-vfprintf(fp, fmt0, ap)
- FILE *fp;
- const char *fmt0;
- _BSD_VA_LIST_ ap;
-{
- int ret;
-
- FLOCKFILE(fp);
- ret = __vfprintf_unlocked(fp, fmt0, ap);
- FUNLOCKFILE(fp);
-
- return ret;
-}
-
-
-
-/* NB: async-signal-safe when fp->_flags & __SAFE */
-int
-__vfprintf_unlocked(fp, fmt0, ap)
- FILE *fp;
- const char *fmt0;
- _BSD_VA_LIST_ ap;
-{
- const char *fmt;/* format string */
- int ch; /* character from fmt */
- int n, m; /* handy integers (short term usage) */
- const char *cp; /* handy char pointer (short term usage) */
- char *bp; /* handy char pointer (short term usage) */
- struct __siov *iovp;/* for PRINT macro */
- int flags; /* flags as above */
- int ret; /* return value accumulator */
- int width; /* width from format (%8d), or 0 */
- int prec; /* precision from format (%.3d), or -1 */
- char sign; /* sign prefix (' ', '+', '-', or \0) */
- wchar_t wc;
- mbstate_t ps;
-#ifndef NO_FLOATING_POINT
- char *decimal_point = NULL;
- char softsign; /* temporary negative sign for floats */
- double _double; /* double precision arguments %[eEfgG] */
- int expt; /* integer value of exponent */
- int expsize = 0; /* character count for expstr */
- int ndig; /* actual number of digits returned by cvt */
- char expstr[7]; /* buffer for exponent string */
- char *dtoaresult = NULL;
-#endif
-
-#ifdef __GNUC__ /* gcc has builtin quad type (long long) SOS */
-#define quad_t long long
-#define u_quad_t unsigned long long
-#endif
-
-#define INTMAX_T intmax_t
-#define UINTMAX_T uintmax_t
-
- UINTMAX_T _uintmax; /* integer arguments %[diouxX] */
- enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
- int dprec; /* a copy of prec if [diouxX], 0 otherwise */
- int realsz; /* field size expanded by dprec */
- int size; /* size of converted field or string */
- const char *xdigs = NULL;/* digits for [xX] conversion */
-#define NIOV 8
- struct __suio uio; /* output information: summary */
- struct __siov iov[NIOV];/* ... and individual io vectors */
- char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
- char ox[2]; /* space for 0x hex-prefix */
-
- /*
- * Choose PADSIZE to trade efficiency vs. size. If larger printf
- * fields occur frequently, increase PADSIZE and make the initialisers
- * below longer.
- */
-#define PADSIZE 16 /* pad chunk size */
- static const char blanks[PADSIZE] =
- {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
- static const char zeroes[PADSIZE] =
- {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
-#ifdef POSITIONAL_PARAMS /* %n$... */
- union parg parg[1 + NL_ARGMAX];
- int positional = 0;
- int argnum = 0;
-
- memset(&parg, 0, sizeof parg);
-#endif
-
- /*
- * BEWARE, these `goto error' on error, and PAD uses `n'.
- */
-#define PRINT(ptr, len) do { \
- iovp->iov_base = __UNCONST(ptr); \
- iovp->iov_len = (len); \
- uio.uio_resid += (len); \
- iovp++; \
- if (++uio.uio_iovcnt >= NIOV) { \
- if (__sprint(fp, &uio)) \
- goto error; \
- iovp = iov; \
- } \
-} while (/*CONSTCOND*/0)
-
-#define PAD(howmany, with) do { \
- if ((n = (howmany)) > 0) { \
- while (n > PADSIZE) { \
- PRINT(with, PADSIZE); \
- n -= PADSIZE; \
- } \
- PRINT(with, n); \
- } \
-} while (/*CONSTCOND*/0)
-
-#define FLUSH() do { \
- if (uio.uio_resid && __sprint(fp, &uio)) \
- goto error; \
- uio.uio_iovcnt = 0; \
- iovp = iov; \
-} while (/*CONSTCOND*/0)
-
- /*
- * To extend shorts properly, we need both signed and unsigned
- * argument extraction methods.
- */
-#define SARG(flags, ap) \
- (flags&MAXINT ? va_arg(ap, intmax_t) : \
- flags&PTRINT ? va_arg(ap, ptrdiff_t) : \
- flags&SIZEINT ? va_arg(ap, ssize_t) : /* XXX */ \
- flags&QUADINT ? va_arg(ap, quad_t) : \
- flags&LONGINT ? va_arg(ap, long) : \
- flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
- (long)va_arg(ap, int))
-#define UARG(flags, ap) \
- (flags&MAXINT ? va_arg(ap, uintmax_t) : \
- flags&PTRINT ? va_arg(ap, uintptr_t) : /* XXX */ \
- flags&SIZEINT ? va_arg(ap, size_t) : \
- flags&QUADINT ? va_arg(ap, u_quad_t) : \
- flags&LONGINT ? va_arg(ap, u_long) : \
- flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
- (u_long)va_arg(ap, u_int))
-
- _DIAGASSERT(fp != NULL);
- _DIAGASSERT(fmt0 != NULL);
-
- _SET_ORIENTATION(fp, -1);
-
- /* sorry, fprintf(read_only_file, "") returns -1, not 0 */
- if (cantwrite(fp)) {
- errno = EBADF;
- return (-1);
- }
-
- /* optimise fprintf(stderr) (and other unbuffered Unix files) */
- if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
- fp->_file >= 0) {
- ret = __sbprintf(fp, fmt0, ap);
- return (ret);
- }
-
- fmt = fmt0;
- uio.uio_iov = iovp = iov;
- uio.uio_resid = 0;
- uio.uio_iovcnt = 0;
- ret = 0;
-
- memset(&ps, 0, sizeof(ps));
-
- /*
- * Scan the format for conversions (`%' character).
- */
- for (;;) {
- cp = fmt;
- if (fp->_flags & __SAFE) {
- for (; *fmt && *fmt != '%'; fmt++)
- continue;
- n = *fmt == '%';
- } else {
- while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
- fmt += n;
- if (wc == '%') {
- fmt--;
- break;
- }
- }
- }
- if ((m = fmt - cp) != 0) {
- PRINT(cp, m);
- ret += m;
- }
- if (n <= 0)
- goto done;
- fmt0 = fmt; /* save pointer to the '%' */
- fmt++; /* skip over '%' */
-
- flags = 0;
- dprec = 0;
- width = 0;
- prec = -1;
- sign = '\0';
-
-#ifdef POSITIONAL_PARAMS
- ch = *fmt;
- if (is_digit(ch) && fmt[1] == '$' && positional >= 0) {
- fmt += 2;
- if (positional == 0) {
- set_printf_args(parg, fmt0, ap);
- positional = 1;
- }
- argnum = to_digit(ch);
- }
-#endif
-
-
-rflag: ch = *fmt++;
-reswitch: switch (ch) {
- case ' ':
- /*
- * ``If the space and + flags both appear, the space
- * flag will be ignored.''
- * -- ANSI X3J11
- */
- if (!sign)
- sign = ' ';
- goto rflag;
- case '#':
- flags |= ALT;
- goto rflag;
- case '*':
-#ifdef POSITIONAL_PARAMS
- if (positional > 0) {
- ch = *fmt++;
- if (!is_digit(ch))
- goto invalid;
- n = to_digit(ch);
- ch = *fmt++;
- if (n == 0 || ch != '$')
- goto invalid;
- width = (int)parg[n]._uintmax;
- } else
-#endif
- width = va_arg(ap, int);
- /*
- * ``A negative field width argument is taken as a
- * - flag followed by a positive field width.''
- * -- ANSI X3J11
- * They don't exclude field widths read from args.
- */
- if (width >= 0)
- goto rflag;
- width = -width;
- /* FALLTHROUGH */
- case '-':
- flags |= LADJUST;
- goto rflag;
- case '+':
- sign = '+';
- goto rflag;
- case '.':
- if ((ch = *fmt++) == '*') {
-#ifdef POSITIONAL_PARAMS
- if (positional > 0) {
- ch = *fmt++;
- if (!is_digit(ch))
- goto invalid;
- n = to_digit(ch);
- ch = *fmt++;
- if (n == 0 || ch != '$')
- goto invalid;
- n = (int)parg[n]._uintmax;
- } else
-#endif
- n = va_arg(ap, int);
- prec = n < 0 ? -1 : n;
- goto rflag;
- }
- n = 0;
- while (is_digit(ch)) {
- n = 10 * n + to_digit(ch);
- ch = *fmt++;
- }
- prec = n < 0 ? -1 : n;
- goto reswitch;
- case '0':
- /*
- * ``Note that 0 is taken as a flag, not as the
- * beginning of a field width.''
- * -- ANSI X3J11
- */
- flags |= ZEROPAD;
- goto rflag;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- n = 0;
- do {
- n = 10 * n + to_digit(ch);
- ch = *fmt++;
- } while (is_digit(ch));
- width = n;
- goto reswitch;
-#ifndef NO_FLOATING_POINT
- case 'L':
- flags |= LONGDBL;
- goto rflag;
-#endif
- case 'h':
- flags |= SHORTINT;
- goto rflag;
- case 'j':
- flags |= MAXINT;
- goto rflag;
- case 'l':
- if (*fmt == 'l') {
- fmt++;
- flags |= QUADINT;
- } else {
- flags |= LONGINT;
- }
- goto rflag;
- case 'q':
- flags |= QUADINT;
- goto rflag;
- case 't':
- flags |= PTRINT;
- goto rflag;
- case 'z':
- flags |= SIZEINT;
- goto rflag;
- case 'c':
-#ifdef POSITIONAL_PARAMS
- if (positional > 0)
- *buf = (int)parg[argnum]._uintmax;
- else
-#endif
- *buf = va_arg(ap, int);
- cp = buf;
- size = 1;
- sign = '\0';
- break;
- case 'D':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'd':
- case 'i':
-#ifdef POSITIONAL_PARAMS
- if (positional > 0)
- _uintmax = parg[argnum]._uintmax;
- else
-#endif
- _uintmax = SARG(flags, ap);
- if ((intmax_t)_uintmax < 0) {
- _uintmax = -_uintmax;
- sign = '-';
- }
- base = DEC;
- goto number;
-#ifndef NO_FLOATING_POINT
- case 'e':
- case 'E':
- case 'f':
- case 'F':
- case 'g':
- case 'G':
- if (prec == -1) {
- prec = DEFPREC;
- } else if ((ch == 'g' || ch == 'G') && prec == 0) {
- prec = 1;
- }
-
-#ifdef POSITIONAL_PARAMS
- if (positional > 0)
- _double = parg[argnum]._double;
- else
-#endif
- if (flags & LONGDBL) {
- _double = (double) va_arg(ap, long double);
- } else {
- _double = va_arg(ap, double);
- }
-
- /* do this before tricky precision changes */
- if (isinf(_double)) {
- if (_double < 0)
- sign = '-';
- if (ch == 'E' || ch == 'F' || ch == 'G')
- cp = "INF";
- else
- cp = "inf";
- size = 3;
- break;
- }
- if (isnan(_double)) {
- if (ch == 'E' || ch == 'F' || ch == 'G')
- cp = "NAN";
- else
- cp = "nan";
- size = 3;
- break;
- }
- if (fp->_flags & __SAFE) {
- if (ch == 'E' || ch == 'F' || ch == 'G')
- cp = "UNK";
- else
- cp = "unk";
- size = 3;
- break;
- }
-
- flags |= FPT;
- if (dtoaresult)
- __freedtoa(dtoaresult);
- cp = dtoaresult = cvt(_double, prec, flags, &softsign,
- &expt, ch, &ndig);
- if (ch == 'g' || ch == 'G') {
- if (expt <= -4 || expt > prec)
- ch = (ch == 'g') ? 'e' : 'E';
- else
- ch = 'g';
- }
- if (ch == 'e' || ch == 'E') {
- --expt;
- expsize = exponent(expstr, expt, ch);
- size = expsize + ndig;
- if (ndig > 1 || flags & ALT)
- ++size;
- } else if (ch == 'f' || ch == 'F') {
- if (expt > 0) {
- size = expt;
- if (prec || flags & ALT)
- size += prec + 1;
- } else /* "0.X" */
- size = prec + 2;
- } else if (expt >= ndig) { /* fixed g fmt */
- size = expt;
- if (flags & ALT)
- ++size;
- } else
- size = ndig + (expt > 0 ?
- 1 : 2 - expt);
-
- if (softsign)
- sign = '-';
- break;
-#endif /* NO_FLOATING_POINT */
- case 'n':
-#ifdef POSITIONAL_PARAMS
- if (positional > 0)
- /*
- * This could be implemented, but it stinks
- * of a security risk.
- */
- PRINT("(%n unassigned)", 15);
- else
-#endif
- if (flags & MAXINT)
- *va_arg(ap, intmax_t *) = ret;
- else if (flags & PTRINT)
- *va_arg(ap, ptrdiff_t *) = ret;
- else if (flags & SIZEINT)
- *va_arg(ap, ssize_t *) = ret; /* XXX */
- else if (flags & QUADINT)
- *va_arg(ap, quad_t *) = ret;
- else if (flags & LONGINT)
- *va_arg(ap, long *) = ret;
- else if (flags & SHORTINT)
- *va_arg(ap, short *) = ret;
- else
- *va_arg(ap, int *) = ret;
- continue; /* no output */
- case 'O':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'o':
-#ifdef POSITIONAL_PARAMS
- if (positional > 0)
- _uintmax = parg[argnum]._uintmax;
- else
-#endif
- _uintmax = UARG(flags, ap);
- base = OCT;
- goto nosign;
- case 'p':
- /*
- * ``The argument shall be a pointer to void. The
- * value of the pointer is converted to a sequence
- * of printable characters, in an implementation-
- * defined manner.''
- * -- ANSI X3J11
- */
-#ifdef POSITIONAL_PARAMS
- if (positional > 0)
- _uintmax = (uintptr_t)parg[argnum]._pointer;
- else
-#endif
- /* NOSTRICT */
- _uintmax = (uintptr_t)va_arg(ap, void *);
- base = HEX;
- xdigs = "0123456789abcdef";
- flags |= HEXPREFIX;
- ch = 'x';
- goto nosign;
- case 's':
-#ifdef POSITIONAL_PARAMS
- if (positional > 0)
- cp = parg[argnum]._pointer;
- else
-#endif
- cp = va_arg(ap, char *);
- if (cp == NULL)
- cp = "(null)";
- if (prec >= 0) {
- /*
- * can't use strlen; can only look for the
- * NUL in the first `prec' characters, and
- * strlen() will go further.
- */
- char *p = memchr(cp, 0, (size_t)prec);
-
- if (p != NULL) {
- size = p - cp;
- if (size > prec)
- size = prec;
- } else
- size = prec;
- } else
- size = strlen(cp);
- sign = '\0';
- break;
- case 'U':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'u':
-#ifdef POSITIONAL_PARAMS
- if (positional > 0)
- _uintmax = parg[argnum]._uintmax;
- else
-#endif
- _uintmax = UARG(flags, ap);
- base = DEC;
- goto nosign;
- case 'X':
- xdigs = "0123456789ABCDEF";
- goto hex;
- case 'x':
- xdigs = "0123456789abcdef";
-hex:
-#ifdef POSITIONAL_PARAMS
- if (positional > 0)
- _uintmax = parg[argnum]._uintmax;
- else
-#endif
- _uintmax = UARG(flags, ap);
- base = HEX;
- /* leading 0x/X only if non-zero */
- if (flags & ALT && _uintmax != 0)
- flags |= HEXPREFIX;
-
- /* unsigned conversions */
-nosign: sign = '\0';
- /*
- * ``... diouXx conversions ... if a precision is
- * specified, the 0 flag will be ignored.''
- * -- ANSI X3J11
- */
-number: if ((dprec = prec) >= 0)
- flags &= ~ZEROPAD;
-
- /*
- * ``The result of converting a zero value with an
- * explicit precision of zero is no characters.''
- * -- ANSI X3J11
- */
- bp = buf + BUF;
- if (_uintmax != 0 || prec != 0) {
- /*
- * Unsigned mod is hard, and unsigned mod
- * by a constant is easier than that by
- * a variable; hence this switch.
- */
- switch (base) {
- case OCT:
- do {
- *--bp = to_char(_uintmax & 7);
- _uintmax >>= 3;
- } while (_uintmax);
- /* handle octal leading 0 */
- if (flags & ALT && *bp != '0')
- *--bp = '0';
- break;
-
- case DEC:
- /* many numbers are 1 digit */
- while (_uintmax >= 10) {
- *--bp = to_char(_uintmax % 10);
- _uintmax /= 10;
- }
- *--bp = to_char(_uintmax);
- break;
-
- case HEX:
- do {
- *--bp = xdigs[(size_t)
- (_uintmax & 15)];
- _uintmax >>= 4;
- } while (_uintmax);
- break;
-
- default:
- cp = "bug in vfprintf: bad base";
- size = strlen(cp);
- goto skipsize;
- }
- }
- cp = bp;
- size = buf + BUF - bp;
- skipsize:
- break;
- default: /* "%?" prints ?, unless ? is NUL */
-invalid:
- if (ch == '\0')
- goto done;
- /* Back up so we output all of the errorous format */
- fmt = fmt0 + 1;
- /* FALLTHROUGH */
- case '%':
- if (fmt != fmt0 + 2)
- goto invalid;
- /* Output a single '%' */
- *buf = '%';
- cp = buf;
- size = 1;
- sign = '\0';
- width = 0;
- prec = -1;
-#ifdef POSITIONAL_PARAMS
- argnum = 1;
-#endif
- break;
- }
-
-#ifdef POSITIONAL_PARAMS
- if (argnum == 0) {
- if (positional == 0)
- positional = -1;
- if (positional > 0)
- goto invalid;
- }
- argnum = 0;
-#endif
-
- /*
- * All reasonable formats wind up here. At this point, `cp'
- * points to a string which (if not flags&LADJUST) should be
- * padded out to `width' places. If flags&ZEROPAD, it should
- * first be prefixed by any sign or other prefix; otherwise,
- * it should be blank padded before the prefix is emitted.
- * After any left-hand padding and prefixing, emit zeroes
- * required by a decimal [diouxX] precision, then print the
- * string proper, then emit zeroes required by any leftover
- * floating precision; finally, if LADJUST, pad with blanks.
- *
- * Compute actual size, so we know how much to pad.
- * size excludes decimal prec; realsz includes it.
- */
- realsz = dprec > size ? dprec : size;
- if (sign)
- realsz++;
- else if (flags & HEXPREFIX)
- realsz+= 2;
-
- /* right-adjusting blank padding */
- if ((flags & (LADJUST|ZEROPAD)) == 0)
- PAD(width - realsz, blanks);
-
- /* prefix */
- if (sign) {
- PRINT(&sign, 1);
- } else if (flags & HEXPREFIX) {
- ox[0] = '0';
- ox[1] = ch;
- PRINT(ox, 2);
- }
-
- /* right-adjusting zero padding */
- if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
- PAD(width - realsz, zeroes);
-
- /* leading zeroes from decimal precision */
- PAD(dprec - size, zeroes);
-
- /* the string or number proper */
-#ifndef NO_FLOATING_POINT
- if ((flags & FPT) == 0) {
- PRINT(cp, size);
- } else { /* glue together f_p fragments */
- if (ch >= 'f') { /* 'f' or 'g' */
- if (decimal_point == NULL)
- decimal_point =
- localeconv()->decimal_point;
- if (_double == 0) {
- /* kludge for __dtoa irregularity */
- PRINT("0", 1);
- if (expt < ndig || (flags & ALT) != 0) {
- PRINT(decimal_point, 1);
- PAD(ndig - 1, zeroes);
- }
- } else if (expt <= 0) {
- PRINT("0", 1);
- PRINT(decimal_point, 1);
- PAD(-expt, zeroes);
- PRINT(cp, ndig);
- } else if (expt >= ndig) {
- PRINT(cp, ndig);
- PAD(expt - ndig, zeroes);
- if (flags & ALT)
- PRINT(".", 1);
- } else {
- PRINT(cp, expt);
- cp += expt;
- PRINT(".", 1);
- PRINT(cp, ndig-expt);
- }
- } else { /* 'e' or 'E' */
- if (ndig > 1 || flags & ALT) {
- ox[0] = *cp++;
- ox[1] = '.';
- PRINT(ox, 2);
- if (_double) {
- PRINT(cp, ndig-1);
- } else /* 0.[0..] */
- /* __dtoa irregularity */
- PAD(ndig - 1, zeroes);
- } else /* XeYYY */
- PRINT(cp, 1);
- PRINT(expstr, expsize);
- }
- }
-#else
- PRINT(cp, size);
-#endif
- /* left-adjusting padding (always blank) */
- if (flags & LADJUST)
- PAD(width - realsz, blanks);
-
- /* finally, adjust ret */
- ret += width > realsz ? width : realsz;
-
- FLUSH(); /* copy out the I/O vectors */
- }
-done:
- FLUSH();
-error:
-#ifndef NO_FLOATING_POINT
- if (dtoaresult)
- __freedtoa(dtoaresult);
-#endif
- if (__sferror(fp))
- ret = -1;
- return (ret);
-}
-
-#ifndef NO_FLOATING_POINT
-
-static char *
-cvt(value, ndigits, flags, sign, decpt, ch, length)
- double value;
- int ndigits, flags, *decpt, ch, *length;
- char *sign;
-{
- int mode, dsgn;
- char *digits, *bp, *rve;
-
- _DIAGASSERT(decpt != NULL);
- _DIAGASSERT(length != NULL);
- _DIAGASSERT(sign != NULL);
-
- if (ch == 'f') {
- mode = 3; /* ndigits after the decimal point */
- } else {
- /* To obtain ndigits after the decimal point for the 'e'
- * and 'E' formats, round to ndigits + 1 significant
- * figures.
- */
- if (ch == 'e' || ch == 'E') {
- ndigits++;
- }
- mode = 2; /* ndigits significant digits */
- }
-
- digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
- if (dsgn) {
- value = -value;
- *sign = '-';
- } else
- *sign = '\000';
- if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */
- bp = digits + ndigits;
- if (ch == 'f') {
- if (*digits == '0' && value)
- *decpt = -ndigits + 1;
- bp += *decpt;
- }
- if (value == 0) /* kludge for __dtoa irregularity */
- rve = bp;
- while (rve < bp)
- *rve++ = '0';
- }
- *length = rve - digits;
- return (digits);
-}
-
-static int
-exponent(p0, expon, fmtch)
- char *p0;
- int expon, fmtch;
-{
- char *p, *t;
- char expbuf[MAXEXP];
-
- _DIAGASSERT(p0 != NULL);
-
- p = p0;
- *p++ = fmtch;
- if (expon < 0) {
- expon = -expon;
- *p++ = '-';
- }
- else
- *p++ = '+';
- t = expbuf + MAXEXP;
- if (expon > 9) {
- do {
- *--t = to_char(expon % 10);
- } while ((expon /= 10) > 9);
- *--t = to_char(expon);
- for (; t < expbuf + MAXEXP; *p++ = *t++);
- }
- else {
- *p++ = '0';
- *p++ = to_char(expon);
- }
- return (p - p0);
-}
-#endif /* NO_FLOATING_POINT */
-
-#ifdef POSITIONAL_PARAMS
-static void parse_fmt(union parg *, const char *);
-
-static void
-set_printf_args(union parg *arg, const char *fmt, _BSD_VA_LIST_ ap)
-{
- int flags;
- int i;
-
- /*
- * In order to set ap so that the n'th argument can be picked next
- * we have to know the type of all the arguments.
- */
- parse_fmt(arg, fmt);
-
- /* Now walk ap along the arguments saving the values */
- for (i = 1; i <= NL_ARGMAX; i++) {
- flags = arg[i].flags;
- if (flags == 0)
- /* arg not used in format */
- break;
- if (flags & POINTER) {
- if (flags & CHARINT)
- arg[i]._pointer = va_arg(ap, char *);
- else
- arg[i]._pointer = va_arg(ap, void *);
- continue;
- }
- if (flags & FPT) {
- if (flags & LONGDBL)
- arg[i]._double = va_arg(ap, long double);
- else
- arg[i]._double = va_arg(ap, double);
- continue;
- }
- if (flags & SIGNED)
- arg[i]._uintmax = SARG(flags, ap);
- else
- arg[i]._uintmax = UARG(flags, ap);
- }
- return;
-}
-
-static void
-parse_fmt(union parg *arg, const char *fmt)
-{
- int argnum;
- int flags;
- int n;
- char ch;
- wchar_t wc;
- mbstate_t ps;
-
- mbrtowc(NULL, NULL, 0, &ps);
-
- for (;;) {
- do {
- n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps);
- if (n <= 0)
- return;
- fmt += n;
- } while (wc != '%');
- /* Positional formats all start "%n$" */
- ch = *fmt++;
- if (ch < '1' || ch > '9' || *fmt != '$')
- continue;
- fmt++;
- argnum = to_digit(ch);
- flags = ALT; /* something non-zero that doesn't matter */
- for (;;) {
- ch = *fmt++;
- switch (ch) {
- case ' ': continue;
- case '#': continue;
- case '-': continue;
- case '+': continue;
- case '*': continue;
- case '0': continue;
- case '.': continue;
- case 'h': flags |= SHORTINT; continue;
- case 'j': flags |= MAXINT; continue;
-#ifdef FLOATING_POINT
- case 'L': flags |= LONGDBL; continue;
-#endif
- case 'q': flags |= QUADINT; continue;
- case 't': flags |= PTRINT; continue;
- case 'z': flags |= SIZEINT; continue;
- case 'l':
- if (fmt[0] == 'l') {
- fmt++;
- flags |= QUADINT;
- } else
- flags |= LONGINT;
- continue;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- if (*fmt == '$') {
- fmt++;
- arg[to_digit(ch)].flags = SIGNED;
- }
- continue;
- case 'D':
- flags |= LONGINT | SIGNED;
- break;
- case 'O': case 'U':
- flags |= LONGINT;
- break;
- case 'd': case 'i':
- flags |= SIGNED;
- break;
- case 'c': case 'o': case 'u': case 'X': case 'x':
- break;
-#ifdef FLOATING_POINT
- case 'e': case 'f': case 'g':
- case 'E': case 'F': case 'G':
- flags |= FPT;
- break;
-#endif /* FLOATING_POINT */
- case 's':
- flags |= CHARINT | POINTER;
- break;
- case 'n': case 'p':
- flags |= POINTER;
- break;
- default:
- /* Unexpected end of format */
- if (ch == 0)
- return;
- ch = 0;
- break;
- }
- if (argnum != 0)
- arg[argnum].flags = flags;
- break;
- }
- }
-}
-#endif
-#endif
#define NARROW
#include "vfwprintf.c"