summaryrefslogtreecommitdiff
path: root/StdLib/LibC/Stdio/vfwprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'StdLib/LibC/Stdio/vfwprintf.c')
-rw-r--r--StdLib/LibC/Stdio/vfwprintf.c2053
1 files changed, 0 insertions, 2053 deletions
diff --git a/StdLib/LibC/Stdio/vfwprintf.c b/StdLib/LibC/Stdio/vfwprintf.c
deleted file mode 100644
index f5cf3940f9..0000000000
--- a/StdLib/LibC/Stdio/vfwprintf.c
+++ /dev/null
@@ -1,2053 +0,0 @@
-/** @file
- Implementation of internals for printf and wprintf.
-
- Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
- This program and the accompanying materials are licensed and made available
- under the terms and conditions of the BSD License that accompanies this
- distribution. The full text of the license may be found at
- http://opensource.org/licenses/bsd-license.
-
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
- Copyright (c) 1990, 1993
- 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:
- - Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- - 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.
- - 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDERS 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.
-
- NetBSD: vfwprintf.c,v 1.9.2.1.4.1 2008/04/08 21:10:55 jdc Exp
- vfprintf.c 8.1 (Berkeley) 6/4/93
-**/
-#include <LibConfig.h>
-
-#include "namespace.h"
-#include <sys/types.h>
-
-#include <assert.h>
-#include <ctype.h>
-#include <limits.h>
-#include <locale.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <wchar.h>
-#include <wctype.h>
-
-#include "reentrant.h"
-#include "local.h"
-#include "extern.h"
-#include "fvwrite.h"
-
-#ifdef _MSC_VER
- // Keep compiler quiet about conversions from larger to smaller types.
- #pragma warning ( disable : 4244 )
-#endif
-
-#ifndef NARROW
-#define MCHAR_T char
-#define CHAR_T wchar_t
-#define STRLEN(a) wcslen(a)
-#define MEMCHR(a, b, c) wmemchr(a, b, c)
-#define SCONV(a, b) __mbsconv(a, b)
-#define STRCONST(a) L ## a
-#define WDECL(a, b) a ## w ## b
-#define END_OF_FILE WEOF
-#define MULTI 0
-#else
-#define MCHAR_T wchar_t
-#define CHAR_T char
-#define STRLEN(a) strlen(a)
-#define MEMCHR(a, b, c) memchr(a, b, c)
-#define SCONV(a, b) __wcsconv(a, b)
-#define STRCONST(a) a
-#define WDECL(a, b) a ## b
-#define END_OF_FILE EOF
-#define MULTI 1
-#endif
-
-union arg {
- int intarg;
- u_int uintarg;
- long longarg;
- unsigned long ulongarg;
- long long longlongarg;
- unsigned long long ulonglongarg;
- ptrdiff_t ptrdiffarg;
- size_t sizearg;
- intmax_t intmaxarg;
- uintmax_t uintmaxarg;
- void *pvoidarg;
- char *pchararg;
- signed char *pschararg;
- short *pshortarg;
- int *pintarg;
- long *plongarg;
- long long *plonglongarg;
- ptrdiff_t *pptrdiffarg;
- size_t *psizearg;
- intmax_t *pintmaxarg;
-#ifndef NO_FLOATING_POINT
- double doublearg;
- long double longdoublearg;
-#endif
- wint_t wintarg;
- wchar_t *pwchararg;
-};
-
-/*
- * Type ids for argument type table.
- */
-enum typeid {
- T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,
- T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG,
- TP_LLONG, T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET,
- T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR,
- TP_SCHAR, T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
-};
-
-static int __sbprintf(FILE *, const CHAR_T *, va_list);
-static CHAR_T *__ujtoa(uintmax_t, CHAR_T *, int, int, const char *, int,
- char, const char *);
-static CHAR_T *__ultoa(u_long, CHAR_T *, int, int, const char *, int,
- char, const char *);
-#ifndef NARROW
-static CHAR_T *__mbsconv(char *, int);
-static wint_t __xfputwc(CHAR_T, FILE *);
-#else
-static char *__wcsconv(wchar_t *, int);
-static int __sprint(FILE *, struct __suio *);
-#endif
-static int __find_arguments(const CHAR_T *, va_list, union arg **);
-static int __grow_type_table(int, enum typeid **, int *);
-
-/*
- * 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(FILE *fp, const CHAR_T *fmt, va_list ap)
-{
- int ret;
- FILE fake;
- struct __sfileext fakeext;
- unsigned char buf[BUFSIZ];
-
- _DIAGASSERT(fp != NULL);
- _DIAGASSERT(fmt != NULL);
- if(fp == NULL) {
- errno = EINVAL;
- return (EOF);
- }
-
- _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 = WDECL(__vf,printf_unlocked)(&fake, fmt, ap);
- if (ret >= 0 && fflush(&fake))
- ret = END_OF_FILE;
- if (fake._flags & __SERR)
- fp->_flags |= __SERR;
- return (ret);
-}
-
-#ifndef NARROW
-/*
- * Like __fputwc, but handles fake string (__SSTR) files properly.
- * File must already be locked.
- */
-static wint_t
-__xfputwc(wchar_t wc, FILE *fp)
-{
- static const mbstate_t initial = { 0 };
- mbstate_t mbs;
- char buf[MB_LEN_MAX];
- struct __suio uio;
- struct __siov iov;
- size_t len;
-
- if ((fp->_flags & __SSTR) == 0)
- return (__fputwc_unlock(wc, fp));
-
- mbs = initial;
- if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) {
- fp->_flags |= __SERR;
- return (END_OF_FILE);
- }
- uio.uio_iov = &iov;
- uio.uio_resid = (int)len;
- uio.uio_iovcnt = 1;
- iov.iov_base = buf;
- iov.iov_len = len;
- return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : END_OF_FILE);
-}
-#else
-/*
- * Flush out all the vectors defined by the given uio,
- * then reset it so that it can be reused.
- */
-static int
-__sprint(FILE *fp, struct __suio *uio)
-{
- int err;
-
- _DIAGASSERT(fp != NULL);
- _DIAGASSERT(uio != NULL);
- if(fp == NULL) {
- errno = EINVAL;
- return (EOF);
- }
-
- 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);
-}
-#endif
-
-/*
- * 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_T)((n) + '0')
-
-/*
- * Convert an unsigned long to ASCII for printf purposes, returning
- * a pointer to the first character of the string representation.
- * Octal numbers can be forced to have a leading zero; hex numbers
- * use the given digits.
- */
-static CHAR_T *
-__ultoa(u_long val, CHAR_T *endp, int base, int octzero, const char *xdigs,
- int needgrp, char thousep, const char *grp)
-{
- CHAR_T *cp = endp;
- LONGN sval;
- int ndig;
-
- /*
- * Handle the three cases separately, in the hope of getting
- * better/faster code.
- */
- switch (base) {
- case 10:
- if (val < 10) { /* many numbers are 1 digit */
- *--cp = to_char(val);
- return (cp);
- }
- ndig = 0;
- /*
- * On many machines, unsigned arithmetic is harder than
- * signed arithmetic, so we do at most one unsigned mod and
- * divide; this is sufficient to reduce the range of
- * the incoming value to where signed arithmetic works.
- */
- if (val > LONG_MAX) {
- *--cp = to_char(val % 10);
- ndig++;
- sval = (LONGN)(val / 10);
- } else
- sval = (LONGN)val;
- do {
- *--cp = to_char(sval % 10);
- ndig++;
- /*
- * If (*grp == CHAR_MAX) then no more grouping
- * should be performed.
- */
- if (needgrp && ndig == *grp && *grp != CHAR_MAX
- && sval > 9) {
- *--cp = thousep;
- ndig = 0;
- /*
- * If (*(grp+1) == '\0') then we have to
- * use *grp character (last grouping rule)
- * for all next cases
- */
- if (*(grp+1) != '\0')
- grp++;
- }
- sval /= 10;
- } while (sval != 0);
- break;
-
- case 8:
- do {
- *--cp = to_char(val & 7);
- val >>= 3;
- } while (val);
- if (octzero && *cp != '0')
- *--cp = '0';
- break;
-
- case 16:
- do {
- *--cp = xdigs[(size_t)val & 15];
- val >>= 4;
- } while (val);
- break;
-
- default: /* oops */
- abort();
- }
- return (cp);
-}
-
-/* Identical to __ultoa, but for intmax_t. */
-static CHAR_T *
-__ujtoa(uintmax_t val, CHAR_T *endp, int base, int octzero,
- const char *xdigs, int needgrp, char thousep, const char *grp)
-{
- CHAR_T *cp = endp;
- intmax_t sval;
- int ndig;
-
- /* quick test for small values; __ultoa is typically much faster */
- /* (perhaps instead we should run until small, then call __ultoa?) */
- if (val <= ULONG_MAX)
- return (__ultoa((u_long)val, endp, base, octzero, xdigs,
- needgrp, thousep, grp));
- switch (base) {
- case 10:
- if (val < 10) {
- *--cp = to_char(val % 10);
- return (cp);
- }
- ndig = 0;
- if (val > INTMAX_MAX) {
- *--cp = to_char(val % 10);
- ndig++;
- sval = val / 10;
- } else
- sval = val;
- do {
- *--cp = to_char(sval % 10);
- ndig++;
- /*
- * If (*grp == CHAR_MAX) then no more grouping
- * should be performed.
- */
- if (needgrp && *grp != CHAR_MAX && ndig == *grp
- && sval > 9) {
- *--cp = thousep;
- ndig = 0;
- /*
- * If (*(grp+1) == '\0') then we have to
- * use *grp character (last grouping rule)
- * for all next cases
- */
- if (*(grp+1) != '\0')
- grp++;
- }
- sval /= 10;
- } while (sval != 0);
- break;
-
- case 8:
- do {
- *--cp = to_char(val & 7);
- val >>= 3;
- } while (val);
- if (octzero && *cp != '0')
- *--cp = '0';
- break;
-
- case 16:
- do {
- *--cp = xdigs[(size_t)val & 15];
- val >>= 4;
- } while (val);
- break;
-
- default:
- abort();
- }
- return (cp);
-}
-
-#ifndef NARROW
-/*
- * Convert a multibyte character string argument for the %s format to a wide
- * string representation. ``prec'' specifies the maximum number of bytes
- * to output. If ``prec'' is greater than or equal to zero, we can't assume
- * that the multibyte char. string ends in a null character.
- */
-static wchar_t *
-__mbsconv(char *mbsarg, int prec)
-{
- static const mbstate_t initial = { 0 };
- mbstate_t mbs;
- wchar_t *convbuf, *wcp;
- const char *p;
- size_t insize, nchars, nconv;
-
- if (mbsarg == NULL)
- return (NULL);
-
- /*
- * Supplied argument is a multibyte string; convert it to wide
- * characters first.
- */
- if (prec >= 0) {
- /*
- * String is not guaranteed to be NUL-terminated. Find the
- * number of characters to print.
- */
- p = mbsarg;
- insize = nchars = nconv = 0;
- mbs = initial;
- while (nchars != (size_t)prec) {
- nconv = mbrlen(p, MB_CUR_MAX, &mbs);
- if (nconv == 0 || nconv == (size_t)-1 ||
- nconv == (size_t)-2)
- break;
- p += nconv;
- nchars++;
- insize += nconv;
- }
- if (nconv == (size_t)-1 || nconv == (size_t)-2)
- return (NULL);
- } else
- insize = strlen(mbsarg);
-
- /*
- * Allocate buffer for the result and perform the conversion,
- * converting at most `size' bytes of the input multibyte string to
- * wide characters for printing.
- */
- convbuf = malloc((insize + 1) * sizeof(*convbuf));
- if (convbuf == NULL)
- return (NULL);
- wcp = convbuf;
- p = mbsarg;
- mbs = initial;
- nconv = 0;
- while (insize != 0) {
- nconv = mbrtowc(wcp, p, insize, &mbs);
- if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2)
- break;
- wcp++;
- p += nconv;
- insize -= nconv;
- }
- if (nconv == (size_t)-1 || nconv == (size_t)-2) {
- free(convbuf);
- return (NULL);
- }
- *wcp = L'\0';
-
- return (convbuf);
-}
-#else
-/*
- * Convert a wide character string argument for the %ls format to a multibyte
- * string representation. If not -1, prec specifies the maximum number of
- * bytes to output, and also means that we can't assume that the wide char.
- * string ends is null-terminated.
- */
-static char *
-__wcsconv(wchar_t *wcsarg, int prec)
-{
- static const mbstate_t initial = { 0 };
- mbstate_t mbs;
- char buf[MB_LEN_MAX];
- wchar_t *p;
- char *convbuf;
- size_t clen, nbytes;
-
- /* Allocate space for the maximum number of bytes we could output. */
- if (prec < 0) {
- p = wcsarg;
- mbs = initial;
- nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
- if (nbytes == (size_t)-1)
- return (NULL);
- } else {
- /*
- * Optimisation: if the output precision is small enough,
- * just allocate enough memory for the maximum instead of
- * scanning the string.
- */
- if (prec < 128)
- nbytes = prec;
- else {
- nbytes = 0;
- p = wcsarg;
- mbs = initial;
- for (;;) {
- clen = wcrtomb(buf, *p++, &mbs);
- if (clen == 0 || clen == (size_t)-1 ||
- nbytes + clen > (size_t)prec)
- break;
- nbytes += clen;
- }
- }
- }
- if ((convbuf = malloc(nbytes + 1)) == NULL)
- return (NULL);
-
- /* Fill the output buffer. */
- p = wcsarg;
- mbs = initial;
- if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
- nbytes, &mbs)) == (size_t)-1) {
- free(convbuf);
- return (NULL);
- }
- convbuf[nbytes] = '\0';
- return (convbuf);
-}
-#endif
-
-/*
- * MT-safe version
- */
-int
-WDECL(vf,printf)(FILE * __restrict fp, const CHAR_T * __restrict fmt0, va_list ap)
-{
- int ret;
-
- if(fp == NULL) {
- errno = EINVAL;
- return (EOF);
- }
- FLOCKFILE(fp);
- ret = WDECL(__vf,printf_unlocked)(fp, fmt0, ap);
- FUNLOCKFILE(fp);
- return (ret);
-}
-
-#ifndef NO_FLOATING_POINT
-
-#include <float.h>
-#include <math.h>
-#include "floatio.h"
-
-#define DEFPREC 6
-
-static int exponent(CHAR_T *, int, int);
-#ifndef WIDE_DOUBLE
-static char *cvt(double, int, int, char *, int *, int, int *);
-#endif
-
-#endif /* !NO_FLOATING_POINT */
-
-/*
- * The size of the buffer we use as scratch space for integer
- * conversions, among other things. Technically, we would need the
- * most space for base 10 conversions with thousands' grouping
- * characters between each pair of digits. 100 bytes is a
- * conservative overestimate even for a 128-bit uintmax_t.
- */
-#define BUF 100
-
-#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
-
-/*
- * Flags used during conversion.
- */
-#define ALT 0x001 /* alternate form */
-#define LADJUST 0x004 /* left adjustment */
-#define LONGDBL 0x008 /* long double */
-#define LONGINT 0x010 /* long integer */
-#define LLONGINT 0x020 /* long long integer */
-#define SHORTINT 0x040 /* short integer */
-#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
-#define FPT 0x100 /* Floating point number */
-#define GROUPING 0x200 /* use grouping ("'" flag) */
- /* C99 additional size modifiers: */
-#define SIZET 0x400 /* size_t */
-#define PTRDIFFT 0x800 /* ptrdiff_t */
-#define INTMAXT 0x1000 /* intmax_t */
-#define CHARINT 0x2000 /* print char using int format */
-
-/*
- * Non-MT-safe version
- */
-int
-WDECL(__vf,printf_unlocked)(FILE *fp, const CHAR_T *fmt0, va_list ap)
-{
- CHAR_T *fmt; /* format string */
- int ch; /* character from fmt */
- int n, n2; /* handy integer (short term usage) */
- CHAR_T *cp; /* handy char pointer (short term usage) */
- int flags; /* flags as above */
- int ret; /* return value accumulator (number of items converted)*/
- int width; /* width from format (%8d), or 0 */
- int prec; /* precision from format; <0 for N/A */
- CHAR_T sign; /* sign prefix (' ', '+', '-', or \0) */
- char thousands_sep; /* locale specific thousands separator */
- const char *grouping; /* locale specific numeric grouping rules */
-#ifndef NO_FLOATING_POINT
- /*
- * We can decompose the printed representation of floating
- * point numbers into several parts, some of which may be empty:
- *
- * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
- * A B ---C--- D E F
- *
- * A: 'sign' holds this value if present; '\0' otherwise
- * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
- * C: cp points to the string MMMNNN. Leading and trailing
- * zeros are not in the string and must be added.
- * D: expchar holds this character; '\0' if no exponent, e.g. %f
- * F: at least two digits for decimal, at least one digit for hex
- */
- char *decimal_point; /* locale specific decimal point */
-#ifdef WIDE_DOUBLE
- int signflag; /* true if float is negative */
- union { /* floating point arguments %[aAeEfFgG] */
- double dbl;
- long double ldbl;
- } fparg;
- char *dtoaend; /* pointer to end of converted digits */
-#else
- double _double; /* double precision arguments %[eEfgG] */
- char softsign; /* temporary negative sign for floats */
-#endif
- char *dtoaresult; /* buffer allocated by dtoa */
- int expt = 0; /* integer value of exponent */
- char expchar; /* exponent character: [eEpP\0] */
- int expsize; /* character count for expstr */
- int lead; /* sig figs before decimal or group sep */
- int ndig; /* actual number of digits returned by dtoa */
- CHAR_T expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */
- int nseps; /* number of group separators with ' */
- int nrepeats; /* number of repeats of the last group */
-#endif
- u_long ulval; /* integer arguments %[diouxX] */
- uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */
- int base; /* base for [diouxX] conversion */
- int dprec; /* a copy of prec if [diouxX], 0 otherwise */
- int realsz; /* field size expanded by dprec, sign, etc */
- int size; /* size of converted field or string */
- int prsize; /* max size of printed field */
- const char *xdigs; /* digits for %[xX] conversion */
-#ifdef NARROW
-#define NIOV 8
- struct __siov *iovp; /* for PRINT macro */
- struct __suio uio; /* output information: summary */
- struct __siov iov[NIOV];/* ... and individual io vectors */
-#else
- int n3;
-#endif
- CHAR_T buf[BUF]; /* buffer with space for digits of uintmax_t */
- CHAR_T ox[2]; /* space for 0x hex-prefix */
- union arg *argtable; /* args, built due to positional arg */
- union arg statargtable [STATIC_ARG_TBL_SIZE];
- int nextarg; /* 1-based argument index */
- va_list orgap; /* original argument pointer */
- CHAR_T *convbuf; /* multibyte to wide conversion result */
-
- /*
- * 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 CHAR_T blanks[PADSIZE] =
- {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
- static CHAR_T zeroes[PADSIZE] =
- {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
-
- static const char xdigs_lower[17] = "0123456789abcdef";
- static const char xdigs_upper[17] = "0123456789ABCDEF";
-
- /*
- * BEWARE, these `goto error' on error, PRINT uses `n2' and
- * PAD uses `n'.
- */
-#ifndef NARROW
-#define PRINT(ptr, len) do { \
- for (n3 = 0; n3 < (len); n3++) \
- __xfputwc((ptr)[n3], fp); \
-} while (/*CONSTCOND*/0)
-#define FLUSH()
-#else
-#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 FLUSH() do { \
- if (uio.uio_resid && __sprint(fp, &uio)) \
- goto error; \
- uio.uio_iovcnt = 0; \
- iovp = iov; \
-} while (/*CONSTCOND*/0)
-#endif /* NARROW */
-
-#define PAD(howmany, with) do { \
- if ((n = (howmany)) > 0) { \
- while (n > PADSIZE) { \
- PRINT(with, PADSIZE); \
- n -= PADSIZE; \
- } \
- PRINT(with, n); \
- } \
-} while (/*CONSTCOND*/0)
-#define PRINTANDPAD(p, ep, len, with) do { \
- n2 = (ep) - (p); \
- if (n2 > (len)) \
- n2 = (len); \
- if (n2 > 0) \
- PRINT((p), n2); \
- PAD((len) - (n2 > 0 ? n2 : 0), (with)); \
-} while(/*CONSTCOND*/0)
-
- /*
- * Get the argument indexed by nextarg. If the argument table is
- * built, use it to get the argument. If its not, get the next
- * argument (and arguments must be gotten sequentially).
- */
-#define GETARG(type) \
- ((/*CONSTCOND*/argtable != NULL) ? *((type*)(void*)(&argtable[nextarg++])) : \
- (nextarg++, va_arg(ap, type)))
-
- /*
- * To extend shorts properly, we need both signed and unsigned
- * argument extraction methods.
- */
-#define SARG() \
- ((long)(flags&LONGINT ? GETARG(long) : \
- flags&SHORTINT ? (short)GETARG(int) : \
- flags&CHARINT ? (signed char)GETARG(int) : \
- GETARG(int)))
-
-#define UARG() \
- ((u_long)(flags&LONGINT ? GETARG(u_long) : \
- flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
- flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
- (u_long)GETARG(u_int)))
-
-#define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT)
-
-#define SJARG() \
- (flags&INTMAXT ? GETARG(intmax_t) : \
- flags&SIZET ? (intmax_t)GETARG(size_t) : \
- flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
- (intmax_t)GETARG(long long))
-
-#define UJARG() \
- (flags&INTMAXT ? GETARG(uintmax_t) : \
- flags&SIZET ? (uintmax_t)GETARG(size_t) : \
- flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
- (uintmax_t)GETARG(unsigned long long))
-
- /*
- * Get * arguments, including the form *nn$. Preserve the nextarg
- * that the argument can be gotten once the type is determined.
- */
-#define GETASTER(val) \
- n2 = 0; \
- cp = fmt; \
- while (is_digit(*cp)) { \
- n2 = 10 * n2 + to_digit(*cp); \
- cp++; \
- } \
- if (*cp == '$') { \
- int hold = nextarg; \
- if (argtable == NULL) { \
- argtable = statargtable; \
- if (__find_arguments(fmt0, orgap, &argtable) == -1) \
- goto oomem; \
- } \
- nextarg = n2; \
- val = GETARG (int); \
- nextarg = hold; \
- fmt = ++cp; \
- } else { \
- val = GETARG (int); \
- }
-
- _DIAGASSERT(fp != NULL);
- _DIAGASSERT(fmt0 != NULL);
- if(fp == NULL) {
- errno = EINVAL;
- return (EOF);
- }
-
- _SET_ORIENTATION(fp, -1);
-
- ndig = -1; /* XXX gcc */
-
- thousands_sep = '\0';
- grouping = NULL;
-#ifndef NO_FLOATING_POINT
- decimal_point = localeconv()->decimal_point;
- expsize = 0; /* XXXGCC -Wuninitialized [sh3,m68000] */
-#endif
- convbuf = NULL;
- /* sorry, f{w,}printf(read_only_file, L"") returns {W,}EOF, not 0 */
- if (cantwrite(fp)) {
- errno = EBADF;
- return (END_OF_FILE);
- }
-
- /* optimise fprintf(stderr) (and other unbuffered Unix files) */
- if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
- fp->_file >= 0)
- return (__sbprintf(fp, fmt0, ap));
-
- fmt = (CHAR_T *)__UNCONST(fmt0);
- argtable = NULL;
- nextarg = 1;
- va_copy(orgap, ap);
-#ifdef NARROW
- uio.uio_iov = iovp = iov;
- uio.uio_resid = 0;
- uio.uio_iovcnt = 0;
-#endif
- ret = 0;
-
- /*
- * Scan the format for conversions (`%' character).
- */
- for (;;)
- {
- const CHAR_T *result;
-
- for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
- continue;
- if ((n = (int)(fmt - cp)) != 0) {
- if ((unsigned)ret + n > INT_MAX) {
- ret = END_OF_FILE;
- goto error;
- }
- PRINT(cp, n);
- ret += n;
- }
- if (ch == '\0')
- goto done;
- fmt++; /* skip over '%' */
-
- flags = 0;
- dprec = 0;
- width = 0;
- prec = -1;
- sign = '\0';
- ox[1] = '\0';
- expchar = '\0';
- lead = 0;
- nseps = nrepeats = 0;
- ulval = 0;
- ujval = 0;
- xdigs = NULL;
-
-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 '*':
- /*-
- * ``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.
- */
- GETASTER (width);
- if (width >= 0)
- goto rflag;
- width = -width;
- /* FALLTHROUGH */
- case '-':
- flags |= LADJUST;
- goto rflag;
- case '+':
- sign = '+';
- goto rflag;
- case '\'':
- flags |= GROUPING;
- thousands_sep = *(localeconv()->thousands_sep);
- grouping = localeconv()->grouping;
- goto rflag;
- case '.':
- if ((ch = *fmt++) == '*') {
- GETASTER (prec);
- goto rflag;
- }
- prec = 0;
- while (is_digit(ch)) {
- prec = 10 * prec + to_digit(ch);
- ch = *fmt++;
- }
- 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));
- if (ch == '$') {
- nextarg = n;
- if (argtable == NULL) {
- argtable = statargtable;
- if (__find_arguments(fmt0, orgap,
- &argtable) == -1)
- goto oomem;
- }
- goto rflag;
- }
- width = n;
- goto reswitch;
-#ifndef NO_FLOATING_POINT
- case 'L':
- flags |= LONGDBL;
- goto rflag;
-#endif
- case 'h':
- if (flags & SHORTINT) {
- flags &= ~SHORTINT;
- flags |= CHARINT;
- } else
- flags |= SHORTINT;
- goto rflag;
- case 'j':
- flags |= INTMAXT;
- goto rflag;
- case 'l':
- if (flags & LONGINT) {
- flags &= ~LONGINT;
- flags |= LLONGINT;
- } else
- flags |= LONGINT;
- goto rflag;
- case 'q':
- flags |= LLONGINT; /* not necessarily */
- goto rflag;
- case 't':
- flags |= PTRDIFFT;
- goto rflag;
- case 'z':
- flags |= SIZET;
- goto rflag;
- case 'C':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'c':
-#ifdef NARROW
- if (flags & LONGINT) {
- static const mbstate_t initial = { 0 };
- mbstate_t mbs;
- size_t mbseqlen;
-
- mbs = initial;
- mbseqlen = wcrtomb(buf,
- /* The compiler "knows" that wint_t may be smaller than an int so
- it warns about it when used as the type argument to va_arg().
- Since any type of parameter smaller than an int is promoted to an int on a
- function call, we must call GETARG with type int instead of wint_t.
- */
- (wchar_t)GETARG(int), &mbs);
- if (mbseqlen == (size_t)-1) {
- fp->_flags |= __SERR;
- goto error;
- }
- size = (int)mbseqlen;
- } else {
- *buf = (char)(GETARG(int));
- size = 1;
- }
-#else
- if (flags & LONGINT)
- *buf = (wchar_t)GETARG(int);
- else
- *buf = (wchar_t)btowc(GETARG(int));
- size = 1;
-#endif
- result = buf;
- sign = '\0';
- break;
- case 'D':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'd':
- case 'i':
- if (flags & INTMAX_SIZE) {
- ujval = SJARG();
- if ((intmax_t)ujval < 0) {
- ujval = (uintmax_t)(-((intmax_t)ujval));
- sign = '-';
- }
- } else {
- ulval = SARG();
- if ((long)ulval < 0) {
- ulval = (u_long)(-((long)ulval));
- sign = '-';
- }
- }
- base = 10;
- goto number;
-#ifndef NO_FLOATING_POINT
-#ifdef WIDE_DOUBLE
- case 'a':
- case 'A':
- if (ch == 'a') {
- ox[1] = 'x';
- xdigs = xdigs_lower;
- expchar = 'p';
- } else {
- ox[1] = 'X';
- xdigs = xdigs_upper;
- expchar = 'P';
- }
- if (flags & LONGDBL) {
- fparg.ldbl = GETARG(long double);
- dtoaresult =
- __hldtoa(fparg.ldbl, xdigs, prec,
- &expt, &signflag, &dtoaend);
- } else {
- fparg.dbl = GETARG(double);
- dtoaresult =
- __hdtoa(fparg.dbl, xdigs, prec,
- &expt, &signflag, &dtoaend);
- }
- if (dtoaresult == NULL)
- goto oomem;
-
- if (prec < 0)
- prec = dtoaend - dtoaresult;
- if (expt == INT_MAX)
- ox[1] = '\0';
- ndig = dtoaend - dtoaresult;
- if (convbuf != NULL)
- free(convbuf);
-#ifndef NARROW
- result = convbuf = __mbsconv(dtoaresult, -1);
-#else
- /*XXX inefficient*/
- result = convbuf = strdup(dtoaresult);
-#endif
- if (result == NULL)
- goto oomem;
- __freedtoa(dtoaresult);
- goto fp_common;
- case 'e':
- case 'E':
- expchar = ch;
- if (prec < 0)
- prec = DEFPREC;
- goto fp_begin;
- case 'f':
- case 'F':
- expchar = '\0';
- goto fp_begin;
- case 'g':
- case 'G':
- expchar = ch - ('g' - 'e');
- if (prec == 0)
- prec = 1;
-fp_begin:
- if (prec < 0)
- prec = DEFPREC;
- if (flags & LONGDBL) {
- fparg.ldbl = GETARG(long double);
- dtoaresult =
- __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
- &expt, &signflag, &dtoaend);
- } else {
- fparg.dbl = GETARG(double);
- dtoaresult =
- __dtoa(fparg.dbl, expchar ? 2 : 3, prec,
- &expt, &signflag, &dtoaend);
- if (expt == 9999)
- expt = INT_MAX;
- }
- if (dtoaresult == NULL)
- goto oomem;
- ndig = dtoaend - dtoaresult;
- if (convbuf != NULL)
- free(convbuf);
-#ifndef NARROW
- result = convbuf = __mbsconv(dtoaresult, -1);
-#else
- /*XXX inefficient*/
- result = convbuf = strdup(dtoaresult);
-#endif
- if (result == NULL)
- goto oomem;
- __freedtoa(dtoaresult);
-fp_common:
- if (signflag)
- sign = '-';
- if (expt == INT_MAX) { /* inf or nan */
- if (*result == 'N') {
- result = (ch >= 'a') ? STRCONST("nan") :
- STRCONST("NAN");
- sign = '\0';
- } else
- result = (ch >= 'a') ? STRCONST("inf") :
- STRCONST("INF");
- size = 3;
- break;
- }
-#else
- //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;
- // }
- case 'e':
- case 'E':
- expchar = ch;
- if (prec < 0)
- prec = DEFPREC;
- goto fp_begin;
- case 'f':
- case 'F':
- expchar = '\0';
- goto fp_begin;
- case 'g':
- case 'G':
- expchar = ch - ('g' - 'e');
- if (prec == 0)
- prec = 1;
-fp_begin:
- if (prec < 0)
- prec = DEFPREC;
-
- if (flags & LONGDBL) {
- _double = (double) GETARG(long double);
- } else {
- _double = GETARG(double);
- }
-
- /* do this before tricky precision changes */
- if (isinf(_double)) {
- if (_double < 0)
- sign = '-';
- if (ch == 'E' || ch == 'F' || ch == 'G')
- result = STRCONST("INF");
- else
- result = STRCONST("inf");
- size = 3;
- break;
- }
- if (isnan(_double)) {
- if (ch == 'E' || ch == 'F' || ch == 'G')
- result = STRCONST("NAN");
- else
- result = STRCONST("nan");
- size = 3;
- break;
- }
-
- flags |= FPT;
- dtoaresult = cvt(_double, prec, flags, &softsign, &expt, ch, &ndig);
- if (dtoaresult == NULL)
- goto oomem;
- if (convbuf != NULL)
- free(convbuf);
-#ifndef NARROW
- result = convbuf = __mbsconv(dtoaresult, -1);
-#else
- /*XXX inefficient*/
- result = convbuf = strdup(dtoaresult);
-#endif
- if (result == NULL)
- goto oomem;
- __freedtoa(dtoaresult);
- if (softsign)
- sign = '-';
-#endif
- flags |= FPT;
- if (ch == 'g' || ch == 'G') {
- if (expt > -4 && expt <= prec) {
- /* Make %[gG] smell like %[fF] */
- expchar = '\0';
- if (flags & ALT)
- prec -= expt;
- else
- prec = ndig - expt;
- if (prec < 0)
- prec = 0;
- } else {
- /*
- * Make %[gG] smell like %[eE], but
- * trim trailing zeroes if no # flag.
- *
- * Note: The precision field used with [gG] is the number significant
- * digits to print. When converting to [eE] the digit before the
- * decimal must not be included in the precision value.
- */
- if (!(flags & ALT))
- prec = ndig - 1;
- }
- }
- if (expchar) {
- dprec = prec; /* In some cases dprec will not be set. Make sure it is set now */
- expsize = exponent(expstr, expt - 1, expchar);
- size = expsize + prec + 1; /* Leading digit + exponent string + precision */
- if (prec >= 1 || flags & ALT)
- ++size; /* Decimal point is added to character count */
- } else {
- /* space for digits before decimal point */
- if (expt > 0)
- size = expt;
- else /* "0" */
- size = 1;
- /* space for decimal pt and following digits */
- if (prec || flags & ALT)
- size += prec + 1;
- if (grouping && expt > 0) {
- /* space for thousands' grouping */
- nseps = nrepeats = 0;
- lead = expt;
- while (*grouping != CHAR_MAX) {
- if (lead <= *grouping)
- break;
- lead -= *grouping;
- if (*(grouping+1)) {
- nseps++;
- grouping++;
- } else
- nrepeats++;
- }
- size += nseps + nrepeats;
- } else
- lead = expt;
- }
- break;
-#endif /* !NO_FLOATING_POINT */
- case 'n':
- /*
- * Assignment-like behavior is specified if the
- * value overflows or is otherwise unrepresentable.
- * C99 says to use `signed char' for %hhn conversions.
- */
- if (flags & LLONGINT)
- *GETARG(long long *) = ret;
- else if (flags & SIZET)
- *GETARG(ssize_t *) = (ssize_t)ret;
- else if (flags & PTRDIFFT)
- *GETARG(ptrdiff_t *) = ret;
- else if (flags & INTMAXT)
- *GETARG(intmax_t *) = ret;
- else if (flags & LONGINT)
- *GETARG(long *) = ret;
- else if (flags & SHORTINT)
- *GETARG(short *) = ret;
- else if (flags & CHARINT)
- *GETARG(signed char *) = ret;
- else
- *GETARG(int *) = ret;
- continue; /* no output */
- case 'O':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'o':
- if (flags & INTMAX_SIZE)
- ujval = UJARG();
- else
- ulval = UARG();
- base = 8;
- 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
- */
- ujval = (uintmax_t) (UINTN) GETARG(void *);
- base = 16;
- xdigs = xdigs_lower;
- flags = flags | INTMAXT;
- ox[1] = 'x';
- goto nosign;
- case 'S':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 's':
- if (((flags & LONGINT) ? 1:0) != MULTI) {
- if ((result = GETARG(CHAR_T *)) == NULL)
- result = STRCONST("(null)");
- } else {
- MCHAR_T *mc;
-
- if (convbuf != NULL)
- free(convbuf);
- if ((mc = GETARG(MCHAR_T *)) == NULL)
- result = STRCONST("(null)");
- else {
- convbuf = SCONV(mc, prec);
- if (convbuf == NULL) {
- fp->_flags |= __SERR;
- goto error;
- }
- result = convbuf;
- }
- }
-
- if (prec >= 0) {
- /*
- * can't use STRLEN; can only look for the
- * NUL in the first `prec' characters, and
- * STRLEN() will go further.
- */
- CHAR_T *p = MEMCHR(result, 0, (size_t)prec);
-
- if (p != NULL) {
- size = p - result;
- if (size > prec)
- size = prec;
- } else
- size = prec;
- } else
- size = (int)STRLEN(result);
- sign = '\0';
- break;
- case 'U':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'u':
- if (flags & INTMAX_SIZE)
- ujval = UJARG();
- else
- ulval = UARG();
- base = 10;
- goto nosign;
- case 'X':
- xdigs = xdigs_upper;
- goto hex;
- case 'x':
- xdigs = xdigs_lower;
-hex:
- if (flags & INTMAX_SIZE)
- ujval = UJARG();
- else
- ulval = UARG();
- base = 16;
- /* leading 0x/X only if non-zero */
- if (flags & ALT &&
- (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
- ox[1] = ch;
-
- flags &= ~GROUPING;
- /* 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
- *
- * ``The C Standard is clear enough as is. The call
- * printf("%#.0o", 0) should print 0.''
- * -- Defect Report #151
- */
- result = cp = buf + BUF;
- if (flags & INTMAX_SIZE) {
- if (ujval != 0 || prec != 0 ||
- (flags & ALT && base == 8))
- {
- result = __ujtoa(ujval, cp, base,
- flags & ALT, xdigs,
- flags & GROUPING, thousands_sep,
- grouping);
- }
- } else {
- if (ulval != 0 || prec != 0 ||
- (flags & ALT && base == 8))
- result = __ultoa(ulval, cp, base,
- flags & ALT, xdigs,
- flags & GROUPING, thousands_sep,
- grouping);
- }
- size = buf + BUF - result;
- if (size > BUF) /* should never happen */
- abort();
- break;
- default: /* "%?" prints ?, unless ? is NUL */
- if (ch == '\0')
- goto done;
- /* pretend it was %c with argument ch */
- *buf = ch;
- result = buf;
- size = 1;
- sign = '\0';
- break;
- }
-
- /*
- * All reasonable formats wind up here. At this point, `result'
- * 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++;
- if (ox[1])
- realsz += 2;
-
- prsize = width > realsz ? width : realsz;
- if ((unsigned)ret + prsize > INT_MAX) {
- ret = END_OF_FILE;
- goto error;
- }
-
- /* right-adjusting blank padding */
- if ((flags & (LADJUST|ZEROPAD)) == 0)
- PAD(width - realsz, blanks);
-
- /* prefix */
- if (sign)
- PRINT(&sign, 1);
-
- if (ox[1]) { /* ox[1] is either x, X, or \0 */
- ox[0] = '0';
- 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(result, size);
- } else { /* glue together f_p fragments */
- if (!expchar) { /* %[fF] or sufficiently short %[gG] */
- if (expt <= 0) {
- PRINT(zeroes, 1);
- if (prec || flags & ALT)
- PRINT(decimal_point, 1);
- PAD(-expt, zeroes);
- /* already handled initial 0's */
- prec += expt;
- } else {
- PRINTANDPAD(result, convbuf + ndig,
- lead, zeroes);
- result += lead;
- if (grouping) {
- while (nseps>0 || nrepeats>0) {
- if (nrepeats > 0)
- nrepeats--;
- else {
- grouping--;
- nseps--;
- }
- PRINT(&thousands_sep,
- 1);
- PRINTANDPAD(result,
- convbuf + ndig,
- *grouping, zeroes);
- result += *grouping;
- }
- if (result > convbuf + ndig)
- result = convbuf + ndig;
- }
- if (prec || flags & ALT) {
- buf[0] = *decimal_point;
- PRINT(buf, 1);
- }
- }
- PRINTANDPAD(result, convbuf + ndig, prec,
- zeroes);
- } else { /* %[eE] or sufficiently long %[gG] */
- if (prec >= 1 || flags & ALT) {
- buf[0] = *result++;
- buf[1] = *decimal_point;
- PRINT(buf, 2);
- PRINT(result, ndig-1);
- PAD(prec - ndig, zeroes);
- } else /* XeYYY */
- PRINT(result, 1);
- PRINT(expstr, expsize);
- }
- }
-#else
- PRINT(result, size);
-#endif
- /* left-adjusting padding (always blank) */
- if (flags & LADJUST)
- PAD(width - realsz, blanks);
-
- /* finally, adjust ret */
- ret += prsize;
- FLUSH();
- }
-done:
- FLUSH();
-error:
- va_end(orgap);
- if (convbuf != NULL)
- free(convbuf);
- if (__sferror(fp))
- ret = END_OF_FILE;
- if ((argtable != NULL) && (argtable != statargtable))
- free (argtable);
- return (ret);
- /* NOTREACHED */
-oomem:
- errno = ENOMEM;
- ret = END_OF_FILE;
- goto error;
-}
-
-/*
- * Find all arguments when a positional parameter is encountered. Returns a
- * table, indexed by argument number, of pointers to each arguments. The
- * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
- * It will be replaces with a malloc-ed one if it overflows.
- */
-static int
-__find_arguments(const CHAR_T *fmt0, va_list ap, union arg **argtable)
-{
- CHAR_T *fmt; /* format string */
- int ch; /* character from fmt */
- int n, n2; /* handy integer (short term usage) */
- CHAR_T *cp; /* handy char pointer (short term usage) */
- int flags; /* flags as above */
- enum typeid *typetable; /* table of types */
- enum typeid stattypetable [STATIC_ARG_TBL_SIZE];
- int tablesize; /* current size of type table */
- int tablemax; /* largest used index in table */
- int nextarg; /* 1-based argument index */
-
- /*
- * Add an argument type to the table, expanding if necessary.
- */
-#define ADDTYPE(type) \
- do { \
- if (nextarg >= tablesize) \
- if (__grow_type_table(nextarg, &typetable, \
- &tablesize) == -1) \
- return -1; \
- if (nextarg > tablemax) \
- tablemax = nextarg; \
- typetable[nextarg++] = type; \
- } while (/*CONSTCOND*/0)
-
-#define ADDSARG() \
- do { \
- if (flags & INTMAXT) \
- ADDTYPE(T_INTMAXT); \
- else if (flags & SIZET) \
- ADDTYPE(T_SIZET); \
- else if (flags & PTRDIFFT) \
- ADDTYPE(T_PTRDIFFT); \
- else if (flags & LLONGINT) \
- ADDTYPE(T_LLONG); \
- else if (flags & LONGINT) \
- ADDTYPE(T_LONG); \
- else \
- ADDTYPE(T_INT); \
- } while (/*CONSTCOND*/0)
-
-#define ADDUARG() \
- do { \
- if (flags & INTMAXT) \
- ADDTYPE(T_UINTMAXT); \
- else if (flags & SIZET) \
- ADDTYPE(T_SIZET); \
- else if (flags & PTRDIFFT) \
- ADDTYPE(T_PTRDIFFT); \
- else if (flags & LLONGINT) \
- ADDTYPE(T_U_LLONG); \
- else if (flags & LONGINT) \
- ADDTYPE(T_U_LONG); \
- else \
- ADDTYPE(T_U_INT); \
- } while (/*CONSTCOND*/0)
- /*
- * Add * arguments to the type array.
- */
-#define ADDASTER() \
- n2 = 0; \
- cp = fmt; \
- while (is_digit(*cp)) { \
- n2 = 10 * n2 + to_digit(*cp); \
- cp++; \
- } \
- if (*cp == '$') { \
- int hold = nextarg; \
- nextarg = n2; \
- ADDTYPE(T_INT); \
- nextarg = hold; \
- fmt = ++cp; \
- } else { \
- ADDTYPE(T_INT); \
- }
- fmt = (CHAR_T *)__UNCONST(fmt0);
- typetable = stattypetable;
- tablesize = STATIC_ARG_TBL_SIZE;
- tablemax = 0;
- nextarg = 1;
- for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
- typetable[n] = T_UNUSED;
-
- /*
- * Scan the format for conversions (`%' character).
- */
- for (;;) {
- for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
- /* void */;
- if (ch == '\0')
- goto done;
- fmt++; /* skip over '%' */
-
- flags = 0;
-
-rflag: ch = *fmt++;
-reswitch: switch (ch) {
- case ' ':
- case '#':
- goto rflag;
- case '*':
- ADDASTER ();
- goto rflag;
- case '-':
- case '+':
- case '\'':
- goto rflag;
- case '.':
- if ((ch = *fmt++) == '*') {
- ADDASTER ();
- goto rflag;
- }
- while (is_digit(ch)) {
- ch = *fmt++;
- }
- goto reswitch;
- case '0':
- 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));
- if (ch == '$') {
- nextarg = n;
- goto rflag;
- }
- goto reswitch;
-#ifndef NO_FLOATING_POINT
- case 'L':
- flags |= LONGDBL;
- goto rflag;
-#endif
- case 'h':
- if (flags & SHORTINT) {
- flags &= ~SHORTINT;
- flags |= CHARINT;
- } else
- flags |= SHORTINT;
- goto rflag;
- case 'j':
- flags |= INTMAXT;
- goto rflag;
- case 'l':
- if (flags & LONGINT) {
- flags &= ~LONGINT;
- flags |= LLONGINT;
- } else
- flags |= LONGINT;
- goto rflag;
- case 'q':
- flags |= LLONGINT; /* not necessarily */
- goto rflag;
- case 't':
- flags |= PTRDIFFT;
- goto rflag;
- case 'z':
- flags |= SIZET;
- goto rflag;
- case 'C':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'c':
- if (flags & LONGINT)
- ADDTYPE(T_WINT);
- else
- ADDTYPE(T_INT);
- break;
- case 'D':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'd':
- case 'i':
- ADDSARG();
- break;
-#ifndef NO_FLOATING_POINT
- case 'a':
- case 'A':
- case 'e':
- case 'E':
- case 'f':
- case 'g':
- case 'G':
- if (flags & LONGDBL)
- ADDTYPE(T_LONG_DOUBLE);
- else
- ADDTYPE(T_DOUBLE);
- break;
-#endif /* !NO_FLOATING_POINT */
- case 'n':
- if (flags & INTMAXT)
- ADDTYPE(TP_INTMAXT);
- else if (flags & PTRDIFFT)
- ADDTYPE(TP_PTRDIFFT);
- else if (flags & SIZET)
- ADDTYPE(TP_SIZET);
- else if (flags & LLONGINT)
- ADDTYPE(TP_LLONG);
- else if (flags & LONGINT)
- ADDTYPE(TP_LONG);
- else if (flags & SHORTINT)
- ADDTYPE(TP_SHORT);
- else if (flags & CHARINT)
- ADDTYPE(TP_SCHAR);
- else
- ADDTYPE(TP_INT);
- continue; /* no output */
- case 'O':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'o':
- ADDUARG();
- break;
- case 'p':
- ADDTYPE(TP_VOID);
- break;
- case 'S':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 's':
- if (flags & LONGINT)
- ADDTYPE(TP_WCHAR);
- else
- ADDTYPE(TP_CHAR);
- break;
- case 'U':
- flags |= LONGINT;
- /*FALLTHROUGH*/
- case 'u':
- case 'X':
- case 'x':
- ADDUARG();
- break;
- default: /* "%?" prints ?, unless ? is NUL */
- if (ch == '\0')
- goto done;
- break;
- }
- }
-done:
- /*
- * Build the argument table.
- */
- if (tablemax >= STATIC_ARG_TBL_SIZE) {
- *argtable = (union arg *)
- malloc (sizeof (union arg) * (tablemax + 1));
- if (*argtable == NULL)
- return -1;
- }
-
- (*argtable) [0].intarg = 0;
- for (n = 1; n <= tablemax; n++) {
- switch (typetable [n]) {
- case T_UNUSED: /* whoops! */
- (*argtable) [n].intarg = va_arg (ap, int);
- break;
- case TP_SCHAR:
- (*argtable) [n].pschararg = va_arg (ap, signed char *);
- break;
- case TP_SHORT:
- (*argtable) [n].pshortarg = va_arg (ap, short *);
- break;
- case T_INT:
- (*argtable) [n].intarg = va_arg (ap, int);
- break;
- case T_U_INT:
- (*argtable) [n].uintarg = va_arg (ap, unsigned int);
- break;
- case TP_INT:
- (*argtable) [n].pintarg = va_arg (ap, int *);
- break;
- case T_LONG:
- (*argtable) [n].longarg = va_arg (ap, long);
- break;
- case T_U_LONG:
- (*argtable) [n].ulongarg = va_arg (ap, unsigned long);
- break;
- case TP_LONG:
- (*argtable) [n].plongarg = va_arg (ap, long *);
- break;
- case T_LLONG:
- (*argtable) [n].longlongarg = va_arg (ap, long long);
- break;
- case T_U_LLONG:
- (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
- break;
- case TP_LLONG:
- (*argtable) [n].plonglongarg = va_arg (ap, long long *);
- break;
- case T_PTRDIFFT:
- (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
- break;
- case TP_PTRDIFFT:
- (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
- break;
- case T_SIZET:
- (*argtable) [n].sizearg = va_arg (ap, size_t);
- break;
- case TP_SIZET:
- (*argtable) [n].psizearg = va_arg (ap, size_t *);
- break;
- case T_INTMAXT:
- (*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
- break;
- case T_UINTMAXT:
- (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
- break;
- case TP_INTMAXT:
- (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
- break;
- case T_DOUBLE:
-#ifndef NO_FLOATING_POINT
- (*argtable) [n].doublearg = va_arg (ap, double);
-#endif
- break;
- case T_LONG_DOUBLE:
-#ifndef NO_FLOATING_POINT
- (*argtable) [n].longdoublearg = va_arg (ap, long double);
-#endif
- break;
- case TP_CHAR:
- (*argtable) [n].pchararg = va_arg (ap, char *);
- break;
- case TP_VOID:
- (*argtable) [n].pvoidarg = va_arg (ap, void *);
- break;
- case T_WINT:
- (*argtable) [n].wintarg = va_arg (ap, int);
- break;
- case TP_WCHAR:
- (*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
- break;
- }
- }
-
- if ((typetable != NULL) && (typetable != stattypetable))
- free (typetable);
- return 0;
-}
-
-/*
- * Increase the size of the type table.
- */
-static int
-__grow_type_table (int nextarg, enum typeid **typetable, int *tablesize)
-{
- enum typeid *const oldtable = *typetable;
- const int oldsize = *tablesize;
- enum typeid *newtable;
- int n, newsize = oldsize * 2;
-
- if (newsize < nextarg + 1)
- newsize = nextarg + 1;
- if (oldsize == STATIC_ARG_TBL_SIZE) {
- if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
- return -1;
- memcpy(newtable, oldtable, oldsize * sizeof(enum typeid));
- } else {
- newtable = realloc(oldtable, newsize * sizeof(enum typeid));
- if (newtable == NULL) {
- free(oldtable);
- return -1;
- }
- }
- for (n = oldsize; n < newsize; n++)
- newtable[n] = T_UNUSED;
-
- *typetable = newtable;
- *tablesize = newsize;
- return 0;
-}
-
-
-#ifndef NO_FLOATING_POINT
-#ifndef WIDE_DOUBLE
-static char *
-cvt(double value, int ndigits, int flags, char *sign, int *decpt, int ch,
- int *length)
-{
- 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 (digits == NULL)
- return NULL;
- 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;
- }
- while (rve < bp)
- *rve++ = '0';
- }
- *length = rve - digits;
- return digits;
-}
-#endif
-
-static int
-exponent(CHAR_T *p0, int expo, int fmtch)
-{
- CHAR_T *p, *t;
- CHAR_T expbuf[MAXEXPDIG];
-
- p = p0;
- *p++ = fmtch;
- if (expo < 0) {
- expo = -expo;
- *p++ = '-';
- }
- else
- *p++ = '+';
- t = expbuf + MAXEXPDIG;
- if (expo > 9) {
- do {
- *--t = to_char(expo % 10);
- } while ((expo /= 10) > 9);
- *--t = to_char(expo);
- for (; t < expbuf + MAXEXPDIG; *p++ = *t++);
- }
- else {
- /*
- * Exponents for decimal floating point conversions
- * (%[eEgG]) must be at least two characters long,
- * whereas exponents for hexadecimal conversions can
- * be only one character long.
- */
- if (fmtch == 'e' || fmtch == 'E')
- *p++ = '0';
- *p++ = to_char(expo);
- }
- return (p - p0);
-}
-#endif /* !NO_FLOATING_POINT */