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 6958f0484fSRodney W. Grimes /* Define FLOATING_POINT to get floating point. */ 7058f0484fSRodney W. Grimes #define FLOATING_POINT 7158f0484fSRodney W. Grimes 72a387081cSDoug Rabson union arg { 73a387081cSDoug Rabson int intarg; 7418ca70d1SBruce Evans u_int uintarg; 75a387081cSDoug Rabson long longarg; 7618ca70d1SBruce Evans u_long ulongarg; 777735bb0fSBill Fenner long long longlongarg; 787735bb0fSBill Fenner unsigned long long ulonglongarg; 797735bb0fSBill Fenner ptrdiff_t ptrdiffarg; 807735bb0fSBill Fenner size_t sizearg; 817735bb0fSBill Fenner intmax_t intmaxarg; 827735bb0fSBill Fenner uintmax_t uintmaxarg; 83a387081cSDoug Rabson void *pvoidarg; 84a387081cSDoug Rabson char *pchararg; 857735bb0fSBill Fenner signed char *pschararg; 86a387081cSDoug Rabson short *pshortarg; 87a387081cSDoug Rabson int *pintarg; 88a387081cSDoug Rabson long *plongarg; 897735bb0fSBill Fenner long long *plonglongarg; 907735bb0fSBill Fenner ptrdiff_t *pptrdiffarg; 917735bb0fSBill Fenner size_t *psizearg; 927735bb0fSBill Fenner intmax_t *pintmaxarg; 93a387081cSDoug Rabson #ifdef FLOATING_POINT 94a387081cSDoug Rabson double doublearg; 95a387081cSDoug Rabson long double longdoublearg; 96a387081cSDoug Rabson #endif 97b9aac308STim J. Robbins wint_t wintarg; 98b9aac308STim J. Robbins wchar_t *pwchararg; 99a387081cSDoug Rabson }; 100a387081cSDoug Rabson 1017735bb0fSBill Fenner /* 1027735bb0fSBill Fenner * Type ids for argument type table. 1037735bb0fSBill Fenner */ 1047735bb0fSBill Fenner enum typeid { 1057735bb0fSBill Fenner T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, 1067735bb0fSBill Fenner T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, 1077735bb0fSBill Fenner T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET, 1087735bb0fSBill Fenner T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, 109b9aac308STim J. Robbins T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR 1107735bb0fSBill Fenner }; 1117735bb0fSBill Fenner 112c05ac53bSDavid E. O'Brien static int __sprint(FILE *, struct __suio *); 1131372519bSDavid E. O'Brien static int __sbprintf(FILE *, const char *, va_list) __printflike(2, 0); 1141372519bSDavid E. O'Brien static char *__ujtoa(uintmax_t, char *, int, int, char *, int, char, 1151372519bSDavid E. O'Brien const char *); 1161372519bSDavid E. O'Brien static char *__ultoa(u_long, char *, int, int, char *, int, char, 1171372519bSDavid E. O'Brien const char *); 118b9aac308STim J. Robbins static char *__wcsconv(wchar_t *, int); 119c05ac53bSDavid E. O'Brien static void __find_arguments(const char *, va_list, union arg **); 120c05ac53bSDavid E. O'Brien static void __grow_type_table(int, enum typeid **, int *); 121ce51cf03SJames Raynard 12258f0484fSRodney W. Grimes /* 12358f0484fSRodney W. Grimes * Flush out all the vectors defined by the given uio, 12458f0484fSRodney W. Grimes * then reset it so that it can be reused. 12558f0484fSRodney W. Grimes */ 12658f0484fSRodney W. Grimes static int 127d201fe46SDaniel Eischen __sprint(FILE *fp, struct __suio *uio) 12858f0484fSRodney W. Grimes { 129d201fe46SDaniel Eischen int err; 13058f0484fSRodney W. Grimes 13158f0484fSRodney W. Grimes if (uio->uio_resid == 0) { 13258f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 13358f0484fSRodney W. Grimes return (0); 13458f0484fSRodney W. Grimes } 13558f0484fSRodney W. Grimes err = __sfvwrite(fp, uio); 13658f0484fSRodney W. Grimes uio->uio_resid = 0; 13758f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 13858f0484fSRodney W. Grimes return (err); 13958f0484fSRodney W. Grimes } 14058f0484fSRodney W. Grimes 14158f0484fSRodney W. Grimes /* 14258f0484fSRodney W. Grimes * Helper function for `fprintf to unbuffered unix file': creates a 14358f0484fSRodney W. Grimes * temporary buffer. We only work on write-only files; this avoids 14458f0484fSRodney W. Grimes * worries about ungetc buffers and so forth. 14558f0484fSRodney W. Grimes */ 14658f0484fSRodney W. Grimes static int 147d201fe46SDaniel Eischen __sbprintf(FILE *fp, const char *fmt, va_list ap) 14858f0484fSRodney W. Grimes { 14958f0484fSRodney W. Grimes int ret; 15058f0484fSRodney W. Grimes FILE fake; 15158f0484fSRodney W. Grimes unsigned char buf[BUFSIZ]; 15258f0484fSRodney W. Grimes 15358f0484fSRodney W. Grimes /* copy the important variables */ 15458f0484fSRodney W. Grimes fake._flags = fp->_flags & ~__SNBF; 15558f0484fSRodney W. Grimes fake._file = fp->_file; 15658f0484fSRodney W. Grimes fake._cookie = fp->_cookie; 15758f0484fSRodney W. Grimes fake._write = fp->_write; 158e74101e4STim J. Robbins fake._extra = fp->_extra; 15958f0484fSRodney W. Grimes 16058f0484fSRodney W. Grimes /* set up the buffer */ 16158f0484fSRodney W. Grimes fake._bf._base = fake._p = buf; 16258f0484fSRodney W. Grimes fake._bf._size = fake._w = sizeof(buf); 16358f0484fSRodney W. Grimes fake._lbfsize = 0; /* not actually used, but Just In Case */ 16458f0484fSRodney W. Grimes 16558f0484fSRodney W. Grimes /* do the work, then copy any error status */ 166d201fe46SDaniel Eischen ret = __vfprintf(&fake, fmt, ap); 167d201fe46SDaniel Eischen if (ret >= 0 && __fflush(&fake)) 16858f0484fSRodney W. Grimes ret = EOF; 16958f0484fSRodney W. Grimes if (fake._flags & __SERR) 17058f0484fSRodney W. Grimes fp->_flags |= __SERR; 17158f0484fSRodney W. Grimes return (ret); 17258f0484fSRodney W. Grimes } 17358f0484fSRodney W. Grimes 17458f0484fSRodney W. Grimes /* 17558f0484fSRodney W. Grimes * Macros for converting digits to letters and vice versa 17658f0484fSRodney W. Grimes */ 17758f0484fSRodney W. Grimes #define to_digit(c) ((c) - '0') 17858f0484fSRodney W. Grimes #define is_digit(c) ((unsigned)to_digit(c) <= 9) 17958f0484fSRodney W. Grimes #define to_char(n) ((n) + '0') 18058f0484fSRodney W. Grimes 18158f0484fSRodney W. Grimes /* 18258f0484fSRodney W. Grimes * Convert an unsigned long to ASCII for printf purposes, returning 18358f0484fSRodney W. Grimes * a pointer to the first character of the string representation. 18458f0484fSRodney W. Grimes * Octal numbers can be forced to have a leading zero; hex numbers 18558f0484fSRodney W. Grimes * use the given digits. 18658f0484fSRodney W. Grimes */ 18758f0484fSRodney W. Grimes static char * 1887735bb0fSBill Fenner __ultoa(u_long val, char *endp, int base, int octzero, char *xdigs, 18998ee7635SAlexey Zelkin int needgrp, char thousep, const char *grp) 19058f0484fSRodney W. Grimes { 1918fb3f3f6SDavid E. O'Brien char *cp = endp; 1928fb3f3f6SDavid E. O'Brien long sval; 1937735bb0fSBill Fenner int ndig; 19458f0484fSRodney W. Grimes 19558f0484fSRodney W. Grimes /* 19658f0484fSRodney W. Grimes * Handle the three cases separately, in the hope of getting 19758f0484fSRodney W. Grimes * better/faster code. 19858f0484fSRodney W. Grimes */ 19958f0484fSRodney W. Grimes switch (base) { 20058f0484fSRodney W. Grimes case 10: 20158f0484fSRodney W. Grimes if (val < 10) { /* many numbers are 1 digit */ 20258f0484fSRodney W. Grimes *--cp = to_char(val); 20358f0484fSRodney W. Grimes return (cp); 20458f0484fSRodney W. Grimes } 2057735bb0fSBill Fenner ndig = 0; 20658f0484fSRodney W. Grimes /* 20758f0484fSRodney W. Grimes * On many machines, unsigned arithmetic is harder than 20858f0484fSRodney W. Grimes * signed arithmetic, so we do at most one unsigned mod and 20958f0484fSRodney W. Grimes * divide; this is sufficient to reduce the range of 21058f0484fSRodney W. Grimes * the incoming value to where signed arithmetic works. 21158f0484fSRodney W. Grimes */ 21258f0484fSRodney W. Grimes if (val > LONG_MAX) { 21358f0484fSRodney W. Grimes *--cp = to_char(val % 10); 2147735bb0fSBill Fenner ndig++; 21558f0484fSRodney W. Grimes sval = val / 10; 21658f0484fSRodney W. Grimes } else 21758f0484fSRodney W. Grimes sval = val; 21858f0484fSRodney W. Grimes do { 21958f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 22098ee7635SAlexey Zelkin ndig++; 22198ee7635SAlexey Zelkin /* 22298ee7635SAlexey Zelkin * If (*grp == CHAR_MAX) then no more grouping 22398ee7635SAlexey Zelkin * should be performed. 22498ee7635SAlexey Zelkin */ 225243e90d6SAlexey Zelkin if (needgrp && ndig == *grp && *grp != CHAR_MAX 226243e90d6SAlexey Zelkin && sval > 9) { 22798ee7635SAlexey Zelkin *--cp = thousep; 2287735bb0fSBill Fenner ndig = 0; 22998ee7635SAlexey Zelkin /* 23098ee7635SAlexey Zelkin * If (*(grp+1) == '\0') then we have to 23198ee7635SAlexey Zelkin * use *grp character (last grouping rule) 23298ee7635SAlexey Zelkin * for all next cases 23398ee7635SAlexey Zelkin */ 2342e394b2fSAlexey Zelkin if (*(grp+1) != '\0') 2352e394b2fSAlexey Zelkin grp++; 2367735bb0fSBill Fenner } 23758f0484fSRodney W. Grimes sval /= 10; 23858f0484fSRodney W. Grimes } while (sval != 0); 23958f0484fSRodney W. Grimes break; 24058f0484fSRodney W. Grimes 24158f0484fSRodney W. Grimes case 8: 24258f0484fSRodney W. Grimes do { 24358f0484fSRodney W. Grimes *--cp = to_char(val & 7); 24458f0484fSRodney W. Grimes val >>= 3; 24558f0484fSRodney W. Grimes } while (val); 24658f0484fSRodney W. Grimes if (octzero && *cp != '0') 24758f0484fSRodney W. Grimes *--cp = '0'; 24858f0484fSRodney W. Grimes break; 24958f0484fSRodney W. Grimes 25058f0484fSRodney W. Grimes case 16: 25158f0484fSRodney W. Grimes do { 25258f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 25358f0484fSRodney W. Grimes val >>= 4; 25458f0484fSRodney W. Grimes } while (val); 25558f0484fSRodney W. Grimes break; 25658f0484fSRodney W. Grimes 25758f0484fSRodney W. Grimes default: /* oops */ 25858f0484fSRodney W. Grimes abort(); 25958f0484fSRodney W. Grimes } 26058f0484fSRodney W. Grimes return (cp); 26158f0484fSRodney W. Grimes } 26258f0484fSRodney W. Grimes 2637735bb0fSBill Fenner /* Identical to __ultoa, but for intmax_t. */ 26458f0484fSRodney W. Grimes static char * 2657735bb0fSBill Fenner __ujtoa(uintmax_t val, char *endp, int base, int octzero, char *xdigs, 26698ee7635SAlexey Zelkin int needgrp, char thousep, const char *grp) 26758f0484fSRodney W. Grimes { 268d201fe46SDaniel Eischen char *cp = endp; 2697735bb0fSBill Fenner intmax_t sval; 2707735bb0fSBill Fenner int ndig; 27158f0484fSRodney W. Grimes 27258f0484fSRodney W. Grimes /* quick test for small values; __ultoa is typically much faster */ 27358f0484fSRodney W. Grimes /* (perhaps instead we should run until small, then call __ultoa?) */ 27458f0484fSRodney W. Grimes if (val <= ULONG_MAX) 2757735bb0fSBill Fenner return (__ultoa((u_long)val, endp, base, octzero, xdigs, 27698ee7635SAlexey Zelkin needgrp, thousep, grp)); 27758f0484fSRodney W. Grimes switch (base) { 27858f0484fSRodney W. Grimes case 10: 27958f0484fSRodney W. Grimes if (val < 10) { 28058f0484fSRodney W. Grimes *--cp = to_char(val % 10); 28158f0484fSRodney W. Grimes return (cp); 28258f0484fSRodney W. Grimes } 2837735bb0fSBill Fenner ndig = 0; 2847735bb0fSBill Fenner if (val > INTMAX_MAX) { 28558f0484fSRodney W. Grimes *--cp = to_char(val % 10); 2867735bb0fSBill Fenner ndig++; 28758f0484fSRodney W. Grimes sval = val / 10; 28858f0484fSRodney W. Grimes } else 28958f0484fSRodney W. Grimes sval = val; 29058f0484fSRodney W. Grimes do { 29158f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 29298ee7635SAlexey Zelkin ndig++; 29398ee7635SAlexey Zelkin /* 29498ee7635SAlexey Zelkin * If (*grp == CHAR_MAX) then no more grouping 29598ee7635SAlexey Zelkin * should be performed. 29698ee7635SAlexey Zelkin */ 297243e90d6SAlexey Zelkin if (needgrp && *grp != CHAR_MAX && ndig == *grp 298243e90d6SAlexey Zelkin && sval > 9) { 29998ee7635SAlexey Zelkin *--cp = thousep; 3007735bb0fSBill Fenner ndig = 0; 30198ee7635SAlexey Zelkin /* 30298ee7635SAlexey Zelkin * If (*(grp+1) == '\0') then we have to 30398ee7635SAlexey Zelkin * use *grp character (last grouping rule) 30498ee7635SAlexey Zelkin * for all next cases 30598ee7635SAlexey Zelkin */ 3062e394b2fSAlexey Zelkin if (*(grp+1) != '\0') 3072e394b2fSAlexey Zelkin grp++; 3087735bb0fSBill Fenner } 30958f0484fSRodney W. Grimes sval /= 10; 31058f0484fSRodney W. Grimes } while (sval != 0); 31158f0484fSRodney W. Grimes break; 31258f0484fSRodney W. Grimes 31358f0484fSRodney W. Grimes case 8: 31458f0484fSRodney W. Grimes do { 31558f0484fSRodney W. Grimes *--cp = to_char(val & 7); 31658f0484fSRodney W. Grimes val >>= 3; 31758f0484fSRodney W. Grimes } while (val); 31858f0484fSRodney W. Grimes if (octzero && *cp != '0') 31958f0484fSRodney W. Grimes *--cp = '0'; 32058f0484fSRodney W. Grimes break; 32158f0484fSRodney W. Grimes 32258f0484fSRodney W. Grimes case 16: 32358f0484fSRodney W. Grimes do { 32458f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 32558f0484fSRodney W. Grimes val >>= 4; 32658f0484fSRodney W. Grimes } while (val); 32758f0484fSRodney W. Grimes break; 32858f0484fSRodney W. Grimes 32958f0484fSRodney W. Grimes default: 33058f0484fSRodney W. Grimes abort(); 33158f0484fSRodney W. Grimes } 33258f0484fSRodney W. Grimes return (cp); 33358f0484fSRodney W. Grimes } 33458f0484fSRodney W. Grimes 335d201fe46SDaniel Eischen /* 336b9aac308STim J. Robbins * Convert a wide character string argument for the %ls format to a multibyte 337b9aac308STim J. Robbins * string representation. ``prec'' specifies the maximum number of bytes 338b9aac308STim J. Robbins * to output. If ``prec'' is greater than or equal to zero, we can't assume 339b9aac308STim J. Robbins * that the wide char. string ends in a null character. 340b9aac308STim J. Robbins */ 341b9aac308STim J. Robbins static char * 342b9aac308STim J. Robbins __wcsconv(wchar_t *wcsarg, int prec) 343b9aac308STim J. Robbins { 344b9aac308STim J. Robbins char buf[MB_LEN_MAX]; 345b9aac308STim J. Robbins wchar_t *p; 346b9aac308STim J. Robbins char *convbuf, *mbp; 347b9aac308STim J. Robbins size_t clen, nbytes; 348b9aac308STim J. Robbins mbstate_t mbs; 349b9aac308STim J. Robbins 350b9aac308STim J. Robbins /* 351b9aac308STim J. Robbins * Determine the number of bytes to output and allocate space for 352b9aac308STim J. Robbins * the output. 353b9aac308STim J. Robbins */ 354b9aac308STim J. Robbins memset(&mbs, 0, sizeof(mbs)); 355b9aac308STim J. Robbins if (prec >= 0) { 356b9aac308STim J. Robbins nbytes = 0; 357b9aac308STim J. Robbins p = wcsarg; 358b9aac308STim J. Robbins for (;;) { 359b9aac308STim J. Robbins clen = wcrtomb(buf, *p++, &mbs); 360b9aac308STim J. Robbins if (clen == 0 || clen == (size_t)-1 || 361b9aac308STim J. Robbins nbytes + clen > prec) 362b9aac308STim J. Robbins break; 363b9aac308STim J. Robbins nbytes += clen; 364b9aac308STim J. Robbins } 365b9aac308STim J. Robbins } else { 366b9aac308STim J. Robbins p = wcsarg; 367b9aac308STim J. Robbins nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); 368b9aac308STim J. Robbins if (nbytes == (size_t)-1) 369b9aac308STim J. Robbins return (NULL); 370b9aac308STim J. Robbins } 371b9aac308STim J. Robbins if ((convbuf = malloc(nbytes + 1)) == NULL) 372b9aac308STim J. Robbins return (NULL); 373b9aac308STim J. Robbins 374b9aac308STim J. Robbins /* 375b9aac308STim J. Robbins * Fill the output buffer with the multibyte representations of as 376b9aac308STim J. Robbins * many wide characters as will fit. 377b9aac308STim J. Robbins */ 378b9aac308STim J. Robbins mbp = convbuf; 379b9aac308STim J. Robbins p = wcsarg; 380b9aac308STim J. Robbins memset(&mbs, 0, sizeof(mbs)); 381b9aac308STim J. Robbins while (mbp - convbuf < nbytes) { 382b9aac308STim J. Robbins clen = wcrtomb(mbp, *p++, &mbs); 383b9aac308STim J. Robbins if (clen == 0 || clen == (size_t)-1) 384b9aac308STim J. Robbins break; 385b9aac308STim J. Robbins mbp += clen; 386b9aac308STim J. Robbins } 387b9aac308STim J. Robbins *mbp = '\0'; 388b9aac308STim J. Robbins if (clen == (size_t)-1) 389b9aac308STim J. Robbins return (NULL); 390b9aac308STim J. Robbins 391b9aac308STim J. Robbins return (convbuf); 392b9aac308STim J. Robbins } 393b9aac308STim J. Robbins 394b9aac308STim J. Robbins /* 395d201fe46SDaniel Eischen * MT-safe version 396d201fe46SDaniel Eischen */ 397d201fe46SDaniel Eischen int 398f8418db7SRobert Drehmel vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) 399f8418db7SRobert Drehmel 400d201fe46SDaniel Eischen { 401d201fe46SDaniel Eischen int ret; 402d201fe46SDaniel Eischen 403d201fe46SDaniel Eischen FLOCKFILE(fp); 404d201fe46SDaniel Eischen ret = __vfprintf(fp, fmt0, ap); 405d201fe46SDaniel Eischen FUNLOCKFILE(fp); 406d201fe46SDaniel Eischen return (ret); 407d201fe46SDaniel Eischen } 408d201fe46SDaniel Eischen 40958f0484fSRodney W. Grimes #ifdef FLOATING_POINT 41058f0484fSRodney W. Grimes #include <math.h> 41158f0484fSRodney W. Grimes #include "floatio.h" 41258f0484fSRodney W. Grimes 41358f0484fSRodney W. Grimes #define DEFPREC 6 41458f0484fSRodney W. Grimes 4156a66acb5SDavid Schultz extern char *__dtoa(double, int, int, int *, int *, char **); 4166a66acb5SDavid Schultz extern void __freedtoa(char *s); 4176a66acb5SDavid Schultz 4186a66acb5SDavid Schultz static char *cvt(double, int, int, char *, int *, int, int *); 419c05ac53bSDavid E. O'Brien static int exponent(char *, int, int); 42058f0484fSRodney W. Grimes 42158f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 42258f0484fSRodney W. Grimes 42338cac8f8SDavid Schultz /* 42438cac8f8SDavid Schultz * The size of the buffer we use as scratch space for integer 42538cac8f8SDavid Schultz * conversions, among other things. Technically, we would need the 42638cac8f8SDavid Schultz * most space for base 10 conversions with thousands' grouping 42738cac8f8SDavid Schultz * characters between each pair of digits. 100 bytes is a 42838cac8f8SDavid Schultz * conservative overestimate even for a 128-bit uintmax_t. 42938cac8f8SDavid Schultz */ 43038cac8f8SDavid Schultz #define BUF 100 43138cac8f8SDavid Schultz 432efb7e53dSJordan K. Hubbard #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 43358f0484fSRodney W. Grimes 43458f0484fSRodney W. Grimes /* 43558f0484fSRodney W. Grimes * Flags used during conversion. 43658f0484fSRodney W. Grimes */ 43758f0484fSRodney W. Grimes #define ALT 0x001 /* alternate form */ 43858f0484fSRodney W. Grimes #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 43958f0484fSRodney W. Grimes #define LADJUST 0x004 /* left adjustment */ 4406a93659fSBruce Evans #define LONGDBL 0x008 /* long double */ 44158f0484fSRodney W. Grimes #define LONGINT 0x010 /* long integer */ 4427735bb0fSBill Fenner #define LLONGINT 0x020 /* long long integer */ 44358f0484fSRodney W. Grimes #define SHORTINT 0x040 /* short integer */ 44458f0484fSRodney W. Grimes #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 44558f0484fSRodney W. Grimes #define FPT 0x100 /* Floating point number */ 44698ee7635SAlexey Zelkin #define GROUPING 0x200 /* use grouping ("'" flag) */ 4477735bb0fSBill Fenner /* C99 additional size modifiers: */ 44898ee7635SAlexey Zelkin #define SIZET 0x400 /* size_t */ 44998ee7635SAlexey Zelkin #define PTRDIFFT 0x800 /* ptrdiff_t */ 45098ee7635SAlexey Zelkin #define INTMAXT 0x1000 /* intmax_t */ 45198ee7635SAlexey Zelkin #define CHARINT 0x2000 /* print char using int format */ 4527735bb0fSBill Fenner 453d201fe46SDaniel Eischen /* 454d201fe46SDaniel Eischen * Non-MT-safe version 455d201fe46SDaniel Eischen */ 45658f0484fSRodney W. Grimes int 457d201fe46SDaniel Eischen __vfprintf(FILE *fp, const char *fmt0, va_list ap) 45858f0484fSRodney W. Grimes { 459d201fe46SDaniel Eischen char *fmt; /* format string */ 460d201fe46SDaniel Eischen int ch; /* character from fmt */ 461d201fe46SDaniel Eischen int n, n2; /* handy integer (short term usage) */ 462d201fe46SDaniel Eischen char *cp; /* handy char pointer (short term usage) */ 463d201fe46SDaniel Eischen struct __siov *iovp; /* for PRINT macro */ 464d201fe46SDaniel Eischen int flags; /* flags as above */ 46558f0484fSRodney W. Grimes int ret; /* return value accumulator */ 46658f0484fSRodney W. Grimes int width; /* width from format (%8d), or 0 */ 46758f0484fSRodney W. Grimes int prec; /* precision from format (%.3d), or -1 */ 46858f0484fSRodney W. Grimes char sign; /* sign prefix (' ', '+', '-', or \0) */ 46998ee7635SAlexey Zelkin char thousands_sep; /* locale specific thousands separator */ 47098ee7635SAlexey Zelkin const char *grouping; /* locale specific numeric grouping rules */ 47158f0484fSRodney W. Grimes #ifdef FLOATING_POINT 4727ae5c679SAlexey Zelkin char *decimal_point; /* locale specific decimal point */ 47358f0484fSRodney W. Grimes char softsign; /* temporary negative sign for floats */ 47458f0484fSRodney W. Grimes double _double; /* double precision arguments %[eEfgG] */ 47558f0484fSRodney W. Grimes int expt; /* integer value of exponent */ 47658f0484fSRodney W. Grimes int expsize; /* character count for expstr */ 47758f0484fSRodney W. Grimes int ndig; /* actual number of digits returned by cvt */ 47838cac8f8SDavid Schultz char expstr[MAXEXPDIG+2]; /* buffer for exponent string */ 4792ffc61baSTor Egge char *dtoaresult; /* buffer allocated by dtoa */ 48058f0484fSRodney W. Grimes #endif 48158f0484fSRodney W. Grimes u_long ulval; /* integer arguments %[diouxX] */ 4827735bb0fSBill Fenner uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ 48358f0484fSRodney W. Grimes int base; /* base for [diouxX] conversion */ 48458f0484fSRodney W. Grimes int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 485261a532aSBill Fenner int realsz; /* field size expanded by dprec, sign, etc */ 48658f0484fSRodney W. Grimes int size; /* size of converted field or string */ 48792e88f87SAndrey A. Chernov int prsize; /* max size of printed field */ 48858f0484fSRodney W. Grimes char *xdigs; /* digits for [xX] conversion */ 48958f0484fSRodney W. Grimes #define NIOV 8 49058f0484fSRodney W. Grimes struct __suio uio; /* output information: summary */ 49158f0484fSRodney W. Grimes struct __siov iov[NIOV];/* ... and individual io vectors */ 49238cac8f8SDavid Schultz char buf[BUF]; /* buffer with space for digits of uintmax_t */ 49358f0484fSRodney W. Grimes char ox[2]; /* space for 0x hex-prefix */ 494a387081cSDoug Rabson union arg *argtable; /* args, built due to positional arg */ 495a387081cSDoug Rabson union arg statargtable [STATIC_ARG_TBL_SIZE]; 496efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 497efb7e53dSJordan K. Hubbard va_list orgap; /* original argument pointer */ 498b9aac308STim J. Robbins char *convbuf; /* wide to multibyte conversion result */ 49958f0484fSRodney W. Grimes 50058f0484fSRodney W. Grimes /* 50158f0484fSRodney W. Grimes * Choose PADSIZE to trade efficiency vs. size. If larger printf 50258f0484fSRodney W. Grimes * fields occur frequently, increase PADSIZE and make the initialisers 50358f0484fSRodney W. Grimes * below longer. 50458f0484fSRodney W. Grimes */ 50558f0484fSRodney W. Grimes #define PADSIZE 16 /* pad chunk size */ 50658f0484fSRodney W. Grimes static char blanks[PADSIZE] = 50758f0484fSRodney W. Grimes {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 50858f0484fSRodney W. Grimes static char zeroes[PADSIZE] = 50958f0484fSRodney W. Grimes {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 51058f0484fSRodney W. Grimes 51158f0484fSRodney W. Grimes /* 51258f0484fSRodney W. Grimes * BEWARE, these `goto error' on error, and PAD uses `n'. 51358f0484fSRodney W. Grimes */ 51458f0484fSRodney W. Grimes #define PRINT(ptr, len) { \ 51558f0484fSRodney W. Grimes iovp->iov_base = (ptr); \ 51658f0484fSRodney W. Grimes iovp->iov_len = (len); \ 51758f0484fSRodney W. Grimes uio.uio_resid += (len); \ 51858f0484fSRodney W. Grimes iovp++; \ 51958f0484fSRodney W. Grimes if (++uio.uio_iovcnt >= NIOV) { \ 52058f0484fSRodney W. Grimes if (__sprint(fp, &uio)) \ 52158f0484fSRodney W. Grimes goto error; \ 52258f0484fSRodney W. Grimes iovp = iov; \ 52358f0484fSRodney W. Grimes } \ 52458f0484fSRodney W. Grimes } 52558f0484fSRodney W. Grimes #define PAD(howmany, with) { \ 52658f0484fSRodney W. Grimes if ((n = (howmany)) > 0) { \ 52758f0484fSRodney W. Grimes while (n > PADSIZE) { \ 52858f0484fSRodney W. Grimes PRINT(with, PADSIZE); \ 52958f0484fSRodney W. Grimes n -= PADSIZE; \ 53058f0484fSRodney W. Grimes } \ 53158f0484fSRodney W. Grimes PRINT(with, n); \ 53258f0484fSRodney W. Grimes } \ 53358f0484fSRodney W. Grimes } 53458f0484fSRodney W. Grimes #define FLUSH() { \ 53558f0484fSRodney W. Grimes if (uio.uio_resid && __sprint(fp, &uio)) \ 53658f0484fSRodney W. Grimes goto error; \ 53758f0484fSRodney W. Grimes uio.uio_iovcnt = 0; \ 53858f0484fSRodney W. Grimes iovp = iov; \ 53958f0484fSRodney W. Grimes } 54058f0484fSRodney W. Grimes 54158f0484fSRodney W. Grimes /* 542efb7e53dSJordan K. Hubbard * Get the argument indexed by nextarg. If the argument table is 543efb7e53dSJordan K. Hubbard * built, use it to get the argument. If its not, get the next 544efb7e53dSJordan K. Hubbard * argument (and arguments must be gotten sequentially). 545efb7e53dSJordan K. Hubbard */ 546efb7e53dSJordan K. Hubbard #define GETARG(type) \ 547a387081cSDoug Rabson ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 548efb7e53dSJordan K. Hubbard (nextarg++, va_arg(ap, type))) 549efb7e53dSJordan K. Hubbard 550efb7e53dSJordan K. Hubbard /* 55158f0484fSRodney W. Grimes * To extend shorts properly, we need both signed and unsigned 55258f0484fSRodney W. Grimes * argument extraction methods. 55358f0484fSRodney W. Grimes */ 55458f0484fSRodney W. Grimes #define SARG() \ 555efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(long) : \ 556efb7e53dSJordan K. Hubbard flags&SHORTINT ? (long)(short)GETARG(int) : \ 5577735bb0fSBill Fenner flags&CHARINT ? (long)(signed char)GETARG(int) : \ 558efb7e53dSJordan K. Hubbard (long)GETARG(int)) 55958f0484fSRodney W. Grimes #define UARG() \ 560efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(u_long) : \ 561efb7e53dSJordan K. Hubbard flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 5627735bb0fSBill Fenner flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ 563efb7e53dSJordan K. Hubbard (u_long)GETARG(u_int)) 5647735bb0fSBill Fenner #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) 5657735bb0fSBill Fenner #define SJARG() \ 5667735bb0fSBill Fenner (flags&INTMAXT ? GETARG(intmax_t) : \ 5677735bb0fSBill Fenner flags&SIZET ? (intmax_t)GETARG(size_t) : \ 5687735bb0fSBill Fenner flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ 5697735bb0fSBill Fenner (intmax_t)GETARG(long long)) 5707735bb0fSBill Fenner #define UJARG() \ 5717735bb0fSBill Fenner (flags&INTMAXT ? GETARG(uintmax_t) : \ 5727735bb0fSBill Fenner flags&SIZET ? (uintmax_t)GETARG(size_t) : \ 5737735bb0fSBill Fenner flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ 5747735bb0fSBill Fenner (uintmax_t)GETARG(unsigned long long)) 575efb7e53dSJordan K. Hubbard 576efb7e53dSJordan K. Hubbard /* 577efb7e53dSJordan K. Hubbard * Get * arguments, including the form *nn$. Preserve the nextarg 578efb7e53dSJordan K. Hubbard * that the argument can be gotten once the type is determined. 579efb7e53dSJordan K. Hubbard */ 580efb7e53dSJordan K. Hubbard #define GETASTER(val) \ 581efb7e53dSJordan K. Hubbard n2 = 0; \ 582efb7e53dSJordan K. Hubbard cp = fmt; \ 583efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 584efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 585efb7e53dSJordan K. Hubbard cp++; \ 586efb7e53dSJordan K. Hubbard } \ 587efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 588efb7e53dSJordan K. Hubbard int hold = nextarg; \ 589efb7e53dSJordan K. Hubbard if (argtable == NULL) { \ 590efb7e53dSJordan K. Hubbard argtable = statargtable; \ 591efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, &argtable); \ 592efb7e53dSJordan K. Hubbard } \ 593efb7e53dSJordan K. Hubbard nextarg = n2; \ 594efb7e53dSJordan K. Hubbard val = GETARG (int); \ 595efb7e53dSJordan K. Hubbard nextarg = hold; \ 596efb7e53dSJordan K. Hubbard fmt = ++cp; \ 597efb7e53dSJordan K. Hubbard } else { \ 598efb7e53dSJordan K. Hubbard val = GETARG (int); \ 599efb7e53dSJordan K. Hubbard } 600efb7e53dSJordan K. Hubbard 60158f0484fSRodney W. Grimes 60298ee7635SAlexey Zelkin thousands_sep = '\0'; 60398ee7635SAlexey Zelkin grouping = NULL; 604b9aac308STim J. Robbins convbuf = NULL; 6052ffc61baSTor Egge #ifdef FLOATING_POINT 6062ffc61baSTor Egge dtoaresult = NULL; 6077735bb0fSBill Fenner decimal_point = localeconv()->decimal_point; 6082ffc61baSTor Egge #endif 60958f0484fSRodney W. Grimes /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 610d201fe46SDaniel Eischen if (cantwrite(fp)) 61158f0484fSRodney W. Grimes return (EOF); 61258f0484fSRodney W. Grimes 61358f0484fSRodney W. Grimes /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 61458f0484fSRodney W. Grimes if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 615d201fe46SDaniel Eischen fp->_file >= 0) 61658f0484fSRodney W. Grimes return (__sbprintf(fp, fmt0, ap)); 61758f0484fSRodney W. Grimes 61858f0484fSRodney W. Grimes fmt = (char *)fmt0; 619efb7e53dSJordan K. Hubbard argtable = NULL; 620efb7e53dSJordan K. Hubbard nextarg = 1; 621d07090a8STim J. Robbins va_copy(orgap, ap); 62258f0484fSRodney W. Grimes uio.uio_iov = iovp = iov; 62358f0484fSRodney W. Grimes uio.uio_resid = 0; 62458f0484fSRodney W. Grimes uio.uio_iovcnt = 0; 62558f0484fSRodney W. Grimes ret = 0; 62658f0484fSRodney W. Grimes 62758f0484fSRodney W. Grimes /* 62858f0484fSRodney W. Grimes * Scan the format for conversions (`%' character). 62958f0484fSRodney W. Grimes */ 63058f0484fSRodney W. Grimes for (;;) { 63158f0484fSRodney W. Grimes for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 63258f0484fSRodney W. Grimes /* void */; 63358f0484fSRodney W. Grimes if ((n = fmt - cp) != 0) { 634b250f248SAndrey A. Chernov if ((unsigned)ret + n > INT_MAX) { 63592e88f87SAndrey A. Chernov ret = EOF; 63692e88f87SAndrey A. Chernov goto error; 63792e88f87SAndrey A. Chernov } 63858f0484fSRodney W. Grimes PRINT(cp, n); 63958f0484fSRodney W. Grimes ret += n; 64058f0484fSRodney W. Grimes } 64158f0484fSRodney W. Grimes if (ch == '\0') 64258f0484fSRodney W. Grimes goto done; 64358f0484fSRodney W. Grimes fmt++; /* skip over '%' */ 64458f0484fSRodney W. Grimes 64558f0484fSRodney W. Grimes flags = 0; 64658f0484fSRodney W. Grimes dprec = 0; 64758f0484fSRodney W. Grimes width = 0; 64858f0484fSRodney W. Grimes prec = -1; 64958f0484fSRodney W. Grimes sign = '\0'; 65058f0484fSRodney W. Grimes 65158f0484fSRodney W. Grimes rflag: ch = *fmt++; 65258f0484fSRodney W. Grimes reswitch: switch (ch) { 65358f0484fSRodney W. Grimes case ' ': 6542e394b2fSAlexey Zelkin /*- 65558f0484fSRodney W. Grimes * ``If the space and + flags both appear, the space 65658f0484fSRodney W. Grimes * flag will be ignored.'' 65758f0484fSRodney W. Grimes * -- ANSI X3J11 65858f0484fSRodney W. Grimes */ 65958f0484fSRodney W. Grimes if (!sign) 66058f0484fSRodney W. Grimes sign = ' '; 66158f0484fSRodney W. Grimes goto rflag; 66258f0484fSRodney W. Grimes case '#': 66358f0484fSRodney W. Grimes flags |= ALT; 66458f0484fSRodney W. Grimes goto rflag; 66558f0484fSRodney W. Grimes case '*': 6662e394b2fSAlexey Zelkin /*- 66758f0484fSRodney W. Grimes * ``A negative field width argument is taken as a 66858f0484fSRodney W. Grimes * - flag followed by a positive field width.'' 66958f0484fSRodney W. Grimes * -- ANSI X3J11 67058f0484fSRodney W. Grimes * They don't exclude field widths read from args. 67158f0484fSRodney W. Grimes */ 672efb7e53dSJordan K. Hubbard GETASTER (width); 673efb7e53dSJordan K. Hubbard if (width >= 0) 67458f0484fSRodney W. Grimes goto rflag; 67558f0484fSRodney W. Grimes width = -width; 67658f0484fSRodney W. Grimes /* FALLTHROUGH */ 67758f0484fSRodney W. Grimes case '-': 67858f0484fSRodney W. Grimes flags |= LADJUST; 67958f0484fSRodney W. Grimes goto rflag; 68058f0484fSRodney W. Grimes case '+': 68158f0484fSRodney W. Grimes sign = '+'; 68258f0484fSRodney W. Grimes goto rflag; 6837735bb0fSBill Fenner case '\'': 68498ee7635SAlexey Zelkin flags |= GROUPING; 68598ee7635SAlexey Zelkin thousands_sep = *(localeconv()->thousands_sep); 68698ee7635SAlexey Zelkin grouping = localeconv()->grouping; 6877735bb0fSBill Fenner goto rflag; 68858f0484fSRodney W. Grimes case '.': 68958f0484fSRodney W. Grimes if ((ch = *fmt++) == '*') { 690efb7e53dSJordan K. Hubbard GETASTER (n); 69158f0484fSRodney W. Grimes prec = n < 0 ? -1 : n; 69258f0484fSRodney W. Grimes goto rflag; 69358f0484fSRodney W. Grimes } 69458f0484fSRodney W. Grimes n = 0; 69558f0484fSRodney W. Grimes while (is_digit(ch)) { 69658f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 69758f0484fSRodney W. Grimes ch = *fmt++; 69858f0484fSRodney W. Grimes } 69958f0484fSRodney W. Grimes prec = n < 0 ? -1 : n; 70058f0484fSRodney W. Grimes goto reswitch; 70158f0484fSRodney W. Grimes case '0': 7022e394b2fSAlexey Zelkin /*- 70358f0484fSRodney W. Grimes * ``Note that 0 is taken as a flag, not as the 70458f0484fSRodney W. Grimes * beginning of a field width.'' 70558f0484fSRodney W. Grimes * -- ANSI X3J11 70658f0484fSRodney W. Grimes */ 70758f0484fSRodney W. Grimes flags |= ZEROPAD; 70858f0484fSRodney W. Grimes goto rflag; 70958f0484fSRodney W. Grimes case '1': case '2': case '3': case '4': 71058f0484fSRodney W. Grimes case '5': case '6': case '7': case '8': case '9': 71158f0484fSRodney W. Grimes n = 0; 71258f0484fSRodney W. Grimes do { 71358f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 71458f0484fSRodney W. Grimes ch = *fmt++; 71558f0484fSRodney W. Grimes } while (is_digit(ch)); 716efb7e53dSJordan K. Hubbard if (ch == '$') { 717efb7e53dSJordan K. Hubbard nextarg = n; 718efb7e53dSJordan K. Hubbard if (argtable == NULL) { 719efb7e53dSJordan K. Hubbard argtable = statargtable; 720efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, 721efb7e53dSJordan K. Hubbard &argtable); 722efb7e53dSJordan K. Hubbard } 723efb7e53dSJordan K. Hubbard goto rflag; 724efb7e53dSJordan K. Hubbard } 72558f0484fSRodney W. Grimes width = n; 72658f0484fSRodney W. Grimes goto reswitch; 72758f0484fSRodney W. Grimes #ifdef FLOATING_POINT 72858f0484fSRodney W. Grimes case 'L': 72958f0484fSRodney W. Grimes flags |= LONGDBL; 73058f0484fSRodney W. Grimes goto rflag; 73158f0484fSRodney W. Grimes #endif 73258f0484fSRodney W. Grimes case 'h': 7337735bb0fSBill Fenner if (flags & SHORTINT) { 7347735bb0fSBill Fenner flags &= ~SHORTINT; 7357735bb0fSBill Fenner flags |= CHARINT; 7367735bb0fSBill Fenner } else 73758f0484fSRodney W. Grimes flags |= SHORTINT; 73858f0484fSRodney W. Grimes goto rflag; 7397735bb0fSBill Fenner case 'j': 7407735bb0fSBill Fenner flags |= INTMAXT; 7417735bb0fSBill Fenner goto rflag; 74258f0484fSRodney W. Grimes case 'l': 7437735bb0fSBill Fenner if (flags & LONGINT) { 7447735bb0fSBill Fenner flags &= ~LONGINT; 7457735bb0fSBill Fenner flags |= LLONGINT; 7467735bb0fSBill Fenner } else 74758f0484fSRodney W. Grimes flags |= LONGINT; 74858f0484fSRodney W. Grimes goto rflag; 74958f0484fSRodney W. Grimes case 'q': 7507735bb0fSBill Fenner flags |= LLONGINT; /* not necessarily */ 7517735bb0fSBill Fenner goto rflag; 7527735bb0fSBill Fenner case 't': 7537735bb0fSBill Fenner flags |= PTRDIFFT; 7547735bb0fSBill Fenner goto rflag; 7557735bb0fSBill Fenner case 'z': 7567735bb0fSBill Fenner flags |= SIZET; 75758f0484fSRodney W. Grimes goto rflag; 758927ecbf3STim J. Robbins case 'C': 759927ecbf3STim J. Robbins flags |= LONGINT; 760927ecbf3STim J. Robbins /*FALLTHROUGH*/ 76158f0484fSRodney W. Grimes case 'c': 762b9aac308STim J. Robbins if (flags & LONGINT) { 763b9aac308STim J. Robbins mbstate_t mbs; 764b9aac308STim J. Robbins size_t mbseqlen; 765b9aac308STim J. Robbins 766b9aac308STim J. Robbins memset(&mbs, 0, sizeof(mbs)); 767b9aac308STim J. Robbins mbseqlen = wcrtomb(cp = buf, 768b9aac308STim J. Robbins (wchar_t)GETARG(wint_t), &mbs); 7696180233fSTim J. Robbins if (mbseqlen == (size_t)-1) { 7706180233fSTim J. Robbins fp->_flags |= __SERR; 771b9aac308STim J. Robbins goto error; 7726180233fSTim J. Robbins } 773b9aac308STim J. Robbins size = (int)mbseqlen; 774b9aac308STim J. Robbins } else { 775efb7e53dSJordan K. Hubbard *(cp = buf) = GETARG(int); 77658f0484fSRodney W. Grimes size = 1; 777b9aac308STim J. Robbins } 77858f0484fSRodney W. Grimes sign = '\0'; 77958f0484fSRodney W. Grimes break; 78058f0484fSRodney W. Grimes case 'D': 78158f0484fSRodney W. Grimes flags |= LONGINT; 78258f0484fSRodney W. Grimes /*FALLTHROUGH*/ 78358f0484fSRodney W. Grimes case 'd': 78458f0484fSRodney W. Grimes case 'i': 7857735bb0fSBill Fenner if (flags & INTMAX_SIZE) { 7867735bb0fSBill Fenner ujval = SJARG(); 7877735bb0fSBill Fenner if ((intmax_t)ujval < 0) { 7887735bb0fSBill Fenner ujval = -ujval; 78958f0484fSRodney W. Grimes sign = '-'; 79058f0484fSRodney W. Grimes } 79158f0484fSRodney W. Grimes } else { 79258f0484fSRodney W. Grimes ulval = SARG(); 79358f0484fSRodney W. Grimes if ((long)ulval < 0) { 79458f0484fSRodney W. Grimes ulval = -ulval; 79558f0484fSRodney W. Grimes sign = '-'; 79658f0484fSRodney W. Grimes } 79758f0484fSRodney W. Grimes } 79858f0484fSRodney W. Grimes base = 10; 79958f0484fSRodney W. Grimes goto number; 80058f0484fSRodney W. Grimes #ifdef FLOATING_POINT 8017735bb0fSBill Fenner #ifdef HEXFLOAT 8027735bb0fSBill Fenner case 'a': 8037735bb0fSBill Fenner case 'A': 8047735bb0fSBill Fenner #endif 805d26be6f0SBruce Evans case 'e': 80658f0484fSRodney W. Grimes case 'E': 8072e394b2fSAlexey Zelkin /*- 80898ee7635SAlexey Zelkin * Grouping apply to %i, %d, %u, %f, %F, %g, %G 80998ee7635SAlexey Zelkin * conversion specifiers only. For other conversions 81098ee7635SAlexey Zelkin * behavior is undefined. 81198ee7635SAlexey Zelkin * -- POSIX 81298ee7635SAlexey Zelkin */ 81398ee7635SAlexey Zelkin flags &= ~GROUPING; 81498ee7635SAlexey Zelkin /*FALLTHROUGH*/ 815d26be6f0SBruce Evans case 'f': 8167735bb0fSBill Fenner case 'F': 817d26be6f0SBruce Evans goto fp_begin; 81858f0484fSRodney W. Grimes case 'g': 81958f0484fSRodney W. Grimes case 'G': 820d26be6f0SBruce Evans if (prec == 0) 821d26be6f0SBruce Evans prec = 1; 822d26be6f0SBruce Evans fp_begin: if (prec == -1) 82358f0484fSRodney W. Grimes prec = DEFPREC; 824d26be6f0SBruce Evans if (flags & LONGDBL) 8256a93659fSBruce Evans /* XXX this loses precision. */ 826efb7e53dSJordan K. Hubbard _double = (double)GETARG(long double); 827d26be6f0SBruce Evans else 828efb7e53dSJordan K. Hubbard _double = GETARG(double); 82958f0484fSRodney W. Grimes /* do this before tricky precision changes */ 83058f0484fSRodney W. Grimes if (isinf(_double)) { 83158f0484fSRodney W. Grimes if (_double < 0) 83258f0484fSRodney W. Grimes sign = '-'; 8337735bb0fSBill Fenner if (isupper(ch)) 8347735bb0fSBill Fenner cp = "INF"; 8357735bb0fSBill Fenner else 8367735bb0fSBill Fenner cp = "inf"; 83758f0484fSRodney W. Grimes size = 3; 83858f0484fSRodney W. Grimes break; 83958f0484fSRodney W. Grimes } 84058f0484fSRodney W. Grimes if (isnan(_double)) { 8417735bb0fSBill Fenner if (isupper(ch)) 8427735bb0fSBill Fenner cp = "NAN"; 8437735bb0fSBill Fenner else 8447735bb0fSBill Fenner cp = "nan"; 84558f0484fSRodney W. Grimes size = 3; 84658f0484fSRodney W. Grimes break; 84758f0484fSRodney W. Grimes } 84858f0484fSRodney W. Grimes flags |= FPT; 8492ffc61baSTor Egge if (dtoaresult != NULL) { 8506a66acb5SDavid Schultz __freedtoa(dtoaresult); 8512ffc61baSTor Egge dtoaresult = NULL; 8522ffc61baSTor Egge } 8536a66acb5SDavid Schultz dtoaresult = cp = cvt(_double, prec, flags, &softsign, 8546a66acb5SDavid Schultz &expt, ch, &ndig); 85558f0484fSRodney W. Grimes if (ch == 'g' || ch == 'G') { 85658f0484fSRodney W. Grimes if (expt <= -4 || expt > prec) 85758f0484fSRodney W. Grimes ch = (ch == 'g') ? 'e' : 'E'; 85858f0484fSRodney W. Grimes else 85958f0484fSRodney W. Grimes ch = 'g'; 86058f0484fSRodney W. Grimes } 8617735bb0fSBill Fenner if (ch == 'e' || ch == 'E') { 86258f0484fSRodney W. Grimes --expt; 86358f0484fSRodney W. Grimes expsize = exponent(expstr, expt, ch); 86458f0484fSRodney W. Grimes size = expsize + ndig; 86558f0484fSRodney W. Grimes if (ndig > 1 || flags & ALT) 86658f0484fSRodney W. Grimes ++size; 8677735bb0fSBill Fenner } else if (ch == 'f' || ch == 'F') { 86858f0484fSRodney W. Grimes if (expt > 0) { 86958f0484fSRodney W. Grimes size = expt; 87058f0484fSRodney W. Grimes if (prec || flags & ALT) 87158f0484fSRodney W. Grimes size += prec + 1; 87258f0484fSRodney W. Grimes } else /* "0.X" */ 87358f0484fSRodney W. Grimes size = prec + 2; 87458f0484fSRodney W. Grimes } else if (expt >= ndig) { /* fixed g fmt */ 87558f0484fSRodney W. Grimes size = expt; 87658f0484fSRodney W. Grimes if (flags & ALT) 87758f0484fSRodney W. Grimes ++size; 87858f0484fSRodney W. Grimes } else 87958f0484fSRodney W. Grimes size = ndig + (expt > 0 ? 88058f0484fSRodney W. Grimes 1 : 2 - expt); 88158f0484fSRodney W. Grimes 88258f0484fSRodney W. Grimes if (softsign) 88358f0484fSRodney W. Grimes sign = '-'; 88458f0484fSRodney W. Grimes break; 88558f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 88658f0484fSRodney W. Grimes case 'n': 8877735bb0fSBill Fenner /* 8887735bb0fSBill Fenner * Assignment-like behavior is specified if the 8897735bb0fSBill Fenner * value overflows or is otherwise unrepresentable. 8907735bb0fSBill Fenner * C99 says to use `signed char' for %hhn conversions. 8917735bb0fSBill Fenner */ 8927735bb0fSBill Fenner if (flags & LLONGINT) 8937735bb0fSBill Fenner *GETARG(long long *) = ret; 8947735bb0fSBill Fenner else if (flags & SIZET) 8957735bb0fSBill Fenner *GETARG(ssize_t *) = (ssize_t)ret; 8967735bb0fSBill Fenner else if (flags & PTRDIFFT) 8977735bb0fSBill Fenner *GETARG(ptrdiff_t *) = ret; 8987735bb0fSBill Fenner else if (flags & INTMAXT) 8997735bb0fSBill Fenner *GETARG(intmax_t *) = ret; 90058f0484fSRodney W. Grimes else if (flags & LONGINT) 9016e690ad4SAndrey A. Chernov *GETARG(long *) = ret; 90258f0484fSRodney W. Grimes else if (flags & SHORTINT) 9036e690ad4SAndrey A. Chernov *GETARG(short *) = ret; 9047735bb0fSBill Fenner else if (flags & CHARINT) 9057735bb0fSBill Fenner *GETARG(signed char *) = ret; 90658f0484fSRodney W. Grimes else 9076e690ad4SAndrey A. Chernov *GETARG(int *) = ret; 90858f0484fSRodney W. Grimes continue; /* no output */ 90958f0484fSRodney W. Grimes case 'O': 91058f0484fSRodney W. Grimes flags |= LONGINT; 91158f0484fSRodney W. Grimes /*FALLTHROUGH*/ 91258f0484fSRodney W. Grimes case 'o': 9137735bb0fSBill Fenner if (flags & INTMAX_SIZE) 9147735bb0fSBill Fenner ujval = UJARG(); 91558f0484fSRodney W. Grimes else 91658f0484fSRodney W. Grimes ulval = UARG(); 91758f0484fSRodney W. Grimes base = 8; 91858f0484fSRodney W. Grimes goto nosign; 91958f0484fSRodney W. Grimes case 'p': 9202e394b2fSAlexey Zelkin /*- 92158f0484fSRodney W. Grimes * ``The argument shall be a pointer to void. The 92258f0484fSRodney W. Grimes * value of the pointer is converted to a sequence 92358f0484fSRodney W. Grimes * of printable characters, in an implementation- 92458f0484fSRodney W. Grimes * defined manner.'' 92558f0484fSRodney W. Grimes * -- ANSI X3J11 92658f0484fSRodney W. Grimes */ 9277735bb0fSBill Fenner ujval = (uintmax_t)(uintptr_t)GETARG(void *); 92858f0484fSRodney W. Grimes base = 16; 92958f0484fSRodney W. Grimes xdigs = "0123456789abcdef"; 9307735bb0fSBill Fenner flags = flags | INTMAXT | HEXPREFIX; 93158f0484fSRodney W. Grimes ch = 'x'; 93258f0484fSRodney W. Grimes goto nosign; 933927ecbf3STim J. Robbins case 'S': 934927ecbf3STim J. Robbins flags |= LONGINT; 935927ecbf3STim J. Robbins /*FALLTHROUGH*/ 93658f0484fSRodney W. Grimes case 's': 937b9aac308STim J. Robbins if (flags & LONGINT) { 938b9aac308STim J. Robbins wchar_t *wcp; 939b9aac308STim J. Robbins 940b9aac308STim J. Robbins if (convbuf != NULL) 941b9aac308STim J. Robbins free(convbuf); 942b9aac308STim J. Robbins if ((wcp = GETARG(wchar_t *)) == NULL) 943b9aac308STim J. Robbins cp = "(null)"; 944b9aac308STim J. Robbins else { 945b9aac308STim J. Robbins convbuf = __wcsconv(wcp, prec); 9466180233fSTim J. Robbins if (convbuf == NULL) { 9476180233fSTim J. Robbins fp->_flags |= __SERR; 948b9aac308STim J. Robbins goto error; 9496180233fSTim J. Robbins } 950b9aac308STim J. Robbins cp = convbuf; 951b9aac308STim J. Robbins } 952b9aac308STim J. Robbins } else if ((cp = GETARG(char *)) == NULL) 95358f0484fSRodney W. Grimes cp = "(null)"; 95458f0484fSRodney W. Grimes if (prec >= 0) { 95558f0484fSRodney W. Grimes /* 95658f0484fSRodney W. Grimes * can't use strlen; can only look for the 95758f0484fSRodney W. Grimes * NUL in the first `prec' characters, and 95858f0484fSRodney W. Grimes * strlen() will go further. 95958f0484fSRodney W. Grimes */ 960ce51cf03SJames Raynard char *p = memchr(cp, 0, (size_t)prec); 96158f0484fSRodney W. Grimes 96258f0484fSRodney W. Grimes if (p != NULL) { 96358f0484fSRodney W. Grimes size = p - cp; 96458f0484fSRodney W. Grimes if (size > prec) 96558f0484fSRodney W. Grimes size = prec; 96658f0484fSRodney W. Grimes } else 96758f0484fSRodney W. Grimes size = prec; 96858f0484fSRodney W. Grimes } else 96958f0484fSRodney W. Grimes size = strlen(cp); 97058f0484fSRodney W. Grimes sign = '\0'; 97158f0484fSRodney W. Grimes break; 97258f0484fSRodney W. Grimes case 'U': 97358f0484fSRodney W. Grimes flags |= LONGINT; 97458f0484fSRodney W. Grimes /*FALLTHROUGH*/ 97558f0484fSRodney W. Grimes case 'u': 9767735bb0fSBill Fenner if (flags & INTMAX_SIZE) 9777735bb0fSBill Fenner ujval = UJARG(); 97858f0484fSRodney W. Grimes else 97958f0484fSRodney W. Grimes ulval = UARG(); 98058f0484fSRodney W. Grimes base = 10; 98158f0484fSRodney W. Grimes goto nosign; 98258f0484fSRodney W. Grimes case 'X': 98358f0484fSRodney W. Grimes xdigs = "0123456789ABCDEF"; 98458f0484fSRodney W. Grimes goto hex; 98558f0484fSRodney W. Grimes case 'x': 98658f0484fSRodney W. Grimes xdigs = "0123456789abcdef"; 9877735bb0fSBill Fenner hex: 9887735bb0fSBill Fenner if (flags & INTMAX_SIZE) 9897735bb0fSBill Fenner ujval = UJARG(); 99058f0484fSRodney W. Grimes else 99158f0484fSRodney W. Grimes ulval = UARG(); 99258f0484fSRodney W. Grimes base = 16; 99358f0484fSRodney W. Grimes /* leading 0x/X only if non-zero */ 99458f0484fSRodney W. Grimes if (flags & ALT && 9957735bb0fSBill Fenner (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 99658f0484fSRodney W. Grimes flags |= HEXPREFIX; 99758f0484fSRodney W. Grimes 99898ee7635SAlexey Zelkin flags &= ~GROUPING; 99958f0484fSRodney W. Grimes /* unsigned conversions */ 100058f0484fSRodney W. Grimes nosign: sign = '\0'; 10012e394b2fSAlexey Zelkin /*- 100258f0484fSRodney W. Grimes * ``... diouXx conversions ... if a precision is 100358f0484fSRodney W. Grimes * specified, the 0 flag will be ignored.'' 100458f0484fSRodney W. Grimes * -- ANSI X3J11 100558f0484fSRodney W. Grimes */ 100658f0484fSRodney W. Grimes number: if ((dprec = prec) >= 0) 100758f0484fSRodney W. Grimes flags &= ~ZEROPAD; 100858f0484fSRodney W. Grimes 10092e394b2fSAlexey Zelkin /*- 101058f0484fSRodney W. Grimes * ``The result of converting a zero value with an 101158f0484fSRodney W. Grimes * explicit precision of zero is no characters.'' 101258f0484fSRodney W. Grimes * -- ANSI X3J11 101358f0484fSRodney W. Grimes */ 101458f0484fSRodney W. Grimes cp = buf + BUF; 10157735bb0fSBill Fenner if (flags & INTMAX_SIZE) { 10167735bb0fSBill Fenner if (ujval != 0 || prec != 0) 10177735bb0fSBill Fenner cp = __ujtoa(ujval, cp, base, 101898ee7635SAlexey Zelkin flags & ALT, xdigs, 101998ee7635SAlexey Zelkin flags & GROUPING, thousands_sep, 102098ee7635SAlexey Zelkin grouping); 102158f0484fSRodney W. Grimes } else { 102258f0484fSRodney W. Grimes if (ulval != 0 || prec != 0) 102358f0484fSRodney W. Grimes cp = __ultoa(ulval, cp, base, 102498ee7635SAlexey Zelkin flags & ALT, xdigs, 102598ee7635SAlexey Zelkin flags & GROUPING, thousands_sep, 102698ee7635SAlexey Zelkin grouping); 102758f0484fSRodney W. Grimes } 102858f0484fSRodney W. Grimes size = buf + BUF - cp; 102938cac8f8SDavid Schultz if (size > BUF) /* should never happen */ 103038cac8f8SDavid Schultz abort(); 103158f0484fSRodney W. Grimes break; 103258f0484fSRodney W. Grimes default: /* "%?" prints ?, unless ? is NUL */ 103358f0484fSRodney W. Grimes if (ch == '\0') 103458f0484fSRodney W. Grimes goto done; 103558f0484fSRodney W. Grimes /* pretend it was %c with argument ch */ 103658f0484fSRodney W. Grimes cp = buf; 103758f0484fSRodney W. Grimes *cp = ch; 103858f0484fSRodney W. Grimes size = 1; 103958f0484fSRodney W. Grimes sign = '\0'; 104058f0484fSRodney W. Grimes break; 104158f0484fSRodney W. Grimes } 104258f0484fSRodney W. Grimes 104358f0484fSRodney W. Grimes /* 104458f0484fSRodney W. Grimes * All reasonable formats wind up here. At this point, `cp' 104558f0484fSRodney W. Grimes * points to a string which (if not flags&LADJUST) should be 104658f0484fSRodney W. Grimes * padded out to `width' places. If flags&ZEROPAD, it should 104758f0484fSRodney W. Grimes * first be prefixed by any sign or other prefix; otherwise, 104858f0484fSRodney W. Grimes * it should be blank padded before the prefix is emitted. 104958f0484fSRodney W. Grimes * After any left-hand padding and prefixing, emit zeroes 105058f0484fSRodney W. Grimes * required by a decimal [diouxX] precision, then print the 105158f0484fSRodney W. Grimes * string proper, then emit zeroes required by any leftover 105258f0484fSRodney W. Grimes * floating precision; finally, if LADJUST, pad with blanks. 105358f0484fSRodney W. Grimes * 105458f0484fSRodney W. Grimes * Compute actual size, so we know how much to pad. 1055261a532aSBill Fenner * size excludes decimal prec; realsz includes it. 105658f0484fSRodney W. Grimes */ 1057261a532aSBill Fenner realsz = dprec > size ? dprec : size; 105858f0484fSRodney W. Grimes if (sign) 1059261a532aSBill Fenner realsz++; 106058f0484fSRodney W. Grimes else if (flags & HEXPREFIX) 1061261a532aSBill Fenner realsz += 2; 106258f0484fSRodney W. Grimes 106392e88f87SAndrey A. Chernov prsize = width > realsz ? width : realsz; 1064b250f248SAndrey A. Chernov if ((unsigned)ret + prsize > INT_MAX) { 106592e88f87SAndrey A. Chernov ret = EOF; 106692e88f87SAndrey A. Chernov goto error; 106792e88f87SAndrey A. Chernov } 106892e88f87SAndrey A. Chernov 106958f0484fSRodney W. Grimes /* right-adjusting blank padding */ 107058f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == 0) 107158f0484fSRodney W. Grimes PAD(width - realsz, blanks); 107258f0484fSRodney W. Grimes 107358f0484fSRodney W. Grimes /* prefix */ 107458f0484fSRodney W. Grimes if (sign) { 107558f0484fSRodney W. Grimes PRINT(&sign, 1); 107658f0484fSRodney W. Grimes } else if (flags & HEXPREFIX) { 107758f0484fSRodney W. Grimes ox[0] = '0'; 107858f0484fSRodney W. Grimes ox[1] = ch; 107958f0484fSRodney W. Grimes PRINT(ox, 2); 108058f0484fSRodney W. Grimes } 108158f0484fSRodney W. Grimes 108258f0484fSRodney W. Grimes /* right-adjusting zero padding */ 108358f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 108458f0484fSRodney W. Grimes PAD(width - realsz, zeroes); 108558f0484fSRodney W. Grimes 108658f0484fSRodney W. Grimes /* leading zeroes from decimal precision */ 1087261a532aSBill Fenner PAD(dprec - size, zeroes); 108858f0484fSRodney W. Grimes 108958f0484fSRodney W. Grimes /* the string or number proper */ 109058f0484fSRodney W. Grimes #ifdef FLOATING_POINT 109158f0484fSRodney W. Grimes if ((flags & FPT) == 0) { 109258f0484fSRodney W. Grimes PRINT(cp, size); 109358f0484fSRodney W. Grimes } else { /* glue together f_p fragments */ 109458f0484fSRodney W. Grimes if (ch >= 'f') { /* 'f' or 'g' */ 109558f0484fSRodney W. Grimes if (_double == 0) { 109658f0484fSRodney W. Grimes /* kludge for __dtoa irregularity */ 109758f0484fSRodney W. Grimes PRINT("0", 1); 10989ad80ab5SAndrey A. Chernov if (expt < ndig || (flags & ALT) != 0) { 10999ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 110058f0484fSRodney W. Grimes PAD(ndig - 1, zeroes); 110158f0484fSRodney W. Grimes } 110258f0484fSRodney W. Grimes } else if (expt <= 0) { 11039ad80ab5SAndrey A. Chernov PRINT("0", 1); 11049ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 110558f0484fSRodney W. Grimes PAD(-expt, zeroes); 110658f0484fSRodney W. Grimes PRINT(cp, ndig); 110758f0484fSRodney W. Grimes } else if (expt >= ndig) { 110858f0484fSRodney W. Grimes PRINT(cp, ndig); 110958f0484fSRodney W. Grimes PAD(expt - ndig, zeroes); 111058f0484fSRodney W. Grimes if (flags & ALT) 11119ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 111258f0484fSRodney W. Grimes } else { 111358f0484fSRodney W. Grimes PRINT(cp, expt); 111458f0484fSRodney W. Grimes cp += expt; 11159ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 111658f0484fSRodney W. Grimes PRINT(cp, ndig-expt); 111758f0484fSRodney W. Grimes } 111858f0484fSRodney W. Grimes } else { /* 'e' or 'E' */ 111958f0484fSRodney W. Grimes if (ndig > 1 || flags & ALT) { 112058f0484fSRodney W. Grimes ox[0] = *cp++; 11219ad80ab5SAndrey A. Chernov ox[1] = *decimal_point; 112258f0484fSRodney W. Grimes PRINT(ox, 2); 1123918bed75SBruce Evans if (_double) { 112458f0484fSRodney W. Grimes PRINT(cp, ndig-1); 112558f0484fSRodney W. Grimes } else /* 0.[0..] */ 112658f0484fSRodney W. Grimes /* __dtoa irregularity */ 112758f0484fSRodney W. Grimes PAD(ndig - 1, zeroes); 112858f0484fSRodney W. Grimes } else /* XeYYY */ 112958f0484fSRodney W. Grimes PRINT(cp, 1); 113058f0484fSRodney W. Grimes PRINT(expstr, expsize); 113158f0484fSRodney W. Grimes } 113258f0484fSRodney W. Grimes } 113358f0484fSRodney W. Grimes #else 113458f0484fSRodney W. Grimes PRINT(cp, size); 113558f0484fSRodney W. Grimes #endif 113658f0484fSRodney W. Grimes /* left-adjusting padding (always blank) */ 113758f0484fSRodney W. Grimes if (flags & LADJUST) 113858f0484fSRodney W. Grimes PAD(width - realsz, blanks); 113958f0484fSRodney W. Grimes 114058f0484fSRodney W. Grimes /* finally, adjust ret */ 114192e88f87SAndrey A. Chernov ret += prsize; 114258f0484fSRodney W. Grimes 114358f0484fSRodney W. Grimes FLUSH(); /* copy out the I/O vectors */ 114458f0484fSRodney W. Grimes } 114558f0484fSRodney W. Grimes done: 114658f0484fSRodney W. Grimes FLUSH(); 114758f0484fSRodney W. Grimes error: 11482ffc61baSTor Egge #ifdef FLOATING_POINT 11492ffc61baSTor Egge if (dtoaresult != NULL) 11506a66acb5SDavid Schultz __freedtoa(dtoaresult); 11512ffc61baSTor Egge #endif 1152b9aac308STim J. Robbins if (convbuf != NULL) 1153b9aac308STim J. Robbins free(convbuf); 1154f70177e7SJulian Elischer if (__sferror(fp)) 1155f70177e7SJulian Elischer ret = EOF; 1156efb7e53dSJordan K. Hubbard if ((argtable != NULL) && (argtable != statargtable)) 1157efb7e53dSJordan K. Hubbard free (argtable); 1158f70177e7SJulian Elischer return (ret); 115958f0484fSRodney W. Grimes /* NOTREACHED */ 116058f0484fSRodney W. Grimes } 116158f0484fSRodney W. Grimes 1162efb7e53dSJordan K. Hubbard /* 1163efb7e53dSJordan K. Hubbard * Find all arguments when a positional parameter is encountered. Returns a 1164efb7e53dSJordan K. Hubbard * table, indexed by argument number, of pointers to each arguments. The 1165efb7e53dSJordan K. Hubbard * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 116642cebaa5SArchie Cobbs * It will be replaces with a malloc-ed one if it overflows. 1167efb7e53dSJordan K. Hubbard */ 1168efb7e53dSJordan K. Hubbard static void 1169a387081cSDoug Rabson __find_arguments (const char *fmt0, va_list ap, union arg **argtable) 1170efb7e53dSJordan K. Hubbard { 1171d201fe46SDaniel Eischen char *fmt; /* format string */ 1172d201fe46SDaniel Eischen int ch; /* character from fmt */ 1173d201fe46SDaniel Eischen int n, n2; /* handy integer (short term usage) */ 1174d201fe46SDaniel Eischen char *cp; /* handy char pointer (short term usage) */ 1175d201fe46SDaniel Eischen int flags; /* flags as above */ 1176efb7e53dSJordan K. Hubbard int width; /* width from format (%8d), or 0 */ 11777735bb0fSBill Fenner enum typeid *typetable; /* table of types */ 11787735bb0fSBill Fenner enum typeid stattypetable [STATIC_ARG_TBL_SIZE]; 1179efb7e53dSJordan K. Hubbard int tablesize; /* current size of type table */ 1180efb7e53dSJordan K. Hubbard int tablemax; /* largest used index in table */ 1181efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 1182efb7e53dSJordan K. Hubbard 1183efb7e53dSJordan K. Hubbard /* 1184efb7e53dSJordan K. Hubbard * Add an argument type to the table, expanding if necessary. 1185efb7e53dSJordan K. Hubbard */ 1186efb7e53dSJordan K. Hubbard #define ADDTYPE(type) \ 1187efb7e53dSJordan K. Hubbard ((nextarg >= tablesize) ? \ 1188efb7e53dSJordan K. Hubbard __grow_type_table(nextarg, &typetable, &tablesize) : 0, \ 118942cebaa5SArchie Cobbs (nextarg > tablemax) ? tablemax = nextarg : 0, \ 119042cebaa5SArchie Cobbs typetable[nextarg++] = type) 1191efb7e53dSJordan K. Hubbard 1192efb7e53dSJordan K. Hubbard #define ADDSARG() \ 11937735bb0fSBill Fenner ((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \ 11947735bb0fSBill Fenner ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 11957735bb0fSBill Fenner ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 11967735bb0fSBill Fenner ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \ 11977735bb0fSBill Fenner ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT)))))) 1198efb7e53dSJordan K. Hubbard 1199efb7e53dSJordan K. Hubbard #define ADDUARG() \ 12007735bb0fSBill Fenner ((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \ 12017735bb0fSBill Fenner ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 12027735bb0fSBill Fenner ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 12037735bb0fSBill Fenner ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \ 12047735bb0fSBill Fenner ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT)))))) 1205efb7e53dSJordan K. Hubbard 1206efb7e53dSJordan K. Hubbard /* 1207efb7e53dSJordan K. Hubbard * Add * arguments to the type array. 1208efb7e53dSJordan K. Hubbard */ 1209efb7e53dSJordan K. Hubbard #define ADDASTER() \ 1210efb7e53dSJordan K. Hubbard n2 = 0; \ 1211efb7e53dSJordan K. Hubbard cp = fmt; \ 1212efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 1213efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 1214efb7e53dSJordan K. Hubbard cp++; \ 1215efb7e53dSJordan K. Hubbard } \ 1216efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 1217efb7e53dSJordan K. Hubbard int hold = nextarg; \ 1218efb7e53dSJordan K. Hubbard nextarg = n2; \ 1219efb7e53dSJordan K. Hubbard ADDTYPE (T_INT); \ 1220efb7e53dSJordan K. Hubbard nextarg = hold; \ 1221efb7e53dSJordan K. Hubbard fmt = ++cp; \ 1222efb7e53dSJordan K. Hubbard } else { \ 1223efb7e53dSJordan K. Hubbard ADDTYPE (T_INT); \ 1224efb7e53dSJordan K. Hubbard } 1225efb7e53dSJordan K. Hubbard fmt = (char *)fmt0; 1226efb7e53dSJordan K. Hubbard typetable = stattypetable; 1227efb7e53dSJordan K. Hubbard tablesize = STATIC_ARG_TBL_SIZE; 1228efb7e53dSJordan K. Hubbard tablemax = 0; 1229efb7e53dSJordan K. Hubbard nextarg = 1; 1230efb7e53dSJordan K. Hubbard memset (typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); 1231efb7e53dSJordan K. Hubbard 1232efb7e53dSJordan K. Hubbard /* 1233efb7e53dSJordan K. Hubbard * Scan the format for conversions (`%' character). 1234efb7e53dSJordan K. Hubbard */ 1235efb7e53dSJordan K. Hubbard for (;;) { 1236efb7e53dSJordan K. Hubbard for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 1237efb7e53dSJordan K. Hubbard /* void */; 1238efb7e53dSJordan K. Hubbard if (ch == '\0') 1239efb7e53dSJordan K. Hubbard goto done; 1240efb7e53dSJordan K. Hubbard fmt++; /* skip over '%' */ 1241efb7e53dSJordan K. Hubbard 1242efb7e53dSJordan K. Hubbard flags = 0; 1243efb7e53dSJordan K. Hubbard width = 0; 1244efb7e53dSJordan K. Hubbard 1245efb7e53dSJordan K. Hubbard rflag: ch = *fmt++; 1246efb7e53dSJordan K. Hubbard reswitch: switch (ch) { 1247efb7e53dSJordan K. Hubbard case ' ': 1248efb7e53dSJordan K. Hubbard case '#': 1249efb7e53dSJordan K. Hubbard goto rflag; 1250efb7e53dSJordan K. Hubbard case '*': 1251efb7e53dSJordan K. Hubbard ADDASTER (); 1252efb7e53dSJordan K. Hubbard goto rflag; 1253efb7e53dSJordan K. Hubbard case '-': 1254efb7e53dSJordan K. Hubbard case '+': 12557735bb0fSBill Fenner case '\'': 1256efb7e53dSJordan K. Hubbard goto rflag; 1257efb7e53dSJordan K. Hubbard case '.': 1258efb7e53dSJordan K. Hubbard if ((ch = *fmt++) == '*') { 1259efb7e53dSJordan K. Hubbard ADDASTER (); 1260efb7e53dSJordan K. Hubbard goto rflag; 1261efb7e53dSJordan K. Hubbard } 1262efb7e53dSJordan K. Hubbard while (is_digit(ch)) { 1263efb7e53dSJordan K. Hubbard ch = *fmt++; 1264efb7e53dSJordan K. Hubbard } 1265efb7e53dSJordan K. Hubbard goto reswitch; 1266efb7e53dSJordan K. Hubbard case '0': 1267efb7e53dSJordan K. Hubbard goto rflag; 1268efb7e53dSJordan K. Hubbard case '1': case '2': case '3': case '4': 1269efb7e53dSJordan K. Hubbard case '5': case '6': case '7': case '8': case '9': 1270efb7e53dSJordan K. Hubbard n = 0; 1271efb7e53dSJordan K. Hubbard do { 1272efb7e53dSJordan K. Hubbard n = 10 * n + to_digit(ch); 1273efb7e53dSJordan K. Hubbard ch = *fmt++; 1274efb7e53dSJordan K. Hubbard } while (is_digit(ch)); 1275efb7e53dSJordan K. Hubbard if (ch == '$') { 1276efb7e53dSJordan K. Hubbard nextarg = n; 1277efb7e53dSJordan K. Hubbard goto rflag; 1278efb7e53dSJordan K. Hubbard } 1279efb7e53dSJordan K. Hubbard width = n; 1280efb7e53dSJordan K. Hubbard goto reswitch; 1281efb7e53dSJordan K. Hubbard #ifdef FLOATING_POINT 1282efb7e53dSJordan K. Hubbard case 'L': 1283efb7e53dSJordan K. Hubbard flags |= LONGDBL; 1284efb7e53dSJordan K. Hubbard goto rflag; 1285efb7e53dSJordan K. Hubbard #endif 1286efb7e53dSJordan K. Hubbard case 'h': 12877735bb0fSBill Fenner if (flags & SHORTINT) { 12887735bb0fSBill Fenner flags &= ~SHORTINT; 12897735bb0fSBill Fenner flags |= CHARINT; 12907735bb0fSBill Fenner } else 1291efb7e53dSJordan K. Hubbard flags |= SHORTINT; 1292efb7e53dSJordan K. Hubbard goto rflag; 12937735bb0fSBill Fenner case 'j': 12947735bb0fSBill Fenner flags |= INTMAXT; 12957735bb0fSBill Fenner goto rflag; 1296efb7e53dSJordan K. Hubbard case 'l': 12977735bb0fSBill Fenner if (flags & LONGINT) { 12987735bb0fSBill Fenner flags &= ~LONGINT; 12997735bb0fSBill Fenner flags |= LLONGINT; 13007735bb0fSBill Fenner } else 1301efb7e53dSJordan K. Hubbard flags |= LONGINT; 1302efb7e53dSJordan K. Hubbard goto rflag; 1303efb7e53dSJordan K. Hubbard case 'q': 13047735bb0fSBill Fenner flags |= LLONGINT; /* not necessarily */ 13057735bb0fSBill Fenner goto rflag; 13067735bb0fSBill Fenner case 't': 13077735bb0fSBill Fenner flags |= PTRDIFFT; 13087735bb0fSBill Fenner goto rflag; 13097735bb0fSBill Fenner case 'z': 13107735bb0fSBill Fenner flags |= SIZET; 1311efb7e53dSJordan K. Hubbard goto rflag; 1312927ecbf3STim J. Robbins case 'C': 1313927ecbf3STim J. Robbins flags |= LONGINT; 1314927ecbf3STim J. Robbins /*FALLTHROUGH*/ 1315efb7e53dSJordan K. Hubbard case 'c': 1316b9aac308STim J. Robbins if (flags & LONGINT) 1317b9aac308STim J. Robbins ADDTYPE(T_WINT); 1318b9aac308STim J. Robbins else 1319efb7e53dSJordan K. Hubbard ADDTYPE(T_INT); 1320efb7e53dSJordan K. Hubbard break; 1321efb7e53dSJordan K. Hubbard case 'D': 1322efb7e53dSJordan K. Hubbard flags |= LONGINT; 1323efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1324efb7e53dSJordan K. Hubbard case 'd': 1325efb7e53dSJordan K. Hubbard case 'i': 1326efb7e53dSJordan K. Hubbard ADDSARG(); 1327efb7e53dSJordan K. Hubbard break; 1328efb7e53dSJordan K. Hubbard #ifdef FLOATING_POINT 13297735bb0fSBill Fenner #ifdef HEXFLOAT 13307735bb0fSBill Fenner case 'a': 13317735bb0fSBill Fenner case 'A': 13327735bb0fSBill Fenner #endif 1333efb7e53dSJordan K. Hubbard case 'e': 1334efb7e53dSJordan K. Hubbard case 'E': 1335efb7e53dSJordan K. Hubbard case 'f': 1336efb7e53dSJordan K. Hubbard case 'g': 1337efb7e53dSJordan K. Hubbard case 'G': 1338efb7e53dSJordan K. Hubbard if (flags & LONGDBL) 1339efb7e53dSJordan K. Hubbard ADDTYPE(T_LONG_DOUBLE); 1340efb7e53dSJordan K. Hubbard else 1341efb7e53dSJordan K. Hubbard ADDTYPE(T_DOUBLE); 1342efb7e53dSJordan K. Hubbard break; 1343efb7e53dSJordan K. Hubbard #endif /* FLOATING_POINT */ 1344efb7e53dSJordan K. Hubbard case 'n': 13457735bb0fSBill Fenner if (flags & INTMAXT) 13467735bb0fSBill Fenner ADDTYPE(TP_INTMAXT); 13477735bb0fSBill Fenner else if (flags & PTRDIFFT) 13487735bb0fSBill Fenner ADDTYPE(TP_PTRDIFFT); 13497735bb0fSBill Fenner else if (flags & SIZET) 13507735bb0fSBill Fenner ADDTYPE(TP_SIZET); 13517735bb0fSBill Fenner else if (flags & LLONGINT) 13527735bb0fSBill Fenner ADDTYPE(TP_LLONG); 1353efb7e53dSJordan K. Hubbard else if (flags & LONGINT) 1354efb7e53dSJordan K. Hubbard ADDTYPE(TP_LONG); 1355efb7e53dSJordan K. Hubbard else if (flags & SHORTINT) 1356efb7e53dSJordan K. Hubbard ADDTYPE(TP_SHORT); 13577735bb0fSBill Fenner else if (flags & CHARINT) 13587735bb0fSBill Fenner ADDTYPE(TP_SCHAR); 1359efb7e53dSJordan K. Hubbard else 1360efb7e53dSJordan K. Hubbard ADDTYPE(TP_INT); 1361efb7e53dSJordan K. Hubbard continue; /* no output */ 1362efb7e53dSJordan K. Hubbard case 'O': 1363efb7e53dSJordan K. Hubbard flags |= LONGINT; 1364efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1365efb7e53dSJordan K. Hubbard case 'o': 1366efb7e53dSJordan K. Hubbard ADDUARG(); 1367efb7e53dSJordan K. Hubbard break; 1368efb7e53dSJordan K. Hubbard case 'p': 1369efb7e53dSJordan K. Hubbard ADDTYPE(TP_VOID); 1370efb7e53dSJordan K. Hubbard break; 1371927ecbf3STim J. Robbins case 'S': 1372927ecbf3STim J. Robbins flags |= LONGINT; 1373927ecbf3STim J. Robbins /*FALLTHROUGH*/ 1374efb7e53dSJordan K. Hubbard case 's': 1375b9aac308STim J. Robbins if (flags & LONGINT) 1376b9aac308STim J. Robbins ADDTYPE(TP_WCHAR); 1377b9aac308STim J. Robbins else 1378efb7e53dSJordan K. Hubbard ADDTYPE(TP_CHAR); 1379efb7e53dSJordan K. Hubbard break; 1380efb7e53dSJordan K. Hubbard case 'U': 1381efb7e53dSJordan K. Hubbard flags |= LONGINT; 1382efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1383efb7e53dSJordan K. Hubbard case 'u': 1384efb7e53dSJordan K. Hubbard case 'X': 1385efb7e53dSJordan K. Hubbard case 'x': 1386efb7e53dSJordan K. Hubbard ADDUARG(); 1387efb7e53dSJordan K. Hubbard break; 1388efb7e53dSJordan K. Hubbard default: /* "%?" prints ?, unless ? is NUL */ 1389efb7e53dSJordan K. Hubbard if (ch == '\0') 1390efb7e53dSJordan K. Hubbard goto done; 1391efb7e53dSJordan K. Hubbard break; 1392efb7e53dSJordan K. Hubbard } 1393efb7e53dSJordan K. Hubbard } 1394efb7e53dSJordan K. Hubbard done: 1395efb7e53dSJordan K. Hubbard /* 1396efb7e53dSJordan K. Hubbard * Build the argument table. 1397efb7e53dSJordan K. Hubbard */ 1398efb7e53dSJordan K. Hubbard if (tablemax >= STATIC_ARG_TBL_SIZE) { 1399a387081cSDoug Rabson *argtable = (union arg *) 1400a387081cSDoug Rabson malloc (sizeof (union arg) * (tablemax + 1)); 1401efb7e53dSJordan K. Hubbard } 1402efb7e53dSJordan K. Hubbard 1403a387081cSDoug Rabson (*argtable) [0].intarg = 0; 1404efb7e53dSJordan K. Hubbard for (n = 1; n <= tablemax; n++) { 1405efb7e53dSJordan K. Hubbard switch (typetable [n]) { 14067735bb0fSBill Fenner case T_UNUSED: /* whoops! */ 1407a387081cSDoug Rabson (*argtable) [n].intarg = va_arg (ap, int); 1408efb7e53dSJordan K. Hubbard break; 14097735bb0fSBill Fenner case TP_SCHAR: 14107735bb0fSBill Fenner (*argtable) [n].pschararg = va_arg (ap, signed char *); 1411efb7e53dSJordan K. Hubbard break; 1412efb7e53dSJordan K. Hubbard case TP_SHORT: 1413a387081cSDoug Rabson (*argtable) [n].pshortarg = va_arg (ap, short *); 1414efb7e53dSJordan K. Hubbard break; 1415efb7e53dSJordan K. Hubbard case T_INT: 1416a387081cSDoug Rabson (*argtable) [n].intarg = va_arg (ap, int); 1417efb7e53dSJordan K. Hubbard break; 1418efb7e53dSJordan K. Hubbard case T_U_INT: 1419a387081cSDoug Rabson (*argtable) [n].uintarg = va_arg (ap, unsigned int); 1420efb7e53dSJordan K. Hubbard break; 1421efb7e53dSJordan K. Hubbard case TP_INT: 1422a387081cSDoug Rabson (*argtable) [n].pintarg = va_arg (ap, int *); 1423efb7e53dSJordan K. Hubbard break; 1424efb7e53dSJordan K. Hubbard case T_LONG: 1425a387081cSDoug Rabson (*argtable) [n].longarg = va_arg (ap, long); 1426efb7e53dSJordan K. Hubbard break; 1427efb7e53dSJordan K. Hubbard case T_U_LONG: 1428a387081cSDoug Rabson (*argtable) [n].ulongarg = va_arg (ap, unsigned long); 1429efb7e53dSJordan K. Hubbard break; 1430efb7e53dSJordan K. Hubbard case TP_LONG: 1431a387081cSDoug Rabson (*argtable) [n].plongarg = va_arg (ap, long *); 1432efb7e53dSJordan K. Hubbard break; 14337735bb0fSBill Fenner case T_LLONG: 14347735bb0fSBill Fenner (*argtable) [n].longlongarg = va_arg (ap, long long); 1435efb7e53dSJordan K. Hubbard break; 14367735bb0fSBill Fenner case T_U_LLONG: 14377735bb0fSBill Fenner (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); 1438efb7e53dSJordan K. Hubbard break; 14397735bb0fSBill Fenner case TP_LLONG: 14407735bb0fSBill Fenner (*argtable) [n].plonglongarg = va_arg (ap, long long *); 14417735bb0fSBill Fenner break; 14427735bb0fSBill Fenner case T_PTRDIFFT: 14437735bb0fSBill Fenner (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); 14447735bb0fSBill Fenner break; 14457735bb0fSBill Fenner case TP_PTRDIFFT: 14467735bb0fSBill Fenner (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); 14477735bb0fSBill Fenner break; 14487735bb0fSBill Fenner case T_SIZET: 14497735bb0fSBill Fenner (*argtable) [n].sizearg = va_arg (ap, size_t); 14507735bb0fSBill Fenner break; 14517735bb0fSBill Fenner case TP_SIZET: 14527735bb0fSBill Fenner (*argtable) [n].psizearg = va_arg (ap, ssize_t *); 14537735bb0fSBill Fenner break; 14547735bb0fSBill Fenner case T_INTMAXT: 14557735bb0fSBill Fenner (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); 14567735bb0fSBill Fenner break; 14577735bb0fSBill Fenner case T_UINTMAXT: 14587735bb0fSBill Fenner (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); 14597735bb0fSBill Fenner break; 14607735bb0fSBill Fenner case TP_INTMAXT: 14617735bb0fSBill Fenner (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); 1462efb7e53dSJordan K. Hubbard break; 1463a387081cSDoug Rabson #ifdef FLOATING_POINT 1464efb7e53dSJordan K. Hubbard case T_DOUBLE: 1465a387081cSDoug Rabson (*argtable) [n].doublearg = va_arg (ap, double); 1466efb7e53dSJordan K. Hubbard break; 1467efb7e53dSJordan K. Hubbard case T_LONG_DOUBLE: 1468a387081cSDoug Rabson (*argtable) [n].longdoublearg = va_arg (ap, long double); 1469efb7e53dSJordan K. Hubbard break; 1470a387081cSDoug Rabson #endif 1471efb7e53dSJordan K. Hubbard case TP_CHAR: 1472a387081cSDoug Rabson (*argtable) [n].pchararg = va_arg (ap, char *); 1473efb7e53dSJordan K. Hubbard break; 1474efb7e53dSJordan K. Hubbard case TP_VOID: 1475a387081cSDoug Rabson (*argtable) [n].pvoidarg = va_arg (ap, void *); 1476efb7e53dSJordan K. Hubbard break; 1477b9aac308STim J. Robbins case T_WINT: 1478b9aac308STim J. Robbins (*argtable) [n].wintarg = va_arg (ap, wint_t); 1479b9aac308STim J. Robbins break; 1480b9aac308STim J. Robbins case TP_WCHAR: 1481b9aac308STim J. Robbins (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); 1482b9aac308STim J. Robbins break; 1483efb7e53dSJordan K. Hubbard } 1484efb7e53dSJordan K. Hubbard } 1485efb7e53dSJordan K. Hubbard 1486efb7e53dSJordan K. Hubbard if ((typetable != NULL) && (typetable != stattypetable)) 1487efb7e53dSJordan K. Hubbard free (typetable); 1488efb7e53dSJordan K. Hubbard } 1489efb7e53dSJordan K. Hubbard 1490efb7e53dSJordan K. Hubbard /* 1491efb7e53dSJordan K. Hubbard * Increase the size of the type table. 1492efb7e53dSJordan K. Hubbard */ 1493efb7e53dSJordan K. Hubbard static void 14947735bb0fSBill Fenner __grow_type_table (int nextarg, enum typeid **typetable, int *tablesize) 1495efb7e53dSJordan K. Hubbard { 14967735bb0fSBill Fenner enum typeid *const oldtable = *typetable; 149742cebaa5SArchie Cobbs const int oldsize = *tablesize; 14987735bb0fSBill Fenner enum typeid *newtable; 149942cebaa5SArchie Cobbs int newsize = oldsize * 2; 1500efb7e53dSJordan K. Hubbard 150142cebaa5SArchie Cobbs if (newsize < nextarg + 1) 150242cebaa5SArchie Cobbs newsize = nextarg + 1; 150342cebaa5SArchie Cobbs if (oldsize == STATIC_ARG_TBL_SIZE) { 150442cebaa5SArchie Cobbs if ((newtable = malloc(newsize)) == NULL) 150542cebaa5SArchie Cobbs abort(); /* XXX handle better */ 150642cebaa5SArchie Cobbs bcopy(oldtable, newtable, oldsize); 1507efb7e53dSJordan K. Hubbard } else { 150842cebaa5SArchie Cobbs if ((newtable = reallocf(oldtable, newsize)) == NULL) 150942cebaa5SArchie Cobbs abort(); /* XXX handle better */ 1510efb7e53dSJordan K. Hubbard } 151142cebaa5SArchie Cobbs memset(&newtable[oldsize], T_UNUSED, newsize - oldsize); 1512efb7e53dSJordan K. Hubbard 151342cebaa5SArchie Cobbs *typetable = newtable; 1514efb7e53dSJordan K. Hubbard *tablesize = newsize; 1515efb7e53dSJordan K. Hubbard } 1516efb7e53dSJordan K. Hubbard 1517efb7e53dSJordan K. Hubbard 151858f0484fSRodney W. Grimes #ifdef FLOATING_POINT 151958f0484fSRodney W. Grimes 152058f0484fSRodney W. Grimes static char * 1521d201fe46SDaniel Eischen cvt(double value, int ndigits, int flags, char *sign, int *decpt, 15226a66acb5SDavid Schultz int ch, int *length) 152358f0484fSRodney W. Grimes { 152458f0484fSRodney W. Grimes int mode, dsgn; 152558f0484fSRodney W. Grimes char *digits, *bp, *rve; 152658f0484fSRodney W. Grimes 152758f0484fSRodney W. Grimes if (ch == 'f') 1528d26be6f0SBruce Evans mode = 3; /* ndigits after the decimal point */ 152958f0484fSRodney W. Grimes else { 1530d26be6f0SBruce Evans /* 1531d26be6f0SBruce Evans * To obtain ndigits after the decimal point for the 'e' 1532d26be6f0SBruce Evans * and 'E' formats, round to ndigits + 1 significant 1533d26be6f0SBruce Evans * figures. 1534d26be6f0SBruce Evans */ 1535d26be6f0SBruce Evans if (ch == 'e' || ch == 'E') 1536d26be6f0SBruce Evans ndigits++; 1537d26be6f0SBruce Evans mode = 2; /* ndigits significant digits */ 153858f0484fSRodney W. Grimes } 15396a66acb5SDavid Schultz digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve); 15403dd65760SJens Schweikhardt *sign = dsgn != 0; 1541d26be6f0SBruce Evans if ((ch != 'g' && ch != 'G') || flags & ALT) { 1542d26be6f0SBruce Evans /* print trailing zeros */ 154358f0484fSRodney W. Grimes bp = digits + ndigits; 154458f0484fSRodney W. Grimes if (ch == 'f') { 15453ba6b6ddSDavid Schultz if ((*digits == '0' || *digits == '\0') && value) 154658f0484fSRodney W. Grimes *decpt = -ndigits + 1; 154758f0484fSRodney W. Grimes bp += *decpt; 154858f0484fSRodney W. Grimes } 154958f0484fSRodney W. Grimes if (value == 0) /* kludge for __dtoa irregularity */ 155058f0484fSRodney W. Grimes rve = bp; 155158f0484fSRodney W. Grimes while (rve < bp) 155258f0484fSRodney W. Grimes *rve++ = '0'; 155358f0484fSRodney W. Grimes } 155458f0484fSRodney W. Grimes *length = rve - digits; 155558f0484fSRodney W. Grimes return (digits); 155658f0484fSRodney W. Grimes } 155758f0484fSRodney W. Grimes 155858f0484fSRodney W. Grimes static int 1559d201fe46SDaniel Eischen exponent(char *p0, int exp, int fmtch) 156058f0484fSRodney W. Grimes { 1561d201fe46SDaniel Eischen char *p, *t; 156238cac8f8SDavid Schultz char expbuf[MAXEXPDIG]; 156358f0484fSRodney W. Grimes 156458f0484fSRodney W. Grimes p = p0; 156558f0484fSRodney W. Grimes *p++ = fmtch; 156658f0484fSRodney W. Grimes if (exp < 0) { 156758f0484fSRodney W. Grimes exp = -exp; 156858f0484fSRodney W. Grimes *p++ = '-'; 156958f0484fSRodney W. Grimes } 157058f0484fSRodney W. Grimes else 157158f0484fSRodney W. Grimes *p++ = '+'; 157238cac8f8SDavid Schultz t = expbuf + MAXEXPDIG; 157358f0484fSRodney W. Grimes if (exp > 9) { 157458f0484fSRodney W. Grimes do { 157558f0484fSRodney W. Grimes *--t = to_char(exp % 10); 157658f0484fSRodney W. Grimes } while ((exp /= 10) > 9); 157758f0484fSRodney W. Grimes *--t = to_char(exp); 157838cac8f8SDavid Schultz for (; t < expbuf + MAXEXPDIG; *p++ = *t++); 157958f0484fSRodney W. Grimes } 158058f0484fSRodney W. Grimes else { 158158f0484fSRodney W. Grimes *p++ = '0'; 158258f0484fSRodney W. Grimes *p++ = to_char(exp); 158358f0484fSRodney W. Grimes } 158458f0484fSRodney W. Grimes return (p - p0); 158558f0484fSRodney W. Grimes } 158658f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 1587