vfprintf.c revision 165742
165942Sgibbs/*- 265942Sgibbs * Copyright (c) 1990, 1993 365942Sgibbs * The Regents of the University of California. All rights reserved. 465942Sgibbs * 565942Sgibbs * This code is derived from software contributed to Berkeley by 665942Sgibbs * Chris Torek. 765942Sgibbs * 865942Sgibbs * Redistribution and use in source and binary forms, with or without 965942Sgibbs * modification, are permitted provided that the following conditions 1065942Sgibbs * are met: 1165942Sgibbs * 1. Redistributions of source code must retain the above copyright 1265942Sgibbs * notice, this list of conditions and the following disclaimer. 1365942Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1465942Sgibbs * notice, this list of conditions and the following disclaimer in the 1565942Sgibbs * documentation and/or other materials provided with the distribution. 1665942Sgibbs * 3. All advertising materials mentioning features or use of this software 1765942Sgibbs * must display the following acknowledgement: 1865942Sgibbs * This product includes software developed by the University of 1965942Sgibbs * California, Berkeley and its contributors. 2065942Sgibbs * 4. Neither the name of the University nor the names of its contributors 2165942Sgibbs * may be used to endorse or promote products derived from this software 2265942Sgibbs * without specific prior written permission. 2365942Sgibbs * 2465942Sgibbs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2565942Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2665942Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2765942Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2865942Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2965942Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3065942Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3165942Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3265942Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3365942Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3465942Sgibbs * SUCH DAMAGE. 3565942Sgibbs */ 3665942Sgibbs 3765942Sgibbs#if defined(LIBC_SCCS) && !defined(lint) 3865942Sgibbsstatic char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; 3965942Sgibbs#endif /* LIBC_SCCS and not lint */ 4065942Sgibbs#include <sys/cdefs.h> 4165942Sgibbs__FBSDID("$FreeBSD: head/lib/libc/stdio/vfprintf.c 165742 2007-01-03 04:57:58Z das $"); 4265942Sgibbs 4365942Sgibbs/* 4465942Sgibbs * Actual printf innards. 4565942Sgibbs * 4665942Sgibbs * This code is large and complicated... 4765942Sgibbs */ 4865942Sgibbs 4965942Sgibbs#include "namespace.h" 5065942Sgibbs#include <sys/types.h> 5165942Sgibbs 5265942Sgibbs#include <ctype.h> 5365942Sgibbs#include <limits.h> 5465942Sgibbs#include <locale.h> 5565942Sgibbs#include <stddef.h> 5665942Sgibbs#include <stdint.h> 5765942Sgibbs#include <stdio.h> 5865942Sgibbs#include <stdlib.h> 5965942Sgibbs#include <string.h> 6065942Sgibbs#include <wchar.h> 6165942Sgibbs#include <printf.h> 6265942Sgibbs 6365942Sgibbs#include <stdarg.h> 6465942Sgibbs#include "un-namespace.h" 6565942Sgibbs 6665942Sgibbs#include "libc_private.h" 6765942Sgibbs#include "local.h" 6865942Sgibbs#include "fvwrite.h" 6965942Sgibbs 7065942Sgibbsunion arg { 7166269Sgibbs int intarg; 7265942Sgibbs u_int uintarg; 7365942Sgibbs long longarg; 7465942Sgibbs u_long ulongarg; 7565942Sgibbs long long longlongarg; 7665942Sgibbs unsigned long long ulonglongarg; 7766269Sgibbs ptrdiff_t ptrdiffarg; 7866269Sgibbs size_t sizearg; 7965942Sgibbs intmax_t intmaxarg; 8065942Sgibbs uintmax_t uintmaxarg; 8165942Sgibbs void *pvoidarg; 8266269Sgibbs char *pchararg; 8365942Sgibbs signed char *pschararg; 8465942Sgibbs short *pshortarg; 8565942Sgibbs int *pintarg; 8665942Sgibbs long *plongarg; 8765942Sgibbs long long *plonglongarg; 8866269Sgibbs ptrdiff_t *pptrdiffarg; 8965942Sgibbs size_t *psizearg; 9065942Sgibbs intmax_t *pintmaxarg; 9165942Sgibbs#ifndef NO_FLOATING_POINT 9265942Sgibbs double doublearg; 9365942Sgibbs long double longdoublearg; 9465942Sgibbs#endif 9565942Sgibbs wint_t wintarg; 9665942Sgibbs wchar_t *pwchararg; 9765942Sgibbs}; 9865942Sgibbs 9965942Sgibbs/* 10065942Sgibbs * Type ids for argument type table. 10165942Sgibbs */ 10265942Sgibbsenum typeid { 10365942Sgibbs T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, 10465942Sgibbs T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, 10565942Sgibbs T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET, 10665942Sgibbs T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, 10765942Sgibbs T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR 10865942Sgibbs}; 10965942Sgibbs 11065942Sgibbsstatic int __sprint(FILE *, struct __suio *); 11165942Sgibbsstatic int __sbprintf(FILE *, const char *, va_list) __printflike(2, 0); 11265942Sgibbsstatic char *__ujtoa(uintmax_t, char *, int, int, const char *, int, char, 11365942Sgibbs const char *); 11465942Sgibbsstatic char *__ultoa(u_long, char *, int, int, const char *, int, char, 11565942Sgibbs const char *); 11665942Sgibbsstatic char *__wcsconv(wchar_t *, int); 11765942Sgibbsstatic void __find_arguments(const char *, va_list, union arg **); 11865942Sgibbsstatic void __grow_type_table(int, enum typeid **, int *); 11965942Sgibbs 12065942Sgibbs/* 12165942Sgibbs * Flush out all the vectors defined by the given uio, 12265942Sgibbs * then reset it so that it can be reused. 12365942Sgibbs */ 12465942Sgibbsstatic int 12565942Sgibbs__sprint(FILE *fp, struct __suio *uio) 12665942Sgibbs{ 12765942Sgibbs int err; 12865942Sgibbs 12965942Sgibbs if (uio->uio_resid == 0) { 13065942Sgibbs uio->uio_iovcnt = 0; 13165942Sgibbs return (0); 13265942Sgibbs } 13365942Sgibbs err = __sfvwrite(fp, uio); 13465942Sgibbs uio->uio_resid = 0; 13565942Sgibbs uio->uio_iovcnt = 0; 13665942Sgibbs return (err); 13765942Sgibbs} 13865942Sgibbs 13965942Sgibbs/* 14065942Sgibbs * Helper function for `fprintf to unbuffered unix file': creates a 14166647Sgibbs * temporary buffer. We only work on write-only files; this avoids 14265942Sgibbs * worries about ungetc buffers and so forth. 14365942Sgibbs */ 14465942Sgibbsstatic int 14565942Sgibbs__sbprintf(FILE *fp, const char *fmt, va_list ap) 14665942Sgibbs{ 14765942Sgibbs int ret; 14866104Sgibbs FILE fake; 14966104Sgibbs unsigned char buf[BUFSIZ]; 15066647Sgibbs 15165942Sgibbs /* copy the important variables */ 15265942Sgibbs fake._flags = fp->_flags & ~__SNBF; 15365942Sgibbs fake._file = fp->_file; 15465942Sgibbs fake._cookie = fp->_cookie; 15565942Sgibbs fake._write = fp->_write; 15665942Sgibbs fake._extra = fp->_extra; 15765942Sgibbs 15865942Sgibbs /* set up the buffer */ 15965942Sgibbs fake._bf._base = fake._p = buf; 16065942Sgibbs fake._bf._size = fake._w = sizeof(buf); 16165942Sgibbs fake._lbfsize = 0; /* not actually used, but Just In Case */ 16265942Sgibbs 16365942Sgibbs /* do the work, then copy any error status */ 16465942Sgibbs ret = __vfprintf(&fake, fmt, ap); 16565942Sgibbs if (ret >= 0 && __fflush(&fake)) 16665942Sgibbs ret = EOF; 16765942Sgibbs if (fake._flags & __SERR) 16865942Sgibbs fp->_flags |= __SERR; 16965942Sgibbs return (ret); 17065942Sgibbs} 17165942Sgibbs 17265942Sgibbs/* 17365942Sgibbs * Macros for converting digits to letters and vice versa 17465942Sgibbs */ 17565942Sgibbs#define to_digit(c) ((c) - '0') 17665942Sgibbs#define is_digit(c) ((unsigned)to_digit(c) <= 9) 17765942Sgibbs#define to_char(n) ((n) + '0') 17865942Sgibbs 17965942Sgibbs/* 18065942Sgibbs * Convert an unsigned long to ASCII for printf purposes, returning 18166104Sgibbs * a pointer to the first character of the string representation. 18266647Sgibbs * Octal numbers can be forced to have a leading zero; hex numbers 18365942Sgibbs * use the given digits. 18465942Sgibbs */ 18565942Sgibbsstatic char * 18665942Sgibbs__ultoa(u_long val, char *endp, int base, int octzero, const char *xdigs, 18765942Sgibbs int needgrp, char thousep, const char *grp) 18865942Sgibbs{ 18965942Sgibbs char *cp = endp; 19065942Sgibbs long sval; 19165942Sgibbs int ndig; 19265942Sgibbs 19365942Sgibbs /* 19465942Sgibbs * Handle the three cases separately, in the hope of getting 19565942Sgibbs * better/faster code. 19665942Sgibbs */ 19765942Sgibbs switch (base) { 19865942Sgibbs case 10: 19965942Sgibbs if (val < 10) { /* many numbers are 1 digit */ 20065942Sgibbs *--cp = to_char(val); 20165942Sgibbs return (cp); 20265942Sgibbs } 20365942Sgibbs ndig = 0; 20465942Sgibbs /* 20565942Sgibbs * On many machines, unsigned arithmetic is harder than 20665942Sgibbs * signed arithmetic, so we do at most one unsigned mod and 20765942Sgibbs * divide; this is sufficient to reduce the range of 20865942Sgibbs * the incoming value to where signed arithmetic works. 20965942Sgibbs */ 21065942Sgibbs if (val > LONG_MAX) { 21165942Sgibbs *--cp = to_char(val % 10); 21265942Sgibbs ndig++; 21365942Sgibbs sval = val / 10; 21465942Sgibbs } else 21565942Sgibbs sval = val; 21665942Sgibbs do { 21765942Sgibbs *--cp = to_char(sval % 10); 21865942Sgibbs ndig++; 21965942Sgibbs /* 22065942Sgibbs * If (*grp == CHAR_MAX) then no more grouping 22165942Sgibbs * should be performed. 22265942Sgibbs */ 22365942Sgibbs if (needgrp && ndig == *grp && *grp != CHAR_MAX 22465942Sgibbs && sval > 9) { 22565942Sgibbs *--cp = thousep; 22665942Sgibbs ndig = 0; 22765942Sgibbs /* 22865942Sgibbs * If (*(grp+1) == '\0') then we have to 22965942Sgibbs * use *grp character (last grouping rule) 23065942Sgibbs * for all next cases 23165942Sgibbs */ 23265942Sgibbs if (*(grp+1) != '\0') 23365942Sgibbs grp++; 23465942Sgibbs } 23565942Sgibbs sval /= 10; 23665942Sgibbs } while (sval != 0); 23765942Sgibbs break; 23865942Sgibbs 23965942Sgibbs case 8: 24065942Sgibbs do { 24165942Sgibbs *--cp = to_char(val & 7); 24265942Sgibbs val >>= 3; 24365942Sgibbs } while (val); 24465942Sgibbs if (octzero && *cp != '0') 24565942Sgibbs *--cp = '0'; 24665942Sgibbs break; 24765942Sgibbs 24865942Sgibbs case 16: 24965942Sgibbs do { 25065942Sgibbs *--cp = xdigs[val & 15]; 25165942Sgibbs val >>= 4; 25265942Sgibbs } while (val); 25365942Sgibbs break; 25465942Sgibbs 25565942Sgibbs default: /* oops */ 25665942Sgibbs abort(); 25765942Sgibbs } 25865942Sgibbs return (cp); 25965942Sgibbs} 26065942Sgibbs 26165942Sgibbs/* Identical to __ultoa, but for intmax_t. */ 26265942Sgibbsstatic char * 26365942Sgibbs__ujtoa(uintmax_t val, char *endp, int base, int octzero, const char *xdigs, 26465942Sgibbs int needgrp, char thousep, const char *grp) 26565942Sgibbs{ 26665942Sgibbs char *cp = endp; 26765942Sgibbs intmax_t sval; 26865942Sgibbs int ndig; 26965942Sgibbs 27065942Sgibbs /* quick test for small values; __ultoa is typically much faster */ 27165942Sgibbs /* (perhaps instead we should run until small, then call __ultoa?) */ 27265942Sgibbs if (val <= ULONG_MAX) 27365942Sgibbs return (__ultoa((u_long)val, endp, base, octzero, xdigs, 27465942Sgibbs needgrp, thousep, grp)); 27565942Sgibbs switch (base) { 27665942Sgibbs case 10: 27765942Sgibbs if (val < 10) { 27865942Sgibbs *--cp = to_char(val % 10); 27965942Sgibbs return (cp); 28065942Sgibbs } 28165942Sgibbs ndig = 0; 28265942Sgibbs if (val > INTMAX_MAX) { 28365942Sgibbs *--cp = to_char(val % 10); 28465942Sgibbs ndig++; 28565942Sgibbs sval = val / 10; 28665942Sgibbs } else 28765942Sgibbs sval = val; 28865942Sgibbs do { 28965942Sgibbs *--cp = to_char(sval % 10); 29065942Sgibbs ndig++; 29165942Sgibbs /* 29265942Sgibbs * If (*grp == CHAR_MAX) then no more grouping 29365942Sgibbs * should be performed. 29465942Sgibbs */ 29565942Sgibbs if (needgrp && *grp != CHAR_MAX && ndig == *grp 29665942Sgibbs && sval > 9) { 29765942Sgibbs *--cp = thousep; 29865942Sgibbs ndig = 0; 29965942Sgibbs /* 30065942Sgibbs * If (*(grp+1) == '\0') then we have to 30165942Sgibbs * use *grp character (last grouping rule) 30265942Sgibbs * for all next cases 30365942Sgibbs */ 30465942Sgibbs if (*(grp+1) != '\0') 30565942Sgibbs grp++; 30665942Sgibbs } 30765942Sgibbs sval /= 10; 30865942Sgibbs } while (sval != 0); 30965942Sgibbs break; 31065942Sgibbs 31165942Sgibbs case 8: 31265942Sgibbs do { 31365942Sgibbs *--cp = to_char(val & 7); 31465942Sgibbs val >>= 3; 31565942Sgibbs } while (val); 31665942Sgibbs if (octzero && *cp != '0') 31765942Sgibbs *--cp = '0'; 31865942Sgibbs break; 31965942Sgibbs 32065942Sgibbs case 16: 32165942Sgibbs do { 32265942Sgibbs *--cp = xdigs[val & 15]; 32365942Sgibbs val >>= 4; 32465942Sgibbs } while (val); 32565942Sgibbs break; 32665942Sgibbs 32765942Sgibbs default: 32865942Sgibbs abort(); 32965942Sgibbs } 33065942Sgibbs return (cp); 33165942Sgibbs} 33265942Sgibbs 33365942Sgibbs/* 33465942Sgibbs * Convert a wide character string argument for the %ls format to a multibyte 33565942Sgibbs * string representation. If not -1, prec specifies the maximum number of 33665942Sgibbs * bytes to output, and also means that we can't assume that the wide char. 33765942Sgibbs * string ends is null-terminated. 33865942Sgibbs */ 33965942Sgibbsstatic char * 34065942Sgibbs__wcsconv(wchar_t *wcsarg, int prec) 34165942Sgibbs{ 34265942Sgibbs static const mbstate_t initial; 34365942Sgibbs mbstate_t mbs; 34465942Sgibbs char buf[MB_LEN_MAX]; 34565942Sgibbs wchar_t *p; 34665942Sgibbs char *convbuf; 34765942Sgibbs size_t clen, nbytes; 34865942Sgibbs 34965942Sgibbs /* Allocate space for the maximum number of bytes we could output. */ 35065942Sgibbs if (prec < 0) { 35165942Sgibbs p = wcsarg; 35265942Sgibbs mbs = initial; 35365942Sgibbs nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); 35465942Sgibbs if (nbytes == (size_t)-1) 35565942Sgibbs return (NULL); 35665942Sgibbs } else { 35765942Sgibbs /* 35865942Sgibbs * Optimisation: if the output precision is small enough, 35965942Sgibbs * just allocate enough memory for the maximum instead of 36065942Sgibbs * scanning the string. 36165942Sgibbs */ 36265942Sgibbs if (prec < 128) 36365942Sgibbs nbytes = prec; 36465942Sgibbs else { 36565942Sgibbs nbytes = 0; 36665942Sgibbs p = wcsarg; 36765942Sgibbs mbs = initial; 36865942Sgibbs for (;;) { 36965942Sgibbs clen = wcrtomb(buf, *p++, &mbs); 37065942Sgibbs if (clen == 0 || clen == (size_t)-1 || 37165942Sgibbs nbytes + clen > prec) 37265942Sgibbs break; 37365942Sgibbs nbytes += clen; 37465942Sgibbs } 37565942Sgibbs } 37665942Sgibbs } 37765942Sgibbs if ((convbuf = malloc(nbytes + 1)) == NULL) 37865942Sgibbs return (NULL); 37965942Sgibbs 38065942Sgibbs /* Fill the output buffer. */ 38165942Sgibbs p = wcsarg; 38265942Sgibbs mbs = initial; 38365942Sgibbs if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p, 38465942Sgibbs nbytes, &mbs)) == (size_t)-1) { 38565942Sgibbs free(convbuf); 38665942Sgibbs return (NULL); 38765942Sgibbs } 38865942Sgibbs convbuf[nbytes] = '\0'; 38965942Sgibbs return (convbuf); 39065942Sgibbs} 39165942Sgibbs 39265942Sgibbs/* 39365942Sgibbs * MT-safe version 39465942Sgibbs */ 39565942Sgibbsint 39665942Sgibbsvfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) 39765942Sgibbs 39865942Sgibbs{ 39965942Sgibbs int ret; 40065942Sgibbs 40165942Sgibbs FLOCKFILE(fp); 40265942Sgibbs ret = __vfprintf(fp, fmt0, ap); 40365942Sgibbs FUNLOCKFILE(fp); 40465942Sgibbs return (ret); 40565942Sgibbs} 40665942Sgibbs 40765942Sgibbs#ifndef NO_FLOATING_POINT 40865942Sgibbs 40965942Sgibbs#define dtoa __dtoa 41065942Sgibbs#define freedtoa __freedtoa 41165942Sgibbs 41265942Sgibbs#include <float.h> 41365942Sgibbs#include <math.h> 41465942Sgibbs#include "floatio.h" 41565942Sgibbs#include "gdtoa.h" 41665942Sgibbs 41765942Sgibbs#define DEFPREC 6 41865942Sgibbs 41965942Sgibbsstatic int exponent(char *, int, int); 42065942Sgibbs 42165942Sgibbs#endif /* !NO_FLOATING_POINT */ 42265942Sgibbs 42365942Sgibbs/* 42465942Sgibbs * The size of the buffer we use as scratch space for integer 42565942Sgibbs * conversions, among other things. Technically, we would need the 42665942Sgibbs * most space for base 10 conversions with thousands' grouping 42765942Sgibbs * characters between each pair of digits. 100 bytes is a 42865942Sgibbs * conservative overestimate even for a 128-bit uintmax_t. 42965942Sgibbs */ 43065942Sgibbs#define BUF 100 43165942Sgibbs 43265942Sgibbs#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 43365942Sgibbs 43465942Sgibbs/* 43565942Sgibbs * Flags used during conversion. 43665942Sgibbs */ 43765942Sgibbs#define ALT 0x001 /* alternate form */ 43865942Sgibbs#define LADJUST 0x004 /* left adjustment */ 43965942Sgibbs#define LONGDBL 0x008 /* long double */ 44065942Sgibbs#define LONGINT 0x010 /* long integer */ 44165942Sgibbs#define LLONGINT 0x020 /* long long integer */ 44266510Sgibbs#define SHORTINT 0x040 /* short integer */ 44365942Sgibbs#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 44465942Sgibbs#define FPT 0x100 /* Floating point number */ 44565942Sgibbs#define GROUPING 0x200 /* use grouping ("'" flag) */ 44665942Sgibbs /* C99 additional size modifiers: */ 44765942Sgibbs#define SIZET 0x400 /* size_t */ 44865942Sgibbs#define PTRDIFFT 0x800 /* ptrdiff_t */ 44965942Sgibbs#define INTMAXT 0x1000 /* intmax_t */ 45065942Sgibbs#define CHARINT 0x2000 /* print char using int format */ 45165942Sgibbs 45265942Sgibbs/* 45365942Sgibbs * Non-MT-safe version 45465942Sgibbs */ 45565942Sgibbsint 45665942Sgibbs__vfprintf(FILE *fp, const char *fmt0, va_list ap) 45765942Sgibbs{ 45865942Sgibbs char *fmt; /* format string */ 45965942Sgibbs int ch; /* character from fmt */ 46065942Sgibbs int n, n2; /* handy integer (short term usage) */ 46165942Sgibbs char *cp; /* handy char pointer (short term usage) */ 46265942Sgibbs struct __siov *iovp; /* for PRINT macro */ 46365942Sgibbs int flags; /* flags as above */ 46465942Sgibbs int ret; /* return value accumulator */ 46565942Sgibbs int width; /* width from format (%8d), or 0 */ 46665942Sgibbs int prec; /* precision from format; <0 for N/A */ 46765942Sgibbs char sign; /* sign prefix (' ', '+', '-', or \0) */ 46865942Sgibbs char thousands_sep; /* locale specific thousands separator */ 46965942Sgibbs const char *grouping; /* locale specific numeric grouping rules */ 47065942Sgibbs 47165942Sgibbs if (__use_xprintf == 0 && getenv("USE_XPRINTF")) 47265942Sgibbs __use_xprintf = 1; 47365942Sgibbs if (__use_xprintf > 0) 47465942Sgibbs return (__xvprintf(fp, fmt0, ap)); 47565942Sgibbs 47665942Sgibbs#ifndef NO_FLOATING_POINT 47765942Sgibbs /* 47865942Sgibbs * We can decompose the printed representation of floating 47965942Sgibbs * point numbers into several parts, some of which may be empty: 48065942Sgibbs * 48165942Sgibbs * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ 48265942Sgibbs * A B ---C--- D E F 48365942Sgibbs * 48465942Sgibbs * A: 'sign' holds this value if present; '\0' otherwise 48565942Sgibbs * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal 48665942Sgibbs * C: cp points to the string MMMNNN. Leading and trailing 48765942Sgibbs * zeros are not in the string and must be added. 48865942Sgibbs * D: expchar holds this character; '\0' if no exponent, e.g. %f 48965942Sgibbs * F: at least two digits for decimal, at least one digit for hex 49065942Sgibbs */ 49165942Sgibbs char *decimal_point; /* locale specific decimal point */ 49265942Sgibbs int signflag; /* true if float is negative */ 49365942Sgibbs union { /* floating point arguments %[aAeEfFgG] */ 49465942Sgibbs double dbl; 49565942Sgibbs long double ldbl; 49665942Sgibbs } fparg; 49765942Sgibbs int expt; /* integer value of exponent */ 49865942Sgibbs char expchar; /* exponent character: [eEpP\0] */ 49965942Sgibbs char *dtoaend; /* pointer to end of converted digits */ 50065942Sgibbs int expsize; /* character count for expstr */ 50165942Sgibbs int lead; /* sig figs before decimal or group sep */ 50265942Sgibbs int ndig; /* actual number of digits returned by dtoa */ 50365942Sgibbs char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ 50465942Sgibbs char *dtoaresult; /* buffer allocated by dtoa */ 50565942Sgibbs int nseps; /* number of group separators with ' */ 50665942Sgibbs int nrepeats; /* number of repeats of the last group */ 50765942Sgibbs#endif 50865942Sgibbs u_long ulval; /* integer arguments %[diouxX] */ 50965942Sgibbs uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ 51065942Sgibbs int base; /* base for [diouxX] conversion */ 51165942Sgibbs int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 51265942Sgibbs int realsz; /* field size expanded by dprec, sign, etc */ 51365942Sgibbs int size; /* size of converted field or string */ 51465942Sgibbs int prsize; /* max size of printed field */ 51565942Sgibbs const char *xdigs; /* digits for %[xX] conversion */ 51665942Sgibbs#define NIOV 8 51765942Sgibbs struct __suio uio; /* output information: summary */ 51865942Sgibbs struct __siov iov[NIOV];/* ... and individual io vectors */ 51965942Sgibbs char buf[BUF]; /* buffer with space for digits of uintmax_t */ 52065942Sgibbs char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ 52165942Sgibbs union arg *argtable; /* args, built due to positional arg */ 52265942Sgibbs union arg statargtable [STATIC_ARG_TBL_SIZE]; 52365942Sgibbs int nextarg; /* 1-based argument index */ 52465942Sgibbs va_list orgap; /* original argument pointer */ 52565942Sgibbs char *convbuf; /* wide to multibyte conversion result */ 52665942Sgibbs 52765942Sgibbs /* 52865942Sgibbs * Choose PADSIZE to trade efficiency vs. size. If larger printf 52965942Sgibbs * fields occur frequently, increase PADSIZE and make the initialisers 53065942Sgibbs * below longer. 53165942Sgibbs */ 53265942Sgibbs#define PADSIZE 16 /* pad chunk size */ 53365942Sgibbs static char blanks[PADSIZE] = 53465942Sgibbs {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 53565942Sgibbs static char zeroes[PADSIZE] = 53665942Sgibbs {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 53765942Sgibbs 53865942Sgibbs static const char xdigs_lower[16] = "0123456789abcdef"; 53965942Sgibbs static const char xdigs_upper[16] = "0123456789ABCDEF"; 54065942Sgibbs 54165942Sgibbs /* 54265942Sgibbs * BEWARE, these `goto error' on error, and PAD uses `n'. 54365942Sgibbs */ 54465942Sgibbs#define PRINT(ptr, len) { \ 54565942Sgibbs iovp->iov_base = (ptr); \ 54665942Sgibbs iovp->iov_len = (len); \ 54765942Sgibbs uio.uio_resid += (len); \ 54865942Sgibbs iovp++; \ 54965942Sgibbs if (++uio.uio_iovcnt >= NIOV) { \ 55065942Sgibbs if (__sprint(fp, &uio)) \ 55165942Sgibbs goto error; \ 55265942Sgibbs iovp = iov; \ 55365942Sgibbs } \ 55465942Sgibbs} 55565942Sgibbs#define PAD(howmany, with) { \ 55665942Sgibbs if ((n = (howmany)) > 0) { \ 55765942Sgibbs while (n > PADSIZE) { \ 55865942Sgibbs PRINT(with, PADSIZE); \ 55965942Sgibbs n -= PADSIZE; \ 56065942Sgibbs } \ 56165942Sgibbs PRINT(with, n); \ 56265942Sgibbs } \ 56365942Sgibbs} 56465942Sgibbs#define PRINTANDPAD(p, ep, len, with) do { \ 56565942Sgibbs n2 = (ep) - (p); \ 56665942Sgibbs if (n2 > (len)) \ 56765942Sgibbs n2 = (len); \ 56865942Sgibbs if (n2 > 0) \ 56965942Sgibbs PRINT((p), n2); \ 57065942Sgibbs PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ 57165942Sgibbs} while(0) 57265942Sgibbs#define FLUSH() { \ 57365942Sgibbs if (uio.uio_resid && __sprint(fp, &uio)) \ 57465942Sgibbs goto error; \ 57565942Sgibbs uio.uio_iovcnt = 0; \ 57665942Sgibbs iovp = iov; \ 57765942Sgibbs} 57865942Sgibbs 57965942Sgibbs /* 58065942Sgibbs * Get the argument indexed by nextarg. If the argument table is 58165942Sgibbs * built, use it to get the argument. If its not, get the next 58265942Sgibbs * argument (and arguments must be gotten sequentially). 58365942Sgibbs */ 58465942Sgibbs#define GETARG(type) \ 58565942Sgibbs ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 58665942Sgibbs (nextarg++, va_arg(ap, type))) 58765942Sgibbs 58865942Sgibbs /* 58965942Sgibbs * To extend shorts properly, we need both signed and unsigned 59065942Sgibbs * argument extraction methods. 59165942Sgibbs */ 59265942Sgibbs#define SARG() \ 59365942Sgibbs (flags&LONGINT ? GETARG(long) : \ 59465942Sgibbs flags&SHORTINT ? (long)(short)GETARG(int) : \ 59565942Sgibbs flags&CHARINT ? (long)(signed char)GETARG(int) : \ 59665942Sgibbs (long)GETARG(int)) 59765942Sgibbs#define UARG() \ 59865942Sgibbs (flags&LONGINT ? GETARG(u_long) : \ 59965942Sgibbs flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 60065942Sgibbs flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ 60165942Sgibbs (u_long)GETARG(u_int)) 60265942Sgibbs#define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) 60365942Sgibbs#define SJARG() \ 60465942Sgibbs (flags&INTMAXT ? GETARG(intmax_t) : \ 60565942Sgibbs flags&SIZET ? (intmax_t)GETARG(size_t) : \ 60665942Sgibbs flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ 60765942Sgibbs (intmax_t)GETARG(long long)) 60865942Sgibbs#define UJARG() \ 60965942Sgibbs (flags&INTMAXT ? GETARG(uintmax_t) : \ 61065942Sgibbs flags&SIZET ? (uintmax_t)GETARG(size_t) : \ 61165942Sgibbs flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ 61265942Sgibbs (uintmax_t)GETARG(unsigned long long)) 61365942Sgibbs 61465942Sgibbs /* 61565942Sgibbs * Get * arguments, including the form *nn$. Preserve the nextarg 61665942Sgibbs * that the argument can be gotten once the type is determined. 61765942Sgibbs */ 61865942Sgibbs#define GETASTER(val) \ 61965942Sgibbs n2 = 0; \ 62065942Sgibbs cp = fmt; \ 62165942Sgibbs while (is_digit(*cp)) { \ 62265942Sgibbs n2 = 10 * n2 + to_digit(*cp); \ 62365942Sgibbs cp++; \ 62465942Sgibbs } \ 62565942Sgibbs if (*cp == '$') { \ 62665942Sgibbs int hold = nextarg; \ 62765942Sgibbs if (argtable == NULL) { \ 62865942Sgibbs argtable = statargtable; \ 62965942Sgibbs __find_arguments (fmt0, orgap, &argtable); \ 63065942Sgibbs } \ 63165942Sgibbs nextarg = n2; \ 63265942Sgibbs val = GETARG (int); \ 63365942Sgibbs nextarg = hold; \ 63465942Sgibbs fmt = ++cp; \ 63565942Sgibbs } else { \ 63665942Sgibbs val = GETARG (int); \ 63765942Sgibbs } 63865942Sgibbs 63965942Sgibbs 64065942Sgibbs thousands_sep = '\0'; 64165942Sgibbs grouping = NULL; 64265942Sgibbs convbuf = NULL; 64365942Sgibbs#ifndef NO_FLOATING_POINT 64465942Sgibbs dtoaresult = NULL; 64565942Sgibbs decimal_point = localeconv()->decimal_point; 64665942Sgibbs#endif 64765942Sgibbs /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 64865942Sgibbs if (prepwrite(fp) != 0) 64965942Sgibbs return (EOF); 65065942Sgibbs 65165942Sgibbs /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 65265942Sgibbs if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 65365942Sgibbs fp->_file >= 0) 65465942Sgibbs return (__sbprintf(fp, fmt0, ap)); 65565942Sgibbs 65665942Sgibbs fmt = (char *)fmt0; 65765942Sgibbs argtable = NULL; 65865942Sgibbs nextarg = 1; 65965942Sgibbs va_copy(orgap, ap); 66065942Sgibbs uio.uio_iov = iovp = iov; 66165942Sgibbs uio.uio_resid = 0; 66265942Sgibbs uio.uio_iovcnt = 0; 66365942Sgibbs ret = 0; 66465942Sgibbs 66565942Sgibbs /* 66665942Sgibbs * Scan the format for conversions (`%' character). 66765942Sgibbs */ 66865942Sgibbs for (;;) { 66965942Sgibbs for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 67065942Sgibbs /* void */; 67165942Sgibbs if ((n = fmt - cp) != 0) { 67265942Sgibbs if ((unsigned)ret + n > INT_MAX) { 67365942Sgibbs ret = EOF; 67465942Sgibbs goto error; 67565942Sgibbs } 67665942Sgibbs PRINT(cp, n); 67765942Sgibbs ret += n; 67865942Sgibbs } 67965942Sgibbs if (ch == '\0') 68065942Sgibbs goto done; 68165942Sgibbs fmt++; /* skip over '%' */ 68265942Sgibbs 68365942Sgibbs flags = 0; 68465942Sgibbs dprec = 0; 68565942Sgibbs width = 0; 68665942Sgibbs prec = -1; 68765942Sgibbs sign = '\0'; 68865942Sgibbs ox[1] = '\0'; 68965942Sgibbs 69065942Sgibbsrflag: ch = *fmt++; 69165942Sgibbsreswitch: switch (ch) { 69265942Sgibbs case ' ': 69365942Sgibbs /*- 69465942Sgibbs * ``If the space and + flags both appear, the space 69565942Sgibbs * flag will be ignored.'' 69665942Sgibbs * -- ANSI X3J11 69765942Sgibbs */ 69865942Sgibbs if (!sign) 69965942Sgibbs sign = ' '; 70065942Sgibbs goto rflag; 70165942Sgibbs case '#': 70265942Sgibbs flags |= ALT; 70365942Sgibbs goto rflag; 70465942Sgibbs case '*': 70565942Sgibbs /*- 70665942Sgibbs * ``A negative field width argument is taken as a 70765942Sgibbs * - flag followed by a positive field width.'' 70865942Sgibbs * -- ANSI X3J11 70965942Sgibbs * They don't exclude field widths read from args. 71065942Sgibbs */ 71165942Sgibbs GETASTER (width); 71265942Sgibbs if (width >= 0) 71365942Sgibbs goto rflag; 71465942Sgibbs width = -width; 71565942Sgibbs /* FALLTHROUGH */ 71665942Sgibbs case '-': 71765942Sgibbs flags |= LADJUST; 71865942Sgibbs goto rflag; 71965942Sgibbs case '+': 72065942Sgibbs sign = '+'; 72165942Sgibbs goto rflag; 72265942Sgibbs case '\'': 72365942Sgibbs flags |= GROUPING; 72465942Sgibbs thousands_sep = *(localeconv()->thousands_sep); 72565942Sgibbs grouping = localeconv()->grouping; 72665942Sgibbs goto rflag; 72765942Sgibbs case '.': 72865942Sgibbs if ((ch = *fmt++) == '*') { 72965942Sgibbs GETASTER (prec); 73065942Sgibbs goto rflag; 73165942Sgibbs } 73265942Sgibbs prec = 0; 73365942Sgibbs while (is_digit(ch)) { 73465942Sgibbs prec = 10 * prec + to_digit(ch); 73565942Sgibbs ch = *fmt++; 73665942Sgibbs } 73765942Sgibbs goto reswitch; 73865942Sgibbs case '0': 73965942Sgibbs /*- 74065942Sgibbs * ``Note that 0 is taken as a flag, not as the 74165942Sgibbs * beginning of a field width.'' 74265942Sgibbs * -- ANSI X3J11 74365942Sgibbs */ 74465942Sgibbs flags |= ZEROPAD; 74565942Sgibbs goto rflag; 74665942Sgibbs case '1': case '2': case '3': case '4': 74765942Sgibbs case '5': case '6': case '7': case '8': case '9': 74865942Sgibbs n = 0; 74965942Sgibbs do { 75065942Sgibbs n = 10 * n + to_digit(ch); 75165942Sgibbs ch = *fmt++; 75265942Sgibbs } while (is_digit(ch)); 75365942Sgibbs if (ch == '$') { 75465942Sgibbs nextarg = n; 75565942Sgibbs if (argtable == NULL) { 75665942Sgibbs argtable = statargtable; 75765942Sgibbs __find_arguments (fmt0, orgap, 75865942Sgibbs &argtable); 75965942Sgibbs } 76065942Sgibbs goto rflag; 76165942Sgibbs } 76265942Sgibbs width = n; 76365942Sgibbs goto reswitch; 76465942Sgibbs#ifndef NO_FLOATING_POINT 76565942Sgibbs case 'L': 76665942Sgibbs flags |= LONGDBL; 76765942Sgibbs goto rflag; 76865942Sgibbs#endif 76965942Sgibbs case 'h': 77065942Sgibbs if (flags & SHORTINT) { 77165942Sgibbs flags &= ~SHORTINT; 77265942Sgibbs flags |= CHARINT; 77365942Sgibbs } else 77465942Sgibbs flags |= SHORTINT; 77565942Sgibbs goto rflag; 77665942Sgibbs case 'j': 77765942Sgibbs flags |= INTMAXT; 77865942Sgibbs goto rflag; 77965942Sgibbs case 'l': 78065942Sgibbs if (flags & LONGINT) { 78165942Sgibbs flags &= ~LONGINT; 78265942Sgibbs flags |= LLONGINT; 78365942Sgibbs } else 78465942Sgibbs flags |= LONGINT; 78565942Sgibbs goto rflag; 78665942Sgibbs case 'q': 78765942Sgibbs flags |= LLONGINT; /* not necessarily */ 78865942Sgibbs goto rflag; 78965942Sgibbs case 't': 79065942Sgibbs flags |= PTRDIFFT; 79165942Sgibbs goto rflag; 79265942Sgibbs case 'z': 79365942Sgibbs flags |= SIZET; 79465942Sgibbs goto rflag; 79565942Sgibbs case 'C': 79665942Sgibbs flags |= LONGINT; 79765942Sgibbs /*FALLTHROUGH*/ 79865942Sgibbs case 'c': 79965942Sgibbs if (flags & LONGINT) { 80065942Sgibbs static const mbstate_t initial; 80165942Sgibbs mbstate_t mbs; 80265942Sgibbs size_t mbseqlen; 80365942Sgibbs 80465942Sgibbs mbs = initial; 80565942Sgibbs mbseqlen = wcrtomb(cp = buf, 80665942Sgibbs (wchar_t)GETARG(wint_t), &mbs); 80765942Sgibbs if (mbseqlen == (size_t)-1) { 80865942Sgibbs fp->_flags |= __SERR; 80965942Sgibbs goto error; 81065942Sgibbs } 81165942Sgibbs size = (int)mbseqlen; 81265942Sgibbs } else { 81365942Sgibbs *(cp = buf) = GETARG(int); 81465942Sgibbs size = 1; 81565942Sgibbs } 81665942Sgibbs sign = '\0'; 81765942Sgibbs break; 81865942Sgibbs case 'D': 81965942Sgibbs flags |= LONGINT; 82065942Sgibbs /*FALLTHROUGH*/ 82165942Sgibbs case 'd': 82265942Sgibbs case 'i': 82365942Sgibbs if (flags & INTMAX_SIZE) { 82465942Sgibbs ujval = SJARG(); 82565942Sgibbs if ((intmax_t)ujval < 0) { 82665942Sgibbs ujval = -ujval; 82765942Sgibbs sign = '-'; 82865942Sgibbs } 82965942Sgibbs } else { 83065942Sgibbs ulval = SARG(); 83165942Sgibbs if ((long)ulval < 0) { 83265942Sgibbs ulval = -ulval; 83365942Sgibbs sign = '-'; 83465942Sgibbs } 83565942Sgibbs } 83665942Sgibbs base = 10; 83765942Sgibbs goto number; 83865942Sgibbs#ifndef NO_FLOATING_POINT 83965942Sgibbs case 'a': 84065942Sgibbs case 'A': 84165942Sgibbs if (ch == 'a') { 84265942Sgibbs ox[1] = 'x'; 84365942Sgibbs xdigs = xdigs_lower; 84465942Sgibbs expchar = 'p'; 84565942Sgibbs } else { 84665942Sgibbs ox[1] = 'X'; 84765942Sgibbs xdigs = xdigs_upper; 84865942Sgibbs expchar = 'P'; 84965942Sgibbs } 85065942Sgibbs if (prec >= 0) 85165942Sgibbs prec++; 85265942Sgibbs if (dtoaresult != NULL) 85365942Sgibbs freedtoa(dtoaresult); 85465942Sgibbs if (flags & LONGDBL) { 85565942Sgibbs fparg.ldbl = GETARG(long double); 85665942Sgibbs dtoaresult = cp = 85765942Sgibbs __hldtoa(fparg.ldbl, xdigs, prec, 85865942Sgibbs &expt, &signflag, &dtoaend); 85965942Sgibbs } else { 86065942Sgibbs fparg.dbl = GETARG(double); 86165942Sgibbs dtoaresult = cp = 86265942Sgibbs __hdtoa(fparg.dbl, xdigs, prec, 86365942Sgibbs &expt, &signflag, &dtoaend); 86465942Sgibbs } 86565942Sgibbs if (prec < 0) 86665942Sgibbs prec = dtoaend - cp; 86765942Sgibbs if (expt == INT_MAX) 86865942Sgibbs ox[1] = '\0'; 86965942Sgibbs goto fp_common; 87065942Sgibbs case 'e': 87165942Sgibbs case 'E': 87265942Sgibbs expchar = ch; 87365942Sgibbs if (prec < 0) /* account for digit before decpt */ 87465942Sgibbs prec = DEFPREC + 1; 87565942Sgibbs else 87665942Sgibbs prec++; 87765942Sgibbs goto fp_begin; 87865942Sgibbs case 'f': 87965942Sgibbs case 'F': 88065942Sgibbs expchar = '\0'; 88165942Sgibbs goto fp_begin; 88265942Sgibbs case 'g': 88365942Sgibbs case 'G': 88465942Sgibbs expchar = ch - ('g' - 'e'); 88565942Sgibbs if (prec == 0) 88665942Sgibbs prec = 1; 88765942Sgibbsfp_begin: 88865942Sgibbs if (prec < 0) 88965942Sgibbs prec = DEFPREC; 89065942Sgibbs if (dtoaresult != NULL) 89165942Sgibbs freedtoa(dtoaresult); 89265942Sgibbs if (flags & LONGDBL) { 89365942Sgibbs fparg.ldbl = GETARG(long double); 89465942Sgibbs dtoaresult = cp = 89565942Sgibbs __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, 89665942Sgibbs &expt, &signflag, &dtoaend); 89765942Sgibbs } else { 89865942Sgibbs fparg.dbl = GETARG(double); 89965942Sgibbs dtoaresult = cp = 90065942Sgibbs dtoa(fparg.dbl, expchar ? 2 : 3, prec, 90165942Sgibbs &expt, &signflag, &dtoaend); 90265942Sgibbs if (expt == 9999) 90365942Sgibbs expt = INT_MAX; 90465942Sgibbs } 90565942Sgibbsfp_common: 90665942Sgibbs if (signflag) 90765942Sgibbs sign = '-'; 90865942Sgibbs if (expt == INT_MAX) { /* inf or nan */ 90965942Sgibbs if (*cp == 'N') { 91065942Sgibbs cp = (ch >= 'a') ? "nan" : "NAN"; 91165942Sgibbs sign = '\0'; 91265942Sgibbs } else 91365942Sgibbs cp = (ch >= 'a') ? "inf" : "INF"; 91465942Sgibbs size = 3; 91565942Sgibbs break; 91665942Sgibbs } 91765942Sgibbs flags |= FPT; 91865942Sgibbs ndig = dtoaend - cp; 91965942Sgibbs if (ch == 'g' || ch == 'G') { 92065942Sgibbs if (expt > -4 && expt <= prec) { 92165942Sgibbs /* Make %[gG] smell like %[fF] */ 92265942Sgibbs expchar = '\0'; 92365942Sgibbs if (flags & ALT) 92465942Sgibbs prec -= expt; 92565942Sgibbs else 92665942Sgibbs prec = ndig - expt; 92765942Sgibbs if (prec < 0) 92865942Sgibbs prec = 0; 92965942Sgibbs } else { 93065942Sgibbs /* 93165942Sgibbs * Make %[gG] smell like %[eE], but 93265942Sgibbs * trim trailing zeroes if no # flag. 93365942Sgibbs */ 93465942Sgibbs if (!(flags & ALT)) 93565942Sgibbs prec = ndig; 93665942Sgibbs } 93765942Sgibbs } 93865942Sgibbs if (expchar) { 93965942Sgibbs expsize = exponent(expstr, expt - 1, expchar); 94065942Sgibbs size = expsize + prec; 94165942Sgibbs if (prec > 1 || flags & ALT) 94265942Sgibbs ++size; 94365942Sgibbs } else { 94465942Sgibbs /* space for digits before decimal point */ 94565942Sgibbs if (expt > 0) 94665942Sgibbs size = expt; 94765942Sgibbs else /* "0" */ 94865942Sgibbs size = 1; 94965942Sgibbs /* space for decimal pt and following digits */ 95065942Sgibbs if (prec || flags & ALT) 95165942Sgibbs size += prec + 1; 95265942Sgibbs if (grouping && expt > 0) { 95365942Sgibbs /* space for thousands' grouping */ 95465942Sgibbs nseps = nrepeats = 0; 95565942Sgibbs lead = expt; 95665942Sgibbs while (*grouping != CHAR_MAX) { 95765942Sgibbs if (lead <= *grouping) 95865942Sgibbs break; 95965942Sgibbs lead -= *grouping; 96065942Sgibbs if (*(grouping+1)) { 96165942Sgibbs nseps++; 96265942Sgibbs grouping++; 96365942Sgibbs } else 96465942Sgibbs nrepeats++; 96565942Sgibbs } 96665942Sgibbs size += nseps + nrepeats; 96765942Sgibbs } else 96865942Sgibbs lead = expt; 96965942Sgibbs } 97065942Sgibbs break; 97165942Sgibbs#endif /* !NO_FLOATING_POINT */ 97265942Sgibbs case 'n': 97365942Sgibbs /* 97465942Sgibbs * Assignment-like behavior is specified if the 97565942Sgibbs * value overflows or is otherwise unrepresentable. 97665942Sgibbs * C99 says to use `signed char' for %hhn conversions. 97765942Sgibbs */ 97865942Sgibbs if (flags & LLONGINT) 97965942Sgibbs *GETARG(long long *) = ret; 98065942Sgibbs else if (flags & SIZET) 98165942Sgibbs *GETARG(ssize_t *) = (ssize_t)ret; 98265942Sgibbs else if (flags & PTRDIFFT) 98365942Sgibbs *GETARG(ptrdiff_t *) = ret; 98465942Sgibbs else if (flags & INTMAXT) 98565942Sgibbs *GETARG(intmax_t *) = ret; 98665942Sgibbs else if (flags & LONGINT) 98765942Sgibbs *GETARG(long *) = ret; 98865942Sgibbs else if (flags & SHORTINT) 98965942Sgibbs *GETARG(short *) = ret; 99065942Sgibbs else if (flags & CHARINT) 99165942Sgibbs *GETARG(signed char *) = ret; 99265942Sgibbs else 99365942Sgibbs *GETARG(int *) = ret; 99465942Sgibbs continue; /* no output */ 99565942Sgibbs case 'O': 99665942Sgibbs flags |= LONGINT; 99765942Sgibbs /*FALLTHROUGH*/ 99865942Sgibbs case 'o': 99965942Sgibbs if (flags & INTMAX_SIZE) 100065942Sgibbs ujval = UJARG(); 100165942Sgibbs else 100265942Sgibbs ulval = UARG(); 100365942Sgibbs base = 8; 100465942Sgibbs goto nosign; 100565942Sgibbs case 'p': 100665942Sgibbs /*- 100765942Sgibbs * ``The argument shall be a pointer to void. The 100865942Sgibbs * value of the pointer is converted to a sequence 100965942Sgibbs * of printable characters, in an implementation- 101065942Sgibbs * defined manner.'' 101165942Sgibbs * -- ANSI X3J11 101265942Sgibbs */ 101365942Sgibbs ujval = (uintmax_t)(uintptr_t)GETARG(void *); 101465942Sgibbs base = 16; 101565942Sgibbs xdigs = xdigs_lower; 101665942Sgibbs flags = flags | INTMAXT; 101765942Sgibbs ox[1] = 'x'; 101865942Sgibbs goto nosign; 101965942Sgibbs case 'S': 102065942Sgibbs flags |= LONGINT; 102165942Sgibbs /*FALLTHROUGH*/ 102265942Sgibbs case 's': 102365942Sgibbs if (flags & LONGINT) { 102465942Sgibbs wchar_t *wcp; 102565942Sgibbs 102665942Sgibbs if (convbuf != NULL) 102765942Sgibbs free(convbuf); 102865942Sgibbs if ((wcp = GETARG(wchar_t *)) == NULL) 102965942Sgibbs cp = "(null)"; 103065942Sgibbs else { 103165942Sgibbs convbuf = __wcsconv(wcp, prec); 103265942Sgibbs if (convbuf == NULL) { 103365942Sgibbs fp->_flags |= __SERR; 103465942Sgibbs goto error; 103565942Sgibbs } 103665942Sgibbs cp = convbuf; 103765942Sgibbs } 103865942Sgibbs } else if ((cp = GETARG(char *)) == NULL) 103965942Sgibbs cp = "(null)"; 104065942Sgibbs if (prec >= 0) { 104165942Sgibbs /* 104265942Sgibbs * can't use strlen; can only look for the 104365942Sgibbs * NUL in the first `prec' characters, and 104465942Sgibbs * strlen() will go further. 104565942Sgibbs */ 104665942Sgibbs char *p = memchr(cp, 0, (size_t)prec); 104765942Sgibbs 104865942Sgibbs if (p != NULL) { 104965942Sgibbs size = p - cp; 105065942Sgibbs if (size > prec) 105165942Sgibbs size = prec; 105265942Sgibbs } else 105365942Sgibbs size = prec; 105465942Sgibbs } else 105565942Sgibbs size = strlen(cp); 105665942Sgibbs sign = '\0'; 105765942Sgibbs break; 105865942Sgibbs case 'U': 105965942Sgibbs flags |= LONGINT; 106065942Sgibbs /*FALLTHROUGH*/ 106165942Sgibbs case 'u': 106265942Sgibbs if (flags & INTMAX_SIZE) 106365942Sgibbs ujval = UJARG(); 106465942Sgibbs else 106565942Sgibbs ulval = UARG(); 106665942Sgibbs base = 10; 106765942Sgibbs goto nosign; 106865942Sgibbs case 'X': 106965942Sgibbs xdigs = xdigs_upper; 107065942Sgibbs goto hex; 107165942Sgibbs case 'x': 107265942Sgibbs xdigs = xdigs_lower; 107365942Sgibbshex: 107465942Sgibbs if (flags & INTMAX_SIZE) 107565942Sgibbs ujval = UJARG(); 107666647Sgibbs else 107765942Sgibbs ulval = UARG(); 107866647Sgibbs base = 16; 107965942Sgibbs /* leading 0x/X only if non-zero */ 108065942Sgibbs if (flags & ALT && 108165942Sgibbs (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 108265942Sgibbs ox[1] = ch; 108365942Sgibbs 108465942Sgibbs flags &= ~GROUPING; 108565942Sgibbs /* unsigned conversions */ 108665942Sgibbsnosign: sign = '\0'; 108765942Sgibbs /*- 108865942Sgibbs * ``... diouXx conversions ... if a precision is 108965942Sgibbs * specified, the 0 flag will be ignored.'' 109065942Sgibbs * -- ANSI X3J11 109165942Sgibbs */ 109265942Sgibbsnumber: if ((dprec = prec) >= 0) 109365942Sgibbs flags &= ~ZEROPAD; 109465942Sgibbs 109565942Sgibbs /*- 109665942Sgibbs * ``The result of converting a zero value with an 109765942Sgibbs * explicit precision of zero is no characters.'' 109865942Sgibbs * -- ANSI X3J11 109965942Sgibbs * 110065942Sgibbs * ``The C Standard is clear enough as is. The call 110165942Sgibbs * printf("%#.0o", 0) should print 0.'' 110265942Sgibbs * -- Defect Report #151 110365942Sgibbs */ 110465942Sgibbs cp = buf + BUF; 110565942Sgibbs if (flags & INTMAX_SIZE) { 110665942Sgibbs if (ujval != 0 || prec != 0 || 110765942Sgibbs (flags & ALT && base == 8)) 110865942Sgibbs cp = __ujtoa(ujval, cp, base, 110965942Sgibbs flags & ALT, xdigs, 111065942Sgibbs flags & GROUPING, thousands_sep, 111165942Sgibbs grouping); 111265942Sgibbs } else { 111365942Sgibbs if (ulval != 0 || prec != 0 || 111465942Sgibbs (flags & ALT && base == 8)) 111565942Sgibbs cp = __ultoa(ulval, cp, base, 111665942Sgibbs flags & ALT, xdigs, 111765942Sgibbs flags & GROUPING, thousands_sep, 111865942Sgibbs grouping); 111965942Sgibbs } 112065942Sgibbs size = buf + BUF - cp; 112165942Sgibbs if (size > BUF) /* should never happen */ 112265942Sgibbs abort(); 112365942Sgibbs break; 112465942Sgibbs default: /* "%?" prints ?, unless ? is NUL */ 112565942Sgibbs if (ch == '\0') 112665942Sgibbs goto done; 112765942Sgibbs /* pretend it was %c with argument ch */ 112865942Sgibbs cp = buf; 112965942Sgibbs *cp = ch; 113065942Sgibbs size = 1; 113165942Sgibbs sign = '\0'; 113265942Sgibbs break; 113365942Sgibbs } 113465942Sgibbs 113565942Sgibbs /* 113665942Sgibbs * All reasonable formats wind up here. At this point, `cp' 113765942Sgibbs * points to a string which (if not flags&LADJUST) should be 113865942Sgibbs * padded out to `width' places. If flags&ZEROPAD, it should 113965942Sgibbs * first be prefixed by any sign or other prefix; otherwise, 114065942Sgibbs * it should be blank padded before the prefix is emitted. 114165942Sgibbs * After any left-hand padding and prefixing, emit zeroes 114265942Sgibbs * required by a decimal [diouxX] precision, then print the 114365942Sgibbs * string proper, then emit zeroes required by any leftover 114465942Sgibbs * floating precision; finally, if LADJUST, pad with blanks. 114566647Sgibbs * 114665942Sgibbs * Compute actual size, so we know how much to pad. 114766647Sgibbs * size excludes decimal prec; realsz includes it. 114865942Sgibbs */ 114965942Sgibbs realsz = dprec > size ? dprec : size; 115065942Sgibbs if (sign) 115165942Sgibbs realsz++; 115265942Sgibbs if (ox[1]) 115365942Sgibbs realsz += 2; 115465942Sgibbs 115565942Sgibbs prsize = width > realsz ? width : realsz; 115665942Sgibbs if ((unsigned)ret + prsize > INT_MAX) { 115765942Sgibbs ret = EOF; 115865942Sgibbs goto error; 115965942Sgibbs } 116065942Sgibbs 116165942Sgibbs /* right-adjusting blank padding */ 116265942Sgibbs if ((flags & (LADJUST|ZEROPAD)) == 0) 116365942Sgibbs PAD(width - realsz, blanks); 116465942Sgibbs 116565942Sgibbs /* prefix */ 116665942Sgibbs if (sign) 116765942Sgibbs PRINT(&sign, 1); 116865942Sgibbs 116965942Sgibbs if (ox[1]) { /* ox[1] is either x, X, or \0 */ 117065942Sgibbs ox[0] = '0'; 117165942Sgibbs PRINT(ox, 2); 117265942Sgibbs } 117365942Sgibbs 117465942Sgibbs /* right-adjusting zero padding */ 117565942Sgibbs if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 117665942Sgibbs PAD(width - realsz, zeroes); 117765942Sgibbs 117865942Sgibbs /* leading zeroes from decimal precision */ 117965942Sgibbs PAD(dprec - size, zeroes); 118065942Sgibbs 118166647Sgibbs /* the string or number proper */ 118265942Sgibbs#ifndef NO_FLOATING_POINT 118365942Sgibbs if ((flags & FPT) == 0) { 118465942Sgibbs PRINT(cp, size); 118565942Sgibbs } else { /* glue together f_p fragments */ 118665942Sgibbs if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 118765942Sgibbs if (expt <= 0) { 118865942Sgibbs PRINT(zeroes, 1); 118965942Sgibbs if (prec || flags & ALT) 119065942Sgibbs PRINT(decimal_point, 1); 119165942Sgibbs PAD(-expt, zeroes); 119265942Sgibbs /* already handled initial 0's */ 119365942Sgibbs prec += expt; 119465942Sgibbs } else { 119565942Sgibbs PRINTANDPAD(cp, dtoaend, lead, zeroes); 119665942Sgibbs cp += lead; 119765942Sgibbs if (grouping) { 119865942Sgibbs while (nseps>0 || nrepeats>0) { 119965942Sgibbs if (nrepeats > 0) 120065942Sgibbs nrepeats--; 120165942Sgibbs else { 120265942Sgibbs grouping--; 120365942Sgibbs nseps--; 120465942Sgibbs } 120565942Sgibbs PRINT(&thousands_sep, 120665942Sgibbs 1); 120765942Sgibbs PRINTANDPAD(cp,dtoaend, 120865942Sgibbs *grouping, zeroes); 120965942Sgibbs cp += *grouping; 121065942Sgibbs } 121165942Sgibbs if (cp > dtoaend) 121265942Sgibbs cp = dtoaend; 121365942Sgibbs } 121465942Sgibbs if (prec || flags & ALT) 121565942Sgibbs PRINT(decimal_point,1); 121665942Sgibbs } 121765942Sgibbs PRINTANDPAD(cp, dtoaend, prec, zeroes); 121865942Sgibbs } else { /* %[eE] or sufficiently long %[gG] */ 121965942Sgibbs if (prec > 1 || flags & ALT) { 122065942Sgibbs buf[0] = *cp++; 122165942Sgibbs buf[1] = *decimal_point; 122265942Sgibbs PRINT(buf, 2); 122365942Sgibbs PRINT(cp, ndig-1); 122465942Sgibbs PAD(prec - ndig, zeroes); 122565942Sgibbs } else /* XeYYY */ 122665942Sgibbs PRINT(cp, 1); 122765942Sgibbs PRINT(expstr, expsize); 122865942Sgibbs } 122965942Sgibbs } 123065942Sgibbs#else 123165942Sgibbs PRINT(cp, size); 123265942Sgibbs#endif 123365942Sgibbs /* left-adjusting padding (always blank) */ 123465942Sgibbs if (flags & LADJUST) 123565942Sgibbs PAD(width - realsz, blanks); 123665942Sgibbs 123765942Sgibbs /* finally, adjust ret */ 123865942Sgibbs ret += prsize; 123965942Sgibbs 124065942Sgibbs FLUSH(); /* copy out the I/O vectors */ 124165942Sgibbs } 124265942Sgibbsdone: 124365942Sgibbs FLUSH(); 124465942Sgibbserror: 124565942Sgibbs va_end(orgap); 124665942Sgibbs#ifndef NO_FLOATING_POINT 124765942Sgibbs if (dtoaresult != NULL) 124865942Sgibbs freedtoa(dtoaresult); 124965942Sgibbs#endif 125065942Sgibbs if (convbuf != NULL) 125165942Sgibbs free(convbuf); 125265942Sgibbs if (__sferror(fp)) 125366647Sgibbs ret = EOF; 125466647Sgibbs if ((argtable != NULL) && (argtable != statargtable)) 125565942Sgibbs free (argtable); 125665942Sgibbs return (ret); 125766647Sgibbs /* NOTREACHED */ 125865942Sgibbs} 125966647Sgibbs 126066647Sgibbs/* 126165942Sgibbs * Find all arguments when a positional parameter is encountered. Returns a 126265942Sgibbs * table, indexed by argument number, of pointers to each arguments. The 126365942Sgibbs * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 126465942Sgibbs * It will be replaces with a malloc-ed one if it overflows. 126565942Sgibbs */ 126665942Sgibbsstatic void 126765942Sgibbs__find_arguments (const char *fmt0, va_list ap, union arg **argtable) 126865942Sgibbs{ 126965942Sgibbs char *fmt; /* format string */ 127065942Sgibbs int ch; /* character from fmt */ 127165942Sgibbs int n, n2; /* handy integer (short term usage) */ 127265942Sgibbs char *cp; /* handy char pointer (short term usage) */ 127365942Sgibbs int flags; /* flags as above */ 127465942Sgibbs int width; /* width from format (%8d), or 0 */ 127565942Sgibbs enum typeid *typetable; /* table of types */ 127665942Sgibbs enum typeid stattypetable [STATIC_ARG_TBL_SIZE]; 127765942Sgibbs int tablesize; /* current size of type table */ 127865942Sgibbs int tablemax; /* largest used index in table */ 127965942Sgibbs int nextarg; /* 1-based argument index */ 128065942Sgibbs 128165942Sgibbs /* 128265942Sgibbs * Add an argument type to the table, expanding if necessary. 128365942Sgibbs */ 128465942Sgibbs#define ADDTYPE(type) \ 128565942Sgibbs ((nextarg >= tablesize) ? \ 128665942Sgibbs __grow_type_table(nextarg, &typetable, &tablesize) : (void)0, \ 128765942Sgibbs (nextarg > tablemax) ? tablemax = nextarg : 0, \ 128865942Sgibbs typetable[nextarg++] = type) 128965942Sgibbs 129065942Sgibbs#define ADDSARG() \ 129165942Sgibbs ((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \ 129265942Sgibbs ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 129365942Sgibbs ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 129465942Sgibbs ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \ 129565942Sgibbs ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT)))))) 129665942Sgibbs 129765942Sgibbs#define ADDUARG() \ 129865942Sgibbs ((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \ 129965942Sgibbs ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 130065942Sgibbs ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 130165942Sgibbs ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \ 130265942Sgibbs ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT)))))) 130365942Sgibbs 130465942Sgibbs /* 130565942Sgibbs * Add * arguments to the type array. 130665942Sgibbs */ 130765942Sgibbs#define ADDASTER() \ 130865942Sgibbs n2 = 0; \ 130965942Sgibbs cp = fmt; \ 131065942Sgibbs while (is_digit(*cp)) { \ 131165942Sgibbs n2 = 10 * n2 + to_digit(*cp); \ 131265942Sgibbs cp++; \ 131365942Sgibbs } \ 131465942Sgibbs if (*cp == '$') { \ 131565942Sgibbs int hold = nextarg; \ 131665942Sgibbs nextarg = n2; \ 131765942Sgibbs ADDTYPE (T_INT); \ 131865942Sgibbs nextarg = hold; \ 131965942Sgibbs fmt = ++cp; \ 132065942Sgibbs } else { \ 132165942Sgibbs ADDTYPE (T_INT); \ 132265942Sgibbs } 132365942Sgibbs fmt = (char *)fmt0; 132465942Sgibbs typetable = stattypetable; 132565942Sgibbs tablesize = STATIC_ARG_TBL_SIZE; 132665942Sgibbs tablemax = 0; 132765942Sgibbs nextarg = 1; 132865942Sgibbs for (n = 0; n < STATIC_ARG_TBL_SIZE; n++) 132965942Sgibbs typetable[n] = T_UNUSED; 133065942Sgibbs 133165942Sgibbs /* 133265942Sgibbs * Scan the format for conversions (`%' character). 133365942Sgibbs */ 133465942Sgibbs for (;;) { 133565942Sgibbs for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 133665942Sgibbs /* void */; 133765942Sgibbs if (ch == '\0') 133865942Sgibbs goto done; 133965942Sgibbs fmt++; /* skip over '%' */ 134065942Sgibbs 134165942Sgibbs flags = 0; 134265942Sgibbs width = 0; 134365942Sgibbs 134465942Sgibbsrflag: ch = *fmt++; 134565942Sgibbsreswitch: switch (ch) { 134665942Sgibbs case ' ': 134765942Sgibbs case '#': 134865942Sgibbs goto rflag; 134965942Sgibbs case '*': 135065942Sgibbs ADDASTER (); 135165942Sgibbs goto rflag; 135265942Sgibbs case '-': 135365942Sgibbs case '+': 135465942Sgibbs case '\'': 135565942Sgibbs goto rflag; 135665942Sgibbs case '.': 135765942Sgibbs if ((ch = *fmt++) == '*') { 135865942Sgibbs ADDASTER (); 135965942Sgibbs goto rflag; 136065942Sgibbs } 136165942Sgibbs while (is_digit(ch)) { 136265942Sgibbs ch = *fmt++; 136365942Sgibbs } 136465942Sgibbs goto reswitch; 136565942Sgibbs case '0': 136665942Sgibbs goto rflag; 136765942Sgibbs case '1': case '2': case '3': case '4': 136865942Sgibbs case '5': case '6': case '7': case '8': case '9': 136965942Sgibbs n = 0; 137065942Sgibbs do { 137165942Sgibbs n = 10 * n + to_digit(ch); 137265942Sgibbs ch = *fmt++; 137365942Sgibbs } while (is_digit(ch)); 137465942Sgibbs if (ch == '$') { 137565942Sgibbs nextarg = n; 137665942Sgibbs goto rflag; 137765942Sgibbs } 137865942Sgibbs width = n; 137965942Sgibbs goto reswitch; 138065942Sgibbs#ifndef NO_FLOATING_POINT 138165942Sgibbs case 'L': 138265942Sgibbs flags |= LONGDBL; 138365942Sgibbs goto rflag; 138465942Sgibbs#endif 138565942Sgibbs case 'h': 138665942Sgibbs if (flags & SHORTINT) { 138765942Sgibbs flags &= ~SHORTINT; 138865942Sgibbs flags |= CHARINT; 138965942Sgibbs } else 139065942Sgibbs flags |= SHORTINT; 139165942Sgibbs goto rflag; 139265942Sgibbs case 'j': 139365942Sgibbs flags |= INTMAXT; 139465942Sgibbs goto rflag; 139565942Sgibbs case 'l': 139665942Sgibbs if (flags & LONGINT) { 139765942Sgibbs flags &= ~LONGINT; 139865942Sgibbs flags |= LLONGINT; 139965942Sgibbs } else 140065942Sgibbs flags |= LONGINT; 140165942Sgibbs goto rflag; 140265942Sgibbs case 'q': 140365942Sgibbs flags |= LLONGINT; /* not necessarily */ 140465942Sgibbs goto rflag; 140565942Sgibbs case 't': 140665942Sgibbs flags |= PTRDIFFT; 140765942Sgibbs goto rflag; 140865942Sgibbs case 'z': 140965942Sgibbs flags |= SIZET; 141065942Sgibbs goto rflag; 141165942Sgibbs case 'C': 141265942Sgibbs flags |= LONGINT; 141365942Sgibbs /*FALLTHROUGH*/ 141465942Sgibbs case 'c': 141565942Sgibbs if (flags & LONGINT) 141665942Sgibbs ADDTYPE(T_WINT); 141765942Sgibbs else 141865942Sgibbs ADDTYPE(T_INT); 141965942Sgibbs break; 142065942Sgibbs case 'D': 142165942Sgibbs flags |= LONGINT; 142265942Sgibbs /*FALLTHROUGH*/ 142365942Sgibbs case 'd': 142465942Sgibbs case 'i': 142565942Sgibbs ADDSARG(); 142665942Sgibbs break; 142765942Sgibbs#ifndef NO_FLOATING_POINT 142865942Sgibbs case 'a': 142965942Sgibbs case 'A': 143065942Sgibbs case 'e': 143165942Sgibbs case 'E': 143265942Sgibbs case 'f': 143365942Sgibbs case 'g': 143465942Sgibbs case 'G': 143565942Sgibbs if (flags & LONGDBL) 143665942Sgibbs ADDTYPE(T_LONG_DOUBLE); 143765942Sgibbs else 143865942Sgibbs ADDTYPE(T_DOUBLE); 143965942Sgibbs break; 144065942Sgibbs#endif /* !NO_FLOATING_POINT */ 144165942Sgibbs case 'n': 144265942Sgibbs if (flags & INTMAXT) 144365942Sgibbs ADDTYPE(TP_INTMAXT); 144465942Sgibbs else if (flags & PTRDIFFT) 144565942Sgibbs ADDTYPE(TP_PTRDIFFT); 144665942Sgibbs else if (flags & SIZET) 144765942Sgibbs ADDTYPE(TP_SIZET); 144865942Sgibbs else if (flags & LLONGINT) 144965942Sgibbs ADDTYPE(TP_LLONG); 145065942Sgibbs else if (flags & LONGINT) 145165942Sgibbs ADDTYPE(TP_LONG); 145265942Sgibbs else if (flags & SHORTINT) 145365942Sgibbs ADDTYPE(TP_SHORT); 145465942Sgibbs else if (flags & CHARINT) 145565942Sgibbs ADDTYPE(TP_SCHAR); 145665942Sgibbs else 145765942Sgibbs ADDTYPE(TP_INT); 145865942Sgibbs continue; /* no output */ 145965942Sgibbs case 'O': 146065942Sgibbs flags |= LONGINT; 146165942Sgibbs /*FALLTHROUGH*/ 146265942Sgibbs case 'o': 146365942Sgibbs ADDUARG(); 146465942Sgibbs break; 146565942Sgibbs case 'p': 146665942Sgibbs ADDTYPE(TP_VOID); 146765942Sgibbs break; 146865942Sgibbs case 'S': 146965942Sgibbs flags |= LONGINT; 147065942Sgibbs /*FALLTHROUGH*/ 147165942Sgibbs case 's': 147265942Sgibbs if (flags & LONGINT) 147365942Sgibbs ADDTYPE(TP_WCHAR); 147465942Sgibbs else 147565942Sgibbs ADDTYPE(TP_CHAR); 147665942Sgibbs break; 147765942Sgibbs case 'U': 147865942Sgibbs flags |= LONGINT; 147965942Sgibbs /*FALLTHROUGH*/ 148065942Sgibbs case 'u': 148165942Sgibbs case 'X': 148265942Sgibbs case 'x': 148365942Sgibbs ADDUARG(); 148465942Sgibbs break; 148565942Sgibbs default: /* "%?" prints ?, unless ? is NUL */ 148665942Sgibbs if (ch == '\0') 148765942Sgibbs goto done; 148865942Sgibbs break; 148965942Sgibbs } 149065942Sgibbs } 149165942Sgibbsdone: 149265942Sgibbs /* 149365942Sgibbs * Build the argument table. 149465942Sgibbs */ 149565942Sgibbs if (tablemax >= STATIC_ARG_TBL_SIZE) { 149665942Sgibbs *argtable = (union arg *) 149765942Sgibbs malloc (sizeof (union arg) * (tablemax + 1)); 149865942Sgibbs } 149965942Sgibbs 150065942Sgibbs (*argtable) [0].intarg = 0; 150165942Sgibbs for (n = 1; n <= tablemax; n++) { 150265942Sgibbs switch (typetable [n]) { 150365942Sgibbs case T_UNUSED: /* whoops! */ 150465942Sgibbs (*argtable) [n].intarg = va_arg (ap, int); 150565942Sgibbs break; 150665942Sgibbs case TP_SCHAR: 150765942Sgibbs (*argtable) [n].pschararg = va_arg (ap, signed char *); 150865942Sgibbs break; 150965942Sgibbs case TP_SHORT: 151065942Sgibbs (*argtable) [n].pshortarg = va_arg (ap, short *); 151165942Sgibbs break; 151265942Sgibbs case T_INT: 151365942Sgibbs (*argtable) [n].intarg = va_arg (ap, int); 151465942Sgibbs break; 151565942Sgibbs case T_U_INT: 151665942Sgibbs (*argtable) [n].uintarg = va_arg (ap, unsigned int); 151765942Sgibbs break; 151865942Sgibbs case TP_INT: 151965942Sgibbs (*argtable) [n].pintarg = va_arg (ap, int *); 152065942Sgibbs break; 152165942Sgibbs case T_LONG: 152265942Sgibbs (*argtable) [n].longarg = va_arg (ap, long); 152365942Sgibbs break; 152465942Sgibbs case T_U_LONG: 152565942Sgibbs (*argtable) [n].ulongarg = va_arg (ap, unsigned long); 152665942Sgibbs break; 152765942Sgibbs case TP_LONG: 152865942Sgibbs (*argtable) [n].plongarg = va_arg (ap, long *); 152965942Sgibbs break; 153065942Sgibbs case T_LLONG: 153165942Sgibbs (*argtable) [n].longlongarg = va_arg (ap, long long); 153265942Sgibbs break; 153365942Sgibbs case T_U_LLONG: 153465942Sgibbs (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); 153565942Sgibbs break; 153665942Sgibbs case TP_LLONG: 153765942Sgibbs (*argtable) [n].plonglongarg = va_arg (ap, long long *); 153865942Sgibbs break; 153965942Sgibbs case T_PTRDIFFT: 154065942Sgibbs (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); 154165942Sgibbs break; 154265942Sgibbs case TP_PTRDIFFT: 154365942Sgibbs (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); 154465942Sgibbs break; 154565942Sgibbs case T_SIZET: 154665942Sgibbs (*argtable) [n].sizearg = va_arg (ap, size_t); 154765942Sgibbs break; 154865942Sgibbs case TP_SIZET: 154965942Sgibbs (*argtable) [n].psizearg = va_arg (ap, size_t *); 155065942Sgibbs break; 155165942Sgibbs case T_INTMAXT: 155265942Sgibbs (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); 155365942Sgibbs break; 155465942Sgibbs case T_UINTMAXT: 155565942Sgibbs (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); 155665942Sgibbs break; 155765942Sgibbs case TP_INTMAXT: 155865942Sgibbs (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); 155965942Sgibbs break; 156065942Sgibbs case T_DOUBLE: 156165942Sgibbs#ifndef NO_FLOATING_POINT 156265942Sgibbs (*argtable) [n].doublearg = va_arg (ap, double); 156365942Sgibbs#endif 156465942Sgibbs break; 156565942Sgibbs case T_LONG_DOUBLE: 156665942Sgibbs#ifndef NO_FLOATING_POINT 156765942Sgibbs (*argtable) [n].longdoublearg = va_arg (ap, long double); 156865942Sgibbs#endif 156965942Sgibbs break; 157065942Sgibbs case TP_CHAR: 157165942Sgibbs (*argtable) [n].pchararg = va_arg (ap, char *); 157265942Sgibbs break; 157365942Sgibbs case TP_VOID: 157465942Sgibbs (*argtable) [n].pvoidarg = va_arg (ap, void *); 157565942Sgibbs break; 157665942Sgibbs case T_WINT: 157765942Sgibbs (*argtable) [n].wintarg = va_arg (ap, wint_t); 157865942Sgibbs break; 157965942Sgibbs case TP_WCHAR: 158065942Sgibbs (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); 158165942Sgibbs break; 158265942Sgibbs } 158365942Sgibbs } 158465942Sgibbs 158565942Sgibbs if ((typetable != NULL) && (typetable != stattypetable)) 158665942Sgibbs free (typetable); 158765942Sgibbs} 158865942Sgibbs 158965942Sgibbs/* 159065942Sgibbs * Increase the size of the type table. 159165942Sgibbs */ 159265942Sgibbsstatic void 159365942Sgibbs__grow_type_table (int nextarg, enum typeid **typetable, int *tablesize) 159465942Sgibbs{ 159565942Sgibbs enum typeid *const oldtable = *typetable; 159665942Sgibbs const int oldsize = *tablesize; 159765942Sgibbs enum typeid *newtable; 159865942Sgibbs int n, newsize = oldsize * 2; 159965942Sgibbs 160065942Sgibbs if (newsize < nextarg + 1) 160165942Sgibbs newsize = nextarg + 1; 160265942Sgibbs if (oldsize == STATIC_ARG_TBL_SIZE) { 160365942Sgibbs if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL) 160465942Sgibbs abort(); /* XXX handle better */ 160565942Sgibbs bcopy(oldtable, newtable, oldsize * sizeof(enum typeid)); 160665942Sgibbs } else { 160765942Sgibbs newtable = reallocf(oldtable, newsize * sizeof(enum typeid)); 160865942Sgibbs if (newtable == NULL) 160965942Sgibbs abort(); /* XXX handle better */ 161065942Sgibbs } 161165942Sgibbs for (n = oldsize; n < newsize; n++) 161265942Sgibbs newtable[n] = T_UNUSED; 161365942Sgibbs 161465942Sgibbs *typetable = newtable; 161565942Sgibbs *tablesize = newsize; 161665942Sgibbs} 161765942Sgibbs 161865942Sgibbs 161965942Sgibbs#ifndef NO_FLOATING_POINT 162065942Sgibbs 162165942Sgibbsstatic int 162265942Sgibbsexponent(char *p0, int exp, int fmtch) 162365942Sgibbs{ 162465942Sgibbs char *p, *t; 162565942Sgibbs char expbuf[MAXEXPDIG]; 162665942Sgibbs 162765942Sgibbs p = p0; 162865942Sgibbs *p++ = fmtch; 162965942Sgibbs if (exp < 0) { 163065942Sgibbs exp = -exp; 163165942Sgibbs *p++ = '-'; 163265942Sgibbs } 163365942Sgibbs else 163465942Sgibbs *p++ = '+'; 163565942Sgibbs t = expbuf + MAXEXPDIG; 163665942Sgibbs if (exp > 9) { 163765942Sgibbs do { 163865942Sgibbs *--t = to_char(exp % 10); 163965942Sgibbs } while ((exp /= 10) > 9); 164065942Sgibbs *--t = to_char(exp); 164165942Sgibbs for (; t < expbuf + MAXEXPDIG; *p++ = *t++); 164265942Sgibbs } 164365942Sgibbs else { 164465942Sgibbs /* 164565942Sgibbs * Exponents for decimal floating point conversions 164665942Sgibbs * (%[eEgG]) must be at least two characters long, 164765942Sgibbs * whereas exponents for hexadecimal conversions can 164865942Sgibbs * be only one character long. 164965942Sgibbs */ 165065942Sgibbs if (fmtch == 'e' || fmtch == 'E') 165165942Sgibbs *p++ = '0'; 165265942Sgibbs *p++ = to_char(exp); 165365942Sgibbs } 165465942Sgibbs return (p - p0); 165565942Sgibbs} 165665942Sgibbs#endif /* !NO_FLOATING_POINT */ 165765942Sgibbs