vfprintf.c revision 178287
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 * 4. Neither the name of the University nor the names of its contributors 171573Srgrimes * may be used to endorse or promote products derived from this software 181573Srgrimes * without specific prior written permission. 191573Srgrimes * 201573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301573Srgrimes * SUCH DAMAGE. 311573Srgrimes */ 321573Srgrimes 331573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 341573Srgrimesstatic char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; 351573Srgrimes#endif /* LIBC_SCCS and not lint */ 3692986Sobrien#include <sys/cdefs.h> 3792986Sobrien__FBSDID("$FreeBSD: head/lib/libc/stdio/vfprintf.c 178287 2008-04-17 22:17:54Z jhb $"); 381573Srgrimes 391573Srgrimes/* 401573Srgrimes * Actual printf innards. 411573Srgrimes * 421573Srgrimes * This code is large and complicated... 431573Srgrimes */ 441573Srgrimes 4571579Sdeischen#include "namespace.h" 461573Srgrimes#include <sys/types.h> 471573Srgrimes 4887113Sfenner#include <ctype.h> 491573Srgrimes#include <limits.h> 5087490Sphantom#include <locale.h> 5187113Sfenner#include <stddef.h> 5287113Sfenner#include <stdint.h> 531573Srgrimes#include <stdio.h> 541573Srgrimes#include <stdlib.h> 551573Srgrimes#include <string.h> 56103633Stjr#include <wchar.h> 57153486Sphk#include <printf.h> 581573Srgrimes 591573Srgrimes#include <stdarg.h> 6071579Sdeischen#include "un-namespace.h" 611573Srgrimes 6271579Sdeischen#include "libc_private.h" 631573Srgrimes#include "local.h" 641573Srgrimes#include "fvwrite.h" 651573Srgrimes 6684922Sdfrunion arg { 6784962Sbde int intarg; 6884962Sbde u_int uintarg; 6984962Sbde long longarg; 7084962Sbde u_long ulongarg; 7187113Sfenner long long longlongarg; 7287113Sfenner unsigned long long ulonglongarg; 7387113Sfenner ptrdiff_t ptrdiffarg; 7487113Sfenner size_t sizearg; 7587113Sfenner intmax_t intmaxarg; 7687113Sfenner uintmax_t uintmaxarg; 7784962Sbde void *pvoidarg; 7884962Sbde char *pchararg; 7987113Sfenner signed char *pschararg; 8084962Sbde short *pshortarg; 8184962Sbde int *pintarg; 8284962Sbde long *plongarg; 8387113Sfenner long long *plonglongarg; 8487113Sfenner ptrdiff_t *pptrdiffarg; 8587113Sfenner size_t *psizearg; 8687113Sfenner intmax_t *pintmaxarg; 87128819Sdas#ifndef NO_FLOATING_POINT 8884962Sbde double doublearg; 8984962Sbde long double longdoublearg; 9084922Sdfr#endif 91103633Stjr wint_t wintarg; 92103633Stjr wchar_t *pwchararg; 9384922Sdfr}; 9484922Sdfr 9587113Sfenner/* 9687113Sfenner * Type ids for argument type table. 9787113Sfenner */ 9887113Sfennerenum typeid { 9987113Sfenner T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, 10087113Sfenner T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, 10187113Sfenner T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET, 10287113Sfenner T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, 103103633Stjr T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR 10487113Sfenner}; 10587113Sfenner 10692905Sobrienstatic int __sprint(FILE *, struct __suio *); 10792941Sobrienstatic int __sbprintf(FILE *, const char *, va_list) __printflike(2, 0); 108113146Sdasstatic char *__ujtoa(uintmax_t, char *, int, int, const char *, int, char, 10992941Sobrien const char *); 110113146Sdasstatic char *__ultoa(u_long, char *, int, int, const char *, int, char, 11192941Sobrien const char *); 112103633Stjrstatic char *__wcsconv(wchar_t *, int); 11392905Sobrienstatic void __find_arguments(const char *, va_list, union arg **); 11492905Sobrienstatic void __grow_type_table(int, enum typeid **, int *); 11516586Sjraynard 1161573Srgrimes/* 1171573Srgrimes * Flush out all the vectors defined by the given uio, 1181573Srgrimes * then reset it so that it can be reused. 1191573Srgrimes */ 1201573Srgrimesstatic int 12171579Sdeischen__sprint(FILE *fp, struct __suio *uio) 1221573Srgrimes{ 12371579Sdeischen int err; 1241573Srgrimes 1251573Srgrimes if (uio->uio_resid == 0) { 1261573Srgrimes uio->uio_iovcnt = 0; 1271573Srgrimes return (0); 1281573Srgrimes } 1291573Srgrimes err = __sfvwrite(fp, uio); 1301573Srgrimes uio->uio_resid = 0; 1311573Srgrimes uio->uio_iovcnt = 0; 1321573Srgrimes return (err); 1331573Srgrimes} 1341573Srgrimes 1351573Srgrimes/* 1361573Srgrimes * Helper function for `fprintf to unbuffered unix file': creates a 1371573Srgrimes * temporary buffer. We only work on write-only files; this avoids 1381573Srgrimes * worries about ungetc buffers and so forth. 1391573Srgrimes */ 1401573Srgrimesstatic int 14171579Sdeischen__sbprintf(FILE *fp, const char *fmt, va_list ap) 1421573Srgrimes{ 1431573Srgrimes int ret; 1441573Srgrimes FILE fake; 1451573Srgrimes unsigned char buf[BUFSIZ]; 1461573Srgrimes 1471573Srgrimes /* copy the important variables */ 1481573Srgrimes fake._flags = fp->_flags & ~__SNBF; 1491573Srgrimes fake._file = fp->_file; 1501573Srgrimes fake._cookie = fp->_cookie; 1511573Srgrimes fake._write = fp->_write; 152178287Sjhb fake._orientation = fp->_orientation; 153178287Sjhb fake._mbstate = fp->_mbstate; 1541573Srgrimes 1551573Srgrimes /* set up the buffer */ 1561573Srgrimes fake._bf._base = fake._p = buf; 1571573Srgrimes fake._bf._size = fake._w = sizeof(buf); 1581573Srgrimes fake._lbfsize = 0; /* not actually used, but Just In Case */ 1591573Srgrimes 1601573Srgrimes /* do the work, then copy any error status */ 16171579Sdeischen ret = __vfprintf(&fake, fmt, ap); 16271579Sdeischen if (ret >= 0 && __fflush(&fake)) 1631573Srgrimes ret = EOF; 1641573Srgrimes if (fake._flags & __SERR) 1651573Srgrimes fp->_flags |= __SERR; 1661573Srgrimes return (ret); 1671573Srgrimes} 1681573Srgrimes 1691573Srgrimes/* 1701573Srgrimes * Macros for converting digits to letters and vice versa 1711573Srgrimes */ 1721573Srgrimes#define to_digit(c) ((c) - '0') 1731573Srgrimes#define is_digit(c) ((unsigned)to_digit(c) <= 9) 1741573Srgrimes#define to_char(n) ((n) + '0') 1751573Srgrimes 1761573Srgrimes/* 1771573Srgrimes * Convert an unsigned long to ASCII for printf purposes, returning 1781573Srgrimes * a pointer to the first character of the string representation. 1791573Srgrimes * Octal numbers can be forced to have a leading zero; hex numbers 1801573Srgrimes * use the given digits. 1811573Srgrimes */ 1821573Srgrimesstatic char * 183113146Sdas__ultoa(u_long val, char *endp, int base, int octzero, const char *xdigs, 18487815Sphantom int needgrp, char thousep, const char *grp) 1851573Srgrimes{ 18692889Sobrien char *cp = endp; 18792889Sobrien long sval; 18887113Sfenner int ndig; 1891573Srgrimes 1901573Srgrimes /* 1911573Srgrimes * Handle the three cases separately, in the hope of getting 1921573Srgrimes * better/faster code. 1931573Srgrimes */ 1941573Srgrimes switch (base) { 1951573Srgrimes case 10: 1961573Srgrimes if (val < 10) { /* many numbers are 1 digit */ 1971573Srgrimes *--cp = to_char(val); 1981573Srgrimes return (cp); 1991573Srgrimes } 20087113Sfenner ndig = 0; 2011573Srgrimes /* 2021573Srgrimes * On many machines, unsigned arithmetic is harder than 2031573Srgrimes * signed arithmetic, so we do at most one unsigned mod and 2041573Srgrimes * divide; this is sufficient to reduce the range of 2051573Srgrimes * the incoming value to where signed arithmetic works. 2061573Srgrimes */ 2071573Srgrimes if (val > LONG_MAX) { 2081573Srgrimes *--cp = to_char(val % 10); 20987113Sfenner ndig++; 2101573Srgrimes sval = val / 10; 2111573Srgrimes } else 2121573Srgrimes sval = val; 2131573Srgrimes do { 2141573Srgrimes *--cp = to_char(sval % 10); 21587815Sphantom ndig++; 21687815Sphantom /* 21787815Sphantom * If (*grp == CHAR_MAX) then no more grouping 21887815Sphantom * should be performed. 21987815Sphantom */ 22087818Sphantom if (needgrp && ndig == *grp && *grp != CHAR_MAX 22187818Sphantom && sval > 9) { 22287815Sphantom *--cp = thousep; 22387113Sfenner ndig = 0; 22487815Sphantom /* 22587815Sphantom * If (*(grp+1) == '\0') then we have to 22687815Sphantom * use *grp character (last grouping rule) 22787815Sphantom * for all next cases 22887815Sphantom */ 22988057Sphantom if (*(grp+1) != '\0') 23088057Sphantom grp++; 23187113Sfenner } 2321573Srgrimes sval /= 10; 2331573Srgrimes } while (sval != 0); 2341573Srgrimes break; 2351573Srgrimes 2361573Srgrimes case 8: 2371573Srgrimes do { 2381573Srgrimes *--cp = to_char(val & 7); 2391573Srgrimes val >>= 3; 2401573Srgrimes } while (val); 2411573Srgrimes if (octzero && *cp != '0') 2421573Srgrimes *--cp = '0'; 2431573Srgrimes break; 2441573Srgrimes 2451573Srgrimes case 16: 2461573Srgrimes do { 2471573Srgrimes *--cp = xdigs[val & 15]; 2481573Srgrimes val >>= 4; 2491573Srgrimes } while (val); 2501573Srgrimes break; 2511573Srgrimes 2521573Srgrimes default: /* oops */ 2531573Srgrimes abort(); 2541573Srgrimes } 2551573Srgrimes return (cp); 2561573Srgrimes} 2571573Srgrimes 25887113Sfenner/* Identical to __ultoa, but for intmax_t. */ 2591573Srgrimesstatic char * 260113146Sdas__ujtoa(uintmax_t val, char *endp, int base, int octzero, const char *xdigs, 26187815Sphantom int needgrp, char thousep, const char *grp) 2621573Srgrimes{ 26371579Sdeischen char *cp = endp; 26487113Sfenner intmax_t sval; 26587113Sfenner int ndig; 2661573Srgrimes 2671573Srgrimes /* quick test for small values; __ultoa is typically much faster */ 2681573Srgrimes /* (perhaps instead we should run until small, then call __ultoa?) */ 2691573Srgrimes if (val <= ULONG_MAX) 27087113Sfenner return (__ultoa((u_long)val, endp, base, octzero, xdigs, 27187815Sphantom needgrp, thousep, grp)); 2721573Srgrimes switch (base) { 2731573Srgrimes case 10: 2741573Srgrimes if (val < 10) { 2751573Srgrimes *--cp = to_char(val % 10); 2761573Srgrimes return (cp); 2771573Srgrimes } 27887113Sfenner ndig = 0; 27987113Sfenner if (val > INTMAX_MAX) { 2801573Srgrimes *--cp = to_char(val % 10); 28187113Sfenner ndig++; 2821573Srgrimes sval = val / 10; 2831573Srgrimes } else 2841573Srgrimes sval = val; 2851573Srgrimes do { 2861573Srgrimes *--cp = to_char(sval % 10); 28787815Sphantom ndig++; 28887815Sphantom /* 28987815Sphantom * If (*grp == CHAR_MAX) then no more grouping 29087815Sphantom * should be performed. 29187815Sphantom */ 29287818Sphantom if (needgrp && *grp != CHAR_MAX && ndig == *grp 29387818Sphantom && sval > 9) { 29487815Sphantom *--cp = thousep; 29587113Sfenner ndig = 0; 29687815Sphantom /* 29787815Sphantom * If (*(grp+1) == '\0') then we have to 29887815Sphantom * use *grp character (last grouping rule) 29987815Sphantom * for all next cases 30087815Sphantom */ 30188057Sphantom if (*(grp+1) != '\0') 30288057Sphantom grp++; 30388057Sphantom } 3041573Srgrimes sval /= 10; 3051573Srgrimes } while (sval != 0); 3061573Srgrimes break; 3071573Srgrimes 3081573Srgrimes case 8: 3091573Srgrimes do { 3101573Srgrimes *--cp = to_char(val & 7); 3111573Srgrimes val >>= 3; 3121573Srgrimes } while (val); 3131573Srgrimes if (octzero && *cp != '0') 3141573Srgrimes *--cp = '0'; 3151573Srgrimes break; 3161573Srgrimes 3171573Srgrimes case 16: 3181573Srgrimes do { 3191573Srgrimes *--cp = xdigs[val & 15]; 3201573Srgrimes val >>= 4; 3211573Srgrimes } while (val); 3221573Srgrimes break; 3231573Srgrimes 3241573Srgrimes default: 3251573Srgrimes abort(); 3261573Srgrimes } 3271573Srgrimes return (cp); 3281573Srgrimes} 3291573Srgrimes 33071579Sdeischen/* 331103633Stjr * Convert a wide character string argument for the %ls format to a multibyte 332148363Stjr * string representation. If not -1, prec specifies the maximum number of 333148363Stjr * bytes to output, and also means that we can't assume that the wide char. 334148363Stjr * string ends is null-terminated. 335103633Stjr */ 336103633Stjrstatic char * 337103633Stjr__wcsconv(wchar_t *wcsarg, int prec) 338103633Stjr{ 339128002Stjr static const mbstate_t initial; 340128002Stjr mbstate_t mbs; 341103633Stjr char buf[MB_LEN_MAX]; 342103633Stjr wchar_t *p; 343148363Stjr char *convbuf; 344103633Stjr size_t clen, nbytes; 345103633Stjr 346148363Stjr /* Allocate space for the maximum number of bytes we could output. */ 347148363Stjr if (prec < 0) { 348103633Stjr p = wcsarg; 349128002Stjr mbs = initial; 350128002Stjr nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); 351103633Stjr if (nbytes == (size_t)-1) 352103633Stjr return (NULL); 353148363Stjr } else { 354148363Stjr /* 355148363Stjr * Optimisation: if the output precision is small enough, 356148363Stjr * just allocate enough memory for the maximum instead of 357148363Stjr * scanning the string. 358148363Stjr */ 359148363Stjr if (prec < 128) 360148363Stjr nbytes = prec; 361148363Stjr else { 362148363Stjr nbytes = 0; 363148363Stjr p = wcsarg; 364148363Stjr mbs = initial; 365148363Stjr for (;;) { 366148363Stjr clen = wcrtomb(buf, *p++, &mbs); 367148363Stjr if (clen == 0 || clen == (size_t)-1 || 368148363Stjr nbytes + clen > prec) 369148363Stjr break; 370148363Stjr nbytes += clen; 371148363Stjr } 372148363Stjr } 373103633Stjr } 374103633Stjr if ((convbuf = malloc(nbytes + 1)) == NULL) 375103633Stjr return (NULL); 376103633Stjr 377148363Stjr /* Fill the output buffer. */ 378103633Stjr p = wcsarg; 379128002Stjr mbs = initial; 380148363Stjr if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p, 381148363Stjr nbytes, &mbs)) == (size_t)-1) { 382113196Sache free(convbuf); 383113196Sache return (NULL); 384113196Sache } 385148363Stjr convbuf[nbytes] = '\0'; 386103633Stjr return (convbuf); 387103633Stjr} 388103633Stjr 389103633Stjr/* 39071579Sdeischen * MT-safe version 39171579Sdeischen */ 39271579Sdeischenint 393103012Stjrvfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) 394101914Srobert 39571579Sdeischen{ 39671579Sdeischen int ret; 39771579Sdeischen 39871579Sdeischen FLOCKFILE(fp); 39971579Sdeischen ret = __vfprintf(fp, fmt0, ap); 40071579Sdeischen FUNLOCKFILE(fp); 40171579Sdeischen return (ret); 40271579Sdeischen} 40371579Sdeischen 404128819Sdas#ifndef NO_FLOATING_POINT 405113146Sdas 406113146Sdas#define dtoa __dtoa 407113146Sdas#define freedtoa __freedtoa 408113146Sdas 409113146Sdas#include <float.h> 4101573Srgrimes#include <math.h> 4111573Srgrimes#include "floatio.h" 412113146Sdas#include "gdtoa.h" 4131573Srgrimes 4141573Srgrimes#define DEFPREC 6 4151573Srgrimes 41692905Sobrienstatic int exponent(char *, int, int); 4171573Srgrimes 418128819Sdas#endif /* !NO_FLOATING_POINT */ 4191573Srgrimes 420113142Sdas/* 421113142Sdas * The size of the buffer we use as scratch space for integer 422113142Sdas * conversions, among other things. Technically, we would need the 423113142Sdas * most space for base 10 conversions with thousands' grouping 424113142Sdas * characters between each pair of digits. 100 bytes is a 425113142Sdas * conservative overestimate even for a 128-bit uintmax_t. 426113142Sdas */ 427113142Sdas#define BUF 100 4281573Srgrimes 42921674Sjkh#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 4301573Srgrimes 4311573Srgrimes/* 4321573Srgrimes * Flags used during conversion. 4331573Srgrimes */ 4341573Srgrimes#define ALT 0x001 /* alternate form */ 4351573Srgrimes#define LADJUST 0x004 /* left adjustment */ 43631871Sbde#define LONGDBL 0x008 /* long double */ 4371573Srgrimes#define LONGINT 0x010 /* long integer */ 43887113Sfenner#define LLONGINT 0x020 /* long long integer */ 4391573Srgrimes#define SHORTINT 0x040 /* short integer */ 4401573Srgrimes#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 44188057Sphantom#define FPT 0x100 /* Floating point number */ 44287815Sphantom#define GROUPING 0x200 /* use grouping ("'" flag) */ 44387113Sfenner /* C99 additional size modifiers: */ 44487815Sphantom#define SIZET 0x400 /* size_t */ 44587815Sphantom#define PTRDIFFT 0x800 /* ptrdiff_t */ 44687815Sphantom#define INTMAXT 0x1000 /* intmax_t */ 44787815Sphantom#define CHARINT 0x2000 /* print char using int format */ 44887113Sfenner 44971579Sdeischen/* 45071579Sdeischen * Non-MT-safe version 45171579Sdeischen */ 4521573Srgrimesint 45371579Sdeischen__vfprintf(FILE *fp, const char *fmt0, va_list ap) 4541573Srgrimes{ 45571579Sdeischen char *fmt; /* format string */ 45671579Sdeischen int ch; /* character from fmt */ 45771579Sdeischen int n, n2; /* handy integer (short term usage) */ 45871579Sdeischen char *cp; /* handy char pointer (short term usage) */ 45971579Sdeischen struct __siov *iovp; /* for PRINT macro */ 46071579Sdeischen int flags; /* flags as above */ 4611573Srgrimes int ret; /* return value accumulator */ 4621573Srgrimes int width; /* width from format (%8d), or 0 */ 463113146Sdas int prec; /* precision from format; <0 for N/A */ 4641573Srgrimes char sign; /* sign prefix (' ', '+', '-', or \0) */ 46587815Sphantom char thousands_sep; /* locale specific thousands separator */ 46687815Sphantom const char *grouping; /* locale specific numeric grouping rules */ 467153486Sphk 468153486Sphk if (__use_xprintf == 0 && getenv("USE_XPRINTF")) 469153486Sphk __use_xprintf = 1; 470153486Sphk if (__use_xprintf > 0) 471153486Sphk return (__xvprintf(fp, fmt0, ap)); 472153486Sphk 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 535165742Sdas static const char xdigs_lower[16] = "0123456789abcdef"; 536165742Sdas 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 */ 645130231Sdas if (prepwrite(fp) != 0) 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; 912169355Sdas flags &= ~ZEROPAD; 9131573Srgrimes break; 9141573Srgrimes } 9151573Srgrimes flags |= FPT; 916113146Sdas ndig = dtoaend - cp; 9171573Srgrimes if (ch == 'g' || ch == 'G') { 918113146Sdas if (expt > -4 && expt <= prec) { 919113146Sdas /* Make %[gG] smell like %[fF] */ 920113146Sdas expchar = '\0'; 921113146Sdas if (flags & ALT) 922113146Sdas prec -= expt; 923113146Sdas else 924113146Sdas prec = ndig - expt; 925113146Sdas if (prec < 0) 926113146Sdas prec = 0; 927113723Sdas } else { 928113723Sdas /* 929113723Sdas * Make %[gG] smell like %[eE], but 930113723Sdas * trim trailing zeroes if no # flag. 931113723Sdas */ 932113723Sdas if (!(flags & ALT)) 933113723Sdas prec = ndig; 934113146Sdas } 9358870Srgrimes } 936113146Sdas if (expchar) { 937113146Sdas expsize = exponent(expstr, expt - 1, expchar); 938113146Sdas size = expsize + prec; 939113191Sdas if (prec > 1 || flags & ALT) 9401573Srgrimes ++size; 941113146Sdas } else { 942113468Sdas /* space for digits before decimal point */ 943113468Sdas if (expt > 0) 9441573Srgrimes size = expt; 945113468Sdas else /* "0" */ 946113468Sdas size = 1; 947113468Sdas /* space for decimal pt and following digits */ 948113468Sdas if (prec || flags & ALT) 949113468Sdas size += prec + 1; 950113146Sdas if (grouping && expt > 0) { 951113146Sdas /* space for thousands' grouping */ 952113146Sdas nseps = nrepeats = 0; 953113146Sdas lead = expt; 954113146Sdas while (*grouping != CHAR_MAX) { 955113146Sdas if (lead <= *grouping) 956113146Sdas break; 957113146Sdas lead -= *grouping; 958113146Sdas if (*(grouping+1)) { 959113146Sdas nseps++; 960113146Sdas grouping++; 961113146Sdas } else 962113146Sdas nrepeats++; 963113146Sdas } 964113146Sdas size += nseps + nrepeats; 965113146Sdas } else 966113194Sdas lead = expt; 967113146Sdas } 9681573Srgrimes break; 969128819Sdas#endif /* !NO_FLOATING_POINT */ 9701573Srgrimes case 'n': 97187113Sfenner /* 97287113Sfenner * Assignment-like behavior is specified if the 97387113Sfenner * value overflows or is otherwise unrepresentable. 97487113Sfenner * C99 says to use `signed char' for %hhn conversions. 97587113Sfenner */ 97687113Sfenner if (flags & LLONGINT) 97787113Sfenner *GETARG(long long *) = ret; 97887113Sfenner else if (flags & SIZET) 97987113Sfenner *GETARG(ssize_t *) = (ssize_t)ret; 98087113Sfenner else if (flags & PTRDIFFT) 98187113Sfenner *GETARG(ptrdiff_t *) = ret; 98287113Sfenner else if (flags & INTMAXT) 98387113Sfenner *GETARG(intmax_t *) = ret; 9841573Srgrimes else if (flags & LONGINT) 98531980Sache *GETARG(long *) = ret; 9861573Srgrimes else if (flags & SHORTINT) 98731980Sache *GETARG(short *) = ret; 98887113Sfenner else if (flags & CHARINT) 98987113Sfenner *GETARG(signed char *) = ret; 9901573Srgrimes else 99131980Sache *GETARG(int *) = ret; 9921573Srgrimes continue; /* no output */ 9931573Srgrimes case 'O': 9941573Srgrimes flags |= LONGINT; 9951573Srgrimes /*FALLTHROUGH*/ 9961573Srgrimes case 'o': 99787113Sfenner if (flags & INTMAX_SIZE) 99887113Sfenner ujval = UJARG(); 9991573Srgrimes else 10001573Srgrimes ulval = UARG(); 10011573Srgrimes base = 8; 10021573Srgrimes goto nosign; 10031573Srgrimes case 'p': 100488057Sphantom /*- 10051573Srgrimes * ``The argument shall be a pointer to void. The 10061573Srgrimes * value of the pointer is converted to a sequence 10071573Srgrimes * of printable characters, in an implementation- 10081573Srgrimes * defined manner.'' 10091573Srgrimes * -- ANSI X3J11 10101573Srgrimes */ 101187113Sfenner ujval = (uintmax_t)(uintptr_t)GETARG(void *); 10121573Srgrimes base = 16; 1013113146Sdas xdigs = xdigs_lower; 1014113146Sdas flags = flags | INTMAXT; 1015113146Sdas ox[1] = 'x'; 10161573Srgrimes goto nosign; 1017105204Stjr case 'S': 1018105204Stjr flags |= LONGINT; 1019105204Stjr /*FALLTHROUGH*/ 10201573Srgrimes case 's': 1021103633Stjr if (flags & LONGINT) { 1022103633Stjr wchar_t *wcp; 1023103633Stjr 1024103633Stjr if (convbuf != NULL) 1025103633Stjr free(convbuf); 1026103633Stjr if ((wcp = GETARG(wchar_t *)) == NULL) 1027103633Stjr cp = "(null)"; 1028103633Stjr else { 1029103633Stjr convbuf = __wcsconv(wcp, prec); 1030105234Stjr if (convbuf == NULL) { 1031105234Stjr fp->_flags |= __SERR; 1032103633Stjr goto error; 1033105234Stjr } 1034103633Stjr cp = convbuf; 1035103633Stjr } 1036103633Stjr } else if ((cp = GETARG(char *)) == NULL) 10371573Srgrimes cp = "(null)"; 10381573Srgrimes if (prec >= 0) { 10391573Srgrimes /* 10401573Srgrimes * can't use strlen; can only look for the 10411573Srgrimes * NUL in the first `prec' characters, and 10421573Srgrimes * strlen() will go further. 10431573Srgrimes */ 104416586Sjraynard char *p = memchr(cp, 0, (size_t)prec); 10451573Srgrimes 10461573Srgrimes if (p != NULL) { 10471573Srgrimes size = p - cp; 10481573Srgrimes if (size > prec) 10491573Srgrimes size = prec; 10501573Srgrimes } else 10511573Srgrimes size = prec; 10521573Srgrimes } else 10531573Srgrimes size = strlen(cp); 10541573Srgrimes sign = '\0'; 10551573Srgrimes break; 10561573Srgrimes case 'U': 10571573Srgrimes flags |= LONGINT; 10581573Srgrimes /*FALLTHROUGH*/ 10591573Srgrimes case 'u': 106087113Sfenner if (flags & INTMAX_SIZE) 106187113Sfenner ujval = UJARG(); 10621573Srgrimes else 10631573Srgrimes ulval = UARG(); 10641573Srgrimes base = 10; 10651573Srgrimes goto nosign; 10661573Srgrimes case 'X': 1067113146Sdas xdigs = xdigs_upper; 10681573Srgrimes goto hex; 10691573Srgrimes case 'x': 1070113146Sdas xdigs = xdigs_lower; 107187113Sfennerhex: 107287113Sfenner if (flags & INTMAX_SIZE) 107387113Sfenner ujval = UJARG(); 10741573Srgrimes else 10751573Srgrimes ulval = UARG(); 10761573Srgrimes base = 16; 10771573Srgrimes /* leading 0x/X only if non-zero */ 10781573Srgrimes if (flags & ALT && 107987113Sfenner (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 1080113146Sdas ox[1] = ch; 10811573Srgrimes 108287815Sphantom flags &= ~GROUPING; 10831573Srgrimes /* unsigned conversions */ 10841573Srgrimesnosign: sign = '\0'; 108588057Sphantom /*- 10861573Srgrimes * ``... diouXx conversions ... if a precision is 10871573Srgrimes * specified, the 0 flag will be ignored.'' 10881573Srgrimes * -- ANSI X3J11 10891573Srgrimes */ 10901573Srgrimesnumber: if ((dprec = prec) >= 0) 10911573Srgrimes flags &= ~ZEROPAD; 10921573Srgrimes 109388057Sphantom /*- 10941573Srgrimes * ``The result of converting a zero value with an 10951573Srgrimes * explicit precision of zero is no characters.'' 10961573Srgrimes * -- ANSI X3J11 1097145172Sdas * 1098145172Sdas * ``The C Standard is clear enough as is. The call 1099145172Sdas * printf("%#.0o", 0) should print 0.'' 1100145172Sdas * -- Defect Report #151 11011573Srgrimes */ 11021573Srgrimes cp = buf + BUF; 110387113Sfenner if (flags & INTMAX_SIZE) { 1104145172Sdas if (ujval != 0 || prec != 0 || 1105145172Sdas (flags & ALT && base == 8)) 110687113Sfenner cp = __ujtoa(ujval, cp, base, 110787815Sphantom flags & ALT, xdigs, 110887815Sphantom flags & GROUPING, thousands_sep, 110987815Sphantom grouping); 11101573Srgrimes } else { 1111145172Sdas if (ulval != 0 || prec != 0 || 1112145172Sdas (flags & ALT && base == 8)) 11131573Srgrimes cp = __ultoa(ulval, cp, base, 111487815Sphantom flags & ALT, xdigs, 111587815Sphantom flags & GROUPING, thousands_sep, 111687815Sphantom grouping); 11171573Srgrimes } 11181573Srgrimes size = buf + BUF - cp; 1119113142Sdas if (size > BUF) /* should never happen */ 1120113142Sdas abort(); 11211573Srgrimes break; 11221573Srgrimes default: /* "%?" prints ?, unless ? is NUL */ 11231573Srgrimes if (ch == '\0') 11241573Srgrimes goto done; 11251573Srgrimes /* pretend it was %c with argument ch */ 11261573Srgrimes cp = buf; 11271573Srgrimes *cp = ch; 11281573Srgrimes size = 1; 11291573Srgrimes sign = '\0'; 11301573Srgrimes break; 11311573Srgrimes } 11321573Srgrimes 11331573Srgrimes /* 11341573Srgrimes * All reasonable formats wind up here. At this point, `cp' 11351573Srgrimes * points to a string which (if not flags&LADJUST) should be 11361573Srgrimes * padded out to `width' places. If flags&ZEROPAD, it should 11371573Srgrimes * first be prefixed by any sign or other prefix; otherwise, 11381573Srgrimes * it should be blank padded before the prefix is emitted. 11391573Srgrimes * After any left-hand padding and prefixing, emit zeroes 11401573Srgrimes * required by a decimal [diouxX] precision, then print the 11411573Srgrimes * string proper, then emit zeroes required by any leftover 11421573Srgrimes * floating precision; finally, if LADJUST, pad with blanks. 11431573Srgrimes * 11441573Srgrimes * Compute actual size, so we know how much to pad. 114514727Sfenner * size excludes decimal prec; realsz includes it. 11461573Srgrimes */ 114714727Sfenner realsz = dprec > size ? dprec : size; 11481573Srgrimes if (sign) 114914727Sfenner realsz++; 1150124657Sdas if (ox[1]) 115114727Sfenner realsz += 2; 11521573Srgrimes 115331983Sache prsize = width > realsz ? width : realsz; 115432253Sache if ((unsigned)ret + prsize > INT_MAX) { 115531983Sache ret = EOF; 115631983Sache goto error; 115731983Sache } 115831983Sache 11591573Srgrimes /* right-adjusting blank padding */ 11601573Srgrimes if ((flags & (LADJUST|ZEROPAD)) == 0) 11611573Srgrimes PAD(width - realsz, blanks); 11621573Srgrimes 11631573Srgrimes /* prefix */ 1164124657Sdas if (sign) 11651573Srgrimes PRINT(&sign, 1); 1166124657Sdas 1167124657Sdas if (ox[1]) { /* ox[1] is either x, X, or \0 */ 11681573Srgrimes ox[0] = '0'; 11691573Srgrimes PRINT(ox, 2); 11701573Srgrimes } 11711573Srgrimes 11721573Srgrimes /* right-adjusting zero padding */ 11731573Srgrimes if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 11741573Srgrimes PAD(width - realsz, zeroes); 11751573Srgrimes 11761573Srgrimes /* leading zeroes from decimal precision */ 117714727Sfenner PAD(dprec - size, zeroes); 11781573Srgrimes 11791573Srgrimes /* the string or number proper */ 1180128819Sdas#ifndef NO_FLOATING_POINT 11811573Srgrimes if ((flags & FPT) == 0) { 11821573Srgrimes PRINT(cp, size); 11831573Srgrimes } else { /* glue together f_p fragments */ 1184113146Sdas if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 1185113146Sdas if (expt <= 0) { 1186113468Sdas PRINT(zeroes, 1); 1187113468Sdas if (prec || flags & ALT) 1188113468Sdas PRINT(decimal_point, 1); 11891573Srgrimes PAD(-expt, zeroes); 1190113191Sdas /* already handled initial 0's */ 1191113191Sdas prec += expt; 11921573Srgrimes } else { 1193113191Sdas PRINTANDPAD(cp, dtoaend, lead, zeroes); 1194113146Sdas cp += lead; 1195113146Sdas if (grouping) { 1196113146Sdas while (nseps>0 || nrepeats>0) { 1197113146Sdas if (nrepeats > 0) 1198113146Sdas nrepeats--; 1199113146Sdas else { 1200113146Sdas grouping--; 1201113146Sdas nseps--; 1202113146Sdas } 1203113146Sdas PRINT(&thousands_sep, 1204113146Sdas 1); 1205113191Sdas PRINTANDPAD(cp,dtoaend, 1206113191Sdas *grouping, zeroes); 1207113146Sdas cp += *grouping; 1208113146Sdas } 1209113191Sdas if (cp > dtoaend) 1210113191Sdas cp = dtoaend; 1211113146Sdas } 1212113146Sdas if (prec || flags & ALT) 1213113146Sdas PRINT(decimal_point,1); 12141573Srgrimes } 1215113191Sdas PRINTANDPAD(cp, dtoaend, prec, zeroes); 1216113146Sdas } else { /* %[eE] or sufficiently long %[gG] */ 1217113191Sdas if (prec > 1 || flags & ALT) { 1218113146Sdas buf[0] = *cp++; 1219113146Sdas buf[1] = *decimal_point; 1220113146Sdas PRINT(buf, 2); 1221113146Sdas PRINT(cp, ndig-1); 1222113146Sdas PAD(prec - ndig, zeroes); 12231573Srgrimes } else /* XeYYY */ 12241573Srgrimes PRINT(cp, 1); 12251573Srgrimes PRINT(expstr, expsize); 12261573Srgrimes } 12271573Srgrimes } 12281573Srgrimes#else 12291573Srgrimes PRINT(cp, size); 12301573Srgrimes#endif 12311573Srgrimes /* left-adjusting padding (always blank) */ 12321573Srgrimes if (flags & LADJUST) 12331573Srgrimes PAD(width - realsz, blanks); 12341573Srgrimes 12351573Srgrimes /* finally, adjust ret */ 123631983Sache ret += prsize; 12371573Srgrimes 12381573Srgrimes FLUSH(); /* copy out the I/O vectors */ 12391573Srgrimes } 12401573Srgrimesdone: 12411573Srgrimes FLUSH(); 12421573Srgrimeserror: 1243134332Sdes va_end(orgap); 1244128819Sdas#ifndef NO_FLOATING_POINT 124572523Stegge if (dtoaresult != NULL) 1246113146Sdas freedtoa(dtoaresult); 124772523Stegge#endif 1248103633Stjr if (convbuf != NULL) 1249103633Stjr free(convbuf); 125013545Sjulian if (__sferror(fp)) 125113545Sjulian ret = EOF; 1252103399Stjr if ((argtable != NULL) && (argtable != statargtable)) 1253103399Stjr free (argtable); 125413545Sjulian return (ret); 12551573Srgrimes /* NOTREACHED */ 12561573Srgrimes} 12571573Srgrimes 125821674Sjkh/* 125921674Sjkh * Find all arguments when a positional parameter is encountered. Returns a 126021674Sjkh * table, indexed by argument number, of pointers to each arguments. The 126121674Sjkh * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 126270725Sarchie * It will be replaces with a malloc-ed one if it overflows. 126321674Sjkh */ 126421674Sjkhstatic void 126584962Sbde__find_arguments (const char *fmt0, va_list ap, union arg **argtable) 126621674Sjkh{ 126771579Sdeischen char *fmt; /* format string */ 126871579Sdeischen int ch; /* character from fmt */ 126971579Sdeischen int n, n2; /* handy integer (short term usage) */ 127071579Sdeischen char *cp; /* handy char pointer (short term usage) */ 127171579Sdeischen int flags; /* flags as above */ 127221674Sjkh int width; /* width from format (%8d), or 0 */ 127387113Sfenner enum typeid *typetable; /* table of types */ 127487113Sfenner enum typeid stattypetable [STATIC_ARG_TBL_SIZE]; 127521674Sjkh int tablesize; /* current size of type table */ 127621674Sjkh int tablemax; /* largest used index in table */ 127721674Sjkh int nextarg; /* 1-based argument index */ 127821674Sjkh 127921674Sjkh /* 128021674Sjkh * Add an argument type to the table, expanding if necessary. 128121674Sjkh */ 128221674Sjkh#define ADDTYPE(type) \ 128321674Sjkh ((nextarg >= tablesize) ? \ 1284130242Sstefanf __grow_type_table(nextarg, &typetable, &tablesize) : (void)0, \ 128570725Sarchie (nextarg > tablemax) ? tablemax = nextarg : 0, \ 128670725Sarchie typetable[nextarg++] = type) 128721674Sjkh 128821674Sjkh#define ADDSARG() \ 128987113Sfenner ((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \ 129087113Sfenner ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 129187113Sfenner ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 129287113Sfenner ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \ 129387113Sfenner ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT)))))) 129421674Sjkh 129521674Sjkh#define ADDUARG() \ 129687113Sfenner ((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \ 129787113Sfenner ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 129887113Sfenner ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 129987113Sfenner ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \ 130087113Sfenner ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT)))))) 130121674Sjkh 130221674Sjkh /* 130321674Sjkh * Add * arguments to the type array. 130421674Sjkh */ 130521674Sjkh#define ADDASTER() \ 130621674Sjkh n2 = 0; \ 130721674Sjkh cp = fmt; \ 130821674Sjkh while (is_digit(*cp)) { \ 130921674Sjkh n2 = 10 * n2 + to_digit(*cp); \ 131021674Sjkh cp++; \ 131121674Sjkh } \ 131221674Sjkh if (*cp == '$') { \ 131321674Sjkh int hold = nextarg; \ 131421674Sjkh nextarg = n2; \ 131521674Sjkh ADDTYPE (T_INT); \ 131621674Sjkh nextarg = hold; \ 131721674Sjkh fmt = ++cp; \ 131821674Sjkh } else { \ 131921674Sjkh ADDTYPE (T_INT); \ 132021674Sjkh } 132121674Sjkh fmt = (char *)fmt0; 132221674Sjkh typetable = stattypetable; 132321674Sjkh tablesize = STATIC_ARG_TBL_SIZE; 132421674Sjkh tablemax = 0; 132521674Sjkh nextarg = 1; 1326128550Stjr for (n = 0; n < STATIC_ARG_TBL_SIZE; n++) 1327128550Stjr typetable[n] = T_UNUSED; 132821674Sjkh 132921674Sjkh /* 133021674Sjkh * Scan the format for conversions (`%' character). 133121674Sjkh */ 133221674Sjkh for (;;) { 133321674Sjkh for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 133421674Sjkh /* void */; 133521674Sjkh if (ch == '\0') 133621674Sjkh goto done; 133721674Sjkh fmt++; /* skip over '%' */ 133821674Sjkh 133921674Sjkh flags = 0; 134021674Sjkh width = 0; 134121674Sjkh 134221674Sjkhrflag: ch = *fmt++; 134321674Sjkhreswitch: switch (ch) { 134421674Sjkh case ' ': 134521674Sjkh case '#': 134621674Sjkh goto rflag; 134721674Sjkh case '*': 134821674Sjkh ADDASTER (); 134921674Sjkh goto rflag; 135021674Sjkh case '-': 135121674Sjkh case '+': 135287113Sfenner case '\'': 135321674Sjkh goto rflag; 135421674Sjkh case '.': 135521674Sjkh if ((ch = *fmt++) == '*') { 135621674Sjkh ADDASTER (); 135721674Sjkh goto rflag; 135821674Sjkh } 135921674Sjkh while (is_digit(ch)) { 136021674Sjkh ch = *fmt++; 136121674Sjkh } 136221674Sjkh goto reswitch; 136321674Sjkh case '0': 136421674Sjkh goto rflag; 136521674Sjkh case '1': case '2': case '3': case '4': 136621674Sjkh case '5': case '6': case '7': case '8': case '9': 136721674Sjkh n = 0; 136821674Sjkh do { 136921674Sjkh n = 10 * n + to_digit(ch); 137021674Sjkh ch = *fmt++; 137121674Sjkh } while (is_digit(ch)); 137221674Sjkh if (ch == '$') { 137321674Sjkh nextarg = n; 137421674Sjkh goto rflag; 137521674Sjkh } 137621674Sjkh width = n; 137721674Sjkh goto reswitch; 1378128819Sdas#ifndef NO_FLOATING_POINT 137921674Sjkh case 'L': 138021674Sjkh flags |= LONGDBL; 138121674Sjkh goto rflag; 138221674Sjkh#endif 138321674Sjkh case 'h': 138487113Sfenner if (flags & SHORTINT) { 138587113Sfenner flags &= ~SHORTINT; 138687113Sfenner flags |= CHARINT; 138787113Sfenner } else 138887113Sfenner flags |= SHORTINT; 138921674Sjkh goto rflag; 139087113Sfenner case 'j': 139187113Sfenner flags |= INTMAXT; 139287113Sfenner goto rflag; 139321674Sjkh case 'l': 139487113Sfenner if (flags & LONGINT) { 139587113Sfenner flags &= ~LONGINT; 139687113Sfenner flags |= LLONGINT; 139787113Sfenner } else 139844674Sdfr flags |= LONGINT; 139921674Sjkh goto rflag; 140021674Sjkh case 'q': 140187113Sfenner flags |= LLONGINT; /* not necessarily */ 140221674Sjkh goto rflag; 140387113Sfenner case 't': 140487113Sfenner flags |= PTRDIFFT; 140587113Sfenner goto rflag; 140687113Sfenner case 'z': 140787113Sfenner flags |= SIZET; 140887113Sfenner goto rflag; 1409105204Stjr case 'C': 1410105204Stjr flags |= LONGINT; 1411105204Stjr /*FALLTHROUGH*/ 141221674Sjkh case 'c': 1413103633Stjr if (flags & LONGINT) 1414103633Stjr ADDTYPE(T_WINT); 1415103633Stjr else 1416103633Stjr ADDTYPE(T_INT); 141721674Sjkh break; 141821674Sjkh case 'D': 141921674Sjkh flags |= LONGINT; 142021674Sjkh /*FALLTHROUGH*/ 142121674Sjkh case 'd': 142221674Sjkh case 'i': 142387113Sfenner ADDSARG(); 142421674Sjkh break; 1425128819Sdas#ifndef NO_FLOATING_POINT 142687113Sfenner case 'a': 142787113Sfenner case 'A': 142821674Sjkh case 'e': 142921674Sjkh case 'E': 143021674Sjkh case 'f': 143121674Sjkh case 'g': 143221674Sjkh case 'G': 143321674Sjkh if (flags & LONGDBL) 143421674Sjkh ADDTYPE(T_LONG_DOUBLE); 143521674Sjkh else 143621674Sjkh ADDTYPE(T_DOUBLE); 143721674Sjkh break; 1438128819Sdas#endif /* !NO_FLOATING_POINT */ 143921674Sjkh case 'n': 144087113Sfenner if (flags & INTMAXT) 144187113Sfenner ADDTYPE(TP_INTMAXT); 144287113Sfenner else if (flags & PTRDIFFT) 144387113Sfenner ADDTYPE(TP_PTRDIFFT); 144487113Sfenner else if (flags & SIZET) 144587113Sfenner ADDTYPE(TP_SIZET); 144687113Sfenner else if (flags & LLONGINT) 144787113Sfenner ADDTYPE(TP_LLONG); 144821674Sjkh else if (flags & LONGINT) 144921674Sjkh ADDTYPE(TP_LONG); 145021674Sjkh else if (flags & SHORTINT) 145121674Sjkh ADDTYPE(TP_SHORT); 145287113Sfenner else if (flags & CHARINT) 145387113Sfenner ADDTYPE(TP_SCHAR); 145421674Sjkh else 145521674Sjkh ADDTYPE(TP_INT); 145621674Sjkh continue; /* no output */ 145721674Sjkh case 'O': 145821674Sjkh flags |= LONGINT; 145921674Sjkh /*FALLTHROUGH*/ 146021674Sjkh case 'o': 146187113Sfenner ADDUARG(); 146221674Sjkh break; 146321674Sjkh case 'p': 146421674Sjkh ADDTYPE(TP_VOID); 146521674Sjkh break; 1466105204Stjr case 'S': 1467105204Stjr flags |= LONGINT; 1468105204Stjr /*FALLTHROUGH*/ 146921674Sjkh case 's': 1470103633Stjr if (flags & LONGINT) 1471103633Stjr ADDTYPE(TP_WCHAR); 1472103633Stjr else 1473103633Stjr ADDTYPE(TP_CHAR); 147421674Sjkh break; 147521674Sjkh case 'U': 147621674Sjkh flags |= LONGINT; 147721674Sjkh /*FALLTHROUGH*/ 147821674Sjkh case 'u': 147921674Sjkh case 'X': 148021674Sjkh case 'x': 148187113Sfenner ADDUARG(); 148221674Sjkh break; 148321674Sjkh default: /* "%?" prints ?, unless ? is NUL */ 148421674Sjkh if (ch == '\0') 148521674Sjkh goto done; 148621674Sjkh break; 148721674Sjkh } 148821674Sjkh } 148921674Sjkhdone: 149021674Sjkh /* 149121674Sjkh * Build the argument table. 149221674Sjkh */ 149321674Sjkh if (tablemax >= STATIC_ARG_TBL_SIZE) { 149484922Sdfr *argtable = (union arg *) 149584922Sdfr malloc (sizeof (union arg) * (tablemax + 1)); 149621674Sjkh } 14971573Srgrimes 149884922Sdfr (*argtable) [0].intarg = 0; 149921674Sjkh for (n = 1; n <= tablemax; n++) { 150021674Sjkh switch (typetable [n]) { 150187113Sfenner case T_UNUSED: /* whoops! */ 150284922Sdfr (*argtable) [n].intarg = va_arg (ap, int); 150321674Sjkh break; 150487113Sfenner case TP_SCHAR: 150587113Sfenner (*argtable) [n].pschararg = va_arg (ap, signed char *); 150621674Sjkh break; 150721674Sjkh case TP_SHORT: 150884922Sdfr (*argtable) [n].pshortarg = va_arg (ap, short *); 150921674Sjkh break; 151021674Sjkh case T_INT: 151184922Sdfr (*argtable) [n].intarg = va_arg (ap, int); 151221674Sjkh break; 151321674Sjkh case T_U_INT: 151484922Sdfr (*argtable) [n].uintarg = va_arg (ap, unsigned int); 151521674Sjkh break; 151621674Sjkh case TP_INT: 151784922Sdfr (*argtable) [n].pintarg = va_arg (ap, int *); 151821674Sjkh break; 151921674Sjkh case T_LONG: 152084922Sdfr (*argtable) [n].longarg = va_arg (ap, long); 152121674Sjkh break; 152221674Sjkh case T_U_LONG: 152384922Sdfr (*argtable) [n].ulongarg = va_arg (ap, unsigned long); 152421674Sjkh break; 152521674Sjkh case TP_LONG: 152684922Sdfr (*argtable) [n].plongarg = va_arg (ap, long *); 152721674Sjkh break; 152887113Sfenner case T_LLONG: 152987113Sfenner (*argtable) [n].longlongarg = va_arg (ap, long long); 153021674Sjkh break; 153187113Sfenner case T_U_LLONG: 153287113Sfenner (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); 153321674Sjkh break; 153487113Sfenner case TP_LLONG: 153587113Sfenner (*argtable) [n].plonglongarg = va_arg (ap, long long *); 153621674Sjkh break; 153787113Sfenner case T_PTRDIFFT: 153887113Sfenner (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); 153987113Sfenner break; 154087113Sfenner case TP_PTRDIFFT: 154187113Sfenner (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); 154287113Sfenner break; 154387113Sfenner case T_SIZET: 154487113Sfenner (*argtable) [n].sizearg = va_arg (ap, size_t); 154587113Sfenner break; 154687113Sfenner case TP_SIZET: 1547162523Skan (*argtable) [n].psizearg = va_arg (ap, size_t *); 154887113Sfenner break; 154987113Sfenner case T_INTMAXT: 155087113Sfenner (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); 155187113Sfenner break; 155287113Sfenner case T_UINTMAXT: 155387113Sfenner (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); 155487113Sfenner break; 155587113Sfenner case TP_INTMAXT: 155687113Sfenner (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); 155787113Sfenner break; 1558157381Sphk case T_DOUBLE: 1559128819Sdas#ifndef NO_FLOATING_POINT 156084922Sdfr (*argtable) [n].doublearg = va_arg (ap, double); 1561157381Sphk#endif 156221674Sjkh break; 156321674Sjkh case T_LONG_DOUBLE: 1564157381Sphk#ifndef NO_FLOATING_POINT 156584922Sdfr (*argtable) [n].longdoublearg = va_arg (ap, long double); 1566157381Sphk#endif 156721674Sjkh break; 156821674Sjkh case TP_CHAR: 156984922Sdfr (*argtable) [n].pchararg = va_arg (ap, char *); 157021674Sjkh break; 157121674Sjkh case TP_VOID: 157284922Sdfr (*argtable) [n].pvoidarg = va_arg (ap, void *); 157321674Sjkh break; 1574103633Stjr case T_WINT: 1575103633Stjr (*argtable) [n].wintarg = va_arg (ap, wint_t); 1576103633Stjr break; 1577103633Stjr case TP_WCHAR: 1578103633Stjr (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); 1579103633Stjr break; 158021674Sjkh } 158121674Sjkh } 158221674Sjkh 158321674Sjkh if ((typetable != NULL) && (typetable != stattypetable)) 158421674Sjkh free (typetable); 158521674Sjkh} 158621674Sjkh 158721674Sjkh/* 158821674Sjkh * Increase the size of the type table. 158921674Sjkh */ 159021674Sjkhstatic void 159187113Sfenner__grow_type_table (int nextarg, enum typeid **typetable, int *tablesize) 159221674Sjkh{ 159387113Sfenner enum typeid *const oldtable = *typetable; 159470725Sarchie const int oldsize = *tablesize; 159587113Sfenner enum typeid *newtable; 1596128550Stjr int n, newsize = oldsize * 2; 159721674Sjkh 159870725Sarchie if (newsize < nextarg + 1) 159970725Sarchie newsize = nextarg + 1; 160070725Sarchie if (oldsize == STATIC_ARG_TBL_SIZE) { 1601128550Stjr if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL) 160270725Sarchie abort(); /* XXX handle better */ 1603128550Stjr bcopy(oldtable, newtable, oldsize * sizeof(enum typeid)); 160421674Sjkh } else { 1605128550Stjr newtable = reallocf(oldtable, newsize * sizeof(enum typeid)); 1606128550Stjr if (newtable == NULL) 160770725Sarchie abort(); /* XXX handle better */ 160821674Sjkh } 1609128550Stjr for (n = oldsize; n < newsize; n++) 1610128550Stjr newtable[n] = T_UNUSED; 161121674Sjkh 161270725Sarchie *typetable = newtable; 161321674Sjkh *tablesize = newsize; 161421674Sjkh} 161521674Sjkh 161621674Sjkh 1617128819Sdas#ifndef NO_FLOATING_POINT 161821674Sjkh 16191573Srgrimesstatic int 162071579Sdeischenexponent(char *p0, int exp, int fmtch) 16211573Srgrimes{ 162271579Sdeischen char *p, *t; 1623113142Sdas char expbuf[MAXEXPDIG]; 16241573Srgrimes 16251573Srgrimes p = p0; 16261573Srgrimes *p++ = fmtch; 16271573Srgrimes if (exp < 0) { 16281573Srgrimes exp = -exp; 16291573Srgrimes *p++ = '-'; 16301573Srgrimes } 16311573Srgrimes else 16321573Srgrimes *p++ = '+'; 1633113142Sdas t = expbuf + MAXEXPDIG; 16341573Srgrimes if (exp > 9) { 16351573Srgrimes do { 16361573Srgrimes *--t = to_char(exp % 10); 16371573Srgrimes } while ((exp /= 10) > 9); 16381573Srgrimes *--t = to_char(exp); 1639113142Sdas for (; t < expbuf + MAXEXPDIG; *p++ = *t++); 16401573Srgrimes } 16411573Srgrimes else { 1642113146Sdas /* 1643113146Sdas * Exponents for decimal floating point conversions 1644113146Sdas * (%[eEgG]) must be at least two characters long, 1645113146Sdas * whereas exponents for hexadecimal conversions can 1646113146Sdas * be only one character long. 1647113146Sdas */ 1648113146Sdas if (fmtch == 'e' || fmtch == 'E') 1649113146Sdas *p++ = '0'; 16501573Srgrimes *p++ = to_char(exp); 16511573Srgrimes } 16521573Srgrimes return (p - p0); 16531573Srgrimes} 1654128819Sdas#endif /* !NO_FLOATING_POINT */ 1655