printf-pos.c revision 128819
11573Srgrimes/*- 21573Srgrimes * Copyright (c) 1990, 1993 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * This code is derived from software contributed to Berkeley by 61573Srgrimes * Chris Torek. 71573Srgrimes * 81573Srgrimes * Redistribution and use in source and binary forms, with or without 91573Srgrimes * modification, are permitted provided that the following conditions 101573Srgrimes * are met: 111573Srgrimes * 1. Redistributions of source code must retain the above copyright 121573Srgrimes * notice, this list of conditions and the following disclaimer. 131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141573Srgrimes * notice, this list of conditions and the following disclaimer in the 151573Srgrimes * documentation and/or other materials provided with the distribution. 161573Srgrimes * 3. All advertising materials mentioning features or use of this software 171573Srgrimes * must display the following acknowledgement: 181573Srgrimes * This product includes software developed by the University of 191573Srgrimes * California, Berkeley and its contributors. 201573Srgrimes * 4. Neither the name of the University nor the names of its contributors 211573Srgrimes * may be used to endorse or promote products derived from this software 221573Srgrimes * without specific prior written permission. 231573Srgrimes * 241573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341573Srgrimes * SUCH DAMAGE. 351573Srgrimes */ 361573Srgrimes 371573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 381573Srgrimesstatic char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; 391573Srgrimes#endif /* LIBC_SCCS and not lint */ 4092986Sobrien#include <sys/cdefs.h> 4192986Sobrien__FBSDID("$FreeBSD: head/lib/libc/stdio/vfprintf.c 128819 2004-05-02 10:55:06Z das $"); 421573Srgrimes 431573Srgrimes/* 441573Srgrimes * Actual printf innards. 451573Srgrimes * 461573Srgrimes * This code is large and complicated... 471573Srgrimes */ 481573Srgrimes 4971579Sdeischen#include "namespace.h" 501573Srgrimes#include <sys/types.h> 511573Srgrimes 5287113Sfenner#include <ctype.h> 531573Srgrimes#include <limits.h> 5487490Sphantom#include <locale.h> 5587113Sfenner#include <stddef.h> 5687113Sfenner#include <stdint.h> 571573Srgrimes#include <stdio.h> 581573Srgrimes#include <stdlib.h> 591573Srgrimes#include <string.h> 60103633Stjr#include <wchar.h> 611573Srgrimes 621573Srgrimes#include <stdarg.h> 6371579Sdeischen#include "un-namespace.h" 641573Srgrimes 6571579Sdeischen#include "libc_private.h" 661573Srgrimes#include "local.h" 671573Srgrimes#include "fvwrite.h" 681573Srgrimes 6984922Sdfrunion arg { 7084962Sbde int intarg; 7184962Sbde u_int uintarg; 7284962Sbde long longarg; 7384962Sbde u_long ulongarg; 7487113Sfenner long long longlongarg; 7587113Sfenner unsigned long long ulonglongarg; 7687113Sfenner ptrdiff_t ptrdiffarg; 7787113Sfenner size_t sizearg; 7887113Sfenner intmax_t intmaxarg; 7987113Sfenner uintmax_t uintmaxarg; 8084962Sbde void *pvoidarg; 8184962Sbde char *pchararg; 8287113Sfenner signed char *pschararg; 8384962Sbde short *pshortarg; 8484962Sbde int *pintarg; 8584962Sbde long *plongarg; 8687113Sfenner long long *plonglongarg; 8787113Sfenner ptrdiff_t *pptrdiffarg; 8887113Sfenner size_t *psizearg; 8987113Sfenner intmax_t *pintmaxarg; 90128819Sdas#ifndef NO_FLOATING_POINT 9184962Sbde double doublearg; 9284962Sbde long double longdoublearg; 9384922Sdfr#endif 94103633Stjr wint_t wintarg; 95103633Stjr wchar_t *pwchararg; 9684922Sdfr}; 9784922Sdfr 9887113Sfenner/* 9987113Sfenner * Type ids for argument type table. 10087113Sfenner */ 10187113Sfennerenum typeid { 10287113Sfenner T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, 10387113Sfenner T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, 10487113Sfenner T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET, 10587113Sfenner T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, 106103633Stjr T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR 10787113Sfenner}; 10887113Sfenner 10992905Sobrienstatic int __sprint(FILE *, struct __suio *); 11092941Sobrienstatic int __sbprintf(FILE *, const char *, va_list) __printflike(2, 0); 111113146Sdasstatic char *__ujtoa(uintmax_t, char *, int, int, const char *, int, char, 11292941Sobrien const char *); 113113146Sdasstatic char *__ultoa(u_long, char *, int, int, const char *, int, char, 11492941Sobrien const char *); 115103633Stjrstatic char *__wcsconv(wchar_t *, int); 11692905Sobrienstatic void __find_arguments(const char *, va_list, union arg **); 11792905Sobrienstatic void __grow_type_table(int, enum typeid **, int *); 11816586Sjraynard 1191573Srgrimes/* 1201573Srgrimes * Flush out all the vectors defined by the given uio, 1211573Srgrimes * then reset it so that it can be reused. 1221573Srgrimes */ 1231573Srgrimesstatic int 12471579Sdeischen__sprint(FILE *fp, struct __suio *uio) 1251573Srgrimes{ 12671579Sdeischen int err; 1271573Srgrimes 1281573Srgrimes if (uio->uio_resid == 0) { 1291573Srgrimes uio->uio_iovcnt = 0; 1301573Srgrimes return (0); 1311573Srgrimes } 1321573Srgrimes err = __sfvwrite(fp, uio); 1331573Srgrimes uio->uio_resid = 0; 1341573Srgrimes uio->uio_iovcnt = 0; 1351573Srgrimes return (err); 1361573Srgrimes} 1371573Srgrimes 1381573Srgrimes/* 1391573Srgrimes * Helper function for `fprintf to unbuffered unix file': creates a 1401573Srgrimes * temporary buffer. We only work on write-only files; this avoids 1411573Srgrimes * worries about ungetc buffers and so forth. 1421573Srgrimes */ 1431573Srgrimesstatic int 14471579Sdeischen__sbprintf(FILE *fp, const char *fmt, va_list ap) 1451573Srgrimes{ 1461573Srgrimes int ret; 1471573Srgrimes FILE fake; 1481573Srgrimes unsigned char buf[BUFSIZ]; 1491573Srgrimes 1501573Srgrimes /* copy the important variables */ 1511573Srgrimes fake._flags = fp->_flags & ~__SNBF; 1521573Srgrimes fake._file = fp->_file; 1531573Srgrimes fake._cookie = fp->_cookie; 1541573Srgrimes fake._write = fp->_write; 155101776Stjr fake._extra = fp->_extra; 1561573Srgrimes 1571573Srgrimes /* set up the buffer */ 1581573Srgrimes fake._bf._base = fake._p = buf; 1591573Srgrimes fake._bf._size = fake._w = sizeof(buf); 1601573Srgrimes fake._lbfsize = 0; /* not actually used, but Just In Case */ 1611573Srgrimes 1621573Srgrimes /* do the work, then copy any error status */ 16371579Sdeischen ret = __vfprintf(&fake, fmt, ap); 16471579Sdeischen if (ret >= 0 && __fflush(&fake)) 1651573Srgrimes ret = EOF; 1661573Srgrimes if (fake._flags & __SERR) 1671573Srgrimes fp->_flags |= __SERR; 1681573Srgrimes return (ret); 1691573Srgrimes} 1701573Srgrimes 1711573Srgrimes/* 1721573Srgrimes * Macros for converting digits to letters and vice versa 1731573Srgrimes */ 1741573Srgrimes#define to_digit(c) ((c) - '0') 1751573Srgrimes#define is_digit(c) ((unsigned)to_digit(c) <= 9) 1761573Srgrimes#define to_char(n) ((n) + '0') 1771573Srgrimes 1781573Srgrimes/* 1791573Srgrimes * Convert an unsigned long to ASCII for printf purposes, returning 1801573Srgrimes * a pointer to the first character of the string representation. 1811573Srgrimes * Octal numbers can be forced to have a leading zero; hex numbers 1821573Srgrimes * use the given digits. 1831573Srgrimes */ 1841573Srgrimesstatic char * 185113146Sdas__ultoa(u_long val, char *endp, int base, int octzero, const char *xdigs, 18687815Sphantom int needgrp, char thousep, const char *grp) 1871573Srgrimes{ 18892889Sobrien char *cp = endp; 18992889Sobrien long sval; 19087113Sfenner int ndig; 1911573Srgrimes 1921573Srgrimes /* 1931573Srgrimes * Handle the three cases separately, in the hope of getting 1941573Srgrimes * better/faster code. 1951573Srgrimes */ 1961573Srgrimes switch (base) { 1971573Srgrimes case 10: 1981573Srgrimes if (val < 10) { /* many numbers are 1 digit */ 1991573Srgrimes *--cp = to_char(val); 2001573Srgrimes return (cp); 2011573Srgrimes } 20287113Sfenner ndig = 0; 2031573Srgrimes /* 2041573Srgrimes * On many machines, unsigned arithmetic is harder than 2051573Srgrimes * signed arithmetic, so we do at most one unsigned mod and 2061573Srgrimes * divide; this is sufficient to reduce the range of 2071573Srgrimes * the incoming value to where signed arithmetic works. 2081573Srgrimes */ 2091573Srgrimes if (val > LONG_MAX) { 2101573Srgrimes *--cp = to_char(val % 10); 21187113Sfenner ndig++; 2121573Srgrimes sval = val / 10; 2131573Srgrimes } else 2141573Srgrimes sval = val; 2151573Srgrimes do { 2161573Srgrimes *--cp = to_char(sval % 10); 21787815Sphantom ndig++; 21887815Sphantom /* 21987815Sphantom * If (*grp == CHAR_MAX) then no more grouping 22087815Sphantom * should be performed. 22187815Sphantom */ 22287818Sphantom if (needgrp && ndig == *grp && *grp != CHAR_MAX 22387818Sphantom && sval > 9) { 22487815Sphantom *--cp = thousep; 22587113Sfenner ndig = 0; 22687815Sphantom /* 22787815Sphantom * If (*(grp+1) == '\0') then we have to 22887815Sphantom * use *grp character (last grouping rule) 22987815Sphantom * for all next cases 23087815Sphantom */ 23188057Sphantom if (*(grp+1) != '\0') 23288057Sphantom grp++; 23387113Sfenner } 2341573Srgrimes sval /= 10; 2351573Srgrimes } while (sval != 0); 2361573Srgrimes break; 2371573Srgrimes 2381573Srgrimes case 8: 2391573Srgrimes do { 2401573Srgrimes *--cp = to_char(val & 7); 2411573Srgrimes val >>= 3; 2421573Srgrimes } while (val); 2431573Srgrimes if (octzero && *cp != '0') 2441573Srgrimes *--cp = '0'; 2451573Srgrimes break; 2461573Srgrimes 2471573Srgrimes case 16: 2481573Srgrimes do { 2491573Srgrimes *--cp = xdigs[val & 15]; 2501573Srgrimes val >>= 4; 2511573Srgrimes } while (val); 2521573Srgrimes break; 2531573Srgrimes 2541573Srgrimes default: /* oops */ 2551573Srgrimes abort(); 2561573Srgrimes } 2571573Srgrimes return (cp); 2581573Srgrimes} 2591573Srgrimes 26087113Sfenner/* Identical to __ultoa, but for intmax_t. */ 2611573Srgrimesstatic char * 262113146Sdas__ujtoa(uintmax_t val, char *endp, int base, int octzero, const char *xdigs, 26387815Sphantom int needgrp, char thousep, const char *grp) 2641573Srgrimes{ 26571579Sdeischen char *cp = endp; 26687113Sfenner intmax_t sval; 26787113Sfenner int ndig; 2681573Srgrimes 2691573Srgrimes /* quick test for small values; __ultoa is typically much faster */ 2701573Srgrimes /* (perhaps instead we should run until small, then call __ultoa?) */ 2711573Srgrimes if (val <= ULONG_MAX) 27287113Sfenner return (__ultoa((u_long)val, endp, base, octzero, xdigs, 27387815Sphantom needgrp, thousep, grp)); 2741573Srgrimes switch (base) { 2751573Srgrimes case 10: 2761573Srgrimes if (val < 10) { 2771573Srgrimes *--cp = to_char(val % 10); 2781573Srgrimes return (cp); 2791573Srgrimes } 28087113Sfenner ndig = 0; 28187113Sfenner if (val > INTMAX_MAX) { 2821573Srgrimes *--cp = to_char(val % 10); 28387113Sfenner ndig++; 2841573Srgrimes sval = val / 10; 2851573Srgrimes } else 2861573Srgrimes sval = val; 2871573Srgrimes do { 2881573Srgrimes *--cp = to_char(sval % 10); 28987815Sphantom ndig++; 29087815Sphantom /* 29187815Sphantom * If (*grp == CHAR_MAX) then no more grouping 29287815Sphantom * should be performed. 29387815Sphantom */ 29487818Sphantom if (needgrp && *grp != CHAR_MAX && ndig == *grp 29587818Sphantom && sval > 9) { 29687815Sphantom *--cp = thousep; 29787113Sfenner ndig = 0; 29887815Sphantom /* 29987815Sphantom * If (*(grp+1) == '\0') then we have to 30087815Sphantom * use *grp character (last grouping rule) 30187815Sphantom * for all next cases 30287815Sphantom */ 30388057Sphantom if (*(grp+1) != '\0') 30488057Sphantom grp++; 30588057Sphantom } 3061573Srgrimes sval /= 10; 3071573Srgrimes } while (sval != 0); 3081573Srgrimes break; 3091573Srgrimes 3101573Srgrimes case 8: 3111573Srgrimes do { 3121573Srgrimes *--cp = to_char(val & 7); 3131573Srgrimes val >>= 3; 3141573Srgrimes } while (val); 3151573Srgrimes if (octzero && *cp != '0') 3161573Srgrimes *--cp = '0'; 3171573Srgrimes break; 3181573Srgrimes 3191573Srgrimes case 16: 3201573Srgrimes do { 3211573Srgrimes *--cp = xdigs[val & 15]; 3221573Srgrimes val >>= 4; 3231573Srgrimes } while (val); 3241573Srgrimes break; 3251573Srgrimes 3261573Srgrimes default: 3271573Srgrimes abort(); 3281573Srgrimes } 3291573Srgrimes return (cp); 3301573Srgrimes} 3311573Srgrimes 33271579Sdeischen/* 333103633Stjr * Convert a wide character string argument for the %ls format to a multibyte 334103633Stjr * string representation. ``prec'' specifies the maximum number of bytes 335103633Stjr * to output. If ``prec'' is greater than or equal to zero, we can't assume 336103633Stjr * that the wide char. string ends in a null character. 337103633Stjr */ 338103633Stjrstatic char * 339103633Stjr__wcsconv(wchar_t *wcsarg, int prec) 340103633Stjr{ 341128002Stjr static const mbstate_t initial; 342128002Stjr mbstate_t mbs; 343103633Stjr char buf[MB_LEN_MAX]; 344103633Stjr wchar_t *p; 345103633Stjr char *convbuf, *mbp; 346103633Stjr size_t clen, nbytes; 347103633Stjr 348103633Stjr /* 349103633Stjr * Determine the number of bytes to output and allocate space for 350103633Stjr * the output. 351103633Stjr */ 352103633Stjr if (prec >= 0) { 353103633Stjr nbytes = 0; 354103633Stjr p = wcsarg; 355128002Stjr mbs = initial; 356103633Stjr for (;;) { 357128002Stjr clen = wcrtomb(buf, *p++, &mbs); 358103633Stjr if (clen == 0 || clen == (size_t)-1 || 359103633Stjr nbytes + clen > prec) 360103633Stjr break; 361103633Stjr nbytes += clen; 362103633Stjr } 363103633Stjr } else { 364103633Stjr p = wcsarg; 365128002Stjr mbs = initial; 366128002Stjr nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); 367103633Stjr if (nbytes == (size_t)-1) 368103633Stjr return (NULL); 369103633Stjr } 370103633Stjr if ((convbuf = malloc(nbytes + 1)) == NULL) 371103633Stjr return (NULL); 372103633Stjr 373103633Stjr /* 374103633Stjr * Fill the output buffer with the multibyte representations of as 375103633Stjr * many wide characters as will fit. 376103633Stjr */ 377103633Stjr mbp = convbuf; 378103633Stjr p = wcsarg; 379128002Stjr mbs = initial; 380103633Stjr while (mbp - convbuf < nbytes) { 381128002Stjr clen = wcrtomb(mbp, *p++, &mbs); 382103633Stjr if (clen == 0 || clen == (size_t)-1) 383103633Stjr break; 384103633Stjr mbp += clen; 385103633Stjr } 386113196Sache if (clen == (size_t)-1) { 387113196Sache free(convbuf); 388113196Sache return (NULL); 389113196Sache } 390103633Stjr *mbp = '\0'; 391103633Stjr 392103633Stjr return (convbuf); 393103633Stjr} 394103633Stjr 395103633Stjr/* 39671579Sdeischen * MT-safe version 39771579Sdeischen */ 39871579Sdeischenint 399103012Stjrvfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) 400101914Srobert 40171579Sdeischen{ 40271579Sdeischen int ret; 40371579Sdeischen 40471579Sdeischen FLOCKFILE(fp); 40571579Sdeischen ret = __vfprintf(fp, fmt0, ap); 40671579Sdeischen FUNLOCKFILE(fp); 40771579Sdeischen return (ret); 40871579Sdeischen} 40971579Sdeischen 410128819Sdas#ifndef NO_FLOATING_POINT 411113146Sdas 412113146Sdas#define dtoa __dtoa 413113146Sdas#define freedtoa __freedtoa 414113146Sdas 415113146Sdas#include <float.h> 4161573Srgrimes#include <math.h> 4171573Srgrimes#include "floatio.h" 418113146Sdas#include "gdtoa.h" 4191573Srgrimes 4201573Srgrimes#define DEFPREC 6 4211573Srgrimes 42292905Sobrienstatic int exponent(char *, int, int); 4231573Srgrimes 424128819Sdas#endif /* !NO_FLOATING_POINT */ 4251573Srgrimes 426113142Sdas/* 427113142Sdas * The size of the buffer we use as scratch space for integer 428113142Sdas * conversions, among other things. Technically, we would need the 429113142Sdas * most space for base 10 conversions with thousands' grouping 430113142Sdas * characters between each pair of digits. 100 bytes is a 431113142Sdas * conservative overestimate even for a 128-bit uintmax_t. 432113142Sdas */ 433113142Sdas#define BUF 100 4341573Srgrimes 43521674Sjkh#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 4361573Srgrimes 4371573Srgrimes/* 4381573Srgrimes * Flags used during conversion. 4391573Srgrimes */ 4401573Srgrimes#define ALT 0x001 /* alternate form */ 4411573Srgrimes#define LADJUST 0x004 /* left adjustment */ 44231871Sbde#define LONGDBL 0x008 /* long double */ 4431573Srgrimes#define LONGINT 0x010 /* long integer */ 44487113Sfenner#define LLONGINT 0x020 /* long long integer */ 4451573Srgrimes#define SHORTINT 0x040 /* short integer */ 4461573Srgrimes#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 44788057Sphantom#define FPT 0x100 /* Floating point number */ 44887815Sphantom#define GROUPING 0x200 /* use grouping ("'" flag) */ 44987113Sfenner /* C99 additional size modifiers: */ 45087815Sphantom#define SIZET 0x400 /* size_t */ 45187815Sphantom#define PTRDIFFT 0x800 /* ptrdiff_t */ 45287815Sphantom#define INTMAXT 0x1000 /* intmax_t */ 45387815Sphantom#define CHARINT 0x2000 /* print char using int format */ 45487113Sfenner 45571579Sdeischen/* 45671579Sdeischen * Non-MT-safe version 45771579Sdeischen */ 4581573Srgrimesint 45971579Sdeischen__vfprintf(FILE *fp, const char *fmt0, va_list ap) 4601573Srgrimes{ 46171579Sdeischen char *fmt; /* format string */ 46271579Sdeischen int ch; /* character from fmt */ 46371579Sdeischen int n, n2; /* handy integer (short term usage) */ 46471579Sdeischen char *cp; /* handy char pointer (short term usage) */ 46571579Sdeischen struct __siov *iovp; /* for PRINT macro */ 46671579Sdeischen int flags; /* flags as above */ 4671573Srgrimes int ret; /* return value accumulator */ 4681573Srgrimes int width; /* width from format (%8d), or 0 */ 469113146Sdas int prec; /* precision from format; <0 for N/A */ 4701573Srgrimes char sign; /* sign prefix (' ', '+', '-', or \0) */ 47187815Sphantom char thousands_sep; /* locale specific thousands separator */ 47287815Sphantom const char *grouping; /* locale specific numeric grouping rules */ 473128819Sdas#ifndef NO_FLOATING_POINT 474113146Sdas /* 475113146Sdas * We can decompose the printed representation of floating 476113146Sdas * point numbers into several parts, some of which may be empty: 477113146Sdas * 478113146Sdas * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ 479113146Sdas * A B ---C--- D E F 480113146Sdas * 481113146Sdas * A: 'sign' holds this value if present; '\0' otherwise 482113146Sdas * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal 483113146Sdas * C: cp points to the string MMMNNN. Leading and trailing 484113146Sdas * zeros are not in the string and must be added. 485113146Sdas * D: expchar holds this character; '\0' if no exponent, e.g. %f 486113146Sdas * F: at least two digits for decimal, at least one digit for hex 487113146Sdas */ 48887490Sphantom char *decimal_point; /* locale specific decimal point */ 489113146Sdas int signflag; /* true if float is negative */ 490113146Sdas union { /* floating point arguments %[aAeEfFgG] */ 491113146Sdas double dbl; 492113146Sdas long double ldbl; 493113146Sdas } fparg; 4941573Srgrimes int expt; /* integer value of exponent */ 495113146Sdas char expchar; /* exponent character: [eEpP\0] */ 496113146Sdas char *dtoaend; /* pointer to end of converted digits */ 4971573Srgrimes int expsize; /* character count for expstr */ 498113146Sdas int lead; /* sig figs before decimal or group sep */ 499113146Sdas int ndig; /* actual number of digits returned by dtoa */ 500113146Sdas char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ 50172523Stegge char *dtoaresult; /* buffer allocated by dtoa */ 502113146Sdas int nseps; /* number of group separators with ' */ 503113146Sdas int nrepeats; /* number of repeats of the last group */ 5041573Srgrimes#endif 5051573Srgrimes u_long ulval; /* integer arguments %[diouxX] */ 50687113Sfenner uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ 5071573Srgrimes int base; /* base for [diouxX] conversion */ 5081573Srgrimes int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 50914727Sfenner int realsz; /* field size expanded by dprec, sign, etc */ 5101573Srgrimes int size; /* size of converted field or string */ 51131983Sache int prsize; /* max size of printed field */ 512113146Sdas const char *xdigs; /* digits for %[xX] conversion */ 5131573Srgrimes#define NIOV 8 5141573Srgrimes struct __suio uio; /* output information: summary */ 5151573Srgrimes struct __siov iov[NIOV];/* ... and individual io vectors */ 516113142Sdas char buf[BUF]; /* buffer with space for digits of uintmax_t */ 517113146Sdas char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ 518103399Stjr union arg *argtable; /* args, built due to positional arg */ 519103399Stjr union arg statargtable [STATIC_ARG_TBL_SIZE]; 520103399Stjr int nextarg; /* 1-based argument index */ 521103399Stjr va_list orgap; /* original argument pointer */ 522103633Stjr char *convbuf; /* wide to multibyte conversion result */ 5231573Srgrimes 5241573Srgrimes /* 5251573Srgrimes * Choose PADSIZE to trade efficiency vs. size. If larger printf 5261573Srgrimes * fields occur frequently, increase PADSIZE and make the initialisers 5271573Srgrimes * below longer. 5281573Srgrimes */ 5291573Srgrimes#define PADSIZE 16 /* pad chunk size */ 5301573Srgrimes static char blanks[PADSIZE] = 5311573Srgrimes {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 5321573Srgrimes static char zeroes[PADSIZE] = 5331573Srgrimes {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 5341573Srgrimes 535113146Sdas static const char xdigs_lower[16] = "0123456789abcdef"; 536113146Sdas static const char xdigs_upper[16] = "0123456789ABCDEF"; 537113146Sdas 5381573Srgrimes /* 5391573Srgrimes * BEWARE, these `goto error' on error, and PAD uses `n'. 5401573Srgrimes */ 5411573Srgrimes#define PRINT(ptr, len) { \ 5421573Srgrimes iovp->iov_base = (ptr); \ 5431573Srgrimes iovp->iov_len = (len); \ 5441573Srgrimes uio.uio_resid += (len); \ 5451573Srgrimes iovp++; \ 5461573Srgrimes if (++uio.uio_iovcnt >= NIOV) { \ 5471573Srgrimes if (__sprint(fp, &uio)) \ 5481573Srgrimes goto error; \ 5491573Srgrimes iovp = iov; \ 5501573Srgrimes } \ 5511573Srgrimes} 5521573Srgrimes#define PAD(howmany, with) { \ 5531573Srgrimes if ((n = (howmany)) > 0) { \ 5541573Srgrimes while (n > PADSIZE) { \ 5551573Srgrimes PRINT(with, PADSIZE); \ 5561573Srgrimes n -= PADSIZE; \ 5571573Srgrimes } \ 5581573Srgrimes PRINT(with, n); \ 5591573Srgrimes } \ 5601573Srgrimes} 561113191Sdas#define PRINTANDPAD(p, ep, len, with) do { \ 562113191Sdas n2 = (ep) - (p); \ 563113191Sdas if (n2 > (len)) \ 564113191Sdas n2 = (len); \ 565113191Sdas if (n2 > 0) \ 566113191Sdas PRINT((p), n2); \ 567113191Sdas PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ 568113191Sdas} while(0) 5691573Srgrimes#define FLUSH() { \ 5701573Srgrimes if (uio.uio_resid && __sprint(fp, &uio)) \ 5711573Srgrimes goto error; \ 5721573Srgrimes uio.uio_iovcnt = 0; \ 5731573Srgrimes iovp = iov; \ 5741573Srgrimes} 5751573Srgrimes 576103399Stjr /* 577103399Stjr * Get the argument indexed by nextarg. If the argument table is 578103399Stjr * built, use it to get the argument. If its not, get the next 579103399Stjr * argument (and arguments must be gotten sequentially). 580103399Stjr */ 58121674Sjkh#define GETARG(type) \ 582103399Stjr ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 583103399Stjr (nextarg++, va_arg(ap, type))) 58421674Sjkh 5851573Srgrimes /* 5861573Srgrimes * To extend shorts properly, we need both signed and unsigned 5871573Srgrimes * argument extraction methods. 5881573Srgrimes */ 5891573Srgrimes#define SARG() \ 59021674Sjkh (flags&LONGINT ? GETARG(long) : \ 59121674Sjkh flags&SHORTINT ? (long)(short)GETARG(int) : \ 59287113Sfenner flags&CHARINT ? (long)(signed char)GETARG(int) : \ 59321674Sjkh (long)GETARG(int)) 5941573Srgrimes#define UARG() \ 59521674Sjkh (flags&LONGINT ? GETARG(u_long) : \ 59621674Sjkh flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 59787113Sfenner flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ 59821674Sjkh (u_long)GETARG(u_int)) 59987113Sfenner#define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) 60087113Sfenner#define SJARG() \ 60187113Sfenner (flags&INTMAXT ? GETARG(intmax_t) : \ 60287113Sfenner flags&SIZET ? (intmax_t)GETARG(size_t) : \ 60387113Sfenner flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ 60487113Sfenner (intmax_t)GETARG(long long)) 60587113Sfenner#define UJARG() \ 60687113Sfenner (flags&INTMAXT ? GETARG(uintmax_t) : \ 60787113Sfenner flags&SIZET ? (uintmax_t)GETARG(size_t) : \ 60887113Sfenner flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ 60987113Sfenner (uintmax_t)GETARG(unsigned long long)) 6101573Srgrimes 611103399Stjr /* 612103399Stjr * Get * arguments, including the form *nn$. Preserve the nextarg 613103399Stjr * that the argument can be gotten once the type is determined. 614103399Stjr */ 61521674Sjkh#define GETASTER(val) \ 616103399Stjr n2 = 0; \ 617103399Stjr cp = fmt; \ 618103399Stjr while (is_digit(*cp)) { \ 619103399Stjr n2 = 10 * n2 + to_digit(*cp); \ 620103399Stjr cp++; \ 621103399Stjr } \ 622103399Stjr if (*cp == '$') { \ 623103399Stjr int hold = nextarg; \ 624103399Stjr if (argtable == NULL) { \ 625103399Stjr argtable = statargtable; \ 626103399Stjr __find_arguments (fmt0, orgap, &argtable); \ 627103399Stjr } \ 628103399Stjr nextarg = n2; \ 62921674Sjkh val = GETARG (int); \ 630103399Stjr nextarg = hold; \ 631103399Stjr fmt = ++cp; \ 632103399Stjr } else { \ 633103399Stjr val = GETARG (int); \ 634103399Stjr } 63587815Sphantom 63688057Sphantom 63787815Sphantom thousands_sep = '\0'; 63887815Sphantom grouping = NULL; 639103633Stjr convbuf = NULL; 640128819Sdas#ifndef NO_FLOATING_POINT 64172523Stegge dtoaresult = NULL; 64287113Sfenner decimal_point = localeconv()->decimal_point; 64372523Stegge#endif 6441573Srgrimes /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 64571579Sdeischen if (cantwrite(fp)) 6461573Srgrimes return (EOF); 6471573Srgrimes 6481573Srgrimes /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 6491573Srgrimes if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 65071579Sdeischen fp->_file >= 0) 6511573Srgrimes return (__sbprintf(fp, fmt0, ap)); 6521573Srgrimes 6531573Srgrimes fmt = (char *)fmt0; 654103399Stjr argtable = NULL; 655103399Stjr nextarg = 1; 656103876Stjr va_copy(orgap, ap); 6571573Srgrimes uio.uio_iov = iovp = iov; 6581573Srgrimes uio.uio_resid = 0; 6591573Srgrimes uio.uio_iovcnt = 0; 6601573Srgrimes ret = 0; 6611573Srgrimes 6621573Srgrimes /* 6631573Srgrimes * Scan the format for conversions (`%' character). 6641573Srgrimes */ 6651573Srgrimes for (;;) { 6661573Srgrimes for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 6671573Srgrimes /* void */; 6681573Srgrimes if ((n = fmt - cp) != 0) { 66932253Sache if ((unsigned)ret + n > INT_MAX) { 67031983Sache ret = EOF; 67131983Sache goto error; 67231983Sache } 6731573Srgrimes PRINT(cp, n); 6741573Srgrimes ret += n; 6751573Srgrimes } 6761573Srgrimes if (ch == '\0') 6771573Srgrimes goto done; 6781573Srgrimes fmt++; /* skip over '%' */ 6791573Srgrimes 6801573Srgrimes flags = 0; 6811573Srgrimes dprec = 0; 6821573Srgrimes width = 0; 6831573Srgrimes prec = -1; 6841573Srgrimes sign = '\0'; 685113146Sdas ox[1] = '\0'; 6861573Srgrimes 6871573Srgrimesrflag: ch = *fmt++; 6881573Srgrimesreswitch: switch (ch) { 6891573Srgrimes case ' ': 69088057Sphantom /*- 6911573Srgrimes * ``If the space and + flags both appear, the space 6921573Srgrimes * flag will be ignored.'' 6931573Srgrimes * -- ANSI X3J11 6941573Srgrimes */ 6951573Srgrimes if (!sign) 6961573Srgrimes sign = ' '; 6971573Srgrimes goto rflag; 6981573Srgrimes case '#': 6991573Srgrimes flags |= ALT; 7001573Srgrimes goto rflag; 7011573Srgrimes case '*': 70288057Sphantom /*- 7031573Srgrimes * ``A negative field width argument is taken as a 7041573Srgrimes * - flag followed by a positive field width.'' 7051573Srgrimes * -- ANSI X3J11 7061573Srgrimes * They don't exclude field widths read from args. 7071573Srgrimes */ 70821674Sjkh GETASTER (width); 70921674Sjkh if (width >= 0) 7101573Srgrimes goto rflag; 7111573Srgrimes width = -width; 7121573Srgrimes /* FALLTHROUGH */ 7131573Srgrimes case '-': 7141573Srgrimes flags |= LADJUST; 7151573Srgrimes goto rflag; 7161573Srgrimes case '+': 7171573Srgrimes sign = '+'; 7181573Srgrimes goto rflag; 71987113Sfenner case '\'': 72087815Sphantom flags |= GROUPING; 72187815Sphantom thousands_sep = *(localeconv()->thousands_sep); 72287815Sphantom grouping = localeconv()->grouping; 72387113Sfenner goto rflag; 7241573Srgrimes case '.': 7251573Srgrimes if ((ch = *fmt++) == '*') { 726113191Sdas GETASTER (prec); 7271573Srgrimes goto rflag; 7281573Srgrimes } 729113191Sdas prec = 0; 7301573Srgrimes while (is_digit(ch)) { 731113191Sdas prec = 10 * prec + to_digit(ch); 7321573Srgrimes ch = *fmt++; 7331573Srgrimes } 7341573Srgrimes goto reswitch; 7351573Srgrimes case '0': 73688057Sphantom /*- 7371573Srgrimes * ``Note that 0 is taken as a flag, not as the 7381573Srgrimes * beginning of a field width.'' 7391573Srgrimes * -- ANSI X3J11 7401573Srgrimes */ 7411573Srgrimes flags |= ZEROPAD; 7421573Srgrimes goto rflag; 7431573Srgrimes case '1': case '2': case '3': case '4': 7441573Srgrimes case '5': case '6': case '7': case '8': case '9': 7451573Srgrimes n = 0; 7461573Srgrimes do { 7471573Srgrimes n = 10 * n + to_digit(ch); 7481573Srgrimes ch = *fmt++; 7491573Srgrimes } while (is_digit(ch)); 75021674Sjkh if (ch == '$') { 75121674Sjkh nextarg = n; 752103399Stjr if (argtable == NULL) { 753103399Stjr argtable = statargtable; 754103399Stjr __find_arguments (fmt0, orgap, 755103399Stjr &argtable); 75621674Sjkh } 75721674Sjkh goto rflag; 758103399Stjr } 7591573Srgrimes width = n; 7601573Srgrimes goto reswitch; 761128819Sdas#ifndef NO_FLOATING_POINT 7621573Srgrimes case 'L': 7631573Srgrimes flags |= LONGDBL; 7641573Srgrimes goto rflag; 7651573Srgrimes#endif 7661573Srgrimes case 'h': 76787113Sfenner if (flags & SHORTINT) { 76887113Sfenner flags &= ~SHORTINT; 76987113Sfenner flags |= CHARINT; 77087113Sfenner } else 77187113Sfenner flags |= SHORTINT; 7721573Srgrimes goto rflag; 77387113Sfenner case 'j': 77487113Sfenner flags |= INTMAXT; 77587113Sfenner goto rflag; 7761573Srgrimes case 'l': 77787113Sfenner if (flags & LONGINT) { 77887113Sfenner flags &= ~LONGINT; 77987113Sfenner flags |= LLONGINT; 78087113Sfenner } else 78144674Sdfr flags |= LONGINT; 7821573Srgrimes goto rflag; 7831573Srgrimes case 'q': 78487113Sfenner flags |= LLONGINT; /* not necessarily */ 7851573Srgrimes goto rflag; 78687113Sfenner case 't': 78787113Sfenner flags |= PTRDIFFT; 78887113Sfenner goto rflag; 78987113Sfenner case 'z': 79087113Sfenner flags |= SIZET; 79187113Sfenner goto rflag; 792105204Stjr case 'C': 793105204Stjr flags |= LONGINT; 794105204Stjr /*FALLTHROUGH*/ 7951573Srgrimes case 'c': 796103633Stjr if (flags & LONGINT) { 797128002Stjr static const mbstate_t initial; 798128002Stjr mbstate_t mbs; 799103633Stjr size_t mbseqlen; 800103633Stjr 801128002Stjr mbs = initial; 802103633Stjr mbseqlen = wcrtomb(cp = buf, 803128002Stjr (wchar_t)GETARG(wint_t), &mbs); 804105234Stjr if (mbseqlen == (size_t)-1) { 805105234Stjr fp->_flags |= __SERR; 806103633Stjr goto error; 807105234Stjr } 808103633Stjr size = (int)mbseqlen; 809103633Stjr } else { 810103633Stjr *(cp = buf) = GETARG(int); 811103633Stjr size = 1; 812103633Stjr } 8131573Srgrimes sign = '\0'; 8141573Srgrimes break; 8151573Srgrimes case 'D': 8161573Srgrimes flags |= LONGINT; 8171573Srgrimes /*FALLTHROUGH*/ 8181573Srgrimes case 'd': 8191573Srgrimes case 'i': 82087113Sfenner if (flags & INTMAX_SIZE) { 82187113Sfenner ujval = SJARG(); 82287113Sfenner if ((intmax_t)ujval < 0) { 82387113Sfenner ujval = -ujval; 8241573Srgrimes sign = '-'; 8251573Srgrimes } 8261573Srgrimes } else { 8271573Srgrimes ulval = SARG(); 8281573Srgrimes if ((long)ulval < 0) { 8291573Srgrimes ulval = -ulval; 8301573Srgrimes sign = '-'; 8311573Srgrimes } 8321573Srgrimes } 8331573Srgrimes base = 10; 8341573Srgrimes goto number; 835128819Sdas#ifndef NO_FLOATING_POINT 83687113Sfenner case 'a': 83787113Sfenner case 'A': 838113146Sdas if (ch == 'a') { 839113146Sdas ox[1] = 'x'; 840113146Sdas xdigs = xdigs_lower; 841113146Sdas expchar = 'p'; 842113146Sdas } else { 843113146Sdas ox[1] = 'X'; 844113146Sdas xdigs = xdigs_upper; 845113146Sdas expchar = 'P'; 846113146Sdas } 847124657Sdas if (prec >= 0) 848124657Sdas prec++; 849124657Sdas if (dtoaresult != NULL) 850124657Sdas freedtoa(dtoaresult); 851113146Sdas if (flags & LONGDBL) { 852124657Sdas fparg.ldbl = GETARG(long double); 853113146Sdas dtoaresult = cp = 854113146Sdas __hldtoa(fparg.ldbl, xdigs, prec, 855113146Sdas &expt, &signflag, &dtoaend); 856113146Sdas } else { 857113146Sdas fparg.dbl = GETARG(double); 858113146Sdas dtoaresult = cp = 859113146Sdas __hdtoa(fparg.dbl, xdigs, prec, 860113146Sdas &expt, &signflag, &dtoaend); 861113146Sdas } 862124657Sdas if (prec < 0) 863124657Sdas prec = dtoaend - cp; 864124657Sdas if (expt == INT_MAX) 865124657Sdas ox[1] = '\0'; 866124657Sdas goto fp_common; 8677033Sbde case 'e': 8681573Srgrimes case 'E': 869113146Sdas expchar = ch; 870113146Sdas if (prec < 0) /* account for digit before decpt */ 871113146Sdas prec = DEFPREC + 1; 872113146Sdas else 873113146Sdas prec++; 874113146Sdas goto fp_begin; 8757033Sbde case 'f': 87687113Sfenner case 'F': 877113146Sdas expchar = '\0'; 8787033Sbde goto fp_begin; 8791573Srgrimes case 'g': 8801573Srgrimes case 'G': 881113146Sdas expchar = ch - ('g' - 'e'); 8827033Sbde if (prec == 0) 8837033Sbde prec = 1; 884113146Sdasfp_begin: 885113146Sdas if (prec < 0) 8861573Srgrimes prec = DEFPREC; 887113146Sdas if (dtoaresult != NULL) 888113146Sdas freedtoa(dtoaresult); 889113146Sdas if (flags & LONGDBL) { 890113146Sdas fparg.ldbl = GETARG(long double); 891113146Sdas dtoaresult = cp = 892113146Sdas __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, 893113146Sdas &expt, &signflag, &dtoaend); 894113146Sdas } else { 895113146Sdas fparg.dbl = GETARG(double); 896113146Sdas dtoaresult = cp = 897113146Sdas dtoa(fparg.dbl, expchar ? 2 : 3, prec, 898113146Sdas &expt, &signflag, &dtoaend); 899113146Sdas if (expt == 9999) 900113146Sdas expt = INT_MAX; 9011573Srgrimes } 902124657Sdasfp_common: 903113146Sdas if (signflag) 904113146Sdas sign = '-'; 905113146Sdas if (expt == INT_MAX) { /* inf or nan */ 906113146Sdas if (*cp == 'N') { 907113146Sdas cp = (ch >= 'a') ? "nan" : "NAN"; 908113146Sdas sign = '\0'; 909113146Sdas } else 910113146Sdas cp = (ch >= 'a') ? "inf" : "INF"; 9111573Srgrimes size = 3; 9121573Srgrimes break; 9131573Srgrimes } 9141573Srgrimes flags |= FPT; 915113146Sdas ndig = dtoaend - cp; 9161573Srgrimes if (ch == 'g' || ch == 'G') { 917113146Sdas if (expt > -4 && expt <= prec) { 918113146Sdas /* Make %[gG] smell like %[fF] */ 919113146Sdas expchar = '\0'; 920113146Sdas if (flags & ALT) 921113146Sdas prec -= expt; 922113146Sdas else 923113146Sdas prec = ndig - expt; 924113146Sdas if (prec < 0) 925113146Sdas prec = 0; 926113723Sdas } else { 927113723Sdas /* 928113723Sdas * Make %[gG] smell like %[eE], but 929113723Sdas * trim trailing zeroes if no # flag. 930113723Sdas */ 931113723Sdas if (!(flags & ALT)) 932113723Sdas prec = ndig; 933113146Sdas } 9348870Srgrimes } 935113146Sdas if (expchar) { 936113146Sdas expsize = exponent(expstr, expt - 1, expchar); 937113146Sdas size = expsize + prec; 938113191Sdas if (prec > 1 || flags & ALT) 9391573Srgrimes ++size; 940113146Sdas } else { 941113468Sdas /* space for digits before decimal point */ 942113468Sdas if (expt > 0) 9431573Srgrimes size = expt; 944113468Sdas else /* "0" */ 945113468Sdas size = 1; 946113468Sdas /* space for decimal pt and following digits */ 947113468Sdas if (prec || flags & ALT) 948113468Sdas size += prec + 1; 949113146Sdas if (grouping && expt > 0) { 950113146Sdas /* space for thousands' grouping */ 951113146Sdas nseps = nrepeats = 0; 952113146Sdas lead = expt; 953113146Sdas while (*grouping != CHAR_MAX) { 954113146Sdas if (lead <= *grouping) 955113146Sdas break; 956113146Sdas lead -= *grouping; 957113146Sdas if (*(grouping+1)) { 958113146Sdas nseps++; 959113146Sdas grouping++; 960113146Sdas } else 961113146Sdas nrepeats++; 962113146Sdas } 963113146Sdas size += nseps + nrepeats; 964113146Sdas } else 965113194Sdas lead = expt; 966113146Sdas } 9671573Srgrimes break; 968128819Sdas#endif /* !NO_FLOATING_POINT */ 9691573Srgrimes case 'n': 97087113Sfenner /* 97187113Sfenner * Assignment-like behavior is specified if the 97287113Sfenner * value overflows or is otherwise unrepresentable. 97387113Sfenner * C99 says to use `signed char' for %hhn conversions. 97487113Sfenner */ 97587113Sfenner if (flags & LLONGINT) 97687113Sfenner *GETARG(long long *) = ret; 97787113Sfenner else if (flags & SIZET) 97887113Sfenner *GETARG(ssize_t *) = (ssize_t)ret; 97987113Sfenner else if (flags & PTRDIFFT) 98087113Sfenner *GETARG(ptrdiff_t *) = ret; 98187113Sfenner else if (flags & INTMAXT) 98287113Sfenner *GETARG(intmax_t *) = ret; 9831573Srgrimes else if (flags & LONGINT) 98431980Sache *GETARG(long *) = ret; 9851573Srgrimes else if (flags & SHORTINT) 98631980Sache *GETARG(short *) = ret; 98787113Sfenner else if (flags & CHARINT) 98887113Sfenner *GETARG(signed char *) = ret; 9891573Srgrimes else 99031980Sache *GETARG(int *) = ret; 9911573Srgrimes continue; /* no output */ 9921573Srgrimes case 'O': 9931573Srgrimes flags |= LONGINT; 9941573Srgrimes /*FALLTHROUGH*/ 9951573Srgrimes case 'o': 99687113Sfenner if (flags & INTMAX_SIZE) 99787113Sfenner ujval = UJARG(); 9981573Srgrimes else 9991573Srgrimes ulval = UARG(); 10001573Srgrimes base = 8; 10011573Srgrimes goto nosign; 10021573Srgrimes case 'p': 100388057Sphantom /*- 10041573Srgrimes * ``The argument shall be a pointer to void. The 10051573Srgrimes * value of the pointer is converted to a sequence 10061573Srgrimes * of printable characters, in an implementation- 10071573Srgrimes * defined manner.'' 10081573Srgrimes * -- ANSI X3J11 10091573Srgrimes */ 101087113Sfenner ujval = (uintmax_t)(uintptr_t)GETARG(void *); 10111573Srgrimes base = 16; 1012113146Sdas xdigs = xdigs_lower; 1013113146Sdas flags = flags | INTMAXT; 1014113146Sdas ox[1] = 'x'; 10151573Srgrimes goto nosign; 1016105204Stjr case 'S': 1017105204Stjr flags |= LONGINT; 1018105204Stjr /*FALLTHROUGH*/ 10191573Srgrimes case 's': 1020103633Stjr if (flags & LONGINT) { 1021103633Stjr wchar_t *wcp; 1022103633Stjr 1023103633Stjr if (convbuf != NULL) 1024103633Stjr free(convbuf); 1025103633Stjr if ((wcp = GETARG(wchar_t *)) == NULL) 1026103633Stjr cp = "(null)"; 1027103633Stjr else { 1028103633Stjr convbuf = __wcsconv(wcp, prec); 1029105234Stjr if (convbuf == NULL) { 1030105234Stjr fp->_flags |= __SERR; 1031103633Stjr goto error; 1032105234Stjr } 1033103633Stjr cp = convbuf; 1034103633Stjr } 1035103633Stjr } else if ((cp = GETARG(char *)) == NULL) 10361573Srgrimes cp = "(null)"; 10371573Srgrimes if (prec >= 0) { 10381573Srgrimes /* 10391573Srgrimes * can't use strlen; can only look for the 10401573Srgrimes * NUL in the first `prec' characters, and 10411573Srgrimes * strlen() will go further. 10421573Srgrimes */ 104316586Sjraynard char *p = memchr(cp, 0, (size_t)prec); 10441573Srgrimes 10451573Srgrimes if (p != NULL) { 10461573Srgrimes size = p - cp; 10471573Srgrimes if (size > prec) 10481573Srgrimes size = prec; 10491573Srgrimes } else 10501573Srgrimes size = prec; 10511573Srgrimes } else 10521573Srgrimes size = strlen(cp); 10531573Srgrimes sign = '\0'; 10541573Srgrimes break; 10551573Srgrimes case 'U': 10561573Srgrimes flags |= LONGINT; 10571573Srgrimes /*FALLTHROUGH*/ 10581573Srgrimes case 'u': 105987113Sfenner if (flags & INTMAX_SIZE) 106087113Sfenner ujval = UJARG(); 10611573Srgrimes else 10621573Srgrimes ulval = UARG(); 10631573Srgrimes base = 10; 10641573Srgrimes goto nosign; 10651573Srgrimes case 'X': 1066113146Sdas xdigs = xdigs_upper; 10671573Srgrimes goto hex; 10681573Srgrimes case 'x': 1069113146Sdas xdigs = xdigs_lower; 107087113Sfennerhex: 107187113Sfenner if (flags & INTMAX_SIZE) 107287113Sfenner ujval = UJARG(); 10731573Srgrimes else 10741573Srgrimes ulval = UARG(); 10751573Srgrimes base = 16; 10761573Srgrimes /* leading 0x/X only if non-zero */ 10771573Srgrimes if (flags & ALT && 107887113Sfenner (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 1079113146Sdas ox[1] = ch; 10801573Srgrimes 108187815Sphantom flags &= ~GROUPING; 10821573Srgrimes /* unsigned conversions */ 10831573Srgrimesnosign: sign = '\0'; 108488057Sphantom /*- 10851573Srgrimes * ``... diouXx conversions ... if a precision is 10861573Srgrimes * specified, the 0 flag will be ignored.'' 10871573Srgrimes * -- ANSI X3J11 10881573Srgrimes */ 10891573Srgrimesnumber: if ((dprec = prec) >= 0) 10901573Srgrimes flags &= ~ZEROPAD; 10911573Srgrimes 109288057Sphantom /*- 10931573Srgrimes * ``The result of converting a zero value with an 10941573Srgrimes * explicit precision of zero is no characters.'' 10951573Srgrimes * -- ANSI X3J11 10961573Srgrimes */ 10971573Srgrimes cp = buf + BUF; 109887113Sfenner if (flags & INTMAX_SIZE) { 109987113Sfenner if (ujval != 0 || prec != 0) 110087113Sfenner cp = __ujtoa(ujval, cp, base, 110187815Sphantom flags & ALT, xdigs, 110287815Sphantom flags & GROUPING, thousands_sep, 110387815Sphantom grouping); 11041573Srgrimes } else { 11051573Srgrimes if (ulval != 0 || prec != 0) 11061573Srgrimes cp = __ultoa(ulval, cp, base, 110787815Sphantom flags & ALT, xdigs, 110887815Sphantom flags & GROUPING, thousands_sep, 110987815Sphantom grouping); 11101573Srgrimes } 11111573Srgrimes size = buf + BUF - cp; 1112113142Sdas if (size > BUF) /* should never happen */ 1113113142Sdas abort(); 11141573Srgrimes break; 11151573Srgrimes default: /* "%?" prints ?, unless ? is NUL */ 11161573Srgrimes if (ch == '\0') 11171573Srgrimes goto done; 11181573Srgrimes /* pretend it was %c with argument ch */ 11191573Srgrimes cp = buf; 11201573Srgrimes *cp = ch; 11211573Srgrimes size = 1; 11221573Srgrimes sign = '\0'; 11231573Srgrimes break; 11241573Srgrimes } 11251573Srgrimes 11261573Srgrimes /* 11271573Srgrimes * All reasonable formats wind up here. At this point, `cp' 11281573Srgrimes * points to a string which (if not flags&LADJUST) should be 11291573Srgrimes * padded out to `width' places. If flags&ZEROPAD, it should 11301573Srgrimes * first be prefixed by any sign or other prefix; otherwise, 11311573Srgrimes * it should be blank padded before the prefix is emitted. 11321573Srgrimes * After any left-hand padding and prefixing, emit zeroes 11331573Srgrimes * required by a decimal [diouxX] precision, then print the 11341573Srgrimes * string proper, then emit zeroes required by any leftover 11351573Srgrimes * floating precision; finally, if LADJUST, pad with blanks. 11361573Srgrimes * 11371573Srgrimes * Compute actual size, so we know how much to pad. 113814727Sfenner * size excludes decimal prec; realsz includes it. 11391573Srgrimes */ 114014727Sfenner realsz = dprec > size ? dprec : size; 11411573Srgrimes if (sign) 114214727Sfenner realsz++; 1143124657Sdas if (ox[1]) 114414727Sfenner realsz += 2; 11451573Srgrimes 114631983Sache prsize = width > realsz ? width : realsz; 114732253Sache if ((unsigned)ret + prsize > INT_MAX) { 114831983Sache ret = EOF; 114931983Sache goto error; 115031983Sache } 115131983Sache 11521573Srgrimes /* right-adjusting blank padding */ 11531573Srgrimes if ((flags & (LADJUST|ZEROPAD)) == 0) 11541573Srgrimes PAD(width - realsz, blanks); 11551573Srgrimes 11561573Srgrimes /* prefix */ 1157124657Sdas if (sign) 11581573Srgrimes PRINT(&sign, 1); 1159124657Sdas 1160124657Sdas if (ox[1]) { /* ox[1] is either x, X, or \0 */ 11611573Srgrimes ox[0] = '0'; 11621573Srgrimes PRINT(ox, 2); 11631573Srgrimes } 11641573Srgrimes 11651573Srgrimes /* right-adjusting zero padding */ 11661573Srgrimes if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 11671573Srgrimes PAD(width - realsz, zeroes); 11681573Srgrimes 11691573Srgrimes /* leading zeroes from decimal precision */ 117014727Sfenner PAD(dprec - size, zeroes); 11711573Srgrimes 11721573Srgrimes /* the string or number proper */ 1173128819Sdas#ifndef NO_FLOATING_POINT 11741573Srgrimes if ((flags & FPT) == 0) { 11751573Srgrimes PRINT(cp, size); 11761573Srgrimes } else { /* glue together f_p fragments */ 1177113146Sdas if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 1178113146Sdas if (expt <= 0) { 1179113468Sdas PRINT(zeroes, 1); 1180113468Sdas if (prec || flags & ALT) 1181113468Sdas PRINT(decimal_point, 1); 11821573Srgrimes PAD(-expt, zeroes); 1183113191Sdas /* already handled initial 0's */ 1184113191Sdas prec += expt; 11851573Srgrimes } else { 1186113191Sdas PRINTANDPAD(cp, dtoaend, lead, zeroes); 1187113146Sdas cp += lead; 1188113146Sdas if (grouping) { 1189113146Sdas while (nseps>0 || nrepeats>0) { 1190113146Sdas if (nrepeats > 0) 1191113146Sdas nrepeats--; 1192113146Sdas else { 1193113146Sdas grouping--; 1194113146Sdas nseps--; 1195113146Sdas } 1196113146Sdas PRINT(&thousands_sep, 1197113146Sdas 1); 1198113191Sdas PRINTANDPAD(cp,dtoaend, 1199113191Sdas *grouping, zeroes); 1200113146Sdas cp += *grouping; 1201113146Sdas } 1202113191Sdas if (cp > dtoaend) 1203113191Sdas cp = dtoaend; 1204113146Sdas } 1205113146Sdas if (prec || flags & ALT) 1206113146Sdas PRINT(decimal_point,1); 12071573Srgrimes } 1208113191Sdas PRINTANDPAD(cp, dtoaend, prec, zeroes); 1209113146Sdas } else { /* %[eE] or sufficiently long %[gG] */ 1210113191Sdas if (prec > 1 || flags & ALT) { 1211113146Sdas buf[0] = *cp++; 1212113146Sdas buf[1] = *decimal_point; 1213113146Sdas PRINT(buf, 2); 1214113146Sdas PRINT(cp, ndig-1); 1215113146Sdas PAD(prec - ndig, zeroes); 12161573Srgrimes } else /* XeYYY */ 12171573Srgrimes PRINT(cp, 1); 12181573Srgrimes PRINT(expstr, expsize); 12191573Srgrimes } 12201573Srgrimes } 12211573Srgrimes#else 12221573Srgrimes PRINT(cp, size); 12231573Srgrimes#endif 12241573Srgrimes /* left-adjusting padding (always blank) */ 12251573Srgrimes if (flags & LADJUST) 12261573Srgrimes PAD(width - realsz, blanks); 12271573Srgrimes 12281573Srgrimes /* finally, adjust ret */ 122931983Sache ret += prsize; 12301573Srgrimes 12311573Srgrimes FLUSH(); /* copy out the I/O vectors */ 12321573Srgrimes } 12331573Srgrimesdone: 12341573Srgrimes FLUSH(); 12351573Srgrimeserror: 1236128819Sdas#ifndef NO_FLOATING_POINT 123772523Stegge if (dtoaresult != NULL) 1238113146Sdas freedtoa(dtoaresult); 123972523Stegge#endif 1240103633Stjr if (convbuf != NULL) 1241103633Stjr free(convbuf); 124213545Sjulian if (__sferror(fp)) 124313545Sjulian ret = EOF; 1244103399Stjr if ((argtable != NULL) && (argtable != statargtable)) 1245103399Stjr free (argtable); 124613545Sjulian return (ret); 12471573Srgrimes /* NOTREACHED */ 12481573Srgrimes} 12491573Srgrimes 125021674Sjkh/* 125121674Sjkh * Find all arguments when a positional parameter is encountered. Returns a 125221674Sjkh * table, indexed by argument number, of pointers to each arguments. The 125321674Sjkh * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 125470725Sarchie * It will be replaces with a malloc-ed one if it overflows. 125521674Sjkh */ 125621674Sjkhstatic void 125784962Sbde__find_arguments (const char *fmt0, va_list ap, union arg **argtable) 125821674Sjkh{ 125971579Sdeischen char *fmt; /* format string */ 126071579Sdeischen int ch; /* character from fmt */ 126171579Sdeischen int n, n2; /* handy integer (short term usage) */ 126271579Sdeischen char *cp; /* handy char pointer (short term usage) */ 126371579Sdeischen int flags; /* flags as above */ 126421674Sjkh int width; /* width from format (%8d), or 0 */ 126587113Sfenner enum typeid *typetable; /* table of types */ 126687113Sfenner enum typeid stattypetable [STATIC_ARG_TBL_SIZE]; 126721674Sjkh int tablesize; /* current size of type table */ 126821674Sjkh int tablemax; /* largest used index in table */ 126921674Sjkh int nextarg; /* 1-based argument index */ 127021674Sjkh 127121674Sjkh /* 127221674Sjkh * Add an argument type to the table, expanding if necessary. 127321674Sjkh */ 127421674Sjkh#define ADDTYPE(type) \ 127521674Sjkh ((nextarg >= tablesize) ? \ 127621674Sjkh __grow_type_table(nextarg, &typetable, &tablesize) : 0, \ 127770725Sarchie (nextarg > tablemax) ? tablemax = nextarg : 0, \ 127870725Sarchie typetable[nextarg++] = type) 127921674Sjkh 128021674Sjkh#define ADDSARG() \ 128187113Sfenner ((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \ 128287113Sfenner ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 128387113Sfenner ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 128487113Sfenner ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \ 128587113Sfenner ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT)))))) 128621674Sjkh 128721674Sjkh#define ADDUARG() \ 128887113Sfenner ((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \ 128987113Sfenner ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 129087113Sfenner ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 129187113Sfenner ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \ 129287113Sfenner ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT)))))) 129321674Sjkh 129421674Sjkh /* 129521674Sjkh * Add * arguments to the type array. 129621674Sjkh */ 129721674Sjkh#define ADDASTER() \ 129821674Sjkh n2 = 0; \ 129921674Sjkh cp = fmt; \ 130021674Sjkh while (is_digit(*cp)) { \ 130121674Sjkh n2 = 10 * n2 + to_digit(*cp); \ 130221674Sjkh cp++; \ 130321674Sjkh } \ 130421674Sjkh if (*cp == '$') { \ 130521674Sjkh int hold = nextarg; \ 130621674Sjkh nextarg = n2; \ 130721674Sjkh ADDTYPE (T_INT); \ 130821674Sjkh nextarg = hold; \ 130921674Sjkh fmt = ++cp; \ 131021674Sjkh } else { \ 131121674Sjkh ADDTYPE (T_INT); \ 131221674Sjkh } 131321674Sjkh fmt = (char *)fmt0; 131421674Sjkh typetable = stattypetable; 131521674Sjkh tablesize = STATIC_ARG_TBL_SIZE; 131621674Sjkh tablemax = 0; 131721674Sjkh nextarg = 1; 1318128550Stjr for (n = 0; n < STATIC_ARG_TBL_SIZE; n++) 1319128550Stjr typetable[n] = T_UNUSED; 132021674Sjkh 132121674Sjkh /* 132221674Sjkh * Scan the format for conversions (`%' character). 132321674Sjkh */ 132421674Sjkh for (;;) { 132521674Sjkh for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 132621674Sjkh /* void */; 132721674Sjkh if (ch == '\0') 132821674Sjkh goto done; 132921674Sjkh fmt++; /* skip over '%' */ 133021674Sjkh 133121674Sjkh flags = 0; 133221674Sjkh width = 0; 133321674Sjkh 133421674Sjkhrflag: ch = *fmt++; 133521674Sjkhreswitch: switch (ch) { 133621674Sjkh case ' ': 133721674Sjkh case '#': 133821674Sjkh goto rflag; 133921674Sjkh case '*': 134021674Sjkh ADDASTER (); 134121674Sjkh goto rflag; 134221674Sjkh case '-': 134321674Sjkh case '+': 134487113Sfenner case '\'': 134521674Sjkh goto rflag; 134621674Sjkh case '.': 134721674Sjkh if ((ch = *fmt++) == '*') { 134821674Sjkh ADDASTER (); 134921674Sjkh goto rflag; 135021674Sjkh } 135121674Sjkh while (is_digit(ch)) { 135221674Sjkh ch = *fmt++; 135321674Sjkh } 135421674Sjkh goto reswitch; 135521674Sjkh case '0': 135621674Sjkh goto rflag; 135721674Sjkh case '1': case '2': case '3': case '4': 135821674Sjkh case '5': case '6': case '7': case '8': case '9': 135921674Sjkh n = 0; 136021674Sjkh do { 136121674Sjkh n = 10 * n + to_digit(ch); 136221674Sjkh ch = *fmt++; 136321674Sjkh } while (is_digit(ch)); 136421674Sjkh if (ch == '$') { 136521674Sjkh nextarg = n; 136621674Sjkh goto rflag; 136721674Sjkh } 136821674Sjkh width = n; 136921674Sjkh goto reswitch; 1370128819Sdas#ifndef NO_FLOATING_POINT 137121674Sjkh case 'L': 137221674Sjkh flags |= LONGDBL; 137321674Sjkh goto rflag; 137421674Sjkh#endif 137521674Sjkh case 'h': 137687113Sfenner if (flags & SHORTINT) { 137787113Sfenner flags &= ~SHORTINT; 137887113Sfenner flags |= CHARINT; 137987113Sfenner } else 138087113Sfenner flags |= SHORTINT; 138121674Sjkh goto rflag; 138287113Sfenner case 'j': 138387113Sfenner flags |= INTMAXT; 138487113Sfenner goto rflag; 138521674Sjkh case 'l': 138687113Sfenner if (flags & LONGINT) { 138787113Sfenner flags &= ~LONGINT; 138887113Sfenner flags |= LLONGINT; 138987113Sfenner } else 139044674Sdfr flags |= LONGINT; 139121674Sjkh goto rflag; 139221674Sjkh case 'q': 139387113Sfenner flags |= LLONGINT; /* not necessarily */ 139421674Sjkh goto rflag; 139587113Sfenner case 't': 139687113Sfenner flags |= PTRDIFFT; 139787113Sfenner goto rflag; 139887113Sfenner case 'z': 139987113Sfenner flags |= SIZET; 140087113Sfenner goto rflag; 1401105204Stjr case 'C': 1402105204Stjr flags |= LONGINT; 1403105204Stjr /*FALLTHROUGH*/ 140421674Sjkh case 'c': 1405103633Stjr if (flags & LONGINT) 1406103633Stjr ADDTYPE(T_WINT); 1407103633Stjr else 1408103633Stjr ADDTYPE(T_INT); 140921674Sjkh break; 141021674Sjkh case 'D': 141121674Sjkh flags |= LONGINT; 141221674Sjkh /*FALLTHROUGH*/ 141321674Sjkh case 'd': 141421674Sjkh case 'i': 141587113Sfenner ADDSARG(); 141621674Sjkh break; 1417128819Sdas#ifndef NO_FLOATING_POINT 141887113Sfenner case 'a': 141987113Sfenner case 'A': 142021674Sjkh case 'e': 142121674Sjkh case 'E': 142221674Sjkh case 'f': 142321674Sjkh case 'g': 142421674Sjkh case 'G': 142521674Sjkh if (flags & LONGDBL) 142621674Sjkh ADDTYPE(T_LONG_DOUBLE); 142721674Sjkh else 142821674Sjkh ADDTYPE(T_DOUBLE); 142921674Sjkh break; 1430128819Sdas#endif /* !NO_FLOATING_POINT */ 143121674Sjkh case 'n': 143287113Sfenner if (flags & INTMAXT) 143387113Sfenner ADDTYPE(TP_INTMAXT); 143487113Sfenner else if (flags & PTRDIFFT) 143587113Sfenner ADDTYPE(TP_PTRDIFFT); 143687113Sfenner else if (flags & SIZET) 143787113Sfenner ADDTYPE(TP_SIZET); 143887113Sfenner else if (flags & LLONGINT) 143987113Sfenner ADDTYPE(TP_LLONG); 144021674Sjkh else if (flags & LONGINT) 144121674Sjkh ADDTYPE(TP_LONG); 144221674Sjkh else if (flags & SHORTINT) 144321674Sjkh ADDTYPE(TP_SHORT); 144487113Sfenner else if (flags & CHARINT) 144587113Sfenner ADDTYPE(TP_SCHAR); 144621674Sjkh else 144721674Sjkh ADDTYPE(TP_INT); 144821674Sjkh continue; /* no output */ 144921674Sjkh case 'O': 145021674Sjkh flags |= LONGINT; 145121674Sjkh /*FALLTHROUGH*/ 145221674Sjkh case 'o': 145387113Sfenner ADDUARG(); 145421674Sjkh break; 145521674Sjkh case 'p': 145621674Sjkh ADDTYPE(TP_VOID); 145721674Sjkh break; 1458105204Stjr case 'S': 1459105204Stjr flags |= LONGINT; 1460105204Stjr /*FALLTHROUGH*/ 146121674Sjkh case 's': 1462103633Stjr if (flags & LONGINT) 1463103633Stjr ADDTYPE(TP_WCHAR); 1464103633Stjr else 1465103633Stjr ADDTYPE(TP_CHAR); 146621674Sjkh break; 146721674Sjkh case 'U': 146821674Sjkh flags |= LONGINT; 146921674Sjkh /*FALLTHROUGH*/ 147021674Sjkh case 'u': 147121674Sjkh case 'X': 147221674Sjkh case 'x': 147387113Sfenner ADDUARG(); 147421674Sjkh break; 147521674Sjkh default: /* "%?" prints ?, unless ? is NUL */ 147621674Sjkh if (ch == '\0') 147721674Sjkh goto done; 147821674Sjkh break; 147921674Sjkh } 148021674Sjkh } 148121674Sjkhdone: 148221674Sjkh /* 148321674Sjkh * Build the argument table. 148421674Sjkh */ 148521674Sjkh if (tablemax >= STATIC_ARG_TBL_SIZE) { 148684922Sdfr *argtable = (union arg *) 148784922Sdfr malloc (sizeof (union arg) * (tablemax + 1)); 148821674Sjkh } 14891573Srgrimes 149084922Sdfr (*argtable) [0].intarg = 0; 149121674Sjkh for (n = 1; n <= tablemax; n++) { 149221674Sjkh switch (typetable [n]) { 149387113Sfenner case T_UNUSED: /* whoops! */ 149484922Sdfr (*argtable) [n].intarg = va_arg (ap, int); 149521674Sjkh break; 149687113Sfenner case TP_SCHAR: 149787113Sfenner (*argtable) [n].pschararg = va_arg (ap, signed char *); 149821674Sjkh break; 149921674Sjkh case TP_SHORT: 150084922Sdfr (*argtable) [n].pshortarg = va_arg (ap, short *); 150121674Sjkh break; 150221674Sjkh case T_INT: 150384922Sdfr (*argtable) [n].intarg = va_arg (ap, int); 150421674Sjkh break; 150521674Sjkh case T_U_INT: 150684922Sdfr (*argtable) [n].uintarg = va_arg (ap, unsigned int); 150721674Sjkh break; 150821674Sjkh case TP_INT: 150984922Sdfr (*argtable) [n].pintarg = va_arg (ap, int *); 151021674Sjkh break; 151121674Sjkh case T_LONG: 151284922Sdfr (*argtable) [n].longarg = va_arg (ap, long); 151321674Sjkh break; 151421674Sjkh case T_U_LONG: 151584922Sdfr (*argtable) [n].ulongarg = va_arg (ap, unsigned long); 151621674Sjkh break; 151721674Sjkh case TP_LONG: 151884922Sdfr (*argtable) [n].plongarg = va_arg (ap, long *); 151921674Sjkh break; 152087113Sfenner case T_LLONG: 152187113Sfenner (*argtable) [n].longlongarg = va_arg (ap, long long); 152221674Sjkh break; 152387113Sfenner case T_U_LLONG: 152487113Sfenner (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); 152521674Sjkh break; 152687113Sfenner case TP_LLONG: 152787113Sfenner (*argtable) [n].plonglongarg = va_arg (ap, long long *); 152821674Sjkh break; 152987113Sfenner case T_PTRDIFFT: 153087113Sfenner (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); 153187113Sfenner break; 153287113Sfenner case TP_PTRDIFFT: 153387113Sfenner (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); 153487113Sfenner break; 153587113Sfenner case T_SIZET: 153687113Sfenner (*argtable) [n].sizearg = va_arg (ap, size_t); 153787113Sfenner break; 153887113Sfenner case TP_SIZET: 153987113Sfenner (*argtable) [n].psizearg = va_arg (ap, ssize_t *); 154087113Sfenner break; 154187113Sfenner case T_INTMAXT: 154287113Sfenner (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); 154387113Sfenner break; 154487113Sfenner case T_UINTMAXT: 154587113Sfenner (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); 154687113Sfenner break; 154787113Sfenner case TP_INTMAXT: 154887113Sfenner (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); 154987113Sfenner break; 1550128819Sdas#ifndef NO_FLOATING_POINT 155121674Sjkh case T_DOUBLE: 155284922Sdfr (*argtable) [n].doublearg = va_arg (ap, double); 155321674Sjkh break; 155421674Sjkh case T_LONG_DOUBLE: 155584922Sdfr (*argtable) [n].longdoublearg = va_arg (ap, long double); 155621674Sjkh break; 155784922Sdfr#endif 155821674Sjkh case TP_CHAR: 155984922Sdfr (*argtable) [n].pchararg = va_arg (ap, char *); 156021674Sjkh break; 156121674Sjkh case TP_VOID: 156284922Sdfr (*argtable) [n].pvoidarg = va_arg (ap, void *); 156321674Sjkh break; 1564103633Stjr case T_WINT: 1565103633Stjr (*argtable) [n].wintarg = va_arg (ap, wint_t); 1566103633Stjr break; 1567103633Stjr case TP_WCHAR: 1568103633Stjr (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); 1569103633Stjr break; 157021674Sjkh } 157121674Sjkh } 157221674Sjkh 157321674Sjkh if ((typetable != NULL) && (typetable != stattypetable)) 157421674Sjkh free (typetable); 157521674Sjkh} 157621674Sjkh 157721674Sjkh/* 157821674Sjkh * Increase the size of the type table. 157921674Sjkh */ 158021674Sjkhstatic void 158187113Sfenner__grow_type_table (int nextarg, enum typeid **typetable, int *tablesize) 158221674Sjkh{ 158387113Sfenner enum typeid *const oldtable = *typetable; 158470725Sarchie const int oldsize = *tablesize; 158587113Sfenner enum typeid *newtable; 1586128550Stjr int n, newsize = oldsize * 2; 158721674Sjkh 158870725Sarchie if (newsize < nextarg + 1) 158970725Sarchie newsize = nextarg + 1; 159070725Sarchie if (oldsize == STATIC_ARG_TBL_SIZE) { 1591128550Stjr if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL) 159270725Sarchie abort(); /* XXX handle better */ 1593128550Stjr bcopy(oldtable, newtable, oldsize * sizeof(enum typeid)); 159421674Sjkh } else { 1595128550Stjr newtable = reallocf(oldtable, newsize * sizeof(enum typeid)); 1596128550Stjr if (newtable == NULL) 159770725Sarchie abort(); /* XXX handle better */ 159821674Sjkh } 1599128550Stjr for (n = oldsize; n < newsize; n++) 1600128550Stjr newtable[n] = T_UNUSED; 160121674Sjkh 160270725Sarchie *typetable = newtable; 160321674Sjkh *tablesize = newsize; 160421674Sjkh} 160521674Sjkh 160621674Sjkh 1607128819Sdas#ifndef NO_FLOATING_POINT 160821674Sjkh 16091573Srgrimesstatic int 161071579Sdeischenexponent(char *p0, int exp, int fmtch) 16111573Srgrimes{ 161271579Sdeischen char *p, *t; 1613113142Sdas char expbuf[MAXEXPDIG]; 16141573Srgrimes 16151573Srgrimes p = p0; 16161573Srgrimes *p++ = fmtch; 16171573Srgrimes if (exp < 0) { 16181573Srgrimes exp = -exp; 16191573Srgrimes *p++ = '-'; 16201573Srgrimes } 16211573Srgrimes else 16221573Srgrimes *p++ = '+'; 1623113142Sdas t = expbuf + MAXEXPDIG; 16241573Srgrimes if (exp > 9) { 16251573Srgrimes do { 16261573Srgrimes *--t = to_char(exp % 10); 16271573Srgrimes } while ((exp /= 10) > 9); 16281573Srgrimes *--t = to_char(exp); 1629113142Sdas for (; t < expbuf + MAXEXPDIG; *p++ = *t++); 16301573Srgrimes } 16311573Srgrimes else { 1632113146Sdas /* 1633113146Sdas * Exponents for decimal floating point conversions 1634113146Sdas * (%[eEgG]) must be at least two characters long, 1635113146Sdas * whereas exponents for hexadecimal conversions can 1636113146Sdas * be only one character long. 1637113146Sdas */ 1638113146Sdas if (fmtch == 'e' || fmtch == 'E') 1639113146Sdas *p++ = '0'; 16401573Srgrimes *p++ = to_char(exp); 16411573Srgrimes } 16421573Srgrimes return (p - p0); 16431573Srgrimes} 1644128819Sdas#endif /* !NO_FLOATING_POINT */ 1645