158f0484fSRodney W. Grimes /*- 258f0484fSRodney W. Grimes * Copyright (c) 1990, 1993 358f0484fSRodney W. Grimes * The Regents of the University of California. All rights reserved. 458f0484fSRodney W. Grimes * 558f0484fSRodney W. Grimes * This code is derived from software contributed to Berkeley by 658f0484fSRodney W. Grimes * Chris Torek. 758f0484fSRodney W. Grimes * 858f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 958f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions 1058f0484fSRodney W. Grimes * are met: 1158f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 1258f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 1358f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 1458f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 1558f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution. 1658f0484fSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 1758f0484fSRodney W. Grimes * must display the following acknowledgement: 1858f0484fSRodney W. Grimes * This product includes software developed by the University of 1958f0484fSRodney W. Grimes * California, Berkeley and its contributors. 2058f0484fSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 2158f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software 2258f0484fSRodney W. Grimes * without specific prior written permission. 2358f0484fSRodney W. Grimes * 2458f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2558f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2658f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2758f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2858f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2958f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3058f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3158f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3258f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3358f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3458f0484fSRodney W. Grimes * SUCH DAMAGE. 3558f0484fSRodney W. Grimes */ 3658f0484fSRodney W. Grimes 3758f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint) 3858f0484fSRodney W. Grimes static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; 3958f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */ 40333fc21eSDavid E. O'Brien #include <sys/cdefs.h> 41333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 4258f0484fSRodney W. Grimes 4358f0484fSRodney W. Grimes /* 4458f0484fSRodney W. Grimes * Actual printf innards. 4558f0484fSRodney W. Grimes * 4658f0484fSRodney W. Grimes * This code is large and complicated... 4758f0484fSRodney W. Grimes */ 4858f0484fSRodney W. Grimes 49d201fe46SDaniel Eischen #include "namespace.h" 5058f0484fSRodney W. Grimes #include <sys/types.h> 5158f0484fSRodney W. Grimes 527735bb0fSBill Fenner #include <ctype.h> 5358f0484fSRodney W. Grimes #include <limits.h> 547ae5c679SAlexey Zelkin #include <locale.h> 557735bb0fSBill Fenner #include <stddef.h> 567735bb0fSBill Fenner #include <stdint.h> 5758f0484fSRodney W. Grimes #include <stdio.h> 5858f0484fSRodney W. Grimes #include <stdlib.h> 5958f0484fSRodney W. Grimes #include <string.h> 60b9aac308STim J. Robbins #include <wchar.h> 6158f0484fSRodney W. Grimes 6258f0484fSRodney W. Grimes #include <stdarg.h> 63d201fe46SDaniel Eischen #include "un-namespace.h" 6458f0484fSRodney W. Grimes 65d201fe46SDaniel Eischen #include "libc_private.h" 6658f0484fSRodney W. Grimes #include "local.h" 6758f0484fSRodney W. Grimes #include "fvwrite.h" 6858f0484fSRodney W. Grimes 69a387081cSDoug Rabson union arg { 70a387081cSDoug Rabson int intarg; 7118ca70d1SBruce Evans u_int uintarg; 72a387081cSDoug Rabson long longarg; 7318ca70d1SBruce Evans u_long ulongarg; 747735bb0fSBill Fenner long long longlongarg; 757735bb0fSBill Fenner unsigned long long ulonglongarg; 767735bb0fSBill Fenner ptrdiff_t ptrdiffarg; 777735bb0fSBill Fenner size_t sizearg; 787735bb0fSBill Fenner intmax_t intmaxarg; 797735bb0fSBill Fenner uintmax_t uintmaxarg; 80a387081cSDoug Rabson void *pvoidarg; 81a387081cSDoug Rabson char *pchararg; 827735bb0fSBill Fenner signed char *pschararg; 83a387081cSDoug Rabson short *pshortarg; 84a387081cSDoug Rabson int *pintarg; 85a387081cSDoug Rabson long *plongarg; 867735bb0fSBill Fenner long long *plonglongarg; 877735bb0fSBill Fenner ptrdiff_t *pptrdiffarg; 887735bb0fSBill Fenner size_t *psizearg; 897735bb0fSBill Fenner intmax_t *pintmaxarg; 908de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 91a387081cSDoug Rabson double doublearg; 92a387081cSDoug Rabson long double longdoublearg; 93a387081cSDoug Rabson #endif 94b9aac308STim J. Robbins wint_t wintarg; 95b9aac308STim J. Robbins wchar_t *pwchararg; 96a387081cSDoug Rabson }; 97a387081cSDoug Rabson 987735bb0fSBill Fenner /* 997735bb0fSBill Fenner * Type ids for argument type table. 1007735bb0fSBill Fenner */ 1017735bb0fSBill Fenner enum typeid { 1027735bb0fSBill Fenner T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, 1037735bb0fSBill Fenner T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, 1047735bb0fSBill Fenner T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET, 1057735bb0fSBill Fenner T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, 106b9aac308STim J. Robbins T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR 1077735bb0fSBill Fenner }; 1087735bb0fSBill Fenner 109c05ac53bSDavid E. O'Brien static int __sprint(FILE *, struct __suio *); 1101372519bSDavid E. O'Brien static int __sbprintf(FILE *, const char *, va_list) __printflike(2, 0); 111ebbad5ecSDavid Schultz static char *__ujtoa(uintmax_t, char *, int, int, const char *, int, char, 1121372519bSDavid E. O'Brien const char *); 113ebbad5ecSDavid Schultz static char *__ultoa(u_long, char *, int, int, const char *, int, char, 1141372519bSDavid E. O'Brien const char *); 115b9aac308STim J. Robbins static char *__wcsconv(wchar_t *, int); 116c05ac53bSDavid E. O'Brien static void __find_arguments(const char *, va_list, union arg **); 117c05ac53bSDavid E. O'Brien static void __grow_type_table(int, enum typeid **, int *); 118ce51cf03SJames Raynard 11958f0484fSRodney W. Grimes /* 12058f0484fSRodney W. Grimes * Flush out all the vectors defined by the given uio, 12158f0484fSRodney W. Grimes * then reset it so that it can be reused. 12258f0484fSRodney W. Grimes */ 12358f0484fSRodney W. Grimes static int 124d201fe46SDaniel Eischen __sprint(FILE *fp, struct __suio *uio) 12558f0484fSRodney W. Grimes { 126d201fe46SDaniel Eischen int err; 12758f0484fSRodney W. Grimes 12858f0484fSRodney W. Grimes if (uio->uio_resid == 0) { 12958f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 13058f0484fSRodney W. Grimes return (0); 13158f0484fSRodney W. Grimes } 13258f0484fSRodney W. Grimes err = __sfvwrite(fp, uio); 13358f0484fSRodney W. Grimes uio->uio_resid = 0; 13458f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 13558f0484fSRodney W. Grimes return (err); 13658f0484fSRodney W. Grimes } 13758f0484fSRodney W. Grimes 13858f0484fSRodney W. Grimes /* 13958f0484fSRodney W. Grimes * Helper function for `fprintf to unbuffered unix file': creates a 14058f0484fSRodney W. Grimes * temporary buffer. We only work on write-only files; this avoids 14158f0484fSRodney W. Grimes * worries about ungetc buffers and so forth. 14258f0484fSRodney W. Grimes */ 14358f0484fSRodney W. Grimes static int 144d201fe46SDaniel Eischen __sbprintf(FILE *fp, const char *fmt, va_list ap) 14558f0484fSRodney W. Grimes { 14658f0484fSRodney W. Grimes int ret; 14758f0484fSRodney W. Grimes FILE fake; 14858f0484fSRodney W. Grimes unsigned char buf[BUFSIZ]; 14958f0484fSRodney W. Grimes 15058f0484fSRodney W. Grimes /* copy the important variables */ 15158f0484fSRodney W. Grimes fake._flags = fp->_flags & ~__SNBF; 15258f0484fSRodney W. Grimes fake._file = fp->_file; 15358f0484fSRodney W. Grimes fake._cookie = fp->_cookie; 15458f0484fSRodney W. Grimes fake._write = fp->_write; 155e74101e4STim J. Robbins fake._extra = fp->_extra; 15658f0484fSRodney W. Grimes 15758f0484fSRodney W. Grimes /* set up the buffer */ 15858f0484fSRodney W. Grimes fake._bf._base = fake._p = buf; 15958f0484fSRodney W. Grimes fake._bf._size = fake._w = sizeof(buf); 16058f0484fSRodney W. Grimes fake._lbfsize = 0; /* not actually used, but Just In Case */ 16158f0484fSRodney W. Grimes 16258f0484fSRodney W. Grimes /* do the work, then copy any error status */ 163d201fe46SDaniel Eischen ret = __vfprintf(&fake, fmt, ap); 164d201fe46SDaniel Eischen if (ret >= 0 && __fflush(&fake)) 16558f0484fSRodney W. Grimes ret = EOF; 16658f0484fSRodney W. Grimes if (fake._flags & __SERR) 16758f0484fSRodney W. Grimes fp->_flags |= __SERR; 16858f0484fSRodney W. Grimes return (ret); 16958f0484fSRodney W. Grimes } 17058f0484fSRodney W. Grimes 17158f0484fSRodney W. Grimes /* 17258f0484fSRodney W. Grimes * Macros for converting digits to letters and vice versa 17358f0484fSRodney W. Grimes */ 17458f0484fSRodney W. Grimes #define to_digit(c) ((c) - '0') 17558f0484fSRodney W. Grimes #define is_digit(c) ((unsigned)to_digit(c) <= 9) 17658f0484fSRodney W. Grimes #define to_char(n) ((n) + '0') 17758f0484fSRodney W. Grimes 17858f0484fSRodney W. Grimes /* 17958f0484fSRodney W. Grimes * Convert an unsigned long to ASCII for printf purposes, returning 18058f0484fSRodney W. Grimes * a pointer to the first character of the string representation. 18158f0484fSRodney W. Grimes * Octal numbers can be forced to have a leading zero; hex numbers 18258f0484fSRodney W. Grimes * use the given digits. 18358f0484fSRodney W. Grimes */ 18458f0484fSRodney W. Grimes static char * 185ebbad5ecSDavid Schultz __ultoa(u_long val, char *endp, int base, int octzero, const char *xdigs, 18698ee7635SAlexey Zelkin int needgrp, char thousep, const char *grp) 18758f0484fSRodney W. Grimes { 1888fb3f3f6SDavid E. O'Brien char *cp = endp; 1898fb3f3f6SDavid E. O'Brien long sval; 1907735bb0fSBill Fenner int ndig; 19158f0484fSRodney W. Grimes 19258f0484fSRodney W. Grimes /* 19358f0484fSRodney W. Grimes * Handle the three cases separately, in the hope of getting 19458f0484fSRodney W. Grimes * better/faster code. 19558f0484fSRodney W. Grimes */ 19658f0484fSRodney W. Grimes switch (base) { 19758f0484fSRodney W. Grimes case 10: 19858f0484fSRodney W. Grimes if (val < 10) { /* many numbers are 1 digit */ 19958f0484fSRodney W. Grimes *--cp = to_char(val); 20058f0484fSRodney W. Grimes return (cp); 20158f0484fSRodney W. Grimes } 2027735bb0fSBill Fenner ndig = 0; 20358f0484fSRodney W. Grimes /* 20458f0484fSRodney W. Grimes * On many machines, unsigned arithmetic is harder than 20558f0484fSRodney W. Grimes * signed arithmetic, so we do at most one unsigned mod and 20658f0484fSRodney W. Grimes * divide; this is sufficient to reduce the range of 20758f0484fSRodney W. Grimes * the incoming value to where signed arithmetic works. 20858f0484fSRodney W. Grimes */ 20958f0484fSRodney W. Grimes if (val > LONG_MAX) { 21058f0484fSRodney W. Grimes *--cp = to_char(val % 10); 2117735bb0fSBill Fenner ndig++; 21258f0484fSRodney W. Grimes sval = val / 10; 21358f0484fSRodney W. Grimes } else 21458f0484fSRodney W. Grimes sval = val; 21558f0484fSRodney W. Grimes do { 21658f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 21798ee7635SAlexey Zelkin ndig++; 21898ee7635SAlexey Zelkin /* 21998ee7635SAlexey Zelkin * If (*grp == CHAR_MAX) then no more grouping 22098ee7635SAlexey Zelkin * should be performed. 22198ee7635SAlexey Zelkin */ 222243e90d6SAlexey Zelkin if (needgrp && ndig == *grp && *grp != CHAR_MAX 223243e90d6SAlexey Zelkin && sval > 9) { 22498ee7635SAlexey Zelkin *--cp = thousep; 2257735bb0fSBill Fenner ndig = 0; 22698ee7635SAlexey Zelkin /* 22798ee7635SAlexey Zelkin * If (*(grp+1) == '\0') then we have to 22898ee7635SAlexey Zelkin * use *grp character (last grouping rule) 22998ee7635SAlexey Zelkin * for all next cases 23098ee7635SAlexey Zelkin */ 2312e394b2fSAlexey Zelkin if (*(grp+1) != '\0') 2322e394b2fSAlexey Zelkin grp++; 2337735bb0fSBill Fenner } 23458f0484fSRodney W. Grimes sval /= 10; 23558f0484fSRodney W. Grimes } while (sval != 0); 23658f0484fSRodney W. Grimes break; 23758f0484fSRodney W. Grimes 23858f0484fSRodney W. Grimes case 8: 23958f0484fSRodney W. Grimes do { 24058f0484fSRodney W. Grimes *--cp = to_char(val & 7); 24158f0484fSRodney W. Grimes val >>= 3; 24258f0484fSRodney W. Grimes } while (val); 24358f0484fSRodney W. Grimes if (octzero && *cp != '0') 24458f0484fSRodney W. Grimes *--cp = '0'; 24558f0484fSRodney W. Grimes break; 24658f0484fSRodney W. Grimes 24758f0484fSRodney W. Grimes case 16: 24858f0484fSRodney W. Grimes do { 24958f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 25058f0484fSRodney W. Grimes val >>= 4; 25158f0484fSRodney W. Grimes } while (val); 25258f0484fSRodney W. Grimes break; 25358f0484fSRodney W. Grimes 25458f0484fSRodney W. Grimes default: /* oops */ 25558f0484fSRodney W. Grimes abort(); 25658f0484fSRodney W. Grimes } 25758f0484fSRodney W. Grimes return (cp); 25858f0484fSRodney W. Grimes } 25958f0484fSRodney W. Grimes 2607735bb0fSBill Fenner /* Identical to __ultoa, but for intmax_t. */ 26158f0484fSRodney W. Grimes static char * 262ebbad5ecSDavid Schultz __ujtoa(uintmax_t val, char *endp, int base, int octzero, const char *xdigs, 26398ee7635SAlexey Zelkin int needgrp, char thousep, const char *grp) 26458f0484fSRodney W. Grimes { 265d201fe46SDaniel Eischen char *cp = endp; 2667735bb0fSBill Fenner intmax_t sval; 2677735bb0fSBill Fenner int ndig; 26858f0484fSRodney W. Grimes 26958f0484fSRodney W. Grimes /* quick test for small values; __ultoa is typically much faster */ 27058f0484fSRodney W. Grimes /* (perhaps instead we should run until small, then call __ultoa?) */ 27158f0484fSRodney W. Grimes if (val <= ULONG_MAX) 2727735bb0fSBill Fenner return (__ultoa((u_long)val, endp, base, octzero, xdigs, 27398ee7635SAlexey Zelkin needgrp, thousep, grp)); 27458f0484fSRodney W. Grimes switch (base) { 27558f0484fSRodney W. Grimes case 10: 27658f0484fSRodney W. Grimes if (val < 10) { 27758f0484fSRodney W. Grimes *--cp = to_char(val % 10); 27858f0484fSRodney W. Grimes return (cp); 27958f0484fSRodney W. Grimes } 2807735bb0fSBill Fenner ndig = 0; 2817735bb0fSBill Fenner if (val > INTMAX_MAX) { 28258f0484fSRodney W. Grimes *--cp = to_char(val % 10); 2837735bb0fSBill Fenner ndig++; 28458f0484fSRodney W. Grimes sval = val / 10; 28558f0484fSRodney W. Grimes } else 28658f0484fSRodney W. Grimes sval = val; 28758f0484fSRodney W. Grimes do { 28858f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 28998ee7635SAlexey Zelkin ndig++; 29098ee7635SAlexey Zelkin /* 29198ee7635SAlexey Zelkin * If (*grp == CHAR_MAX) then no more grouping 29298ee7635SAlexey Zelkin * should be performed. 29398ee7635SAlexey Zelkin */ 294243e90d6SAlexey Zelkin if (needgrp && *grp != CHAR_MAX && ndig == *grp 295243e90d6SAlexey Zelkin && sval > 9) { 29698ee7635SAlexey Zelkin *--cp = thousep; 2977735bb0fSBill Fenner ndig = 0; 29898ee7635SAlexey Zelkin /* 29998ee7635SAlexey Zelkin * If (*(grp+1) == '\0') then we have to 30098ee7635SAlexey Zelkin * use *grp character (last grouping rule) 30198ee7635SAlexey Zelkin * for all next cases 30298ee7635SAlexey Zelkin */ 3032e394b2fSAlexey Zelkin if (*(grp+1) != '\0') 3042e394b2fSAlexey Zelkin grp++; 3057735bb0fSBill Fenner } 30658f0484fSRodney W. Grimes sval /= 10; 30758f0484fSRodney W. Grimes } while (sval != 0); 30858f0484fSRodney W. Grimes break; 30958f0484fSRodney W. Grimes 31058f0484fSRodney W. Grimes case 8: 31158f0484fSRodney W. Grimes do { 31258f0484fSRodney W. Grimes *--cp = to_char(val & 7); 31358f0484fSRodney W. Grimes val >>= 3; 31458f0484fSRodney W. Grimes } while (val); 31558f0484fSRodney W. Grimes if (octzero && *cp != '0') 31658f0484fSRodney W. Grimes *--cp = '0'; 31758f0484fSRodney W. Grimes break; 31858f0484fSRodney W. Grimes 31958f0484fSRodney W. Grimes case 16: 32058f0484fSRodney W. Grimes do { 32158f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 32258f0484fSRodney W. Grimes val >>= 4; 32358f0484fSRodney W. Grimes } while (val); 32458f0484fSRodney W. Grimes break; 32558f0484fSRodney W. Grimes 32658f0484fSRodney W. Grimes default: 32758f0484fSRodney W. Grimes abort(); 32858f0484fSRodney W. Grimes } 32958f0484fSRodney W. Grimes return (cp); 33058f0484fSRodney W. Grimes } 33158f0484fSRodney W. Grimes 332d201fe46SDaniel Eischen /* 333b9aac308STim J. Robbins * Convert a wide character string argument for the %ls format to a multibyte 334b9aac308STim J. Robbins * string representation. ``prec'' specifies the maximum number of bytes 335b9aac308STim J. Robbins * to output. If ``prec'' is greater than or equal to zero, we can't assume 336b9aac308STim J. Robbins * that the wide char. string ends in a null character. 337b9aac308STim J. Robbins */ 338b9aac308STim J. Robbins static char * 339b9aac308STim J. Robbins __wcsconv(wchar_t *wcsarg, int prec) 340b9aac308STim J. Robbins { 34193996f6dSTim J. Robbins static const mbstate_t initial; 34293996f6dSTim J. Robbins mbstate_t mbs; 343b9aac308STim J. Robbins char buf[MB_LEN_MAX]; 344b9aac308STim J. Robbins wchar_t *p; 345b9aac308STim J. Robbins char *convbuf, *mbp; 346b9aac308STim J. Robbins size_t clen, nbytes; 347b9aac308STim J. Robbins 348b9aac308STim J. Robbins /* 349b9aac308STim J. Robbins * Determine the number of bytes to output and allocate space for 350b9aac308STim J. Robbins * the output. 351b9aac308STim J. Robbins */ 352b9aac308STim J. Robbins if (prec >= 0) { 353b9aac308STim J. Robbins nbytes = 0; 354b9aac308STim J. Robbins p = wcsarg; 35593996f6dSTim J. Robbins mbs = initial; 356b9aac308STim J. Robbins for (;;) { 35793996f6dSTim J. Robbins clen = wcrtomb(buf, *p++, &mbs); 358b9aac308STim J. Robbins if (clen == 0 || clen == (size_t)-1 || 359b9aac308STim J. Robbins nbytes + clen > prec) 360b9aac308STim J. Robbins break; 361b9aac308STim J. Robbins nbytes += clen; 362b9aac308STim J. Robbins } 363b9aac308STim J. Robbins } else { 364b9aac308STim J. Robbins p = wcsarg; 36593996f6dSTim J. Robbins mbs = initial; 36693996f6dSTim J. Robbins nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); 367b9aac308STim J. Robbins if (nbytes == (size_t)-1) 368b9aac308STim J. Robbins return (NULL); 369b9aac308STim J. Robbins } 370b9aac308STim J. Robbins if ((convbuf = malloc(nbytes + 1)) == NULL) 371b9aac308STim J. Robbins return (NULL); 372b9aac308STim J. Robbins 373b9aac308STim J. Robbins /* 374b9aac308STim J. Robbins * Fill the output buffer with the multibyte representations of as 375b9aac308STim J. Robbins * many wide characters as will fit. 376b9aac308STim J. Robbins */ 377b9aac308STim J. Robbins mbp = convbuf; 378b9aac308STim J. Robbins p = wcsarg; 37993996f6dSTim J. Robbins mbs = initial; 380b9aac308STim J. Robbins while (mbp - convbuf < nbytes) { 38193996f6dSTim J. Robbins clen = wcrtomb(mbp, *p++, &mbs); 382b9aac308STim J. Robbins if (clen == 0 || clen == (size_t)-1) 383b9aac308STim J. Robbins break; 384b9aac308STim J. Robbins mbp += clen; 385b9aac308STim J. Robbins } 3866f098a48SAndrey A. Chernov if (clen == (size_t)-1) { 3876f098a48SAndrey A. Chernov free(convbuf); 388b9aac308STim J. Robbins return (NULL); 3896f098a48SAndrey A. Chernov } 3906f098a48SAndrey A. Chernov *mbp = '\0'; 391b9aac308STim J. Robbins 392b9aac308STim J. Robbins return (convbuf); 393b9aac308STim J. Robbins } 394b9aac308STim J. Robbins 395b9aac308STim J. Robbins /* 396d201fe46SDaniel Eischen * MT-safe version 397d201fe46SDaniel Eischen */ 398d201fe46SDaniel Eischen int 399f8418db7SRobert Drehmel vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) 400f8418db7SRobert Drehmel 401d201fe46SDaniel Eischen { 402d201fe46SDaniel Eischen int ret; 403d201fe46SDaniel Eischen 404d201fe46SDaniel Eischen FLOCKFILE(fp); 405d201fe46SDaniel Eischen ret = __vfprintf(fp, fmt0, ap); 406d201fe46SDaniel Eischen FUNLOCKFILE(fp); 407d201fe46SDaniel Eischen return (ret); 408d201fe46SDaniel Eischen } 409d201fe46SDaniel Eischen 4108de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 411ebbad5ecSDavid Schultz 412ebbad5ecSDavid Schultz #define dtoa __dtoa 413ebbad5ecSDavid Schultz #define freedtoa __freedtoa 414ebbad5ecSDavid Schultz 415ebbad5ecSDavid Schultz #include <float.h> 41658f0484fSRodney W. Grimes #include <math.h> 41758f0484fSRodney W. Grimes #include "floatio.h" 418ebbad5ecSDavid Schultz #include "gdtoa.h" 41958f0484fSRodney W. Grimes 42058f0484fSRodney W. Grimes #define DEFPREC 6 42158f0484fSRodney W. Grimes 422c05ac53bSDavid E. O'Brien static int exponent(char *, int, int); 42358f0484fSRodney W. Grimes 4248de9e897SDavid Schultz #endif /* !NO_FLOATING_POINT */ 42558f0484fSRodney W. Grimes 42638cac8f8SDavid Schultz /* 42738cac8f8SDavid Schultz * The size of the buffer we use as scratch space for integer 42838cac8f8SDavid Schultz * conversions, among other things. Technically, we would need the 42938cac8f8SDavid Schultz * most space for base 10 conversions with thousands' grouping 43038cac8f8SDavid Schultz * characters between each pair of digits. 100 bytes is a 43138cac8f8SDavid Schultz * conservative overestimate even for a 128-bit uintmax_t. 43238cac8f8SDavid Schultz */ 43338cac8f8SDavid Schultz #define BUF 100 43438cac8f8SDavid Schultz 435efb7e53dSJordan K. Hubbard #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 43658f0484fSRodney W. Grimes 43758f0484fSRodney W. Grimes /* 43858f0484fSRodney W. Grimes * Flags used during conversion. 43958f0484fSRodney W. Grimes */ 44058f0484fSRodney W. Grimes #define ALT 0x001 /* alternate form */ 44158f0484fSRodney W. Grimes #define LADJUST 0x004 /* left adjustment */ 4426a93659fSBruce Evans #define LONGDBL 0x008 /* long double */ 44358f0484fSRodney W. Grimes #define LONGINT 0x010 /* long integer */ 4447735bb0fSBill Fenner #define LLONGINT 0x020 /* long long integer */ 44558f0484fSRodney W. Grimes #define SHORTINT 0x040 /* short integer */ 44658f0484fSRodney W. Grimes #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 44758f0484fSRodney W. Grimes #define FPT 0x100 /* Floating point number */ 44898ee7635SAlexey Zelkin #define GROUPING 0x200 /* use grouping ("'" flag) */ 4497735bb0fSBill Fenner /* C99 additional size modifiers: */ 45098ee7635SAlexey Zelkin #define SIZET 0x400 /* size_t */ 45198ee7635SAlexey Zelkin #define PTRDIFFT 0x800 /* ptrdiff_t */ 45298ee7635SAlexey Zelkin #define INTMAXT 0x1000 /* intmax_t */ 45398ee7635SAlexey Zelkin #define CHARINT 0x2000 /* print char using int format */ 4547735bb0fSBill Fenner 455d201fe46SDaniel Eischen /* 456d201fe46SDaniel Eischen * Non-MT-safe version 457d201fe46SDaniel Eischen */ 45858f0484fSRodney W. Grimes int 459d201fe46SDaniel Eischen __vfprintf(FILE *fp, const char *fmt0, va_list ap) 46058f0484fSRodney W. Grimes { 461d201fe46SDaniel Eischen char *fmt; /* format string */ 462d201fe46SDaniel Eischen int ch; /* character from fmt */ 463d201fe46SDaniel Eischen int n, n2; /* handy integer (short term usage) */ 464d201fe46SDaniel Eischen char *cp; /* handy char pointer (short term usage) */ 465d201fe46SDaniel Eischen struct __siov *iovp; /* for PRINT macro */ 466d201fe46SDaniel Eischen int flags; /* flags as above */ 46758f0484fSRodney W. Grimes int ret; /* return value accumulator */ 46858f0484fSRodney W. Grimes int width; /* width from format (%8d), or 0 */ 469ebbad5ecSDavid Schultz int prec; /* precision from format; <0 for N/A */ 47058f0484fSRodney W. Grimes char sign; /* sign prefix (' ', '+', '-', or \0) */ 47198ee7635SAlexey Zelkin char thousands_sep; /* locale specific thousands separator */ 47298ee7635SAlexey Zelkin const char *grouping; /* locale specific numeric grouping rules */ 4738de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 474ebbad5ecSDavid Schultz /* 475ebbad5ecSDavid Schultz * We can decompose the printed representation of floating 476ebbad5ecSDavid Schultz * point numbers into several parts, some of which may be empty: 477ebbad5ecSDavid Schultz * 478ebbad5ecSDavid Schultz * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ 479ebbad5ecSDavid Schultz * A B ---C--- D E F 480ebbad5ecSDavid Schultz * 481ebbad5ecSDavid Schultz * A: 'sign' holds this value if present; '\0' otherwise 482ebbad5ecSDavid Schultz * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal 483ebbad5ecSDavid Schultz * C: cp points to the string MMMNNN. Leading and trailing 484ebbad5ecSDavid Schultz * zeros are not in the string and must be added. 485ebbad5ecSDavid Schultz * D: expchar holds this character; '\0' if no exponent, e.g. %f 486ebbad5ecSDavid Schultz * F: at least two digits for decimal, at least one digit for hex 487ebbad5ecSDavid Schultz */ 4887ae5c679SAlexey Zelkin char *decimal_point; /* locale specific decimal point */ 489ebbad5ecSDavid Schultz int signflag; /* true if float is negative */ 490ebbad5ecSDavid Schultz union { /* floating point arguments %[aAeEfFgG] */ 491ebbad5ecSDavid Schultz double dbl; 492ebbad5ecSDavid Schultz long double ldbl; 493ebbad5ecSDavid Schultz } fparg; 49458f0484fSRodney W. Grimes int expt; /* integer value of exponent */ 495ebbad5ecSDavid Schultz char expchar; /* exponent character: [eEpP\0] */ 496ebbad5ecSDavid Schultz char *dtoaend; /* pointer to end of converted digits */ 49758f0484fSRodney W. Grimes int expsize; /* character count for expstr */ 498ebbad5ecSDavid Schultz int lead; /* sig figs before decimal or group sep */ 499ebbad5ecSDavid Schultz int ndig; /* actual number of digits returned by dtoa */ 500ebbad5ecSDavid Schultz char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ 5012ffc61baSTor Egge char *dtoaresult; /* buffer allocated by dtoa */ 502ebbad5ecSDavid Schultz int nseps; /* number of group separators with ' */ 503ebbad5ecSDavid Schultz int nrepeats; /* number of repeats of the last group */ 50458f0484fSRodney W. Grimes #endif 50558f0484fSRodney W. Grimes u_long ulval; /* integer arguments %[diouxX] */ 5067735bb0fSBill Fenner uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ 50758f0484fSRodney W. Grimes int base; /* base for [diouxX] conversion */ 50858f0484fSRodney W. Grimes int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 509261a532aSBill Fenner int realsz; /* field size expanded by dprec, sign, etc */ 51058f0484fSRodney W. Grimes int size; /* size of converted field or string */ 51192e88f87SAndrey A. Chernov int prsize; /* max size of printed field */ 512ebbad5ecSDavid Schultz const char *xdigs; /* digits for %[xX] conversion */ 51358f0484fSRodney W. Grimes #define NIOV 8 51458f0484fSRodney W. Grimes struct __suio uio; /* output information: summary */ 51558f0484fSRodney W. Grimes struct __siov iov[NIOV];/* ... and individual io vectors */ 51638cac8f8SDavid Schultz char buf[BUF]; /* buffer with space for digits of uintmax_t */ 517ebbad5ecSDavid Schultz char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ 518a387081cSDoug Rabson union arg *argtable; /* args, built due to positional arg */ 519a387081cSDoug Rabson union arg statargtable [STATIC_ARG_TBL_SIZE]; 520efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 521efb7e53dSJordan K. Hubbard va_list orgap; /* original argument pointer */ 522b9aac308STim J. Robbins char *convbuf; /* wide to multibyte conversion result */ 52358f0484fSRodney W. Grimes 52458f0484fSRodney W. Grimes /* 52558f0484fSRodney W. Grimes * Choose PADSIZE to trade efficiency vs. size. If larger printf 52658f0484fSRodney W. Grimes * fields occur frequently, increase PADSIZE and make the initialisers 52758f0484fSRodney W. Grimes * below longer. 52858f0484fSRodney W. Grimes */ 52958f0484fSRodney W. Grimes #define PADSIZE 16 /* pad chunk size */ 53058f0484fSRodney W. Grimes static char blanks[PADSIZE] = 53158f0484fSRodney W. Grimes {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 53258f0484fSRodney W. Grimes static char zeroes[PADSIZE] = 53358f0484fSRodney W. Grimes {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 53458f0484fSRodney W. Grimes 535ebbad5ecSDavid Schultz static const char xdigs_lower[16] = "0123456789abcdef"; 536ebbad5ecSDavid Schultz static const char xdigs_upper[16] = "0123456789ABCDEF"; 537ebbad5ecSDavid Schultz 53858f0484fSRodney W. Grimes /* 53958f0484fSRodney W. Grimes * BEWARE, these `goto error' on error, and PAD uses `n'. 54058f0484fSRodney W. Grimes */ 54158f0484fSRodney W. Grimes #define PRINT(ptr, len) { \ 54258f0484fSRodney W. Grimes iovp->iov_base = (ptr); \ 54358f0484fSRodney W. Grimes iovp->iov_len = (len); \ 54458f0484fSRodney W. Grimes uio.uio_resid += (len); \ 54558f0484fSRodney W. Grimes iovp++; \ 54658f0484fSRodney W. Grimes if (++uio.uio_iovcnt >= NIOV) { \ 54758f0484fSRodney W. Grimes if (__sprint(fp, &uio)) \ 54858f0484fSRodney W. Grimes goto error; \ 54958f0484fSRodney W. Grimes iovp = iov; \ 55058f0484fSRodney W. Grimes } \ 55158f0484fSRodney W. Grimes } 55258f0484fSRodney W. Grimes #define PAD(howmany, with) { \ 55358f0484fSRodney W. Grimes if ((n = (howmany)) > 0) { \ 55458f0484fSRodney W. Grimes while (n > PADSIZE) { \ 55558f0484fSRodney W. Grimes PRINT(with, PADSIZE); \ 55658f0484fSRodney W. Grimes n -= PADSIZE; \ 55758f0484fSRodney W. Grimes } \ 55858f0484fSRodney W. Grimes PRINT(with, n); \ 55958f0484fSRodney W. Grimes } \ 56058f0484fSRodney W. Grimes } 5613b204b7dSDavid Schultz #define PRINTANDPAD(p, ep, len, with) do { \ 5623b204b7dSDavid Schultz n2 = (ep) - (p); \ 5633b204b7dSDavid Schultz if (n2 > (len)) \ 5643b204b7dSDavid Schultz n2 = (len); \ 5653b204b7dSDavid Schultz if (n2 > 0) \ 5663b204b7dSDavid Schultz PRINT((p), n2); \ 5673b204b7dSDavid Schultz PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ 5683b204b7dSDavid Schultz } while(0) 56958f0484fSRodney W. Grimes #define FLUSH() { \ 57058f0484fSRodney W. Grimes if (uio.uio_resid && __sprint(fp, &uio)) \ 57158f0484fSRodney W. Grimes goto error; \ 57258f0484fSRodney W. Grimes uio.uio_iovcnt = 0; \ 57358f0484fSRodney W. Grimes iovp = iov; \ 57458f0484fSRodney W. Grimes } 57558f0484fSRodney W. Grimes 57658f0484fSRodney W. Grimes /* 577efb7e53dSJordan K. Hubbard * Get the argument indexed by nextarg. If the argument table is 578efb7e53dSJordan K. Hubbard * built, use it to get the argument. If its not, get the next 579efb7e53dSJordan K. Hubbard * argument (and arguments must be gotten sequentially). 580efb7e53dSJordan K. Hubbard */ 581efb7e53dSJordan K. Hubbard #define GETARG(type) \ 582a387081cSDoug Rabson ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 583efb7e53dSJordan K. Hubbard (nextarg++, va_arg(ap, type))) 584efb7e53dSJordan K. Hubbard 585efb7e53dSJordan K. Hubbard /* 58658f0484fSRodney W. Grimes * To extend shorts properly, we need both signed and unsigned 58758f0484fSRodney W. Grimes * argument extraction methods. 58858f0484fSRodney W. Grimes */ 58958f0484fSRodney W. Grimes #define SARG() \ 590efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(long) : \ 591efb7e53dSJordan K. Hubbard flags&SHORTINT ? (long)(short)GETARG(int) : \ 5927735bb0fSBill Fenner flags&CHARINT ? (long)(signed char)GETARG(int) : \ 593efb7e53dSJordan K. Hubbard (long)GETARG(int)) 59458f0484fSRodney W. Grimes #define UARG() \ 595efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(u_long) : \ 596efb7e53dSJordan K. Hubbard flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 5977735bb0fSBill Fenner flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ 598efb7e53dSJordan K. Hubbard (u_long)GETARG(u_int)) 5997735bb0fSBill Fenner #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) 6007735bb0fSBill Fenner #define SJARG() \ 6017735bb0fSBill Fenner (flags&INTMAXT ? GETARG(intmax_t) : \ 6027735bb0fSBill Fenner flags&SIZET ? (intmax_t)GETARG(size_t) : \ 6037735bb0fSBill Fenner flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ 6047735bb0fSBill Fenner (intmax_t)GETARG(long long)) 6057735bb0fSBill Fenner #define UJARG() \ 6067735bb0fSBill Fenner (flags&INTMAXT ? GETARG(uintmax_t) : \ 6077735bb0fSBill Fenner flags&SIZET ? (uintmax_t)GETARG(size_t) : \ 6087735bb0fSBill Fenner flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ 6097735bb0fSBill Fenner (uintmax_t)GETARG(unsigned long long)) 610efb7e53dSJordan K. Hubbard 611efb7e53dSJordan K. Hubbard /* 612efb7e53dSJordan K. Hubbard * Get * arguments, including the form *nn$. Preserve the nextarg 613efb7e53dSJordan K. Hubbard * that the argument can be gotten once the type is determined. 614efb7e53dSJordan K. Hubbard */ 615efb7e53dSJordan K. Hubbard #define GETASTER(val) \ 616efb7e53dSJordan K. Hubbard n2 = 0; \ 617efb7e53dSJordan K. Hubbard cp = fmt; \ 618efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 619efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 620efb7e53dSJordan K. Hubbard cp++; \ 621efb7e53dSJordan K. Hubbard } \ 622efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 623efb7e53dSJordan K. Hubbard int hold = nextarg; \ 624efb7e53dSJordan K. Hubbard if (argtable == NULL) { \ 625efb7e53dSJordan K. Hubbard argtable = statargtable; \ 626efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, &argtable); \ 627efb7e53dSJordan K. Hubbard } \ 628efb7e53dSJordan K. Hubbard nextarg = n2; \ 629efb7e53dSJordan K. Hubbard val = GETARG (int); \ 630efb7e53dSJordan K. Hubbard nextarg = hold; \ 631efb7e53dSJordan K. Hubbard fmt = ++cp; \ 632efb7e53dSJordan K. Hubbard } else { \ 633efb7e53dSJordan K. Hubbard val = GETARG (int); \ 634efb7e53dSJordan K. Hubbard } 635efb7e53dSJordan K. Hubbard 63658f0484fSRodney W. Grimes 63798ee7635SAlexey Zelkin thousands_sep = '\0'; 63898ee7635SAlexey Zelkin grouping = NULL; 639b9aac308STim J. Robbins convbuf = NULL; 6408de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 6412ffc61baSTor Egge dtoaresult = NULL; 6427735bb0fSBill Fenner decimal_point = localeconv()->decimal_point; 6432ffc61baSTor Egge #endif 64458f0484fSRodney W. Grimes /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 64552183d46SDavid Schultz if (prepwrite(fp) != 0) 64658f0484fSRodney W. Grimes return (EOF); 64758f0484fSRodney W. Grimes 64858f0484fSRodney W. Grimes /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 64958f0484fSRodney W. Grimes if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 650d201fe46SDaniel Eischen fp->_file >= 0) 65158f0484fSRodney W. Grimes return (__sbprintf(fp, fmt0, ap)); 65258f0484fSRodney W. Grimes 65358f0484fSRodney W. Grimes fmt = (char *)fmt0; 654efb7e53dSJordan K. Hubbard argtable = NULL; 655efb7e53dSJordan K. Hubbard nextarg = 1; 656d07090a8STim J. Robbins va_copy(orgap, ap); 65758f0484fSRodney W. Grimes uio.uio_iov = iovp = iov; 65858f0484fSRodney W. Grimes uio.uio_resid = 0; 65958f0484fSRodney W. Grimes uio.uio_iovcnt = 0; 66058f0484fSRodney W. Grimes ret = 0; 66158f0484fSRodney W. Grimes 66258f0484fSRodney W. Grimes /* 66358f0484fSRodney W. Grimes * Scan the format for conversions (`%' character). 66458f0484fSRodney W. Grimes */ 66558f0484fSRodney W. Grimes for (;;) { 66658f0484fSRodney W. Grimes for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 66758f0484fSRodney W. Grimes /* void */; 66858f0484fSRodney W. Grimes if ((n = fmt - cp) != 0) { 669b250f248SAndrey A. Chernov if ((unsigned)ret + n > INT_MAX) { 67092e88f87SAndrey A. Chernov ret = EOF; 67192e88f87SAndrey A. Chernov goto error; 67292e88f87SAndrey A. Chernov } 67358f0484fSRodney W. Grimes PRINT(cp, n); 67458f0484fSRodney W. Grimes ret += n; 67558f0484fSRodney W. Grimes } 67658f0484fSRodney W. Grimes if (ch == '\0') 67758f0484fSRodney W. Grimes goto done; 67858f0484fSRodney W. Grimes fmt++; /* skip over '%' */ 67958f0484fSRodney W. Grimes 68058f0484fSRodney W. Grimes flags = 0; 68158f0484fSRodney W. Grimes dprec = 0; 68258f0484fSRodney W. Grimes width = 0; 68358f0484fSRodney W. Grimes prec = -1; 68458f0484fSRodney W. Grimes sign = '\0'; 685ebbad5ecSDavid Schultz ox[1] = '\0'; 68658f0484fSRodney W. Grimes 68758f0484fSRodney W. Grimes rflag: ch = *fmt++; 68858f0484fSRodney W. Grimes reswitch: switch (ch) { 68958f0484fSRodney W. Grimes case ' ': 6902e394b2fSAlexey Zelkin /*- 69158f0484fSRodney W. Grimes * ``If the space and + flags both appear, the space 69258f0484fSRodney W. Grimes * flag will be ignored.'' 69358f0484fSRodney W. Grimes * -- ANSI X3J11 69458f0484fSRodney W. Grimes */ 69558f0484fSRodney W. Grimes if (!sign) 69658f0484fSRodney W. Grimes sign = ' '; 69758f0484fSRodney W. Grimes goto rflag; 69858f0484fSRodney W. Grimes case '#': 69958f0484fSRodney W. Grimes flags |= ALT; 70058f0484fSRodney W. Grimes goto rflag; 70158f0484fSRodney W. Grimes case '*': 7022e394b2fSAlexey Zelkin /*- 70358f0484fSRodney W. Grimes * ``A negative field width argument is taken as a 70458f0484fSRodney W. Grimes * - flag followed by a positive field width.'' 70558f0484fSRodney W. Grimes * -- ANSI X3J11 70658f0484fSRodney W. Grimes * They don't exclude field widths read from args. 70758f0484fSRodney W. Grimes */ 708efb7e53dSJordan K. Hubbard GETASTER (width); 709efb7e53dSJordan K. Hubbard if (width >= 0) 71058f0484fSRodney W. Grimes goto rflag; 71158f0484fSRodney W. Grimes width = -width; 71258f0484fSRodney W. Grimes /* FALLTHROUGH */ 71358f0484fSRodney W. Grimes case '-': 71458f0484fSRodney W. Grimes flags |= LADJUST; 71558f0484fSRodney W. Grimes goto rflag; 71658f0484fSRodney W. Grimes case '+': 71758f0484fSRodney W. Grimes sign = '+'; 71858f0484fSRodney W. Grimes goto rflag; 7197735bb0fSBill Fenner case '\'': 72098ee7635SAlexey Zelkin flags |= GROUPING; 72198ee7635SAlexey Zelkin thousands_sep = *(localeconv()->thousands_sep); 72298ee7635SAlexey Zelkin grouping = localeconv()->grouping; 7237735bb0fSBill Fenner goto rflag; 72458f0484fSRodney W. Grimes case '.': 72558f0484fSRodney W. Grimes if ((ch = *fmt++) == '*') { 7263b204b7dSDavid Schultz GETASTER (prec); 72758f0484fSRodney W. Grimes goto rflag; 72858f0484fSRodney W. Grimes } 7293b204b7dSDavid Schultz prec = 0; 73058f0484fSRodney W. Grimes while (is_digit(ch)) { 7313b204b7dSDavid Schultz prec = 10 * prec + to_digit(ch); 73258f0484fSRodney W. Grimes ch = *fmt++; 73358f0484fSRodney W. Grimes } 73458f0484fSRodney W. Grimes goto reswitch; 73558f0484fSRodney W. Grimes case '0': 7362e394b2fSAlexey Zelkin /*- 73758f0484fSRodney W. Grimes * ``Note that 0 is taken as a flag, not as the 73858f0484fSRodney W. Grimes * beginning of a field width.'' 73958f0484fSRodney W. Grimes * -- ANSI X3J11 74058f0484fSRodney W. Grimes */ 74158f0484fSRodney W. Grimes flags |= ZEROPAD; 74258f0484fSRodney W. Grimes goto rflag; 74358f0484fSRodney W. Grimes case '1': case '2': case '3': case '4': 74458f0484fSRodney W. Grimes case '5': case '6': case '7': case '8': case '9': 74558f0484fSRodney W. Grimes n = 0; 74658f0484fSRodney W. Grimes do { 74758f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 74858f0484fSRodney W. Grimes ch = *fmt++; 74958f0484fSRodney W. Grimes } while (is_digit(ch)); 750efb7e53dSJordan K. Hubbard if (ch == '$') { 751efb7e53dSJordan K. Hubbard nextarg = n; 752efb7e53dSJordan K. Hubbard if (argtable == NULL) { 753efb7e53dSJordan K. Hubbard argtable = statargtable; 754efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, 755efb7e53dSJordan K. Hubbard &argtable); 756efb7e53dSJordan K. Hubbard } 757efb7e53dSJordan K. Hubbard goto rflag; 758efb7e53dSJordan K. Hubbard } 75958f0484fSRodney W. Grimes width = n; 76058f0484fSRodney W. Grimes goto reswitch; 7618de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 76258f0484fSRodney W. Grimes case 'L': 76358f0484fSRodney W. Grimes flags |= LONGDBL; 76458f0484fSRodney W. Grimes goto rflag; 76558f0484fSRodney W. Grimes #endif 76658f0484fSRodney W. Grimes case 'h': 7677735bb0fSBill Fenner if (flags & SHORTINT) { 7687735bb0fSBill Fenner flags &= ~SHORTINT; 7697735bb0fSBill Fenner flags |= CHARINT; 7707735bb0fSBill Fenner } else 77158f0484fSRodney W. Grimes flags |= SHORTINT; 77258f0484fSRodney W. Grimes goto rflag; 7737735bb0fSBill Fenner case 'j': 7747735bb0fSBill Fenner flags |= INTMAXT; 7757735bb0fSBill Fenner goto rflag; 77658f0484fSRodney W. Grimes case 'l': 7777735bb0fSBill Fenner if (flags & LONGINT) { 7787735bb0fSBill Fenner flags &= ~LONGINT; 7797735bb0fSBill Fenner flags |= LLONGINT; 7807735bb0fSBill Fenner } else 78158f0484fSRodney W. Grimes flags |= LONGINT; 78258f0484fSRodney W. Grimes goto rflag; 78358f0484fSRodney W. Grimes case 'q': 7847735bb0fSBill Fenner flags |= LLONGINT; /* not necessarily */ 7857735bb0fSBill Fenner goto rflag; 7867735bb0fSBill Fenner case 't': 7877735bb0fSBill Fenner flags |= PTRDIFFT; 7887735bb0fSBill Fenner goto rflag; 7897735bb0fSBill Fenner case 'z': 7907735bb0fSBill Fenner flags |= SIZET; 79158f0484fSRodney W. Grimes goto rflag; 792927ecbf3STim J. Robbins case 'C': 793927ecbf3STim J. Robbins flags |= LONGINT; 794927ecbf3STim J. Robbins /*FALLTHROUGH*/ 79558f0484fSRodney W. Grimes case 'c': 796b9aac308STim J. Robbins if (flags & LONGINT) { 79793996f6dSTim J. Robbins static const mbstate_t initial; 79893996f6dSTim J. Robbins mbstate_t mbs; 799b9aac308STim J. Robbins size_t mbseqlen; 800b9aac308STim J. Robbins 80193996f6dSTim J. Robbins mbs = initial; 802b9aac308STim J. Robbins mbseqlen = wcrtomb(cp = buf, 80393996f6dSTim J. Robbins (wchar_t)GETARG(wint_t), &mbs); 8046180233fSTim J. Robbins if (mbseqlen == (size_t)-1) { 8056180233fSTim J. Robbins fp->_flags |= __SERR; 806b9aac308STim J. Robbins goto error; 8076180233fSTim J. Robbins } 808b9aac308STim J. Robbins size = (int)mbseqlen; 809b9aac308STim J. Robbins } else { 810efb7e53dSJordan K. Hubbard *(cp = buf) = GETARG(int); 81158f0484fSRodney W. Grimes size = 1; 812b9aac308STim J. Robbins } 81358f0484fSRodney W. Grimes sign = '\0'; 81458f0484fSRodney W. Grimes break; 81558f0484fSRodney W. Grimes case 'D': 81658f0484fSRodney W. Grimes flags |= LONGINT; 81758f0484fSRodney W. Grimes /*FALLTHROUGH*/ 81858f0484fSRodney W. Grimes case 'd': 81958f0484fSRodney W. Grimes case 'i': 8207735bb0fSBill Fenner if (flags & INTMAX_SIZE) { 8217735bb0fSBill Fenner ujval = SJARG(); 8227735bb0fSBill Fenner if ((intmax_t)ujval < 0) { 8237735bb0fSBill Fenner ujval = -ujval; 82458f0484fSRodney W. Grimes sign = '-'; 82558f0484fSRodney W. Grimes } 82658f0484fSRodney W. Grimes } else { 82758f0484fSRodney W. Grimes ulval = SARG(); 82858f0484fSRodney W. Grimes if ((long)ulval < 0) { 82958f0484fSRodney W. Grimes ulval = -ulval; 83058f0484fSRodney W. Grimes sign = '-'; 83158f0484fSRodney W. Grimes } 83258f0484fSRodney W. Grimes } 83358f0484fSRodney W. Grimes base = 10; 83458f0484fSRodney W. Grimes goto number; 8358de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 8367735bb0fSBill Fenner case 'a': 8377735bb0fSBill Fenner case 'A': 838ebbad5ecSDavid Schultz if (ch == 'a') { 839ebbad5ecSDavid Schultz ox[1] = 'x'; 840ebbad5ecSDavid Schultz xdigs = xdigs_lower; 841ebbad5ecSDavid Schultz expchar = 'p'; 842ebbad5ecSDavid Schultz } else { 843ebbad5ecSDavid Schultz ox[1] = 'X'; 844ebbad5ecSDavid Schultz xdigs = xdigs_upper; 845ebbad5ecSDavid Schultz expchar = 'P'; 846ebbad5ecSDavid Schultz } 847904322a5SDavid Schultz if (prec >= 0) 848904322a5SDavid Schultz prec++; 849904322a5SDavid Schultz if (dtoaresult != NULL) 850904322a5SDavid Schultz freedtoa(dtoaresult); 851ebbad5ecSDavid Schultz if (flags & LONGDBL) { 852904322a5SDavid Schultz fparg.ldbl = GETARG(long double); 853ebbad5ecSDavid Schultz dtoaresult = cp = 854ebbad5ecSDavid Schultz __hldtoa(fparg.ldbl, xdigs, prec, 855ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 856ebbad5ecSDavid Schultz } else { 857ebbad5ecSDavid Schultz fparg.dbl = GETARG(double); 858ebbad5ecSDavid Schultz dtoaresult = cp = 859ebbad5ecSDavid Schultz __hdtoa(fparg.dbl, xdigs, prec, 860ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 861ebbad5ecSDavid Schultz } 862904322a5SDavid Schultz if (prec < 0) 863904322a5SDavid Schultz prec = dtoaend - cp; 864904322a5SDavid Schultz if (expt == INT_MAX) 865904322a5SDavid Schultz ox[1] = '\0'; 866904322a5SDavid Schultz goto fp_common; 867d26be6f0SBruce Evans case 'e': 86858f0484fSRodney W. Grimes case 'E': 869ebbad5ecSDavid Schultz expchar = ch; 870ebbad5ecSDavid Schultz if (prec < 0) /* account for digit before decpt */ 871ebbad5ecSDavid Schultz prec = DEFPREC + 1; 872ebbad5ecSDavid Schultz else 873ebbad5ecSDavid Schultz prec++; 874ebbad5ecSDavid Schultz goto fp_begin; 875d26be6f0SBruce Evans case 'f': 8767735bb0fSBill Fenner case 'F': 877ebbad5ecSDavid Schultz expchar = '\0'; 878d26be6f0SBruce Evans goto fp_begin; 87958f0484fSRodney W. Grimes case 'g': 88058f0484fSRodney W. Grimes case 'G': 881ebbad5ecSDavid Schultz expchar = ch - ('g' - 'e'); 882d26be6f0SBruce Evans if (prec == 0) 883d26be6f0SBruce Evans prec = 1; 884ebbad5ecSDavid Schultz fp_begin: 885ebbad5ecSDavid Schultz if (prec < 0) 88658f0484fSRodney W. Grimes prec = DEFPREC; 887ebbad5ecSDavid Schultz if (dtoaresult != NULL) 888ebbad5ecSDavid Schultz freedtoa(dtoaresult); 889ebbad5ecSDavid Schultz if (flags & LONGDBL) { 890ebbad5ecSDavid Schultz fparg.ldbl = GETARG(long double); 891ebbad5ecSDavid Schultz dtoaresult = cp = 892ebbad5ecSDavid Schultz __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, 893ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 894ebbad5ecSDavid Schultz } else { 895ebbad5ecSDavid Schultz fparg.dbl = GETARG(double); 896ebbad5ecSDavid Schultz dtoaresult = cp = 897ebbad5ecSDavid Schultz dtoa(fparg.dbl, expchar ? 2 : 3, prec, 898ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 899ebbad5ecSDavid Schultz if (expt == 9999) 900ebbad5ecSDavid Schultz expt = INT_MAX; 90158f0484fSRodney W. Grimes } 902904322a5SDavid Schultz fp_common: 903ebbad5ecSDavid Schultz if (signflag) 904ebbad5ecSDavid Schultz sign = '-'; 905ebbad5ecSDavid Schultz if (expt == INT_MAX) { /* inf or nan */ 906ebbad5ecSDavid Schultz if (*cp == 'N') { 907ebbad5ecSDavid Schultz cp = (ch >= 'a') ? "nan" : "NAN"; 908ebbad5ecSDavid Schultz sign = '\0'; 909ebbad5ecSDavid Schultz } else 910ebbad5ecSDavid Schultz cp = (ch >= 'a') ? "inf" : "INF"; 91158f0484fSRodney W. Grimes size = 3; 91258f0484fSRodney W. Grimes break; 91358f0484fSRodney W. Grimes } 91458f0484fSRodney W. Grimes flags |= FPT; 915ebbad5ecSDavid Schultz ndig = dtoaend - cp; 91658f0484fSRodney W. Grimes if (ch == 'g' || ch == 'G') { 917ebbad5ecSDavid Schultz if (expt > -4 && expt <= prec) { 918ebbad5ecSDavid Schultz /* Make %[gG] smell like %[fF] */ 919ebbad5ecSDavid Schultz expchar = '\0'; 920ebbad5ecSDavid Schultz if (flags & ALT) 921ebbad5ecSDavid Schultz prec -= expt; 92258f0484fSRodney W. Grimes else 923ebbad5ecSDavid Schultz prec = ndig - expt; 924ebbad5ecSDavid Schultz if (prec < 0) 925ebbad5ecSDavid Schultz prec = 0; 9261f2a0cdfSDavid Schultz } else { 9271f2a0cdfSDavid Schultz /* 9281f2a0cdfSDavid Schultz * Make %[gG] smell like %[eE], but 9291f2a0cdfSDavid Schultz * trim trailing zeroes if no # flag. 9301f2a0cdfSDavid Schultz */ 9311f2a0cdfSDavid Schultz if (!(flags & ALT)) 9321f2a0cdfSDavid Schultz prec = ndig; 93358f0484fSRodney W. Grimes } 934ebbad5ecSDavid Schultz } 935ebbad5ecSDavid Schultz if (expchar) { 936ebbad5ecSDavid Schultz expsize = exponent(expstr, expt - 1, expchar); 937ebbad5ecSDavid Schultz size = expsize + prec; 9383b204b7dSDavid Schultz if (prec > 1 || flags & ALT) 93958f0484fSRodney W. Grimes ++size; 940ebbad5ecSDavid Schultz } else { 94181ae2e9aSDavid Schultz /* space for digits before decimal point */ 94281ae2e9aSDavid Schultz if (expt > 0) 94358f0484fSRodney W. Grimes size = expt; 94481ae2e9aSDavid Schultz else /* "0" */ 94581ae2e9aSDavid Schultz size = 1; 94681ae2e9aSDavid Schultz /* space for decimal pt and following digits */ 94758f0484fSRodney W. Grimes if (prec || flags & ALT) 94858f0484fSRodney W. Grimes size += prec + 1; 949ebbad5ecSDavid Schultz if (grouping && expt > 0) { 950ebbad5ecSDavid Schultz /* space for thousands' grouping */ 951ebbad5ecSDavid Schultz nseps = nrepeats = 0; 952ebbad5ecSDavid Schultz lead = expt; 953ebbad5ecSDavid Schultz while (*grouping != CHAR_MAX) { 954ebbad5ecSDavid Schultz if (lead <= *grouping) 955ebbad5ecSDavid Schultz break; 956ebbad5ecSDavid Schultz lead -= *grouping; 957ebbad5ecSDavid Schultz if (*(grouping+1)) { 958ebbad5ecSDavid Schultz nseps++; 959ebbad5ecSDavid Schultz grouping++; 96058f0484fSRodney W. Grimes } else 961ebbad5ecSDavid Schultz nrepeats++; 962ebbad5ecSDavid Schultz } 963ebbad5ecSDavid Schultz size += nseps + nrepeats; 964ebbad5ecSDavid Schultz } else 965d890afb8SDavid Schultz lead = expt; 966ebbad5ecSDavid Schultz } 96758f0484fSRodney W. Grimes break; 9688de9e897SDavid Schultz #endif /* !NO_FLOATING_POINT */ 96958f0484fSRodney W. Grimes case 'n': 9707735bb0fSBill Fenner /* 9717735bb0fSBill Fenner * Assignment-like behavior is specified if the 9727735bb0fSBill Fenner * value overflows or is otherwise unrepresentable. 9737735bb0fSBill Fenner * C99 says to use `signed char' for %hhn conversions. 9747735bb0fSBill Fenner */ 9757735bb0fSBill Fenner if (flags & LLONGINT) 9767735bb0fSBill Fenner *GETARG(long long *) = ret; 9777735bb0fSBill Fenner else if (flags & SIZET) 9787735bb0fSBill Fenner *GETARG(ssize_t *) = (ssize_t)ret; 9797735bb0fSBill Fenner else if (flags & PTRDIFFT) 9807735bb0fSBill Fenner *GETARG(ptrdiff_t *) = ret; 9817735bb0fSBill Fenner else if (flags & INTMAXT) 9827735bb0fSBill Fenner *GETARG(intmax_t *) = ret; 98358f0484fSRodney W. Grimes else if (flags & LONGINT) 9846e690ad4SAndrey A. Chernov *GETARG(long *) = ret; 98558f0484fSRodney W. Grimes else if (flags & SHORTINT) 9866e690ad4SAndrey A. Chernov *GETARG(short *) = ret; 9877735bb0fSBill Fenner else if (flags & CHARINT) 9887735bb0fSBill Fenner *GETARG(signed char *) = ret; 98958f0484fSRodney W. Grimes else 9906e690ad4SAndrey A. Chernov *GETARG(int *) = ret; 99158f0484fSRodney W. Grimes continue; /* no output */ 99258f0484fSRodney W. Grimes case 'O': 99358f0484fSRodney W. Grimes flags |= LONGINT; 99458f0484fSRodney W. Grimes /*FALLTHROUGH*/ 99558f0484fSRodney W. Grimes case 'o': 9967735bb0fSBill Fenner if (flags & INTMAX_SIZE) 9977735bb0fSBill Fenner ujval = UJARG(); 99858f0484fSRodney W. Grimes else 99958f0484fSRodney W. Grimes ulval = UARG(); 100058f0484fSRodney W. Grimes base = 8; 100158f0484fSRodney W. Grimes goto nosign; 100258f0484fSRodney W. Grimes case 'p': 10032e394b2fSAlexey Zelkin /*- 100458f0484fSRodney W. Grimes * ``The argument shall be a pointer to void. The 100558f0484fSRodney W. Grimes * value of the pointer is converted to a sequence 100658f0484fSRodney W. Grimes * of printable characters, in an implementation- 100758f0484fSRodney W. Grimes * defined manner.'' 100858f0484fSRodney W. Grimes * -- ANSI X3J11 100958f0484fSRodney W. Grimes */ 10107735bb0fSBill Fenner ujval = (uintmax_t)(uintptr_t)GETARG(void *); 101158f0484fSRodney W. Grimes base = 16; 1012ebbad5ecSDavid Schultz xdigs = xdigs_lower; 1013ebbad5ecSDavid Schultz flags = flags | INTMAXT; 1014ebbad5ecSDavid Schultz ox[1] = 'x'; 101558f0484fSRodney W. Grimes goto nosign; 1016927ecbf3STim J. Robbins case 'S': 1017927ecbf3STim J. Robbins flags |= LONGINT; 1018927ecbf3STim J. Robbins /*FALLTHROUGH*/ 101958f0484fSRodney W. Grimes case 's': 1020b9aac308STim J. Robbins if (flags & LONGINT) { 1021b9aac308STim J. Robbins wchar_t *wcp; 1022b9aac308STim J. Robbins 1023b9aac308STim J. Robbins if (convbuf != NULL) 1024b9aac308STim J. Robbins free(convbuf); 1025b9aac308STim J. Robbins if ((wcp = GETARG(wchar_t *)) == NULL) 1026b9aac308STim J. Robbins cp = "(null)"; 1027b9aac308STim J. Robbins else { 1028b9aac308STim J. Robbins convbuf = __wcsconv(wcp, prec); 10296180233fSTim J. Robbins if (convbuf == NULL) { 10306180233fSTim J. Robbins fp->_flags |= __SERR; 1031b9aac308STim J. Robbins goto error; 10326180233fSTim J. Robbins } 1033b9aac308STim J. Robbins cp = convbuf; 1034b9aac308STim J. Robbins } 1035b9aac308STim J. Robbins } else if ((cp = GETARG(char *)) == NULL) 103658f0484fSRodney W. Grimes cp = "(null)"; 103758f0484fSRodney W. Grimes if (prec >= 0) { 103858f0484fSRodney W. Grimes /* 103958f0484fSRodney W. Grimes * can't use strlen; can only look for the 104058f0484fSRodney W. Grimes * NUL in the first `prec' characters, and 104158f0484fSRodney W. Grimes * strlen() will go further. 104258f0484fSRodney W. Grimes */ 1043ce51cf03SJames Raynard char *p = memchr(cp, 0, (size_t)prec); 104458f0484fSRodney W. Grimes 104558f0484fSRodney W. Grimes if (p != NULL) { 104658f0484fSRodney W. Grimes size = p - cp; 104758f0484fSRodney W. Grimes if (size > prec) 104858f0484fSRodney W. Grimes size = prec; 104958f0484fSRodney W. Grimes } else 105058f0484fSRodney W. Grimes size = prec; 105158f0484fSRodney W. Grimes } else 105258f0484fSRodney W. Grimes size = strlen(cp); 105358f0484fSRodney W. Grimes sign = '\0'; 105458f0484fSRodney W. Grimes break; 105558f0484fSRodney W. Grimes case 'U': 105658f0484fSRodney W. Grimes flags |= LONGINT; 105758f0484fSRodney W. Grimes /*FALLTHROUGH*/ 105858f0484fSRodney W. Grimes case 'u': 10597735bb0fSBill Fenner if (flags & INTMAX_SIZE) 10607735bb0fSBill Fenner ujval = UJARG(); 106158f0484fSRodney W. Grimes else 106258f0484fSRodney W. Grimes ulval = UARG(); 106358f0484fSRodney W. Grimes base = 10; 106458f0484fSRodney W. Grimes goto nosign; 106558f0484fSRodney W. Grimes case 'X': 1066ebbad5ecSDavid Schultz xdigs = xdigs_upper; 106758f0484fSRodney W. Grimes goto hex; 106858f0484fSRodney W. Grimes case 'x': 1069ebbad5ecSDavid Schultz xdigs = xdigs_lower; 10707735bb0fSBill Fenner hex: 10717735bb0fSBill Fenner if (flags & INTMAX_SIZE) 10727735bb0fSBill Fenner ujval = UJARG(); 107358f0484fSRodney W. Grimes else 107458f0484fSRodney W. Grimes ulval = UARG(); 107558f0484fSRodney W. Grimes base = 16; 107658f0484fSRodney W. Grimes /* leading 0x/X only if non-zero */ 107758f0484fSRodney W. Grimes if (flags & ALT && 10787735bb0fSBill Fenner (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 1079ebbad5ecSDavid Schultz ox[1] = ch; 108058f0484fSRodney W. Grimes 108198ee7635SAlexey Zelkin flags &= ~GROUPING; 108258f0484fSRodney W. Grimes /* unsigned conversions */ 108358f0484fSRodney W. Grimes nosign: sign = '\0'; 10842e394b2fSAlexey Zelkin /*- 108558f0484fSRodney W. Grimes * ``... diouXx conversions ... if a precision is 108658f0484fSRodney W. Grimes * specified, the 0 flag will be ignored.'' 108758f0484fSRodney W. Grimes * -- ANSI X3J11 108858f0484fSRodney W. Grimes */ 108958f0484fSRodney W. Grimes number: if ((dprec = prec) >= 0) 109058f0484fSRodney W. Grimes flags &= ~ZEROPAD; 109158f0484fSRodney W. Grimes 10922e394b2fSAlexey Zelkin /*- 109358f0484fSRodney W. Grimes * ``The result of converting a zero value with an 109458f0484fSRodney W. Grimes * explicit precision of zero is no characters.'' 109558f0484fSRodney W. Grimes * -- ANSI X3J11 10961be5319aSDavid Schultz * 10971be5319aSDavid Schultz * ``The C Standard is clear enough as is. The call 10981be5319aSDavid Schultz * printf("%#.0o", 0) should print 0.'' 10991be5319aSDavid Schultz * -- Defect Report #151 110058f0484fSRodney W. Grimes */ 110158f0484fSRodney W. Grimes cp = buf + BUF; 11027735bb0fSBill Fenner if (flags & INTMAX_SIZE) { 11031be5319aSDavid Schultz if (ujval != 0 || prec != 0 || 11041be5319aSDavid Schultz (flags & ALT && base == 8)) 11057735bb0fSBill Fenner cp = __ujtoa(ujval, cp, base, 110698ee7635SAlexey Zelkin flags & ALT, xdigs, 110798ee7635SAlexey Zelkin flags & GROUPING, thousands_sep, 110898ee7635SAlexey Zelkin grouping); 110958f0484fSRodney W. Grimes } else { 11101be5319aSDavid Schultz if (ulval != 0 || prec != 0 || 11111be5319aSDavid Schultz (flags & ALT && base == 8)) 111258f0484fSRodney W. Grimes cp = __ultoa(ulval, cp, base, 111398ee7635SAlexey Zelkin flags & ALT, xdigs, 111498ee7635SAlexey Zelkin flags & GROUPING, thousands_sep, 111598ee7635SAlexey Zelkin grouping); 111658f0484fSRodney W. Grimes } 111758f0484fSRodney W. Grimes size = buf + BUF - cp; 111838cac8f8SDavid Schultz if (size > BUF) /* should never happen */ 111938cac8f8SDavid Schultz abort(); 112058f0484fSRodney W. Grimes break; 112158f0484fSRodney W. Grimes default: /* "%?" prints ?, unless ? is NUL */ 112258f0484fSRodney W. Grimes if (ch == '\0') 112358f0484fSRodney W. Grimes goto done; 112458f0484fSRodney W. Grimes /* pretend it was %c with argument ch */ 112558f0484fSRodney W. Grimes cp = buf; 112658f0484fSRodney W. Grimes *cp = ch; 112758f0484fSRodney W. Grimes size = 1; 112858f0484fSRodney W. Grimes sign = '\0'; 112958f0484fSRodney W. Grimes break; 113058f0484fSRodney W. Grimes } 113158f0484fSRodney W. Grimes 113258f0484fSRodney W. Grimes /* 113358f0484fSRodney W. Grimes * All reasonable formats wind up here. At this point, `cp' 113458f0484fSRodney W. Grimes * points to a string which (if not flags&LADJUST) should be 113558f0484fSRodney W. Grimes * padded out to `width' places. If flags&ZEROPAD, it should 113658f0484fSRodney W. Grimes * first be prefixed by any sign or other prefix; otherwise, 113758f0484fSRodney W. Grimes * it should be blank padded before the prefix is emitted. 113858f0484fSRodney W. Grimes * After any left-hand padding and prefixing, emit zeroes 113958f0484fSRodney W. Grimes * required by a decimal [diouxX] precision, then print the 114058f0484fSRodney W. Grimes * string proper, then emit zeroes required by any leftover 114158f0484fSRodney W. Grimes * floating precision; finally, if LADJUST, pad with blanks. 114258f0484fSRodney W. Grimes * 114358f0484fSRodney W. Grimes * Compute actual size, so we know how much to pad. 1144261a532aSBill Fenner * size excludes decimal prec; realsz includes it. 114558f0484fSRodney W. Grimes */ 1146261a532aSBill Fenner realsz = dprec > size ? dprec : size; 114758f0484fSRodney W. Grimes if (sign) 1148261a532aSBill Fenner realsz++; 1149904322a5SDavid Schultz if (ox[1]) 1150261a532aSBill Fenner realsz += 2; 115158f0484fSRodney W. Grimes 115292e88f87SAndrey A. Chernov prsize = width > realsz ? width : realsz; 1153b250f248SAndrey A. Chernov if ((unsigned)ret + prsize > INT_MAX) { 115492e88f87SAndrey A. Chernov ret = EOF; 115592e88f87SAndrey A. Chernov goto error; 115692e88f87SAndrey A. Chernov } 115792e88f87SAndrey A. Chernov 115858f0484fSRodney W. Grimes /* right-adjusting blank padding */ 115958f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == 0) 116058f0484fSRodney W. Grimes PAD(width - realsz, blanks); 116158f0484fSRodney W. Grimes 116258f0484fSRodney W. Grimes /* prefix */ 1163904322a5SDavid Schultz if (sign) 116458f0484fSRodney W. Grimes PRINT(&sign, 1); 1165904322a5SDavid Schultz 1166904322a5SDavid Schultz if (ox[1]) { /* ox[1] is either x, X, or \0 */ 116758f0484fSRodney W. Grimes ox[0] = '0'; 116858f0484fSRodney W. Grimes PRINT(ox, 2); 116958f0484fSRodney W. Grimes } 117058f0484fSRodney W. Grimes 117158f0484fSRodney W. Grimes /* right-adjusting zero padding */ 117258f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 117358f0484fSRodney W. Grimes PAD(width - realsz, zeroes); 117458f0484fSRodney W. Grimes 117558f0484fSRodney W. Grimes /* leading zeroes from decimal precision */ 1176261a532aSBill Fenner PAD(dprec - size, zeroes); 117758f0484fSRodney W. Grimes 117858f0484fSRodney W. Grimes /* the string or number proper */ 11798de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 118058f0484fSRodney W. Grimes if ((flags & FPT) == 0) { 118158f0484fSRodney W. Grimes PRINT(cp, size); 118258f0484fSRodney W. Grimes } else { /* glue together f_p fragments */ 1183ebbad5ecSDavid Schultz if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 1184ebbad5ecSDavid Schultz if (expt <= 0) { 118581ae2e9aSDavid Schultz PRINT(zeroes, 1); 118681ae2e9aSDavid Schultz if (prec || flags & ALT) 118781ae2e9aSDavid Schultz PRINT(decimal_point, 1); 118858f0484fSRodney W. Grimes PAD(-expt, zeroes); 11893b204b7dSDavid Schultz /* already handled initial 0's */ 11903b204b7dSDavid Schultz prec += expt; 119158f0484fSRodney W. Grimes } else { 11923b204b7dSDavid Schultz PRINTANDPAD(cp, dtoaend, lead, zeroes); 1193ebbad5ecSDavid Schultz cp += lead; 1194ebbad5ecSDavid Schultz if (grouping) { 1195ebbad5ecSDavid Schultz while (nseps>0 || nrepeats>0) { 1196ebbad5ecSDavid Schultz if (nrepeats > 0) 1197ebbad5ecSDavid Schultz nrepeats--; 1198ebbad5ecSDavid Schultz else { 1199ebbad5ecSDavid Schultz grouping--; 1200ebbad5ecSDavid Schultz nseps--; 120158f0484fSRodney W. Grimes } 1202ebbad5ecSDavid Schultz PRINT(&thousands_sep, 1203ebbad5ecSDavid Schultz 1); 12043b204b7dSDavid Schultz PRINTANDPAD(cp,dtoaend, 12053b204b7dSDavid Schultz *grouping, zeroes); 1206ebbad5ecSDavid Schultz cp += *grouping; 1207ebbad5ecSDavid Schultz } 12083b204b7dSDavid Schultz if (cp > dtoaend) 12093b204b7dSDavid Schultz cp = dtoaend; 1210ebbad5ecSDavid Schultz } 1211ebbad5ecSDavid Schultz if (prec || flags & ALT) 1212ebbad5ecSDavid Schultz PRINT(decimal_point,1); 1213ebbad5ecSDavid Schultz } 12143b204b7dSDavid Schultz PRINTANDPAD(cp, dtoaend, prec, zeroes); 1215ebbad5ecSDavid Schultz } else { /* %[eE] or sufficiently long %[gG] */ 12163b204b7dSDavid Schultz if (prec > 1 || flags & ALT) { 1217ebbad5ecSDavid Schultz buf[0] = *cp++; 1218ebbad5ecSDavid Schultz buf[1] = *decimal_point; 1219ebbad5ecSDavid Schultz PRINT(buf, 2); 122058f0484fSRodney W. Grimes PRINT(cp, ndig-1); 1221ebbad5ecSDavid Schultz PAD(prec - ndig, zeroes); 122258f0484fSRodney W. Grimes } else /* XeYYY */ 122358f0484fSRodney W. Grimes PRINT(cp, 1); 122458f0484fSRodney W. Grimes PRINT(expstr, expsize); 122558f0484fSRodney W. Grimes } 122658f0484fSRodney W. Grimes } 122758f0484fSRodney W. Grimes #else 122858f0484fSRodney W. Grimes PRINT(cp, size); 122958f0484fSRodney W. Grimes #endif 123058f0484fSRodney W. Grimes /* left-adjusting padding (always blank) */ 123158f0484fSRodney W. Grimes if (flags & LADJUST) 123258f0484fSRodney W. Grimes PAD(width - realsz, blanks); 123358f0484fSRodney W. Grimes 123458f0484fSRodney W. Grimes /* finally, adjust ret */ 123592e88f87SAndrey A. Chernov ret += prsize; 123658f0484fSRodney W. Grimes 123758f0484fSRodney W. Grimes FLUSH(); /* copy out the I/O vectors */ 123858f0484fSRodney W. Grimes } 123958f0484fSRodney W. Grimes done: 124058f0484fSRodney W. Grimes FLUSH(); 124158f0484fSRodney W. Grimes error: 1242096ad104SDag-Erling Smørgrav va_end(orgap); 12438de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 12442ffc61baSTor Egge if (dtoaresult != NULL) 1245ebbad5ecSDavid Schultz freedtoa(dtoaresult); 12462ffc61baSTor Egge #endif 1247b9aac308STim J. Robbins if (convbuf != NULL) 1248b9aac308STim J. Robbins free(convbuf); 1249f70177e7SJulian Elischer if (__sferror(fp)) 1250f70177e7SJulian Elischer ret = EOF; 1251efb7e53dSJordan K. Hubbard if ((argtable != NULL) && (argtable != statargtable)) 1252efb7e53dSJordan K. Hubbard free (argtable); 1253f70177e7SJulian Elischer return (ret); 125458f0484fSRodney W. Grimes /* NOTREACHED */ 125558f0484fSRodney W. Grimes } 125658f0484fSRodney W. Grimes 1257efb7e53dSJordan K. Hubbard /* 1258efb7e53dSJordan K. Hubbard * Find all arguments when a positional parameter is encountered. Returns a 1259efb7e53dSJordan K. Hubbard * table, indexed by argument number, of pointers to each arguments. The 1260efb7e53dSJordan K. Hubbard * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 126142cebaa5SArchie Cobbs * It will be replaces with a malloc-ed one if it overflows. 1262efb7e53dSJordan K. Hubbard */ 1263efb7e53dSJordan K. Hubbard static void 1264a387081cSDoug Rabson __find_arguments (const char *fmt0, va_list ap, union arg **argtable) 1265efb7e53dSJordan K. Hubbard { 1266d201fe46SDaniel Eischen char *fmt; /* format string */ 1267d201fe46SDaniel Eischen int ch; /* character from fmt */ 1268d201fe46SDaniel Eischen int n, n2; /* handy integer (short term usage) */ 1269d201fe46SDaniel Eischen char *cp; /* handy char pointer (short term usage) */ 1270d201fe46SDaniel Eischen int flags; /* flags as above */ 1271efb7e53dSJordan K. Hubbard int width; /* width from format (%8d), or 0 */ 12727735bb0fSBill Fenner enum typeid *typetable; /* table of types */ 12737735bb0fSBill Fenner enum typeid stattypetable [STATIC_ARG_TBL_SIZE]; 1274efb7e53dSJordan K. Hubbard int tablesize; /* current size of type table */ 1275efb7e53dSJordan K. Hubbard int tablemax; /* largest used index in table */ 1276efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 1277efb7e53dSJordan K. Hubbard 1278efb7e53dSJordan K. Hubbard /* 1279efb7e53dSJordan K. Hubbard * Add an argument type to the table, expanding if necessary. 1280efb7e53dSJordan K. Hubbard */ 1281efb7e53dSJordan K. Hubbard #define ADDTYPE(type) \ 1282efb7e53dSJordan K. Hubbard ((nextarg >= tablesize) ? \ 1283cf6fc341SStefan Farfeleder __grow_type_table(nextarg, &typetable, &tablesize) : (void)0, \ 128442cebaa5SArchie Cobbs (nextarg > tablemax) ? tablemax = nextarg : 0, \ 128542cebaa5SArchie Cobbs typetable[nextarg++] = type) 1286efb7e53dSJordan K. Hubbard 1287efb7e53dSJordan K. Hubbard #define ADDSARG() \ 12887735bb0fSBill Fenner ((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \ 12897735bb0fSBill Fenner ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 12907735bb0fSBill Fenner ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 12917735bb0fSBill Fenner ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \ 12927735bb0fSBill Fenner ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT)))))) 1293efb7e53dSJordan K. Hubbard 1294efb7e53dSJordan K. Hubbard #define ADDUARG() \ 12957735bb0fSBill Fenner ((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \ 12967735bb0fSBill Fenner ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 12977735bb0fSBill Fenner ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 12987735bb0fSBill Fenner ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \ 12997735bb0fSBill Fenner ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT)))))) 1300efb7e53dSJordan K. Hubbard 1301efb7e53dSJordan K. Hubbard /* 1302efb7e53dSJordan K. Hubbard * Add * arguments to the type array. 1303efb7e53dSJordan K. Hubbard */ 1304efb7e53dSJordan K. Hubbard #define ADDASTER() \ 1305efb7e53dSJordan K. Hubbard n2 = 0; \ 1306efb7e53dSJordan K. Hubbard cp = fmt; \ 1307efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 1308efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 1309efb7e53dSJordan K. Hubbard cp++; \ 1310efb7e53dSJordan K. Hubbard } \ 1311efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 1312efb7e53dSJordan K. Hubbard int hold = nextarg; \ 1313efb7e53dSJordan K. Hubbard nextarg = n2; \ 1314efb7e53dSJordan K. Hubbard ADDTYPE (T_INT); \ 1315efb7e53dSJordan K. Hubbard nextarg = hold; \ 1316efb7e53dSJordan K. Hubbard fmt = ++cp; \ 1317efb7e53dSJordan K. Hubbard } else { \ 1318efb7e53dSJordan K. Hubbard ADDTYPE (T_INT); \ 1319efb7e53dSJordan K. Hubbard } 1320efb7e53dSJordan K. Hubbard fmt = (char *)fmt0; 1321efb7e53dSJordan K. Hubbard typetable = stattypetable; 1322efb7e53dSJordan K. Hubbard tablesize = STATIC_ARG_TBL_SIZE; 1323efb7e53dSJordan K. Hubbard tablemax = 0; 1324efb7e53dSJordan K. Hubbard nextarg = 1; 1325ccc8c6c3STim J. Robbins for (n = 0; n < STATIC_ARG_TBL_SIZE; n++) 1326ccc8c6c3STim J. Robbins typetable[n] = T_UNUSED; 1327efb7e53dSJordan K. Hubbard 1328efb7e53dSJordan K. Hubbard /* 1329efb7e53dSJordan K. Hubbard * Scan the format for conversions (`%' character). 1330efb7e53dSJordan K. Hubbard */ 1331efb7e53dSJordan K. Hubbard for (;;) { 1332efb7e53dSJordan K. Hubbard for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 1333efb7e53dSJordan K. Hubbard /* void */; 1334efb7e53dSJordan K. Hubbard if (ch == '\0') 1335efb7e53dSJordan K. Hubbard goto done; 1336efb7e53dSJordan K. Hubbard fmt++; /* skip over '%' */ 1337efb7e53dSJordan K. Hubbard 1338efb7e53dSJordan K. Hubbard flags = 0; 1339efb7e53dSJordan K. Hubbard width = 0; 1340efb7e53dSJordan K. Hubbard 1341efb7e53dSJordan K. Hubbard rflag: ch = *fmt++; 1342efb7e53dSJordan K. Hubbard reswitch: switch (ch) { 1343efb7e53dSJordan K. Hubbard case ' ': 1344efb7e53dSJordan K. Hubbard case '#': 1345efb7e53dSJordan K. Hubbard goto rflag; 1346efb7e53dSJordan K. Hubbard case '*': 1347efb7e53dSJordan K. Hubbard ADDASTER (); 1348efb7e53dSJordan K. Hubbard goto rflag; 1349efb7e53dSJordan K. Hubbard case '-': 1350efb7e53dSJordan K. Hubbard case '+': 13517735bb0fSBill Fenner case '\'': 1352efb7e53dSJordan K. Hubbard goto rflag; 1353efb7e53dSJordan K. Hubbard case '.': 1354efb7e53dSJordan K. Hubbard if ((ch = *fmt++) == '*') { 1355efb7e53dSJordan K. Hubbard ADDASTER (); 1356efb7e53dSJordan K. Hubbard goto rflag; 1357efb7e53dSJordan K. Hubbard } 1358efb7e53dSJordan K. Hubbard while (is_digit(ch)) { 1359efb7e53dSJordan K. Hubbard ch = *fmt++; 1360efb7e53dSJordan K. Hubbard } 1361efb7e53dSJordan K. Hubbard goto reswitch; 1362efb7e53dSJordan K. Hubbard case '0': 1363efb7e53dSJordan K. Hubbard goto rflag; 1364efb7e53dSJordan K. Hubbard case '1': case '2': case '3': case '4': 1365efb7e53dSJordan K. Hubbard case '5': case '6': case '7': case '8': case '9': 1366efb7e53dSJordan K. Hubbard n = 0; 1367efb7e53dSJordan K. Hubbard do { 1368efb7e53dSJordan K. Hubbard n = 10 * n + to_digit(ch); 1369efb7e53dSJordan K. Hubbard ch = *fmt++; 1370efb7e53dSJordan K. Hubbard } while (is_digit(ch)); 1371efb7e53dSJordan K. Hubbard if (ch == '$') { 1372efb7e53dSJordan K. Hubbard nextarg = n; 1373efb7e53dSJordan K. Hubbard goto rflag; 1374efb7e53dSJordan K. Hubbard } 1375efb7e53dSJordan K. Hubbard width = n; 1376efb7e53dSJordan K. Hubbard goto reswitch; 13778de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 1378efb7e53dSJordan K. Hubbard case 'L': 1379efb7e53dSJordan K. Hubbard flags |= LONGDBL; 1380efb7e53dSJordan K. Hubbard goto rflag; 1381efb7e53dSJordan K. Hubbard #endif 1382efb7e53dSJordan K. Hubbard case 'h': 13837735bb0fSBill Fenner if (flags & SHORTINT) { 13847735bb0fSBill Fenner flags &= ~SHORTINT; 13857735bb0fSBill Fenner flags |= CHARINT; 13867735bb0fSBill Fenner } else 1387efb7e53dSJordan K. Hubbard flags |= SHORTINT; 1388efb7e53dSJordan K. Hubbard goto rflag; 13897735bb0fSBill Fenner case 'j': 13907735bb0fSBill Fenner flags |= INTMAXT; 13917735bb0fSBill Fenner goto rflag; 1392efb7e53dSJordan K. Hubbard case 'l': 13937735bb0fSBill Fenner if (flags & LONGINT) { 13947735bb0fSBill Fenner flags &= ~LONGINT; 13957735bb0fSBill Fenner flags |= LLONGINT; 13967735bb0fSBill Fenner } else 1397efb7e53dSJordan K. Hubbard flags |= LONGINT; 1398efb7e53dSJordan K. Hubbard goto rflag; 1399efb7e53dSJordan K. Hubbard case 'q': 14007735bb0fSBill Fenner flags |= LLONGINT; /* not necessarily */ 14017735bb0fSBill Fenner goto rflag; 14027735bb0fSBill Fenner case 't': 14037735bb0fSBill Fenner flags |= PTRDIFFT; 14047735bb0fSBill Fenner goto rflag; 14057735bb0fSBill Fenner case 'z': 14067735bb0fSBill Fenner flags |= SIZET; 1407efb7e53dSJordan K. Hubbard goto rflag; 1408927ecbf3STim J. Robbins case 'C': 1409927ecbf3STim J. Robbins flags |= LONGINT; 1410927ecbf3STim J. Robbins /*FALLTHROUGH*/ 1411efb7e53dSJordan K. Hubbard case 'c': 1412b9aac308STim J. Robbins if (flags & LONGINT) 1413b9aac308STim J. Robbins ADDTYPE(T_WINT); 1414b9aac308STim J. Robbins else 1415efb7e53dSJordan K. Hubbard ADDTYPE(T_INT); 1416efb7e53dSJordan K. Hubbard break; 1417efb7e53dSJordan K. Hubbard case 'D': 1418efb7e53dSJordan K. Hubbard flags |= LONGINT; 1419efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1420efb7e53dSJordan K. Hubbard case 'd': 1421efb7e53dSJordan K. Hubbard case 'i': 1422efb7e53dSJordan K. Hubbard ADDSARG(); 1423efb7e53dSJordan K. Hubbard break; 14248de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 14257735bb0fSBill Fenner case 'a': 14267735bb0fSBill Fenner case 'A': 1427efb7e53dSJordan K. Hubbard case 'e': 1428efb7e53dSJordan K. Hubbard case 'E': 1429efb7e53dSJordan K. Hubbard case 'f': 1430efb7e53dSJordan K. Hubbard case 'g': 1431efb7e53dSJordan K. Hubbard case 'G': 1432efb7e53dSJordan K. Hubbard if (flags & LONGDBL) 1433efb7e53dSJordan K. Hubbard ADDTYPE(T_LONG_DOUBLE); 1434efb7e53dSJordan K. Hubbard else 1435efb7e53dSJordan K. Hubbard ADDTYPE(T_DOUBLE); 1436efb7e53dSJordan K. Hubbard break; 14378de9e897SDavid Schultz #endif /* !NO_FLOATING_POINT */ 1438efb7e53dSJordan K. Hubbard case 'n': 14397735bb0fSBill Fenner if (flags & INTMAXT) 14407735bb0fSBill Fenner ADDTYPE(TP_INTMAXT); 14417735bb0fSBill Fenner else if (flags & PTRDIFFT) 14427735bb0fSBill Fenner ADDTYPE(TP_PTRDIFFT); 14437735bb0fSBill Fenner else if (flags & SIZET) 14447735bb0fSBill Fenner ADDTYPE(TP_SIZET); 14457735bb0fSBill Fenner else if (flags & LLONGINT) 14467735bb0fSBill Fenner ADDTYPE(TP_LLONG); 1447efb7e53dSJordan K. Hubbard else if (flags & LONGINT) 1448efb7e53dSJordan K. Hubbard ADDTYPE(TP_LONG); 1449efb7e53dSJordan K. Hubbard else if (flags & SHORTINT) 1450efb7e53dSJordan K. Hubbard ADDTYPE(TP_SHORT); 14517735bb0fSBill Fenner else if (flags & CHARINT) 14527735bb0fSBill Fenner ADDTYPE(TP_SCHAR); 1453efb7e53dSJordan K. Hubbard else 1454efb7e53dSJordan K. Hubbard ADDTYPE(TP_INT); 1455efb7e53dSJordan K. Hubbard continue; /* no output */ 1456efb7e53dSJordan K. Hubbard case 'O': 1457efb7e53dSJordan K. Hubbard flags |= LONGINT; 1458efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1459efb7e53dSJordan K. Hubbard case 'o': 1460efb7e53dSJordan K. Hubbard ADDUARG(); 1461efb7e53dSJordan K. Hubbard break; 1462efb7e53dSJordan K. Hubbard case 'p': 1463efb7e53dSJordan K. Hubbard ADDTYPE(TP_VOID); 1464efb7e53dSJordan K. Hubbard break; 1465927ecbf3STim J. Robbins case 'S': 1466927ecbf3STim J. Robbins flags |= LONGINT; 1467927ecbf3STim J. Robbins /*FALLTHROUGH*/ 1468efb7e53dSJordan K. Hubbard case 's': 1469b9aac308STim J. Robbins if (flags & LONGINT) 1470b9aac308STim J. Robbins ADDTYPE(TP_WCHAR); 1471b9aac308STim J. Robbins else 1472efb7e53dSJordan K. Hubbard ADDTYPE(TP_CHAR); 1473efb7e53dSJordan K. Hubbard break; 1474efb7e53dSJordan K. Hubbard case 'U': 1475efb7e53dSJordan K. Hubbard flags |= LONGINT; 1476efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1477efb7e53dSJordan K. Hubbard case 'u': 1478efb7e53dSJordan K. Hubbard case 'X': 1479efb7e53dSJordan K. Hubbard case 'x': 1480efb7e53dSJordan K. Hubbard ADDUARG(); 1481efb7e53dSJordan K. Hubbard break; 1482efb7e53dSJordan K. Hubbard default: /* "%?" prints ?, unless ? is NUL */ 1483efb7e53dSJordan K. Hubbard if (ch == '\0') 1484efb7e53dSJordan K. Hubbard goto done; 1485efb7e53dSJordan K. Hubbard break; 1486efb7e53dSJordan K. Hubbard } 1487efb7e53dSJordan K. Hubbard } 1488efb7e53dSJordan K. Hubbard done: 1489efb7e53dSJordan K. Hubbard /* 1490efb7e53dSJordan K. Hubbard * Build the argument table. 1491efb7e53dSJordan K. Hubbard */ 1492efb7e53dSJordan K. Hubbard if (tablemax >= STATIC_ARG_TBL_SIZE) { 1493a387081cSDoug Rabson *argtable = (union arg *) 1494a387081cSDoug Rabson malloc (sizeof (union arg) * (tablemax + 1)); 1495efb7e53dSJordan K. Hubbard } 1496efb7e53dSJordan K. Hubbard 1497a387081cSDoug Rabson (*argtable) [0].intarg = 0; 1498efb7e53dSJordan K. Hubbard for (n = 1; n <= tablemax; n++) { 1499efb7e53dSJordan K. Hubbard switch (typetable [n]) { 15007735bb0fSBill Fenner case T_UNUSED: /* whoops! */ 1501a387081cSDoug Rabson (*argtable) [n].intarg = va_arg (ap, int); 1502efb7e53dSJordan K. Hubbard break; 15037735bb0fSBill Fenner case TP_SCHAR: 15047735bb0fSBill Fenner (*argtable) [n].pschararg = va_arg (ap, signed char *); 1505efb7e53dSJordan K. Hubbard break; 1506efb7e53dSJordan K. Hubbard case TP_SHORT: 1507a387081cSDoug Rabson (*argtable) [n].pshortarg = va_arg (ap, short *); 1508efb7e53dSJordan K. Hubbard break; 1509efb7e53dSJordan K. Hubbard case T_INT: 1510a387081cSDoug Rabson (*argtable) [n].intarg = va_arg (ap, int); 1511efb7e53dSJordan K. Hubbard break; 1512efb7e53dSJordan K. Hubbard case T_U_INT: 1513a387081cSDoug Rabson (*argtable) [n].uintarg = va_arg (ap, unsigned int); 1514efb7e53dSJordan K. Hubbard break; 1515efb7e53dSJordan K. Hubbard case TP_INT: 1516a387081cSDoug Rabson (*argtable) [n].pintarg = va_arg (ap, int *); 1517efb7e53dSJordan K. Hubbard break; 1518efb7e53dSJordan K. Hubbard case T_LONG: 1519a387081cSDoug Rabson (*argtable) [n].longarg = va_arg (ap, long); 1520efb7e53dSJordan K. Hubbard break; 1521efb7e53dSJordan K. Hubbard case T_U_LONG: 1522a387081cSDoug Rabson (*argtable) [n].ulongarg = va_arg (ap, unsigned long); 1523efb7e53dSJordan K. Hubbard break; 1524efb7e53dSJordan K. Hubbard case TP_LONG: 1525a387081cSDoug Rabson (*argtable) [n].plongarg = va_arg (ap, long *); 1526efb7e53dSJordan K. Hubbard break; 15277735bb0fSBill Fenner case T_LLONG: 15287735bb0fSBill Fenner (*argtable) [n].longlongarg = va_arg (ap, long long); 1529efb7e53dSJordan K. Hubbard break; 15307735bb0fSBill Fenner case T_U_LLONG: 15317735bb0fSBill Fenner (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); 1532efb7e53dSJordan K. Hubbard break; 15337735bb0fSBill Fenner case TP_LLONG: 15347735bb0fSBill Fenner (*argtable) [n].plonglongarg = va_arg (ap, long long *); 15357735bb0fSBill Fenner break; 15367735bb0fSBill Fenner case T_PTRDIFFT: 15377735bb0fSBill Fenner (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); 15387735bb0fSBill Fenner break; 15397735bb0fSBill Fenner case TP_PTRDIFFT: 15407735bb0fSBill Fenner (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); 15417735bb0fSBill Fenner break; 15427735bb0fSBill Fenner case T_SIZET: 15437735bb0fSBill Fenner (*argtable) [n].sizearg = va_arg (ap, size_t); 15447735bb0fSBill Fenner break; 15457735bb0fSBill Fenner case TP_SIZET: 15467735bb0fSBill Fenner (*argtable) [n].psizearg = va_arg (ap, ssize_t *); 15477735bb0fSBill Fenner break; 15487735bb0fSBill Fenner case T_INTMAXT: 15497735bb0fSBill Fenner (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); 15507735bb0fSBill Fenner break; 15517735bb0fSBill Fenner case T_UINTMAXT: 15527735bb0fSBill Fenner (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); 15537735bb0fSBill Fenner break; 15547735bb0fSBill Fenner case TP_INTMAXT: 15557735bb0fSBill Fenner (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); 1556efb7e53dSJordan K. Hubbard break; 15578de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 1558efb7e53dSJordan K. Hubbard case T_DOUBLE: 1559a387081cSDoug Rabson (*argtable) [n].doublearg = va_arg (ap, double); 1560efb7e53dSJordan K. Hubbard break; 1561efb7e53dSJordan K. Hubbard case T_LONG_DOUBLE: 1562a387081cSDoug Rabson (*argtable) [n].longdoublearg = va_arg (ap, long double); 1563efb7e53dSJordan K. Hubbard break; 1564a387081cSDoug Rabson #endif 1565efb7e53dSJordan K. Hubbard case TP_CHAR: 1566a387081cSDoug Rabson (*argtable) [n].pchararg = va_arg (ap, char *); 1567efb7e53dSJordan K. Hubbard break; 1568efb7e53dSJordan K. Hubbard case TP_VOID: 1569a387081cSDoug Rabson (*argtable) [n].pvoidarg = va_arg (ap, void *); 1570efb7e53dSJordan K. Hubbard break; 1571b9aac308STim J. Robbins case T_WINT: 1572b9aac308STim J. Robbins (*argtable) [n].wintarg = va_arg (ap, wint_t); 1573b9aac308STim J. Robbins break; 1574b9aac308STim J. Robbins case TP_WCHAR: 1575b9aac308STim J. Robbins (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); 1576b9aac308STim J. Robbins break; 1577efb7e53dSJordan K. Hubbard } 1578efb7e53dSJordan K. Hubbard } 1579efb7e53dSJordan K. Hubbard 1580efb7e53dSJordan K. Hubbard if ((typetable != NULL) && (typetable != stattypetable)) 1581efb7e53dSJordan K. Hubbard free (typetable); 1582efb7e53dSJordan K. Hubbard } 1583efb7e53dSJordan K. Hubbard 1584efb7e53dSJordan K. Hubbard /* 1585efb7e53dSJordan K. Hubbard * Increase the size of the type table. 1586efb7e53dSJordan K. Hubbard */ 1587efb7e53dSJordan K. Hubbard static void 15887735bb0fSBill Fenner __grow_type_table (int nextarg, enum typeid **typetable, int *tablesize) 1589efb7e53dSJordan K. Hubbard { 15907735bb0fSBill Fenner enum typeid *const oldtable = *typetable; 159142cebaa5SArchie Cobbs const int oldsize = *tablesize; 15927735bb0fSBill Fenner enum typeid *newtable; 1593ccc8c6c3STim J. Robbins int n, newsize = oldsize * 2; 1594efb7e53dSJordan K. Hubbard 159542cebaa5SArchie Cobbs if (newsize < nextarg + 1) 159642cebaa5SArchie Cobbs newsize = nextarg + 1; 159742cebaa5SArchie Cobbs if (oldsize == STATIC_ARG_TBL_SIZE) { 1598ccc8c6c3STim J. Robbins if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL) 159942cebaa5SArchie Cobbs abort(); /* XXX handle better */ 1600ccc8c6c3STim J. Robbins bcopy(oldtable, newtable, oldsize * sizeof(enum typeid)); 1601efb7e53dSJordan K. Hubbard } else { 1602ccc8c6c3STim J. Robbins newtable = reallocf(oldtable, newsize * sizeof(enum typeid)); 1603ccc8c6c3STim J. Robbins if (newtable == NULL) 160442cebaa5SArchie Cobbs abort(); /* XXX handle better */ 1605efb7e53dSJordan K. Hubbard } 1606ccc8c6c3STim J. Robbins for (n = oldsize; n < newsize; n++) 1607ccc8c6c3STim J. Robbins newtable[n] = T_UNUSED; 1608efb7e53dSJordan K. Hubbard 160942cebaa5SArchie Cobbs *typetable = newtable; 1610efb7e53dSJordan K. Hubbard *tablesize = newsize; 1611efb7e53dSJordan K. Hubbard } 1612efb7e53dSJordan K. Hubbard 1613efb7e53dSJordan K. Hubbard 16148de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 161558f0484fSRodney W. Grimes 161658f0484fSRodney W. Grimes static int 1617d201fe46SDaniel Eischen exponent(char *p0, int exp, int fmtch) 161858f0484fSRodney W. Grimes { 1619d201fe46SDaniel Eischen char *p, *t; 162038cac8f8SDavid Schultz char expbuf[MAXEXPDIG]; 162158f0484fSRodney W. Grimes 162258f0484fSRodney W. Grimes p = p0; 162358f0484fSRodney W. Grimes *p++ = fmtch; 162458f0484fSRodney W. Grimes if (exp < 0) { 162558f0484fSRodney W. Grimes exp = -exp; 162658f0484fSRodney W. Grimes *p++ = '-'; 162758f0484fSRodney W. Grimes } 162858f0484fSRodney W. Grimes else 162958f0484fSRodney W. Grimes *p++ = '+'; 163038cac8f8SDavid Schultz t = expbuf + MAXEXPDIG; 163158f0484fSRodney W. Grimes if (exp > 9) { 163258f0484fSRodney W. Grimes do { 163358f0484fSRodney W. Grimes *--t = to_char(exp % 10); 163458f0484fSRodney W. Grimes } while ((exp /= 10) > 9); 163558f0484fSRodney W. Grimes *--t = to_char(exp); 163638cac8f8SDavid Schultz for (; t < expbuf + MAXEXPDIG; *p++ = *t++); 163758f0484fSRodney W. Grimes } 163858f0484fSRodney W. Grimes else { 1639ebbad5ecSDavid Schultz /* 1640ebbad5ecSDavid Schultz * Exponents for decimal floating point conversions 1641ebbad5ecSDavid Schultz * (%[eEgG]) must be at least two characters long, 1642ebbad5ecSDavid Schultz * whereas exponents for hexadecimal conversions can 1643ebbad5ecSDavid Schultz * be only one character long. 1644ebbad5ecSDavid Schultz */ 1645ebbad5ecSDavid Schultz if (fmtch == 'e' || fmtch == 'E') 164658f0484fSRodney W. Grimes *p++ = '0'; 164758f0484fSRodney W. Grimes *p++ = to_char(exp); 164858f0484fSRodney W. Grimes } 164958f0484fSRodney W. Grimes return (p - p0); 165058f0484fSRodney W. Grimes } 16518de9e897SDavid Schultz #endif /* !NO_FLOATING_POINT */ 1652