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 * 4. Neither the name of the University nor the names of its contributors 1758f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software 1858f0484fSRodney W. Grimes * without specific prior written permission. 1958f0484fSRodney W. Grimes * 2058f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2158f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2258f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2358f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2458f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2558f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2658f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2758f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2858f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2958f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3058f0484fSRodney W. Grimes * SUCH DAMAGE. 3158f0484fSRodney W. Grimes */ 3258f0484fSRodney W. Grimes 3358f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint) 3458f0484fSRodney W. Grimes static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; 3558f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */ 36333fc21eSDavid E. O'Brien #include <sys/cdefs.h> 37333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 3858f0484fSRodney W. Grimes 3958f0484fSRodney W. Grimes /* 4058f0484fSRodney W. Grimes * Actual printf innards. 4158f0484fSRodney W. Grimes * 4258f0484fSRodney W. Grimes * This code is large and complicated... 4358f0484fSRodney W. Grimes */ 4458f0484fSRodney W. Grimes 45d201fe46SDaniel Eischen #include "namespace.h" 4658f0484fSRodney W. Grimes #include <sys/types.h> 4758f0484fSRodney W. Grimes 487735bb0fSBill Fenner #include <ctype.h> 4958f0484fSRodney W. Grimes #include <limits.h> 507ae5c679SAlexey Zelkin #include <locale.h> 517735bb0fSBill Fenner #include <stddef.h> 527735bb0fSBill Fenner #include <stdint.h> 5358f0484fSRodney W. Grimes #include <stdio.h> 5458f0484fSRodney W. Grimes #include <stdlib.h> 5558f0484fSRodney W. Grimes #include <string.h> 56b9aac308STim J. Robbins #include <wchar.h> 5775067f4fSPoul-Henning Kamp #include <printf.h> 5858f0484fSRodney W. Grimes 5958f0484fSRodney W. Grimes #include <stdarg.h> 60d201fe46SDaniel Eischen #include "un-namespace.h" 6158f0484fSRodney W. Grimes 62d201fe46SDaniel Eischen #include "libc_private.h" 6358f0484fSRodney W. Grimes #include "local.h" 6458f0484fSRodney W. Grimes #include "fvwrite.h" 6558f0484fSRodney W. Grimes 66a387081cSDoug Rabson union arg { 67a387081cSDoug Rabson int intarg; 6818ca70d1SBruce Evans u_int uintarg; 69a387081cSDoug Rabson long longarg; 7018ca70d1SBruce Evans u_long ulongarg; 717735bb0fSBill Fenner long long longlongarg; 727735bb0fSBill Fenner unsigned long long ulonglongarg; 737735bb0fSBill Fenner ptrdiff_t ptrdiffarg; 747735bb0fSBill Fenner size_t sizearg; 757735bb0fSBill Fenner intmax_t intmaxarg; 767735bb0fSBill Fenner uintmax_t uintmaxarg; 77a387081cSDoug Rabson void *pvoidarg; 78a387081cSDoug Rabson char *pchararg; 797735bb0fSBill Fenner signed char *pschararg; 80a387081cSDoug Rabson short *pshortarg; 81a387081cSDoug Rabson int *pintarg; 82a387081cSDoug Rabson long *plongarg; 837735bb0fSBill Fenner long long *plonglongarg; 847735bb0fSBill Fenner ptrdiff_t *pptrdiffarg; 857735bb0fSBill Fenner size_t *psizearg; 867735bb0fSBill Fenner intmax_t *pintmaxarg; 878de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 88a387081cSDoug Rabson double doublearg; 89a387081cSDoug Rabson long double longdoublearg; 90a387081cSDoug Rabson #endif 91b9aac308STim J. Robbins wint_t wintarg; 92b9aac308STim J. Robbins wchar_t *pwchararg; 93a387081cSDoug Rabson }; 94a387081cSDoug Rabson 957735bb0fSBill Fenner /* 967735bb0fSBill Fenner * Type ids for argument type table. 977735bb0fSBill Fenner */ 987735bb0fSBill Fenner enum typeid { 997735bb0fSBill Fenner T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, 1007735bb0fSBill Fenner T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, 1017735bb0fSBill Fenner T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET, 1027735bb0fSBill Fenner T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, 103b9aac308STim J. Robbins T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR 1047735bb0fSBill Fenner }; 1057735bb0fSBill Fenner 106e5abb5e6SDavid Schultz #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 107e5abb5e6SDavid Schultz 108e5abb5e6SDavid Schultz /* An expandable array of types. */ 109e5abb5e6SDavid Schultz struct typetable { 110e5abb5e6SDavid Schultz enum typeid *table; /* table of types */ 111e5abb5e6SDavid Schultz enum typeid stattable[STATIC_ARG_TBL_SIZE]; 112e5abb5e6SDavid Schultz int tablesize; /* current size of type table */ 113e5abb5e6SDavid Schultz int tablemax; /* largest used index in table */ 114e5abb5e6SDavid Schultz int nextarg; /* 1-based argument index */ 115e5abb5e6SDavid Schultz }; 116e5abb5e6SDavid Schultz 117c05ac53bSDavid E. O'Brien static int __sprint(FILE *, struct __suio *); 1181372519bSDavid E. O'Brien static int __sbprintf(FILE *, const char *, va_list) __printflike(2, 0); 119ebbad5ecSDavid Schultz static char *__ujtoa(uintmax_t, char *, int, int, const char *, int, char, 1201372519bSDavid E. O'Brien const char *); 121ebbad5ecSDavid Schultz static char *__ultoa(u_long, char *, int, int, const char *, int, char, 1221372519bSDavid E. O'Brien const char *); 123b9aac308STim J. Robbins static char *__wcsconv(wchar_t *, int); 124c05ac53bSDavid E. O'Brien static void __find_arguments(const char *, va_list, union arg **); 125e5abb5e6SDavid Schultz static void __grow_type_table(struct typetable *); 126ce51cf03SJames Raynard 12758f0484fSRodney W. Grimes /* 12858f0484fSRodney W. Grimes * Flush out all the vectors defined by the given uio, 12958f0484fSRodney W. Grimes * then reset it so that it can be reused. 13058f0484fSRodney W. Grimes */ 13158f0484fSRodney W. Grimes static int 132d201fe46SDaniel Eischen __sprint(FILE *fp, struct __suio *uio) 13358f0484fSRodney W. Grimes { 134d201fe46SDaniel Eischen int err; 13558f0484fSRodney W. Grimes 13658f0484fSRodney W. Grimes if (uio->uio_resid == 0) { 13758f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 13858f0484fSRodney W. Grimes return (0); 13958f0484fSRodney W. Grimes } 14058f0484fSRodney W. Grimes err = __sfvwrite(fp, uio); 14158f0484fSRodney W. Grimes uio->uio_resid = 0; 14258f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 14358f0484fSRodney W. Grimes return (err); 14458f0484fSRodney W. Grimes } 14558f0484fSRodney W. Grimes 14658f0484fSRodney W. Grimes /* 14758f0484fSRodney W. Grimes * Helper function for `fprintf to unbuffered unix file': creates a 14858f0484fSRodney W. Grimes * temporary buffer. We only work on write-only files; this avoids 14958f0484fSRodney W. Grimes * worries about ungetc buffers and so forth. 15058f0484fSRodney W. Grimes */ 15158f0484fSRodney W. Grimes static int 152d201fe46SDaniel Eischen __sbprintf(FILE *fp, const char *fmt, va_list ap) 15358f0484fSRodney W. Grimes { 15458f0484fSRodney W. Grimes int ret; 15558f0484fSRodney W. Grimes FILE fake; 15658f0484fSRodney W. Grimes unsigned char buf[BUFSIZ]; 15758f0484fSRodney W. Grimes 15858f0484fSRodney W. Grimes /* copy the important variables */ 15958f0484fSRodney W. Grimes fake._flags = fp->_flags & ~__SNBF; 16058f0484fSRodney W. Grimes fake._file = fp->_file; 16158f0484fSRodney W. Grimes fake._cookie = fp->_cookie; 16258f0484fSRodney W. Grimes fake._write = fp->_write; 1631e98f887SJohn Baldwin fake._orientation = fp->_orientation; 1641e98f887SJohn Baldwin fake._mbstate = fp->_mbstate; 16558f0484fSRodney W. Grimes 16658f0484fSRodney W. Grimes /* set up the buffer */ 16758f0484fSRodney W. Grimes fake._bf._base = fake._p = buf; 16858f0484fSRodney W. Grimes fake._bf._size = fake._w = sizeof(buf); 16958f0484fSRodney W. Grimes fake._lbfsize = 0; /* not actually used, but Just In Case */ 17058f0484fSRodney W. Grimes 17158f0484fSRodney W. Grimes /* do the work, then copy any error status */ 172d201fe46SDaniel Eischen ret = __vfprintf(&fake, fmt, ap); 173d201fe46SDaniel Eischen if (ret >= 0 && __fflush(&fake)) 17458f0484fSRodney W. Grimes ret = EOF; 17558f0484fSRodney W. Grimes if (fake._flags & __SERR) 17658f0484fSRodney W. Grimes fp->_flags |= __SERR; 17758f0484fSRodney W. Grimes return (ret); 17858f0484fSRodney W. Grimes } 17958f0484fSRodney W. Grimes 18058f0484fSRodney W. Grimes /* 18158f0484fSRodney W. Grimes * Macros for converting digits to letters and vice versa 18258f0484fSRodney W. Grimes */ 18358f0484fSRodney W. Grimes #define to_digit(c) ((c) - '0') 18458f0484fSRodney W. Grimes #define is_digit(c) ((unsigned)to_digit(c) <= 9) 18558f0484fSRodney W. Grimes #define to_char(n) ((n) + '0') 18658f0484fSRodney W. Grimes 18758f0484fSRodney W. Grimes /* 18858f0484fSRodney W. Grimes * Convert an unsigned long to ASCII for printf purposes, returning 18958f0484fSRodney W. Grimes * a pointer to the first character of the string representation. 19058f0484fSRodney W. Grimes * Octal numbers can be forced to have a leading zero; hex numbers 19158f0484fSRodney W. Grimes * use the given digits. 19258f0484fSRodney W. Grimes */ 19358f0484fSRodney W. Grimes static char * 194ebbad5ecSDavid Schultz __ultoa(u_long val, char *endp, int base, int octzero, const char *xdigs, 19598ee7635SAlexey Zelkin int needgrp, char thousep, const char *grp) 19658f0484fSRodney W. Grimes { 1978fb3f3f6SDavid E. O'Brien char *cp = endp; 1988fb3f3f6SDavid E. O'Brien long sval; 1997735bb0fSBill Fenner int ndig; 20058f0484fSRodney W. Grimes 20158f0484fSRodney W. Grimes /* 20258f0484fSRodney W. Grimes * Handle the three cases separately, in the hope of getting 20358f0484fSRodney W. Grimes * better/faster code. 20458f0484fSRodney W. Grimes */ 20558f0484fSRodney W. Grimes switch (base) { 20658f0484fSRodney W. Grimes case 10: 20758f0484fSRodney W. Grimes if (val < 10) { /* many numbers are 1 digit */ 20858f0484fSRodney W. Grimes *--cp = to_char(val); 20958f0484fSRodney W. Grimes return (cp); 21058f0484fSRodney W. Grimes } 2117735bb0fSBill Fenner ndig = 0; 21258f0484fSRodney W. Grimes /* 21358f0484fSRodney W. Grimes * On many machines, unsigned arithmetic is harder than 21458f0484fSRodney W. Grimes * signed arithmetic, so we do at most one unsigned mod and 21558f0484fSRodney W. Grimes * divide; this is sufficient to reduce the range of 21658f0484fSRodney W. Grimes * the incoming value to where signed arithmetic works. 21758f0484fSRodney W. Grimes */ 21858f0484fSRodney W. Grimes if (val > LONG_MAX) { 21958f0484fSRodney W. Grimes *--cp = to_char(val % 10); 2207735bb0fSBill Fenner ndig++; 22158f0484fSRodney W. Grimes sval = val / 10; 22258f0484fSRodney W. Grimes } else 22358f0484fSRodney W. Grimes sval = val; 22458f0484fSRodney W. Grimes do { 22558f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 22698ee7635SAlexey Zelkin ndig++; 22798ee7635SAlexey Zelkin /* 22898ee7635SAlexey Zelkin * If (*grp == CHAR_MAX) then no more grouping 22998ee7635SAlexey Zelkin * should be performed. 23098ee7635SAlexey Zelkin */ 231243e90d6SAlexey Zelkin if (needgrp && ndig == *grp && *grp != CHAR_MAX 232243e90d6SAlexey Zelkin && sval > 9) { 23398ee7635SAlexey Zelkin *--cp = thousep; 2347735bb0fSBill Fenner ndig = 0; 23598ee7635SAlexey Zelkin /* 23698ee7635SAlexey Zelkin * If (*(grp+1) == '\0') then we have to 23798ee7635SAlexey Zelkin * use *grp character (last grouping rule) 23898ee7635SAlexey Zelkin * for all next cases 23998ee7635SAlexey Zelkin */ 2402e394b2fSAlexey Zelkin if (*(grp+1) != '\0') 2412e394b2fSAlexey Zelkin grp++; 2427735bb0fSBill Fenner } 24358f0484fSRodney W. Grimes sval /= 10; 24458f0484fSRodney W. Grimes } while (sval != 0); 24558f0484fSRodney W. Grimes break; 24658f0484fSRodney W. Grimes 24758f0484fSRodney W. Grimes case 8: 24858f0484fSRodney W. Grimes do { 24958f0484fSRodney W. Grimes *--cp = to_char(val & 7); 25058f0484fSRodney W. Grimes val >>= 3; 25158f0484fSRodney W. Grimes } while (val); 25258f0484fSRodney W. Grimes if (octzero && *cp != '0') 25358f0484fSRodney W. Grimes *--cp = '0'; 25458f0484fSRodney W. Grimes break; 25558f0484fSRodney W. Grimes 25658f0484fSRodney W. Grimes case 16: 25758f0484fSRodney W. Grimes do { 25858f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 25958f0484fSRodney W. Grimes val >>= 4; 26058f0484fSRodney W. Grimes } while (val); 26158f0484fSRodney W. Grimes break; 26258f0484fSRodney W. Grimes 26358f0484fSRodney W. Grimes default: /* oops */ 26458f0484fSRodney W. Grimes abort(); 26558f0484fSRodney W. Grimes } 26658f0484fSRodney W. Grimes return (cp); 26758f0484fSRodney W. Grimes } 26858f0484fSRodney W. Grimes 2697735bb0fSBill Fenner /* Identical to __ultoa, but for intmax_t. */ 27058f0484fSRodney W. Grimes static char * 271ebbad5ecSDavid Schultz __ujtoa(uintmax_t val, char *endp, int base, int octzero, const char *xdigs, 27298ee7635SAlexey Zelkin int needgrp, char thousep, const char *grp) 27358f0484fSRodney W. Grimes { 274d201fe46SDaniel Eischen char *cp = endp; 2757735bb0fSBill Fenner intmax_t sval; 2767735bb0fSBill Fenner int ndig; 27758f0484fSRodney W. Grimes 27858f0484fSRodney W. Grimes /* quick test for small values; __ultoa is typically much faster */ 27958f0484fSRodney W. Grimes /* (perhaps instead we should run until small, then call __ultoa?) */ 28058f0484fSRodney W. Grimes if (val <= ULONG_MAX) 2817735bb0fSBill Fenner return (__ultoa((u_long)val, endp, base, octzero, xdigs, 28298ee7635SAlexey Zelkin needgrp, thousep, grp)); 28358f0484fSRodney W. Grimes switch (base) { 28458f0484fSRodney W. Grimes case 10: 28558f0484fSRodney W. Grimes if (val < 10) { 28658f0484fSRodney W. Grimes *--cp = to_char(val % 10); 28758f0484fSRodney W. Grimes return (cp); 28858f0484fSRodney W. Grimes } 2897735bb0fSBill Fenner ndig = 0; 2907735bb0fSBill Fenner if (val > INTMAX_MAX) { 29158f0484fSRodney W. Grimes *--cp = to_char(val % 10); 2927735bb0fSBill Fenner ndig++; 29358f0484fSRodney W. Grimes sval = val / 10; 29458f0484fSRodney W. Grimes } else 29558f0484fSRodney W. Grimes sval = val; 29658f0484fSRodney W. Grimes do { 29758f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 29898ee7635SAlexey Zelkin ndig++; 29998ee7635SAlexey Zelkin /* 30098ee7635SAlexey Zelkin * If (*grp == CHAR_MAX) then no more grouping 30198ee7635SAlexey Zelkin * should be performed. 30298ee7635SAlexey Zelkin */ 303243e90d6SAlexey Zelkin if (needgrp && *grp != CHAR_MAX && ndig == *grp 304243e90d6SAlexey Zelkin && sval > 9) { 30598ee7635SAlexey Zelkin *--cp = thousep; 3067735bb0fSBill Fenner ndig = 0; 30798ee7635SAlexey Zelkin /* 30898ee7635SAlexey Zelkin * If (*(grp+1) == '\0') then we have to 30998ee7635SAlexey Zelkin * use *grp character (last grouping rule) 31098ee7635SAlexey Zelkin * for all next cases 31198ee7635SAlexey Zelkin */ 3122e394b2fSAlexey Zelkin if (*(grp+1) != '\0') 3132e394b2fSAlexey Zelkin grp++; 3147735bb0fSBill Fenner } 31558f0484fSRodney W. Grimes sval /= 10; 31658f0484fSRodney W. Grimes } while (sval != 0); 31758f0484fSRodney W. Grimes break; 31858f0484fSRodney W. Grimes 31958f0484fSRodney W. Grimes case 8: 32058f0484fSRodney W. Grimes do { 32158f0484fSRodney W. Grimes *--cp = to_char(val & 7); 32258f0484fSRodney W. Grimes val >>= 3; 32358f0484fSRodney W. Grimes } while (val); 32458f0484fSRodney W. Grimes if (octzero && *cp != '0') 32558f0484fSRodney W. Grimes *--cp = '0'; 32658f0484fSRodney W. Grimes break; 32758f0484fSRodney W. Grimes 32858f0484fSRodney W. Grimes case 16: 32958f0484fSRodney W. Grimes do { 33058f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 33158f0484fSRodney W. Grimes val >>= 4; 33258f0484fSRodney W. Grimes } while (val); 33358f0484fSRodney W. Grimes break; 33458f0484fSRodney W. Grimes 33558f0484fSRodney W. Grimes default: 33658f0484fSRodney W. Grimes abort(); 33758f0484fSRodney W. Grimes } 33858f0484fSRodney W. Grimes return (cp); 33958f0484fSRodney W. Grimes } 34058f0484fSRodney W. Grimes 341d201fe46SDaniel Eischen /* 342b9aac308STim J. Robbins * Convert a wide character string argument for the %ls format to a multibyte 343d48c77b5STim J. Robbins * string representation. If not -1, prec specifies the maximum number of 344d48c77b5STim J. Robbins * bytes to output, and also means that we can't assume that the wide char. 345d48c77b5STim J. Robbins * string ends is null-terminated. 346b9aac308STim J. Robbins */ 347b9aac308STim J. Robbins static char * 348b9aac308STim J. Robbins __wcsconv(wchar_t *wcsarg, int prec) 349b9aac308STim J. Robbins { 35093996f6dSTim J. Robbins static const mbstate_t initial; 35193996f6dSTim J. Robbins mbstate_t mbs; 352b9aac308STim J. Robbins char buf[MB_LEN_MAX]; 353b9aac308STim J. Robbins wchar_t *p; 354d48c77b5STim J. Robbins char *convbuf; 355b9aac308STim J. Robbins size_t clen, nbytes; 356b9aac308STim J. Robbins 357d48c77b5STim J. Robbins /* Allocate space for the maximum number of bytes we could output. */ 358d48c77b5STim J. Robbins if (prec < 0) { 359d48c77b5STim J. Robbins p = wcsarg; 360d48c77b5STim J. Robbins mbs = initial; 361d48c77b5STim J. Robbins nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); 362d48c77b5STim J. Robbins if (nbytes == (size_t)-1) 363d48c77b5STim J. Robbins return (NULL); 364d48c77b5STim J. Robbins } else { 365b9aac308STim J. Robbins /* 366d48c77b5STim J. Robbins * Optimisation: if the output precision is small enough, 367d48c77b5STim J. Robbins * just allocate enough memory for the maximum instead of 368d48c77b5STim J. Robbins * scanning the string. 369b9aac308STim J. Robbins */ 370d48c77b5STim J. Robbins if (prec < 128) 371d48c77b5STim J. Robbins nbytes = prec; 372d48c77b5STim J. Robbins else { 373b9aac308STim J. Robbins nbytes = 0; 374b9aac308STim J. Robbins p = wcsarg; 37593996f6dSTim J. Robbins mbs = initial; 376b9aac308STim J. Robbins for (;;) { 37793996f6dSTim J. Robbins clen = wcrtomb(buf, *p++, &mbs); 378b9aac308STim J. Robbins if (clen == 0 || clen == (size_t)-1 || 379b9aac308STim J. Robbins nbytes + clen > prec) 380b9aac308STim J. Robbins break; 381b9aac308STim J. Robbins nbytes += clen; 382b9aac308STim J. Robbins } 383d48c77b5STim J. Robbins } 384b9aac308STim J. Robbins } 385b9aac308STim J. Robbins if ((convbuf = malloc(nbytes + 1)) == NULL) 386b9aac308STim J. Robbins return (NULL); 387b9aac308STim J. Robbins 388d48c77b5STim J. Robbins /* Fill the output buffer. */ 389b9aac308STim J. Robbins p = wcsarg; 39093996f6dSTim J. Robbins mbs = initial; 391d48c77b5STim J. Robbins if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p, 392d48c77b5STim J. Robbins nbytes, &mbs)) == (size_t)-1) { 3936f098a48SAndrey A. Chernov free(convbuf); 394b9aac308STim J. Robbins return (NULL); 3956f098a48SAndrey A. Chernov } 396d48c77b5STim J. Robbins convbuf[nbytes] = '\0'; 397b9aac308STim J. Robbins return (convbuf); 398b9aac308STim J. Robbins } 399b9aac308STim J. Robbins 400b9aac308STim J. Robbins /* 401d201fe46SDaniel Eischen * MT-safe version 402d201fe46SDaniel Eischen */ 403d201fe46SDaniel Eischen int 404f8418db7SRobert Drehmel vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) 405f8418db7SRobert Drehmel 406d201fe46SDaniel Eischen { 407d201fe46SDaniel Eischen int ret; 408d201fe46SDaniel Eischen 409d201fe46SDaniel Eischen FLOCKFILE(fp); 410d201fe46SDaniel Eischen ret = __vfprintf(fp, fmt0, ap); 411d201fe46SDaniel Eischen FUNLOCKFILE(fp); 412d201fe46SDaniel Eischen return (ret); 413d201fe46SDaniel Eischen } 414d201fe46SDaniel Eischen 4158de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 416ebbad5ecSDavid Schultz 417ebbad5ecSDavid Schultz #define dtoa __dtoa 418ebbad5ecSDavid Schultz #define freedtoa __freedtoa 419ebbad5ecSDavid Schultz 420ebbad5ecSDavid Schultz #include <float.h> 42158f0484fSRodney W. Grimes #include <math.h> 42258f0484fSRodney W. Grimes #include "floatio.h" 423ebbad5ecSDavid Schultz #include "gdtoa.h" 42458f0484fSRodney W. Grimes 42558f0484fSRodney W. Grimes #define DEFPREC 6 42658f0484fSRodney W. Grimes 427c05ac53bSDavid E. O'Brien static int exponent(char *, int, int); 42858f0484fSRodney W. Grimes 4298de9e897SDavid Schultz #endif /* !NO_FLOATING_POINT */ 43058f0484fSRodney W. Grimes 43138cac8f8SDavid Schultz /* 43238cac8f8SDavid Schultz * The size of the buffer we use as scratch space for integer 43338cac8f8SDavid Schultz * conversions, among other things. Technically, we would need the 43438cac8f8SDavid Schultz * most space for base 10 conversions with thousands' grouping 43538cac8f8SDavid Schultz * characters between each pair of digits. 100 bytes is a 43638cac8f8SDavid Schultz * conservative overestimate even for a 128-bit uintmax_t. 43738cac8f8SDavid Schultz */ 43838cac8f8SDavid Schultz #define BUF 100 43938cac8f8SDavid Schultz 44058f0484fSRodney W. Grimes /* 44158f0484fSRodney W. Grimes * Flags used during conversion. 44258f0484fSRodney W. Grimes */ 44358f0484fSRodney W. Grimes #define ALT 0x001 /* alternate form */ 44458f0484fSRodney W. Grimes #define LADJUST 0x004 /* left adjustment */ 4456a93659fSBruce Evans #define LONGDBL 0x008 /* long double */ 44658f0484fSRodney W. Grimes #define LONGINT 0x010 /* long integer */ 4477735bb0fSBill Fenner #define LLONGINT 0x020 /* long long integer */ 44858f0484fSRodney W. Grimes #define SHORTINT 0x040 /* short integer */ 44958f0484fSRodney W. Grimes #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 45058f0484fSRodney W. Grimes #define FPT 0x100 /* Floating point number */ 45198ee7635SAlexey Zelkin #define GROUPING 0x200 /* use grouping ("'" flag) */ 4527735bb0fSBill Fenner /* C99 additional size modifiers: */ 45398ee7635SAlexey Zelkin #define SIZET 0x400 /* size_t */ 45498ee7635SAlexey Zelkin #define PTRDIFFT 0x800 /* ptrdiff_t */ 45598ee7635SAlexey Zelkin #define INTMAXT 0x1000 /* intmax_t */ 45698ee7635SAlexey Zelkin #define CHARINT 0x2000 /* print char using int format */ 4577735bb0fSBill Fenner 458d201fe46SDaniel Eischen /* 459d201fe46SDaniel Eischen * Non-MT-safe version 460d201fe46SDaniel Eischen */ 46158f0484fSRodney W. Grimes int 462d201fe46SDaniel Eischen __vfprintf(FILE *fp, const char *fmt0, va_list ap) 46358f0484fSRodney W. Grimes { 464d201fe46SDaniel Eischen char *fmt; /* format string */ 465d201fe46SDaniel Eischen int ch; /* character from fmt */ 466d201fe46SDaniel Eischen int n, n2; /* handy integer (short term usage) */ 467d201fe46SDaniel Eischen char *cp; /* handy char pointer (short term usage) */ 468d201fe46SDaniel Eischen struct __siov *iovp; /* for PRINT macro */ 469d201fe46SDaniel Eischen int flags; /* flags as above */ 47058f0484fSRodney W. Grimes int ret; /* return value accumulator */ 47158f0484fSRodney W. Grimes int width; /* width from format (%8d), or 0 */ 472ebbad5ecSDavid Schultz int prec; /* precision from format; <0 for N/A */ 47358f0484fSRodney W. Grimes char sign; /* sign prefix (' ', '+', '-', or \0) */ 47498ee7635SAlexey Zelkin char thousands_sep; /* locale specific thousands separator */ 47598ee7635SAlexey Zelkin const char *grouping; /* locale specific numeric grouping rules */ 47675067f4fSPoul-Henning Kamp 47775067f4fSPoul-Henning Kamp if (__use_xprintf == 0 && getenv("USE_XPRINTF")) 47875067f4fSPoul-Henning Kamp __use_xprintf = 1; 47975067f4fSPoul-Henning Kamp if (__use_xprintf > 0) 48075067f4fSPoul-Henning Kamp return (__xvprintf(fp, fmt0, ap)); 48175067f4fSPoul-Henning Kamp 4828de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 483ebbad5ecSDavid Schultz /* 484ebbad5ecSDavid Schultz * We can decompose the printed representation of floating 485ebbad5ecSDavid Schultz * point numbers into several parts, some of which may be empty: 486ebbad5ecSDavid Schultz * 487ebbad5ecSDavid Schultz * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ 488ebbad5ecSDavid Schultz * A B ---C--- D E F 489ebbad5ecSDavid Schultz * 490ebbad5ecSDavid Schultz * A: 'sign' holds this value if present; '\0' otherwise 491ebbad5ecSDavid Schultz * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal 492ebbad5ecSDavid Schultz * C: cp points to the string MMMNNN. Leading and trailing 493ebbad5ecSDavid Schultz * zeros are not in the string and must be added. 494ebbad5ecSDavid Schultz * D: expchar holds this character; '\0' if no exponent, e.g. %f 495ebbad5ecSDavid Schultz * F: at least two digits for decimal, at least one digit for hex 496ebbad5ecSDavid Schultz */ 4977ae5c679SAlexey Zelkin char *decimal_point; /* locale specific decimal point */ 498ebbad5ecSDavid Schultz int signflag; /* true if float is negative */ 499ebbad5ecSDavid Schultz union { /* floating point arguments %[aAeEfFgG] */ 500ebbad5ecSDavid Schultz double dbl; 501ebbad5ecSDavid Schultz long double ldbl; 502ebbad5ecSDavid Schultz } fparg; 50358f0484fSRodney W. Grimes int expt; /* integer value of exponent */ 504ebbad5ecSDavid Schultz char expchar; /* exponent character: [eEpP\0] */ 505ebbad5ecSDavid Schultz char *dtoaend; /* pointer to end of converted digits */ 50658f0484fSRodney W. Grimes int expsize; /* character count for expstr */ 507ebbad5ecSDavid Schultz int lead; /* sig figs before decimal or group sep */ 508ebbad5ecSDavid Schultz int ndig; /* actual number of digits returned by dtoa */ 509ebbad5ecSDavid Schultz char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ 5102ffc61baSTor Egge char *dtoaresult; /* buffer allocated by dtoa */ 511ebbad5ecSDavid Schultz int nseps; /* number of group separators with ' */ 512ebbad5ecSDavid Schultz int nrepeats; /* number of repeats of the last group */ 51358f0484fSRodney W. Grimes #endif 51458f0484fSRodney W. Grimes u_long ulval; /* integer arguments %[diouxX] */ 5157735bb0fSBill Fenner uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ 51658f0484fSRodney W. Grimes int base; /* base for [diouxX] conversion */ 51758f0484fSRodney W. Grimes int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 518261a532aSBill Fenner int realsz; /* field size expanded by dprec, sign, etc */ 51958f0484fSRodney W. Grimes int size; /* size of converted field or string */ 52092e88f87SAndrey A. Chernov int prsize; /* max size of printed field */ 521ebbad5ecSDavid Schultz const char *xdigs; /* digits for %[xX] conversion */ 52258f0484fSRodney W. Grimes #define NIOV 8 52358f0484fSRodney W. Grimes struct __suio uio; /* output information: summary */ 52458f0484fSRodney W. Grimes struct __siov iov[NIOV];/* ... and individual io vectors */ 52538cac8f8SDavid Schultz char buf[BUF]; /* buffer with space for digits of uintmax_t */ 526ebbad5ecSDavid Schultz char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ 527a387081cSDoug Rabson union arg *argtable; /* args, built due to positional arg */ 528a387081cSDoug Rabson union arg statargtable [STATIC_ARG_TBL_SIZE]; 529efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 530efb7e53dSJordan K. Hubbard va_list orgap; /* original argument pointer */ 531b9aac308STim J. Robbins char *convbuf; /* wide to multibyte conversion result */ 53258f0484fSRodney W. Grimes 53358f0484fSRodney W. Grimes /* 53458f0484fSRodney W. Grimes * Choose PADSIZE to trade efficiency vs. size. If larger printf 53558f0484fSRodney W. Grimes * fields occur frequently, increase PADSIZE and make the initialisers 53658f0484fSRodney W. Grimes * below longer. 53758f0484fSRodney W. Grimes */ 53858f0484fSRodney W. Grimes #define PADSIZE 16 /* pad chunk size */ 53958f0484fSRodney W. Grimes static char blanks[PADSIZE] = 54058f0484fSRodney W. Grimes {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 54158f0484fSRodney W. Grimes static char zeroes[PADSIZE] = 54258f0484fSRodney W. Grimes {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 54358f0484fSRodney W. Grimes 544ac9913a7SDavid Schultz static const char xdigs_lower[16] = "0123456789abcdef"; 545ac9913a7SDavid Schultz static const char xdigs_upper[16] = "0123456789ABCDEF"; 546ebbad5ecSDavid Schultz 54758f0484fSRodney W. Grimes /* 54858f0484fSRodney W. Grimes * BEWARE, these `goto error' on error, and PAD uses `n'. 54958f0484fSRodney W. Grimes */ 55058f0484fSRodney W. Grimes #define PRINT(ptr, len) { \ 55158f0484fSRodney W. Grimes iovp->iov_base = (ptr); \ 55258f0484fSRodney W. Grimes iovp->iov_len = (len); \ 55358f0484fSRodney W. Grimes uio.uio_resid += (len); \ 55458f0484fSRodney W. Grimes iovp++; \ 55558f0484fSRodney W. Grimes if (++uio.uio_iovcnt >= NIOV) { \ 55658f0484fSRodney W. Grimes if (__sprint(fp, &uio)) \ 55758f0484fSRodney W. Grimes goto error; \ 55858f0484fSRodney W. Grimes iovp = iov; \ 55958f0484fSRodney W. Grimes } \ 56058f0484fSRodney W. Grimes } 56158f0484fSRodney W. Grimes #define PAD(howmany, with) { \ 56258f0484fSRodney W. Grimes if ((n = (howmany)) > 0) { \ 56358f0484fSRodney W. Grimes while (n > PADSIZE) { \ 56458f0484fSRodney W. Grimes PRINT(with, PADSIZE); \ 56558f0484fSRodney W. Grimes n -= PADSIZE; \ 56658f0484fSRodney W. Grimes } \ 56758f0484fSRodney W. Grimes PRINT(with, n); \ 56858f0484fSRodney W. Grimes } \ 56958f0484fSRodney W. Grimes } 5703b204b7dSDavid Schultz #define PRINTANDPAD(p, ep, len, with) do { \ 5713b204b7dSDavid Schultz n2 = (ep) - (p); \ 5723b204b7dSDavid Schultz if (n2 > (len)) \ 5733b204b7dSDavid Schultz n2 = (len); \ 5743b204b7dSDavid Schultz if (n2 > 0) \ 5753b204b7dSDavid Schultz PRINT((p), n2); \ 5763b204b7dSDavid Schultz PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ 5773b204b7dSDavid Schultz } while(0) 57858f0484fSRodney W. Grimes #define FLUSH() { \ 57958f0484fSRodney W. Grimes if (uio.uio_resid && __sprint(fp, &uio)) \ 58058f0484fSRodney W. Grimes goto error; \ 58158f0484fSRodney W. Grimes uio.uio_iovcnt = 0; \ 58258f0484fSRodney W. Grimes iovp = iov; \ 58358f0484fSRodney W. Grimes } 58458f0484fSRodney W. Grimes 58558f0484fSRodney W. Grimes /* 586efb7e53dSJordan K. Hubbard * Get the argument indexed by nextarg. If the argument table is 587efb7e53dSJordan K. Hubbard * built, use it to get the argument. If its not, get the next 588efb7e53dSJordan K. Hubbard * argument (and arguments must be gotten sequentially). 589efb7e53dSJordan K. Hubbard */ 590efb7e53dSJordan K. Hubbard #define GETARG(type) \ 591a387081cSDoug Rabson ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 592efb7e53dSJordan K. Hubbard (nextarg++, va_arg(ap, type))) 593efb7e53dSJordan K. Hubbard 594efb7e53dSJordan K. Hubbard /* 59558f0484fSRodney W. Grimes * To extend shorts properly, we need both signed and unsigned 59658f0484fSRodney W. Grimes * argument extraction methods. 59758f0484fSRodney W. Grimes */ 59858f0484fSRodney W. Grimes #define SARG() \ 599efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(long) : \ 600efb7e53dSJordan K. Hubbard flags&SHORTINT ? (long)(short)GETARG(int) : \ 6017735bb0fSBill Fenner flags&CHARINT ? (long)(signed char)GETARG(int) : \ 602efb7e53dSJordan K. Hubbard (long)GETARG(int)) 60358f0484fSRodney W. Grimes #define UARG() \ 604efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(u_long) : \ 605efb7e53dSJordan K. Hubbard flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 6067735bb0fSBill Fenner flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ 607efb7e53dSJordan K. Hubbard (u_long)GETARG(u_int)) 6087735bb0fSBill Fenner #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) 6097735bb0fSBill Fenner #define SJARG() \ 6107735bb0fSBill Fenner (flags&INTMAXT ? GETARG(intmax_t) : \ 6117735bb0fSBill Fenner flags&SIZET ? (intmax_t)GETARG(size_t) : \ 6127735bb0fSBill Fenner flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ 6137735bb0fSBill Fenner (intmax_t)GETARG(long long)) 6147735bb0fSBill Fenner #define UJARG() \ 6157735bb0fSBill Fenner (flags&INTMAXT ? GETARG(uintmax_t) : \ 6167735bb0fSBill Fenner flags&SIZET ? (uintmax_t)GETARG(size_t) : \ 6177735bb0fSBill Fenner flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ 6187735bb0fSBill Fenner (uintmax_t)GETARG(unsigned long long)) 619efb7e53dSJordan K. Hubbard 620efb7e53dSJordan K. Hubbard /* 621efb7e53dSJordan K. Hubbard * Get * arguments, including the form *nn$. Preserve the nextarg 622efb7e53dSJordan K. Hubbard * that the argument can be gotten once the type is determined. 623efb7e53dSJordan K. Hubbard */ 624efb7e53dSJordan K. Hubbard #define GETASTER(val) \ 625efb7e53dSJordan K. Hubbard n2 = 0; \ 626efb7e53dSJordan K. Hubbard cp = fmt; \ 627efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 628efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 629efb7e53dSJordan K. Hubbard cp++; \ 630efb7e53dSJordan K. Hubbard } \ 631efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 632efb7e53dSJordan K. Hubbard int hold = nextarg; \ 633efb7e53dSJordan K. Hubbard if (argtable == NULL) { \ 634efb7e53dSJordan K. Hubbard argtable = statargtable; \ 635efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, &argtable); \ 636efb7e53dSJordan K. Hubbard } \ 637efb7e53dSJordan K. Hubbard nextarg = n2; \ 638efb7e53dSJordan K. Hubbard val = GETARG (int); \ 639efb7e53dSJordan K. Hubbard nextarg = hold; \ 640efb7e53dSJordan K. Hubbard fmt = ++cp; \ 641efb7e53dSJordan K. Hubbard } else { \ 642efb7e53dSJordan K. Hubbard val = GETARG (int); \ 643efb7e53dSJordan K. Hubbard } 644efb7e53dSJordan K. Hubbard 64558f0484fSRodney W. Grimes 64698ee7635SAlexey Zelkin thousands_sep = '\0'; 64798ee7635SAlexey Zelkin grouping = NULL; 648b9aac308STim J. Robbins convbuf = NULL; 6498de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 6502ffc61baSTor Egge dtoaresult = NULL; 6517735bb0fSBill Fenner decimal_point = localeconv()->decimal_point; 6522ffc61baSTor Egge #endif 65358f0484fSRodney W. Grimes /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 65452183d46SDavid Schultz if (prepwrite(fp) != 0) 65558f0484fSRodney W. Grimes return (EOF); 65658f0484fSRodney W. Grimes 65758f0484fSRodney W. Grimes /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 65858f0484fSRodney W. Grimes if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 659d201fe46SDaniel Eischen fp->_file >= 0) 66058f0484fSRodney W. Grimes return (__sbprintf(fp, fmt0, ap)); 66158f0484fSRodney W. Grimes 66258f0484fSRodney W. Grimes fmt = (char *)fmt0; 663efb7e53dSJordan K. Hubbard argtable = NULL; 664efb7e53dSJordan K. Hubbard nextarg = 1; 665d07090a8STim J. Robbins va_copy(orgap, ap); 66658f0484fSRodney W. Grimes uio.uio_iov = iovp = iov; 66758f0484fSRodney W. Grimes uio.uio_resid = 0; 66858f0484fSRodney W. Grimes uio.uio_iovcnt = 0; 66958f0484fSRodney W. Grimes ret = 0; 67058f0484fSRodney W. Grimes 67158f0484fSRodney W. Grimes /* 67258f0484fSRodney W. Grimes * Scan the format for conversions (`%' character). 67358f0484fSRodney W. Grimes */ 67458f0484fSRodney W. Grimes for (;;) { 67558f0484fSRodney W. Grimes for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 67658f0484fSRodney W. Grimes /* void */; 67758f0484fSRodney W. Grimes if ((n = fmt - cp) != 0) { 678b250f248SAndrey A. Chernov if ((unsigned)ret + n > INT_MAX) { 67992e88f87SAndrey A. Chernov ret = EOF; 68092e88f87SAndrey A. Chernov goto error; 68192e88f87SAndrey A. Chernov } 68258f0484fSRodney W. Grimes PRINT(cp, n); 68358f0484fSRodney W. Grimes ret += n; 68458f0484fSRodney W. Grimes } 68558f0484fSRodney W. Grimes if (ch == '\0') 68658f0484fSRodney W. Grimes goto done; 68758f0484fSRodney W. Grimes fmt++; /* skip over '%' */ 68858f0484fSRodney W. Grimes 68958f0484fSRodney W. Grimes flags = 0; 69058f0484fSRodney W. Grimes dprec = 0; 69158f0484fSRodney W. Grimes width = 0; 69258f0484fSRodney W. Grimes prec = -1; 69358f0484fSRodney W. Grimes sign = '\0'; 694ebbad5ecSDavid Schultz ox[1] = '\0'; 69558f0484fSRodney W. Grimes 69658f0484fSRodney W. Grimes rflag: ch = *fmt++; 69758f0484fSRodney W. Grimes reswitch: switch (ch) { 69858f0484fSRodney W. Grimes case ' ': 6992e394b2fSAlexey Zelkin /*- 70058f0484fSRodney W. Grimes * ``If the space and + flags both appear, the space 70158f0484fSRodney W. Grimes * flag will be ignored.'' 70258f0484fSRodney W. Grimes * -- ANSI X3J11 70358f0484fSRodney W. Grimes */ 70458f0484fSRodney W. Grimes if (!sign) 70558f0484fSRodney W. Grimes sign = ' '; 70658f0484fSRodney W. Grimes goto rflag; 70758f0484fSRodney W. Grimes case '#': 70858f0484fSRodney W. Grimes flags |= ALT; 70958f0484fSRodney W. Grimes goto rflag; 71058f0484fSRodney W. Grimes case '*': 7112e394b2fSAlexey Zelkin /*- 71258f0484fSRodney W. Grimes * ``A negative field width argument is taken as a 71358f0484fSRodney W. Grimes * - flag followed by a positive field width.'' 71458f0484fSRodney W. Grimes * -- ANSI X3J11 71558f0484fSRodney W. Grimes * They don't exclude field widths read from args. 71658f0484fSRodney W. Grimes */ 717efb7e53dSJordan K. Hubbard GETASTER (width); 718efb7e53dSJordan K. Hubbard if (width >= 0) 71958f0484fSRodney W. Grimes goto rflag; 72058f0484fSRodney W. Grimes width = -width; 72158f0484fSRodney W. Grimes /* FALLTHROUGH */ 72258f0484fSRodney W. Grimes case '-': 72358f0484fSRodney W. Grimes flags |= LADJUST; 72458f0484fSRodney W. Grimes goto rflag; 72558f0484fSRodney W. Grimes case '+': 72658f0484fSRodney W. Grimes sign = '+'; 72758f0484fSRodney W. Grimes goto rflag; 7287735bb0fSBill Fenner case '\'': 72998ee7635SAlexey Zelkin flags |= GROUPING; 73098ee7635SAlexey Zelkin thousands_sep = *(localeconv()->thousands_sep); 73198ee7635SAlexey Zelkin grouping = localeconv()->grouping; 7327735bb0fSBill Fenner goto rflag; 73358f0484fSRodney W. Grimes case '.': 73458f0484fSRodney W. Grimes if ((ch = *fmt++) == '*') { 7353b204b7dSDavid Schultz GETASTER (prec); 73658f0484fSRodney W. Grimes goto rflag; 73758f0484fSRodney W. Grimes } 7383b204b7dSDavid Schultz prec = 0; 73958f0484fSRodney W. Grimes while (is_digit(ch)) { 7403b204b7dSDavid Schultz prec = 10 * prec + to_digit(ch); 74158f0484fSRodney W. Grimes ch = *fmt++; 74258f0484fSRodney W. Grimes } 74358f0484fSRodney W. Grimes goto reswitch; 74458f0484fSRodney W. Grimes case '0': 7452e394b2fSAlexey Zelkin /*- 74658f0484fSRodney W. Grimes * ``Note that 0 is taken as a flag, not as the 74758f0484fSRodney W. Grimes * beginning of a field width.'' 74858f0484fSRodney W. Grimes * -- ANSI X3J11 74958f0484fSRodney W. Grimes */ 75058f0484fSRodney W. Grimes flags |= ZEROPAD; 75158f0484fSRodney W. Grimes goto rflag; 75258f0484fSRodney W. Grimes case '1': case '2': case '3': case '4': 75358f0484fSRodney W. Grimes case '5': case '6': case '7': case '8': case '9': 75458f0484fSRodney W. Grimes n = 0; 75558f0484fSRodney W. Grimes do { 75658f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 75758f0484fSRodney W. Grimes ch = *fmt++; 75858f0484fSRodney W. Grimes } while (is_digit(ch)); 759efb7e53dSJordan K. Hubbard if (ch == '$') { 760efb7e53dSJordan K. Hubbard nextarg = n; 761efb7e53dSJordan K. Hubbard if (argtable == NULL) { 762efb7e53dSJordan K. Hubbard argtable = statargtable; 763efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, 764efb7e53dSJordan K. Hubbard &argtable); 765efb7e53dSJordan K. Hubbard } 766efb7e53dSJordan K. Hubbard goto rflag; 767efb7e53dSJordan K. Hubbard } 76858f0484fSRodney W. Grimes width = n; 76958f0484fSRodney W. Grimes goto reswitch; 7708de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 77158f0484fSRodney W. Grimes case 'L': 77258f0484fSRodney W. Grimes flags |= LONGDBL; 77358f0484fSRodney W. Grimes goto rflag; 77458f0484fSRodney W. Grimes #endif 77558f0484fSRodney W. Grimes case 'h': 7767735bb0fSBill Fenner if (flags & SHORTINT) { 7777735bb0fSBill Fenner flags &= ~SHORTINT; 7787735bb0fSBill Fenner flags |= CHARINT; 7797735bb0fSBill Fenner } else 78058f0484fSRodney W. Grimes flags |= SHORTINT; 78158f0484fSRodney W. Grimes goto rflag; 7827735bb0fSBill Fenner case 'j': 7837735bb0fSBill Fenner flags |= INTMAXT; 7847735bb0fSBill Fenner goto rflag; 78558f0484fSRodney W. Grimes case 'l': 7867735bb0fSBill Fenner if (flags & LONGINT) { 7877735bb0fSBill Fenner flags &= ~LONGINT; 7887735bb0fSBill Fenner flags |= LLONGINT; 7897735bb0fSBill Fenner } else 79058f0484fSRodney W. Grimes flags |= LONGINT; 79158f0484fSRodney W. Grimes goto rflag; 79258f0484fSRodney W. Grimes case 'q': 7937735bb0fSBill Fenner flags |= LLONGINT; /* not necessarily */ 7947735bb0fSBill Fenner goto rflag; 7957735bb0fSBill Fenner case 't': 7967735bb0fSBill Fenner flags |= PTRDIFFT; 7977735bb0fSBill Fenner goto rflag; 7987735bb0fSBill Fenner case 'z': 7997735bb0fSBill Fenner flags |= SIZET; 80058f0484fSRodney W. Grimes goto rflag; 801927ecbf3STim J. Robbins case 'C': 802927ecbf3STim J. Robbins flags |= LONGINT; 803927ecbf3STim J. Robbins /*FALLTHROUGH*/ 80458f0484fSRodney W. Grimes case 'c': 805b9aac308STim J. Robbins if (flags & LONGINT) { 80693996f6dSTim J. Robbins static const mbstate_t initial; 80793996f6dSTim J. Robbins mbstate_t mbs; 808b9aac308STim J. Robbins size_t mbseqlen; 809b9aac308STim J. Robbins 81093996f6dSTim J. Robbins mbs = initial; 811b9aac308STim J. Robbins mbseqlen = wcrtomb(cp = buf, 81293996f6dSTim J. Robbins (wchar_t)GETARG(wint_t), &mbs); 8136180233fSTim J. Robbins if (mbseqlen == (size_t)-1) { 8146180233fSTim J. Robbins fp->_flags |= __SERR; 815b9aac308STim J. Robbins goto error; 8166180233fSTim J. Robbins } 817b9aac308STim J. Robbins size = (int)mbseqlen; 818b9aac308STim J. Robbins } else { 819efb7e53dSJordan K. Hubbard *(cp = buf) = GETARG(int); 82058f0484fSRodney W. Grimes size = 1; 821b9aac308STim J. Robbins } 82258f0484fSRodney W. Grimes sign = '\0'; 82358f0484fSRodney W. Grimes break; 82458f0484fSRodney W. Grimes case 'D': 82558f0484fSRodney W. Grimes flags |= LONGINT; 82658f0484fSRodney W. Grimes /*FALLTHROUGH*/ 82758f0484fSRodney W. Grimes case 'd': 82858f0484fSRodney W. Grimes case 'i': 8297735bb0fSBill Fenner if (flags & INTMAX_SIZE) { 8307735bb0fSBill Fenner ujval = SJARG(); 8317735bb0fSBill Fenner if ((intmax_t)ujval < 0) { 8327735bb0fSBill Fenner ujval = -ujval; 83358f0484fSRodney W. Grimes sign = '-'; 83458f0484fSRodney W. Grimes } 83558f0484fSRodney W. Grimes } else { 83658f0484fSRodney W. Grimes ulval = SARG(); 83758f0484fSRodney W. Grimes if ((long)ulval < 0) { 83858f0484fSRodney W. Grimes ulval = -ulval; 83958f0484fSRodney W. Grimes sign = '-'; 84058f0484fSRodney W. Grimes } 84158f0484fSRodney W. Grimes } 84258f0484fSRodney W. Grimes base = 10; 84358f0484fSRodney W. Grimes goto number; 8448de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 8457735bb0fSBill Fenner case 'a': 8467735bb0fSBill Fenner case 'A': 847ebbad5ecSDavid Schultz if (ch == 'a') { 848ebbad5ecSDavid Schultz ox[1] = 'x'; 849ebbad5ecSDavid Schultz xdigs = xdigs_lower; 850ebbad5ecSDavid Schultz expchar = 'p'; 851ebbad5ecSDavid Schultz } else { 852ebbad5ecSDavid Schultz ox[1] = 'X'; 853ebbad5ecSDavid Schultz xdigs = xdigs_upper; 854ebbad5ecSDavid Schultz expchar = 'P'; 855ebbad5ecSDavid Schultz } 856904322a5SDavid Schultz if (prec >= 0) 857904322a5SDavid Schultz prec++; 858904322a5SDavid Schultz if (dtoaresult != NULL) 859904322a5SDavid Schultz freedtoa(dtoaresult); 860ebbad5ecSDavid Schultz if (flags & LONGDBL) { 861904322a5SDavid Schultz fparg.ldbl = GETARG(long double); 862ebbad5ecSDavid Schultz dtoaresult = cp = 863ebbad5ecSDavid Schultz __hldtoa(fparg.ldbl, xdigs, prec, 864ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 865ebbad5ecSDavid Schultz } else { 866ebbad5ecSDavid Schultz fparg.dbl = GETARG(double); 867ebbad5ecSDavid Schultz dtoaresult = cp = 868ebbad5ecSDavid Schultz __hdtoa(fparg.dbl, xdigs, prec, 869ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 870ebbad5ecSDavid Schultz } 871904322a5SDavid Schultz if (prec < 0) 872904322a5SDavid Schultz prec = dtoaend - cp; 873904322a5SDavid Schultz if (expt == INT_MAX) 874904322a5SDavid Schultz ox[1] = '\0'; 875904322a5SDavid Schultz goto fp_common; 876d26be6f0SBruce Evans case 'e': 87758f0484fSRodney W. Grimes case 'E': 878ebbad5ecSDavid Schultz expchar = ch; 879ebbad5ecSDavid Schultz if (prec < 0) /* account for digit before decpt */ 880ebbad5ecSDavid Schultz prec = DEFPREC + 1; 881ebbad5ecSDavid Schultz else 882ebbad5ecSDavid Schultz prec++; 883ebbad5ecSDavid Schultz goto fp_begin; 884d26be6f0SBruce Evans case 'f': 8857735bb0fSBill Fenner case 'F': 886ebbad5ecSDavid Schultz expchar = '\0'; 887d26be6f0SBruce Evans goto fp_begin; 88858f0484fSRodney W. Grimes case 'g': 88958f0484fSRodney W. Grimes case 'G': 890ebbad5ecSDavid Schultz expchar = ch - ('g' - 'e'); 891d26be6f0SBruce Evans if (prec == 0) 892d26be6f0SBruce Evans prec = 1; 893ebbad5ecSDavid Schultz fp_begin: 894ebbad5ecSDavid Schultz if (prec < 0) 89558f0484fSRodney W. Grimes prec = DEFPREC; 896ebbad5ecSDavid Schultz if (dtoaresult != NULL) 897ebbad5ecSDavid Schultz freedtoa(dtoaresult); 898ebbad5ecSDavid Schultz if (flags & LONGDBL) { 899ebbad5ecSDavid Schultz fparg.ldbl = GETARG(long double); 900ebbad5ecSDavid Schultz dtoaresult = cp = 901ebbad5ecSDavid Schultz __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, 902ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 903ebbad5ecSDavid Schultz } else { 904ebbad5ecSDavid Schultz fparg.dbl = GETARG(double); 905ebbad5ecSDavid Schultz dtoaresult = cp = 906ebbad5ecSDavid Schultz dtoa(fparg.dbl, expchar ? 2 : 3, prec, 907ebbad5ecSDavid Schultz &expt, &signflag, &dtoaend); 908ebbad5ecSDavid Schultz if (expt == 9999) 909ebbad5ecSDavid Schultz expt = INT_MAX; 91058f0484fSRodney W. Grimes } 911904322a5SDavid Schultz fp_common: 912ebbad5ecSDavid Schultz if (signflag) 913ebbad5ecSDavid Schultz sign = '-'; 914ebbad5ecSDavid Schultz if (expt == INT_MAX) { /* inf or nan */ 915ebbad5ecSDavid Schultz if (*cp == 'N') { 916ebbad5ecSDavid Schultz cp = (ch >= 'a') ? "nan" : "NAN"; 917ebbad5ecSDavid Schultz sign = '\0'; 918ebbad5ecSDavid Schultz } else 919ebbad5ecSDavid Schultz cp = (ch >= 'a') ? "inf" : "INF"; 92058f0484fSRodney W. Grimes size = 3; 921970a466cSDavid Schultz flags &= ~ZEROPAD; 92258f0484fSRodney W. Grimes break; 92358f0484fSRodney W. Grimes } 92458f0484fSRodney W. Grimes flags |= FPT; 925ebbad5ecSDavid Schultz ndig = dtoaend - cp; 92658f0484fSRodney W. Grimes if (ch == 'g' || ch == 'G') { 927ebbad5ecSDavid Schultz if (expt > -4 && expt <= prec) { 928ebbad5ecSDavid Schultz /* Make %[gG] smell like %[fF] */ 929ebbad5ecSDavid Schultz expchar = '\0'; 930ebbad5ecSDavid Schultz if (flags & ALT) 931ebbad5ecSDavid Schultz prec -= expt; 93258f0484fSRodney W. Grimes else 933ebbad5ecSDavid Schultz prec = ndig - expt; 934ebbad5ecSDavid Schultz if (prec < 0) 935ebbad5ecSDavid Schultz prec = 0; 9361f2a0cdfSDavid Schultz } else { 9371f2a0cdfSDavid Schultz /* 9381f2a0cdfSDavid Schultz * Make %[gG] smell like %[eE], but 9391f2a0cdfSDavid Schultz * trim trailing zeroes if no # flag. 9401f2a0cdfSDavid Schultz */ 9411f2a0cdfSDavid Schultz if (!(flags & ALT)) 9421f2a0cdfSDavid Schultz prec = ndig; 94358f0484fSRodney W. Grimes } 944ebbad5ecSDavid Schultz } 945ebbad5ecSDavid Schultz if (expchar) { 946ebbad5ecSDavid Schultz expsize = exponent(expstr, expt - 1, expchar); 947ebbad5ecSDavid Schultz size = expsize + prec; 9483b204b7dSDavid Schultz if (prec > 1 || flags & ALT) 94958f0484fSRodney W. Grimes ++size; 950ebbad5ecSDavid Schultz } else { 95181ae2e9aSDavid Schultz /* space for digits before decimal point */ 95281ae2e9aSDavid Schultz if (expt > 0) 95358f0484fSRodney W. Grimes size = expt; 95481ae2e9aSDavid Schultz else /* "0" */ 95581ae2e9aSDavid Schultz size = 1; 95681ae2e9aSDavid Schultz /* space for decimal pt and following digits */ 95758f0484fSRodney W. Grimes if (prec || flags & ALT) 95858f0484fSRodney W. Grimes size += prec + 1; 959ebbad5ecSDavid Schultz if (grouping && expt > 0) { 960ebbad5ecSDavid Schultz /* space for thousands' grouping */ 961ebbad5ecSDavid Schultz nseps = nrepeats = 0; 962ebbad5ecSDavid Schultz lead = expt; 963ebbad5ecSDavid Schultz while (*grouping != CHAR_MAX) { 964ebbad5ecSDavid Schultz if (lead <= *grouping) 965ebbad5ecSDavid Schultz break; 966ebbad5ecSDavid Schultz lead -= *grouping; 967ebbad5ecSDavid Schultz if (*(grouping+1)) { 968ebbad5ecSDavid Schultz nseps++; 969ebbad5ecSDavid Schultz grouping++; 97058f0484fSRodney W. Grimes } else 971ebbad5ecSDavid Schultz nrepeats++; 972ebbad5ecSDavid Schultz } 973ebbad5ecSDavid Schultz size += nseps + nrepeats; 974ebbad5ecSDavid Schultz } else 975d890afb8SDavid Schultz lead = expt; 976ebbad5ecSDavid Schultz } 97758f0484fSRodney W. Grimes break; 9788de9e897SDavid Schultz #endif /* !NO_FLOATING_POINT */ 97958f0484fSRodney W. Grimes case 'n': 9807735bb0fSBill Fenner /* 9817735bb0fSBill Fenner * Assignment-like behavior is specified if the 9827735bb0fSBill Fenner * value overflows or is otherwise unrepresentable. 9837735bb0fSBill Fenner * C99 says to use `signed char' for %hhn conversions. 9847735bb0fSBill Fenner */ 9857735bb0fSBill Fenner if (flags & LLONGINT) 9867735bb0fSBill Fenner *GETARG(long long *) = ret; 9877735bb0fSBill Fenner else if (flags & SIZET) 9887735bb0fSBill Fenner *GETARG(ssize_t *) = (ssize_t)ret; 9897735bb0fSBill Fenner else if (flags & PTRDIFFT) 9907735bb0fSBill Fenner *GETARG(ptrdiff_t *) = ret; 9917735bb0fSBill Fenner else if (flags & INTMAXT) 9927735bb0fSBill Fenner *GETARG(intmax_t *) = ret; 99358f0484fSRodney W. Grimes else if (flags & LONGINT) 9946e690ad4SAndrey A. Chernov *GETARG(long *) = ret; 99558f0484fSRodney W. Grimes else if (flags & SHORTINT) 9966e690ad4SAndrey A. Chernov *GETARG(short *) = ret; 9977735bb0fSBill Fenner else if (flags & CHARINT) 9987735bb0fSBill Fenner *GETARG(signed char *) = ret; 99958f0484fSRodney W. Grimes else 10006e690ad4SAndrey A. Chernov *GETARG(int *) = ret; 100158f0484fSRodney W. Grimes continue; /* no output */ 100258f0484fSRodney W. Grimes case 'O': 100358f0484fSRodney W. Grimes flags |= LONGINT; 100458f0484fSRodney W. Grimes /*FALLTHROUGH*/ 100558f0484fSRodney W. Grimes case 'o': 10067735bb0fSBill Fenner if (flags & INTMAX_SIZE) 10077735bb0fSBill Fenner ujval = UJARG(); 100858f0484fSRodney W. Grimes else 100958f0484fSRodney W. Grimes ulval = UARG(); 101058f0484fSRodney W. Grimes base = 8; 101158f0484fSRodney W. Grimes goto nosign; 101258f0484fSRodney W. Grimes case 'p': 10132e394b2fSAlexey Zelkin /*- 101458f0484fSRodney W. Grimes * ``The argument shall be a pointer to void. The 101558f0484fSRodney W. Grimes * value of the pointer is converted to a sequence 101658f0484fSRodney W. Grimes * of printable characters, in an implementation- 101758f0484fSRodney W. Grimes * defined manner.'' 101858f0484fSRodney W. Grimes * -- ANSI X3J11 101958f0484fSRodney W. Grimes */ 10207735bb0fSBill Fenner ujval = (uintmax_t)(uintptr_t)GETARG(void *); 102158f0484fSRodney W. Grimes base = 16; 1022ebbad5ecSDavid Schultz xdigs = xdigs_lower; 1023ebbad5ecSDavid Schultz flags = flags | INTMAXT; 1024ebbad5ecSDavid Schultz ox[1] = 'x'; 102558f0484fSRodney W. Grimes goto nosign; 1026927ecbf3STim J. Robbins case 'S': 1027927ecbf3STim J. Robbins flags |= LONGINT; 1028927ecbf3STim J. Robbins /*FALLTHROUGH*/ 102958f0484fSRodney W. Grimes case 's': 1030b9aac308STim J. Robbins if (flags & LONGINT) { 1031b9aac308STim J. Robbins wchar_t *wcp; 1032b9aac308STim J. Robbins 1033b9aac308STim J. Robbins if (convbuf != NULL) 1034b9aac308STim J. Robbins free(convbuf); 1035b9aac308STim J. Robbins if ((wcp = GETARG(wchar_t *)) == NULL) 1036b9aac308STim J. Robbins cp = "(null)"; 1037b9aac308STim J. Robbins else { 1038b9aac308STim J. Robbins convbuf = __wcsconv(wcp, prec); 10396180233fSTim J. Robbins if (convbuf == NULL) { 10406180233fSTim J. Robbins fp->_flags |= __SERR; 1041b9aac308STim J. Robbins goto error; 10426180233fSTim J. Robbins } 1043b9aac308STim J. Robbins cp = convbuf; 1044b9aac308STim J. Robbins } 1045b9aac308STim J. Robbins } else if ((cp = GETARG(char *)) == NULL) 104658f0484fSRodney W. Grimes cp = "(null)"; 104758f0484fSRodney W. Grimes if (prec >= 0) { 104858f0484fSRodney W. Grimes /* 104958f0484fSRodney W. Grimes * can't use strlen; can only look for the 105058f0484fSRodney W. Grimes * NUL in the first `prec' characters, and 105158f0484fSRodney W. Grimes * strlen() will go further. 105258f0484fSRodney W. Grimes */ 1053ce51cf03SJames Raynard char *p = memchr(cp, 0, (size_t)prec); 105458f0484fSRodney W. Grimes 105558f0484fSRodney W. Grimes if (p != NULL) { 105658f0484fSRodney W. Grimes size = p - cp; 105758f0484fSRodney W. Grimes if (size > prec) 105858f0484fSRodney W. Grimes size = prec; 105958f0484fSRodney W. Grimes } else 106058f0484fSRodney W. Grimes size = prec; 106158f0484fSRodney W. Grimes } else 106258f0484fSRodney W. Grimes size = strlen(cp); 106358f0484fSRodney W. Grimes sign = '\0'; 106458f0484fSRodney W. Grimes break; 106558f0484fSRodney W. Grimes case 'U': 106658f0484fSRodney W. Grimes flags |= LONGINT; 106758f0484fSRodney W. Grimes /*FALLTHROUGH*/ 106858f0484fSRodney W. Grimes case 'u': 10697735bb0fSBill Fenner if (flags & INTMAX_SIZE) 10707735bb0fSBill Fenner ujval = UJARG(); 107158f0484fSRodney W. Grimes else 107258f0484fSRodney W. Grimes ulval = UARG(); 107358f0484fSRodney W. Grimes base = 10; 107458f0484fSRodney W. Grimes goto nosign; 107558f0484fSRodney W. Grimes case 'X': 1076ebbad5ecSDavid Schultz xdigs = xdigs_upper; 107758f0484fSRodney W. Grimes goto hex; 107858f0484fSRodney W. Grimes case 'x': 1079ebbad5ecSDavid Schultz xdigs = xdigs_lower; 10807735bb0fSBill Fenner hex: 10817735bb0fSBill Fenner if (flags & INTMAX_SIZE) 10827735bb0fSBill Fenner ujval = UJARG(); 108358f0484fSRodney W. Grimes else 108458f0484fSRodney W. Grimes ulval = UARG(); 108558f0484fSRodney W. Grimes base = 16; 108658f0484fSRodney W. Grimes /* leading 0x/X only if non-zero */ 108758f0484fSRodney W. Grimes if (flags & ALT && 10887735bb0fSBill Fenner (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 1089ebbad5ecSDavid Schultz ox[1] = ch; 109058f0484fSRodney W. Grimes 109198ee7635SAlexey Zelkin flags &= ~GROUPING; 109258f0484fSRodney W. Grimes /* unsigned conversions */ 109358f0484fSRodney W. Grimes nosign: sign = '\0'; 10942e394b2fSAlexey Zelkin /*- 109558f0484fSRodney W. Grimes * ``... diouXx conversions ... if a precision is 109658f0484fSRodney W. Grimes * specified, the 0 flag will be ignored.'' 109758f0484fSRodney W. Grimes * -- ANSI X3J11 109858f0484fSRodney W. Grimes */ 109958f0484fSRodney W. Grimes number: if ((dprec = prec) >= 0) 110058f0484fSRodney W. Grimes flags &= ~ZEROPAD; 110158f0484fSRodney W. Grimes 11022e394b2fSAlexey Zelkin /*- 110358f0484fSRodney W. Grimes * ``The result of converting a zero value with an 110458f0484fSRodney W. Grimes * explicit precision of zero is no characters.'' 110558f0484fSRodney W. Grimes * -- ANSI X3J11 11061be5319aSDavid Schultz * 11071be5319aSDavid Schultz * ``The C Standard is clear enough as is. The call 11081be5319aSDavid Schultz * printf("%#.0o", 0) should print 0.'' 11091be5319aSDavid Schultz * -- Defect Report #151 111058f0484fSRodney W. Grimes */ 111158f0484fSRodney W. Grimes cp = buf + BUF; 11127735bb0fSBill Fenner if (flags & INTMAX_SIZE) { 11131be5319aSDavid Schultz if (ujval != 0 || prec != 0 || 11141be5319aSDavid Schultz (flags & ALT && base == 8)) 11157735bb0fSBill Fenner cp = __ujtoa(ujval, cp, base, 111698ee7635SAlexey Zelkin flags & ALT, xdigs, 111798ee7635SAlexey Zelkin flags & GROUPING, thousands_sep, 111898ee7635SAlexey Zelkin grouping); 111958f0484fSRodney W. Grimes } else { 11201be5319aSDavid Schultz if (ulval != 0 || prec != 0 || 11211be5319aSDavid Schultz (flags & ALT && base == 8)) 112258f0484fSRodney W. Grimes cp = __ultoa(ulval, cp, base, 112398ee7635SAlexey Zelkin flags & ALT, xdigs, 112498ee7635SAlexey Zelkin flags & GROUPING, thousands_sep, 112598ee7635SAlexey Zelkin grouping); 112658f0484fSRodney W. Grimes } 112758f0484fSRodney W. Grimes size = buf + BUF - cp; 112838cac8f8SDavid Schultz if (size > BUF) /* should never happen */ 112938cac8f8SDavid Schultz abort(); 113058f0484fSRodney W. Grimes break; 113158f0484fSRodney W. Grimes default: /* "%?" prints ?, unless ? is NUL */ 113258f0484fSRodney W. Grimes if (ch == '\0') 113358f0484fSRodney W. Grimes goto done; 113458f0484fSRodney W. Grimes /* pretend it was %c with argument ch */ 113558f0484fSRodney W. Grimes cp = buf; 113658f0484fSRodney W. Grimes *cp = ch; 113758f0484fSRodney W. Grimes size = 1; 113858f0484fSRodney W. Grimes sign = '\0'; 113958f0484fSRodney W. Grimes break; 114058f0484fSRodney W. Grimes } 114158f0484fSRodney W. Grimes 114258f0484fSRodney W. Grimes /* 114358f0484fSRodney W. Grimes * All reasonable formats wind up here. At this point, `cp' 114458f0484fSRodney W. Grimes * points to a string which (if not flags&LADJUST) should be 114558f0484fSRodney W. Grimes * padded out to `width' places. If flags&ZEROPAD, it should 114658f0484fSRodney W. Grimes * first be prefixed by any sign or other prefix; otherwise, 114758f0484fSRodney W. Grimes * it should be blank padded before the prefix is emitted. 114858f0484fSRodney W. Grimes * After any left-hand padding and prefixing, emit zeroes 114958f0484fSRodney W. Grimes * required by a decimal [diouxX] precision, then print the 115058f0484fSRodney W. Grimes * string proper, then emit zeroes required by any leftover 115158f0484fSRodney W. Grimes * floating precision; finally, if LADJUST, pad with blanks. 115258f0484fSRodney W. Grimes * 115358f0484fSRodney W. Grimes * Compute actual size, so we know how much to pad. 1154261a532aSBill Fenner * size excludes decimal prec; realsz includes it. 115558f0484fSRodney W. Grimes */ 1156261a532aSBill Fenner realsz = dprec > size ? dprec : size; 115758f0484fSRodney W. Grimes if (sign) 1158261a532aSBill Fenner realsz++; 1159904322a5SDavid Schultz if (ox[1]) 1160261a532aSBill Fenner realsz += 2; 116158f0484fSRodney W. Grimes 116292e88f87SAndrey A. Chernov prsize = width > realsz ? width : realsz; 1163b250f248SAndrey A. Chernov if ((unsigned)ret + prsize > INT_MAX) { 116492e88f87SAndrey A. Chernov ret = EOF; 116592e88f87SAndrey A. Chernov goto error; 116692e88f87SAndrey A. Chernov } 116792e88f87SAndrey A. Chernov 116858f0484fSRodney W. Grimes /* right-adjusting blank padding */ 116958f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == 0) 117058f0484fSRodney W. Grimes PAD(width - realsz, blanks); 117158f0484fSRodney W. Grimes 117258f0484fSRodney W. Grimes /* prefix */ 1173904322a5SDavid Schultz if (sign) 117458f0484fSRodney W. Grimes PRINT(&sign, 1); 1175904322a5SDavid Schultz 1176904322a5SDavid Schultz if (ox[1]) { /* ox[1] is either x, X, or \0 */ 117758f0484fSRodney W. Grimes ox[0] = '0'; 117858f0484fSRodney W. Grimes PRINT(ox, 2); 117958f0484fSRodney W. Grimes } 118058f0484fSRodney W. Grimes 118158f0484fSRodney W. Grimes /* right-adjusting zero padding */ 118258f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 118358f0484fSRodney W. Grimes PAD(width - realsz, zeroes); 118458f0484fSRodney W. Grimes 118558f0484fSRodney W. Grimes /* leading zeroes from decimal precision */ 1186261a532aSBill Fenner PAD(dprec - size, zeroes); 118758f0484fSRodney W. Grimes 118858f0484fSRodney W. Grimes /* the string or number proper */ 11898de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 119058f0484fSRodney W. Grimes if ((flags & FPT) == 0) { 119158f0484fSRodney W. Grimes PRINT(cp, size); 119258f0484fSRodney W. Grimes } else { /* glue together f_p fragments */ 1193ebbad5ecSDavid Schultz if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 1194ebbad5ecSDavid Schultz if (expt <= 0) { 119581ae2e9aSDavid Schultz PRINT(zeroes, 1); 119681ae2e9aSDavid Schultz if (prec || flags & ALT) 119781ae2e9aSDavid Schultz PRINT(decimal_point, 1); 119858f0484fSRodney W. Grimes PAD(-expt, zeroes); 11993b204b7dSDavid Schultz /* already handled initial 0's */ 12003b204b7dSDavid Schultz prec += expt; 120158f0484fSRodney W. Grimes } else { 12023b204b7dSDavid Schultz PRINTANDPAD(cp, dtoaend, lead, zeroes); 1203ebbad5ecSDavid Schultz cp += lead; 1204ebbad5ecSDavid Schultz if (grouping) { 1205ebbad5ecSDavid Schultz while (nseps>0 || nrepeats>0) { 1206ebbad5ecSDavid Schultz if (nrepeats > 0) 1207ebbad5ecSDavid Schultz nrepeats--; 1208ebbad5ecSDavid Schultz else { 1209ebbad5ecSDavid Schultz grouping--; 1210ebbad5ecSDavid Schultz nseps--; 121158f0484fSRodney W. Grimes } 1212ebbad5ecSDavid Schultz PRINT(&thousands_sep, 1213ebbad5ecSDavid Schultz 1); 12143b204b7dSDavid Schultz PRINTANDPAD(cp,dtoaend, 12153b204b7dSDavid Schultz *grouping, zeroes); 1216ebbad5ecSDavid Schultz cp += *grouping; 1217ebbad5ecSDavid Schultz } 12183b204b7dSDavid Schultz if (cp > dtoaend) 12193b204b7dSDavid Schultz cp = dtoaend; 1220ebbad5ecSDavid Schultz } 1221ebbad5ecSDavid Schultz if (prec || flags & ALT) 1222ebbad5ecSDavid Schultz PRINT(decimal_point,1); 1223ebbad5ecSDavid Schultz } 12243b204b7dSDavid Schultz PRINTANDPAD(cp, dtoaend, prec, zeroes); 1225ebbad5ecSDavid Schultz } else { /* %[eE] or sufficiently long %[gG] */ 12263b204b7dSDavid Schultz if (prec > 1 || flags & ALT) { 1227ebbad5ecSDavid Schultz buf[0] = *cp++; 1228ebbad5ecSDavid Schultz buf[1] = *decimal_point; 1229ebbad5ecSDavid Schultz PRINT(buf, 2); 123058f0484fSRodney W. Grimes PRINT(cp, ndig-1); 1231ebbad5ecSDavid Schultz PAD(prec - ndig, zeroes); 123258f0484fSRodney W. Grimes } else /* XeYYY */ 123358f0484fSRodney W. Grimes PRINT(cp, 1); 123458f0484fSRodney W. Grimes PRINT(expstr, expsize); 123558f0484fSRodney W. Grimes } 123658f0484fSRodney W. Grimes } 123758f0484fSRodney W. Grimes #else 123858f0484fSRodney W. Grimes PRINT(cp, size); 123958f0484fSRodney W. Grimes #endif 124058f0484fSRodney W. Grimes /* left-adjusting padding (always blank) */ 124158f0484fSRodney W. Grimes if (flags & LADJUST) 124258f0484fSRodney W. Grimes PAD(width - realsz, blanks); 124358f0484fSRodney W. Grimes 124458f0484fSRodney W. Grimes /* finally, adjust ret */ 124592e88f87SAndrey A. Chernov ret += prsize; 124658f0484fSRodney W. Grimes 124758f0484fSRodney W. Grimes FLUSH(); /* copy out the I/O vectors */ 124858f0484fSRodney W. Grimes } 124958f0484fSRodney W. Grimes done: 125058f0484fSRodney W. Grimes FLUSH(); 125158f0484fSRodney W. Grimes error: 1252096ad104SDag-Erling Smørgrav va_end(orgap); 12538de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 12542ffc61baSTor Egge if (dtoaresult != NULL) 1255ebbad5ecSDavid Schultz freedtoa(dtoaresult); 12562ffc61baSTor Egge #endif 1257b9aac308STim J. Robbins if (convbuf != NULL) 1258b9aac308STim J. Robbins free(convbuf); 1259f70177e7SJulian Elischer if (__sferror(fp)) 1260f70177e7SJulian Elischer ret = EOF; 1261efb7e53dSJordan K. Hubbard if ((argtable != NULL) && (argtable != statargtable)) 1262efb7e53dSJordan K. Hubbard free (argtable); 1263f70177e7SJulian Elischer return (ret); 126458f0484fSRodney W. Grimes /* NOTREACHED */ 126558f0484fSRodney W. Grimes } 126658f0484fSRodney W. Grimes 1267efb7e53dSJordan K. Hubbard /* 1268e5abb5e6SDavid Schultz * Initialize a struct typetable. 1269e5abb5e6SDavid Schultz */ 1270e5abb5e6SDavid Schultz static inline void 1271e5abb5e6SDavid Schultz inittypes(struct typetable *types) 1272e5abb5e6SDavid Schultz { 1273e5abb5e6SDavid Schultz int n; 1274e5abb5e6SDavid Schultz 1275e5abb5e6SDavid Schultz types->table = types->stattable; 1276e5abb5e6SDavid Schultz types->tablesize = STATIC_ARG_TBL_SIZE; 1277e5abb5e6SDavid Schultz types->tablemax = 0; 1278e5abb5e6SDavid Schultz types->nextarg = 1; 1279e5abb5e6SDavid Schultz for (n = 0; n < STATIC_ARG_TBL_SIZE; n++) 1280e5abb5e6SDavid Schultz types->table[n] = T_UNUSED; 1281e5abb5e6SDavid Schultz } 1282e5abb5e6SDavid Schultz 1283e5abb5e6SDavid Schultz /* 1284e5abb5e6SDavid Schultz * struct typetable destructor. 1285e5abb5e6SDavid Schultz */ 1286e5abb5e6SDavid Schultz static inline void 1287e5abb5e6SDavid Schultz freetypes(struct typetable *types) 1288e5abb5e6SDavid Schultz { 1289e5abb5e6SDavid Schultz 1290e5abb5e6SDavid Schultz if (types->table != types->stattable) 1291e5abb5e6SDavid Schultz free (types->table); 1292e5abb5e6SDavid Schultz } 1293e5abb5e6SDavid Schultz 1294e5abb5e6SDavid Schultz /* 1295e5abb5e6SDavid Schultz * Add an argument type to the table, expanding if necessary. 1296e5abb5e6SDavid Schultz */ 1297e5abb5e6SDavid Schultz static inline void 1298e5abb5e6SDavid Schultz addtype(struct typetable *types, enum typeid type) 1299e5abb5e6SDavid Schultz { 1300e5abb5e6SDavid Schultz 1301e5abb5e6SDavid Schultz if (types->nextarg >= types->tablesize) 1302e5abb5e6SDavid Schultz __grow_type_table(types); 1303e5abb5e6SDavid Schultz if (types->nextarg > types->tablemax) 1304e5abb5e6SDavid Schultz types->tablemax = types->nextarg; 1305e5abb5e6SDavid Schultz types->table[types->nextarg++] = type; 1306e5abb5e6SDavid Schultz } 1307e5abb5e6SDavid Schultz 1308e5abb5e6SDavid Schultz static inline void 1309e5abb5e6SDavid Schultz addsarg(struct typetable *types, int flags) 1310e5abb5e6SDavid Schultz { 1311e5abb5e6SDavid Schultz 1312e5abb5e6SDavid Schultz if (flags & INTMAXT) 1313e5abb5e6SDavid Schultz addtype(types, T_INTMAXT); 1314e5abb5e6SDavid Schultz else if (flags & SIZET) 1315e5abb5e6SDavid Schultz addtype(types, T_SIZET); 1316e5abb5e6SDavid Schultz else if (flags & PTRDIFFT) 1317e5abb5e6SDavid Schultz addtype(types, T_PTRDIFFT); 1318e5abb5e6SDavid Schultz else if (flags & LLONGINT) 1319e5abb5e6SDavid Schultz addtype(types, T_LLONG); 1320e5abb5e6SDavid Schultz else if (flags & LONGINT) 1321e5abb5e6SDavid Schultz addtype(types, T_LONG); 1322e5abb5e6SDavid Schultz else 1323e5abb5e6SDavid Schultz addtype(types, T_INT); 1324e5abb5e6SDavid Schultz } 1325e5abb5e6SDavid Schultz 1326e5abb5e6SDavid Schultz static inline void 1327e5abb5e6SDavid Schultz adduarg(struct typetable *types, int flags) 1328e5abb5e6SDavid Schultz { 1329e5abb5e6SDavid Schultz 1330e5abb5e6SDavid Schultz if (flags & INTMAXT) 1331e5abb5e6SDavid Schultz addtype(types, T_UINTMAXT); 1332e5abb5e6SDavid Schultz else if (flags & SIZET) 1333e5abb5e6SDavid Schultz addtype(types, T_SIZET); 1334e5abb5e6SDavid Schultz else if (flags & PTRDIFFT) 1335e5abb5e6SDavid Schultz addtype(types, T_PTRDIFFT); 1336e5abb5e6SDavid Schultz else if (flags & LLONGINT) 1337e5abb5e6SDavid Schultz addtype(types, T_U_LLONG); 1338e5abb5e6SDavid Schultz else if (flags & LONGINT) 1339e5abb5e6SDavid Schultz addtype(types, T_U_LONG); 1340e5abb5e6SDavid Schultz else 1341e5abb5e6SDavid Schultz addtype(types, T_U_INT); 1342e5abb5e6SDavid Schultz } 1343e5abb5e6SDavid Schultz 1344e5abb5e6SDavid Schultz /* 1345e5abb5e6SDavid Schultz * Add * arguments to the type array. 1346e5abb5e6SDavid Schultz */ 1347e5abb5e6SDavid Schultz static inline void 1348e5abb5e6SDavid Schultz addaster(struct typetable *types, char **fmtp) 1349e5abb5e6SDavid Schultz { 1350e5abb5e6SDavid Schultz char *cp; 1351e5abb5e6SDavid Schultz int n2; 1352e5abb5e6SDavid Schultz 1353e5abb5e6SDavid Schultz n2 = 0; 1354e5abb5e6SDavid Schultz cp = *fmtp; 1355e5abb5e6SDavid Schultz while (is_digit(*cp)) { 1356e5abb5e6SDavid Schultz n2 = 10 * n2 + to_digit(*cp); 1357e5abb5e6SDavid Schultz cp++; 1358e5abb5e6SDavid Schultz } 1359e5abb5e6SDavid Schultz if (*cp == '$') { 1360e5abb5e6SDavid Schultz int hold = types->nextarg; 1361e5abb5e6SDavid Schultz types->nextarg = n2; 1362e5abb5e6SDavid Schultz addtype(types, T_INT); 1363e5abb5e6SDavid Schultz types->nextarg = hold; 1364e5abb5e6SDavid Schultz *fmtp = ++cp; 1365e5abb5e6SDavid Schultz } else { 1366e5abb5e6SDavid Schultz addtype(types, T_INT); 1367e5abb5e6SDavid Schultz } 1368e5abb5e6SDavid Schultz } 1369e5abb5e6SDavid Schultz 1370e5abb5e6SDavid Schultz /* 1371efb7e53dSJordan K. Hubbard * Find all arguments when a positional parameter is encountered. Returns a 1372efb7e53dSJordan K. Hubbard * table, indexed by argument number, of pointers to each arguments. The 1373efb7e53dSJordan K. Hubbard * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 137442cebaa5SArchie Cobbs * It will be replaces with a malloc-ed one if it overflows. 1375efb7e53dSJordan K. Hubbard */ 1376efb7e53dSJordan K. Hubbard static void 1377a387081cSDoug Rabson __find_arguments (const char *fmt0, va_list ap, union arg **argtable) 1378efb7e53dSJordan K. Hubbard { 1379d201fe46SDaniel Eischen char *fmt; /* format string */ 1380d201fe46SDaniel Eischen int ch; /* character from fmt */ 1381e5abb5e6SDavid Schultz int n; /* handy integer (short term usage) */ 1382d201fe46SDaniel Eischen int flags; /* flags as above */ 1383efb7e53dSJordan K. Hubbard int width; /* width from format (%8d), or 0 */ 1384e5abb5e6SDavid Schultz struct typetable types; /* table of types */ 1385efb7e53dSJordan K. Hubbard 1386efb7e53dSJordan K. Hubbard fmt = (char *)fmt0; 1387e5abb5e6SDavid Schultz inittypes(&types); 1388efb7e53dSJordan K. Hubbard 1389efb7e53dSJordan K. Hubbard /* 1390efb7e53dSJordan K. Hubbard * Scan the format for conversions (`%' character). 1391efb7e53dSJordan K. Hubbard */ 1392efb7e53dSJordan K. Hubbard for (;;) { 1393e5abb5e6SDavid Schultz while ((ch = *fmt) != '\0' && ch != '%') 1394e5abb5e6SDavid Schultz fmt++; 1395efb7e53dSJordan K. Hubbard if (ch == '\0') 1396efb7e53dSJordan K. Hubbard goto done; 1397efb7e53dSJordan K. Hubbard fmt++; /* skip over '%' */ 1398efb7e53dSJordan K. Hubbard 1399efb7e53dSJordan K. Hubbard flags = 0; 1400efb7e53dSJordan K. Hubbard width = 0; 1401efb7e53dSJordan K. Hubbard 1402efb7e53dSJordan K. Hubbard rflag: ch = *fmt++; 1403efb7e53dSJordan K. Hubbard reswitch: switch (ch) { 1404efb7e53dSJordan K. Hubbard case ' ': 1405efb7e53dSJordan K. Hubbard case '#': 1406efb7e53dSJordan K. Hubbard goto rflag; 1407efb7e53dSJordan K. Hubbard case '*': 1408e5abb5e6SDavid Schultz addaster(&types, &fmt); 1409efb7e53dSJordan K. Hubbard goto rflag; 1410efb7e53dSJordan K. Hubbard case '-': 1411efb7e53dSJordan K. Hubbard case '+': 14127735bb0fSBill Fenner case '\'': 1413efb7e53dSJordan K. Hubbard goto rflag; 1414efb7e53dSJordan K. Hubbard case '.': 1415efb7e53dSJordan K. Hubbard if ((ch = *fmt++) == '*') { 1416e5abb5e6SDavid Schultz addaster(&types, &fmt); 1417efb7e53dSJordan K. Hubbard goto rflag; 1418efb7e53dSJordan K. Hubbard } 1419efb7e53dSJordan K. Hubbard while (is_digit(ch)) { 1420efb7e53dSJordan K. Hubbard ch = *fmt++; 1421efb7e53dSJordan K. Hubbard } 1422efb7e53dSJordan K. Hubbard goto reswitch; 1423efb7e53dSJordan K. Hubbard case '0': 1424efb7e53dSJordan K. Hubbard goto rflag; 1425efb7e53dSJordan K. Hubbard case '1': case '2': case '3': case '4': 1426efb7e53dSJordan K. Hubbard case '5': case '6': case '7': case '8': case '9': 1427efb7e53dSJordan K. Hubbard n = 0; 1428efb7e53dSJordan K. Hubbard do { 1429efb7e53dSJordan K. Hubbard n = 10 * n + to_digit(ch); 1430efb7e53dSJordan K. Hubbard ch = *fmt++; 1431efb7e53dSJordan K. Hubbard } while (is_digit(ch)); 1432efb7e53dSJordan K. Hubbard if (ch == '$') { 1433e5abb5e6SDavid Schultz types.nextarg = n; 1434efb7e53dSJordan K. Hubbard goto rflag; 1435efb7e53dSJordan K. Hubbard } 1436efb7e53dSJordan K. Hubbard width = n; 1437efb7e53dSJordan K. Hubbard goto reswitch; 14388de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 1439efb7e53dSJordan K. Hubbard case 'L': 1440efb7e53dSJordan K. Hubbard flags |= LONGDBL; 1441efb7e53dSJordan K. Hubbard goto rflag; 1442efb7e53dSJordan K. Hubbard #endif 1443efb7e53dSJordan K. Hubbard case 'h': 14447735bb0fSBill Fenner if (flags & SHORTINT) { 14457735bb0fSBill Fenner flags &= ~SHORTINT; 14467735bb0fSBill Fenner flags |= CHARINT; 14477735bb0fSBill Fenner } else 1448efb7e53dSJordan K. Hubbard flags |= SHORTINT; 1449efb7e53dSJordan K. Hubbard goto rflag; 14507735bb0fSBill Fenner case 'j': 14517735bb0fSBill Fenner flags |= INTMAXT; 14527735bb0fSBill Fenner goto rflag; 1453efb7e53dSJordan K. Hubbard case 'l': 14547735bb0fSBill Fenner if (flags & LONGINT) { 14557735bb0fSBill Fenner flags &= ~LONGINT; 14567735bb0fSBill Fenner flags |= LLONGINT; 14577735bb0fSBill Fenner } else 1458efb7e53dSJordan K. Hubbard flags |= LONGINT; 1459efb7e53dSJordan K. Hubbard goto rflag; 1460efb7e53dSJordan K. Hubbard case 'q': 14617735bb0fSBill Fenner flags |= LLONGINT; /* not necessarily */ 14627735bb0fSBill Fenner goto rflag; 14637735bb0fSBill Fenner case 't': 14647735bb0fSBill Fenner flags |= PTRDIFFT; 14657735bb0fSBill Fenner goto rflag; 14667735bb0fSBill Fenner case 'z': 14677735bb0fSBill Fenner flags |= SIZET; 1468efb7e53dSJordan K. Hubbard goto rflag; 1469927ecbf3STim J. Robbins case 'C': 1470927ecbf3STim J. Robbins flags |= LONGINT; 1471927ecbf3STim J. Robbins /*FALLTHROUGH*/ 1472efb7e53dSJordan K. Hubbard case 'c': 1473b9aac308STim J. Robbins if (flags & LONGINT) 1474e5abb5e6SDavid Schultz addtype(&types, T_WINT); 1475b9aac308STim J. Robbins else 1476e5abb5e6SDavid Schultz addtype(&types, T_INT); 1477efb7e53dSJordan K. Hubbard break; 1478efb7e53dSJordan K. Hubbard case 'D': 1479efb7e53dSJordan K. Hubbard flags |= LONGINT; 1480efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1481efb7e53dSJordan K. Hubbard case 'd': 1482efb7e53dSJordan K. Hubbard case 'i': 1483e5abb5e6SDavid Schultz addsarg(&types, flags); 1484efb7e53dSJordan K. Hubbard break; 14858de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 14867735bb0fSBill Fenner case 'a': 14877735bb0fSBill Fenner case 'A': 1488efb7e53dSJordan K. Hubbard case 'e': 1489efb7e53dSJordan K. Hubbard case 'E': 1490efb7e53dSJordan K. Hubbard case 'f': 1491efb7e53dSJordan K. Hubbard case 'g': 1492efb7e53dSJordan K. Hubbard case 'G': 1493efb7e53dSJordan K. Hubbard if (flags & LONGDBL) 1494e5abb5e6SDavid Schultz addtype(&types, T_LONG_DOUBLE); 1495efb7e53dSJordan K. Hubbard else 1496e5abb5e6SDavid Schultz addtype(&types, T_DOUBLE); 1497efb7e53dSJordan K. Hubbard break; 14988de9e897SDavid Schultz #endif /* !NO_FLOATING_POINT */ 1499efb7e53dSJordan K. Hubbard case 'n': 15007735bb0fSBill Fenner if (flags & INTMAXT) 1501e5abb5e6SDavid Schultz addtype(&types, TP_INTMAXT); 15027735bb0fSBill Fenner else if (flags & PTRDIFFT) 1503e5abb5e6SDavid Schultz addtype(&types, TP_PTRDIFFT); 15047735bb0fSBill Fenner else if (flags & SIZET) 1505e5abb5e6SDavid Schultz addtype(&types, TP_SIZET); 15067735bb0fSBill Fenner else if (flags & LLONGINT) 1507e5abb5e6SDavid Schultz addtype(&types, TP_LLONG); 1508efb7e53dSJordan K. Hubbard else if (flags & LONGINT) 1509e5abb5e6SDavid Schultz addtype(&types, TP_LONG); 1510efb7e53dSJordan K. Hubbard else if (flags & SHORTINT) 1511e5abb5e6SDavid Schultz addtype(&types, TP_SHORT); 15127735bb0fSBill Fenner else if (flags & CHARINT) 1513e5abb5e6SDavid Schultz addtype(&types, TP_SCHAR); 1514efb7e53dSJordan K. Hubbard else 1515e5abb5e6SDavid Schultz addtype(&types, TP_INT); 1516efb7e53dSJordan K. Hubbard continue; /* no output */ 1517efb7e53dSJordan K. Hubbard case 'O': 1518efb7e53dSJordan K. Hubbard flags |= LONGINT; 1519efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1520efb7e53dSJordan K. Hubbard case 'o': 1521e5abb5e6SDavid Schultz adduarg(&types, flags); 1522efb7e53dSJordan K. Hubbard break; 1523efb7e53dSJordan K. Hubbard case 'p': 1524e5abb5e6SDavid Schultz addtype(&types, TP_VOID); 1525efb7e53dSJordan K. Hubbard break; 1526927ecbf3STim J. Robbins case 'S': 1527927ecbf3STim J. Robbins flags |= LONGINT; 1528927ecbf3STim J. Robbins /*FALLTHROUGH*/ 1529efb7e53dSJordan K. Hubbard case 's': 1530b9aac308STim J. Robbins if (flags & LONGINT) 1531e5abb5e6SDavid Schultz addtype(&types, TP_WCHAR); 1532b9aac308STim J. Robbins else 1533e5abb5e6SDavid Schultz addtype(&types, TP_CHAR); 1534efb7e53dSJordan K. Hubbard break; 1535efb7e53dSJordan K. Hubbard case 'U': 1536efb7e53dSJordan K. Hubbard flags |= LONGINT; 1537efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1538efb7e53dSJordan K. Hubbard case 'u': 1539efb7e53dSJordan K. Hubbard case 'X': 1540efb7e53dSJordan K. Hubbard case 'x': 1541e5abb5e6SDavid Schultz adduarg(&types, flags); 1542efb7e53dSJordan K. Hubbard break; 1543efb7e53dSJordan K. Hubbard default: /* "%?" prints ?, unless ? is NUL */ 1544efb7e53dSJordan K. Hubbard if (ch == '\0') 1545efb7e53dSJordan K. Hubbard goto done; 1546efb7e53dSJordan K. Hubbard break; 1547efb7e53dSJordan K. Hubbard } 1548efb7e53dSJordan K. Hubbard } 1549efb7e53dSJordan K. Hubbard done: 1550efb7e53dSJordan K. Hubbard /* 1551efb7e53dSJordan K. Hubbard * Build the argument table. 1552efb7e53dSJordan K. Hubbard */ 1553e5abb5e6SDavid Schultz if (types.tablemax >= STATIC_ARG_TBL_SIZE) { 1554a387081cSDoug Rabson *argtable = (union arg *) 1555e5abb5e6SDavid Schultz malloc (sizeof (union arg) * (types.tablemax + 1)); 1556efb7e53dSJordan K. Hubbard } 1557efb7e53dSJordan K. Hubbard 1558a387081cSDoug Rabson (*argtable) [0].intarg = 0; 1559e5abb5e6SDavid Schultz for (n = 1; n <= types.tablemax; n++) { 1560e5abb5e6SDavid Schultz switch (types.table[n]) { 15617735bb0fSBill Fenner case T_UNUSED: /* whoops! */ 1562a387081cSDoug Rabson (*argtable) [n].intarg = va_arg (ap, int); 1563efb7e53dSJordan K. Hubbard break; 15647735bb0fSBill Fenner case TP_SCHAR: 15657735bb0fSBill Fenner (*argtable) [n].pschararg = va_arg (ap, signed char *); 1566efb7e53dSJordan K. Hubbard break; 1567efb7e53dSJordan K. Hubbard case TP_SHORT: 1568a387081cSDoug Rabson (*argtable) [n].pshortarg = va_arg (ap, short *); 1569efb7e53dSJordan K. Hubbard break; 1570efb7e53dSJordan K. Hubbard case T_INT: 1571a387081cSDoug Rabson (*argtable) [n].intarg = va_arg (ap, int); 1572efb7e53dSJordan K. Hubbard break; 1573efb7e53dSJordan K. Hubbard case T_U_INT: 1574a387081cSDoug Rabson (*argtable) [n].uintarg = va_arg (ap, unsigned int); 1575efb7e53dSJordan K. Hubbard break; 1576efb7e53dSJordan K. Hubbard case TP_INT: 1577a387081cSDoug Rabson (*argtable) [n].pintarg = va_arg (ap, int *); 1578efb7e53dSJordan K. Hubbard break; 1579efb7e53dSJordan K. Hubbard case T_LONG: 1580a387081cSDoug Rabson (*argtable) [n].longarg = va_arg (ap, long); 1581efb7e53dSJordan K. Hubbard break; 1582efb7e53dSJordan K. Hubbard case T_U_LONG: 1583a387081cSDoug Rabson (*argtable) [n].ulongarg = va_arg (ap, unsigned long); 1584efb7e53dSJordan K. Hubbard break; 1585efb7e53dSJordan K. Hubbard case TP_LONG: 1586a387081cSDoug Rabson (*argtable) [n].plongarg = va_arg (ap, long *); 1587efb7e53dSJordan K. Hubbard break; 15887735bb0fSBill Fenner case T_LLONG: 15897735bb0fSBill Fenner (*argtable) [n].longlongarg = va_arg (ap, long long); 1590efb7e53dSJordan K. Hubbard break; 15917735bb0fSBill Fenner case T_U_LLONG: 15927735bb0fSBill Fenner (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); 1593efb7e53dSJordan K. Hubbard break; 15947735bb0fSBill Fenner case TP_LLONG: 15957735bb0fSBill Fenner (*argtable) [n].plonglongarg = va_arg (ap, long long *); 15967735bb0fSBill Fenner break; 15977735bb0fSBill Fenner case T_PTRDIFFT: 15987735bb0fSBill Fenner (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); 15997735bb0fSBill Fenner break; 16007735bb0fSBill Fenner case TP_PTRDIFFT: 16017735bb0fSBill Fenner (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); 16027735bb0fSBill Fenner break; 16037735bb0fSBill Fenner case T_SIZET: 16047735bb0fSBill Fenner (*argtable) [n].sizearg = va_arg (ap, size_t); 16057735bb0fSBill Fenner break; 16067735bb0fSBill Fenner case TP_SIZET: 1607500b77c7SAlexander Kabaev (*argtable) [n].psizearg = va_arg (ap, size_t *); 16087735bb0fSBill Fenner break; 16097735bb0fSBill Fenner case T_INTMAXT: 16107735bb0fSBill Fenner (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); 16117735bb0fSBill Fenner break; 16127735bb0fSBill Fenner case T_UINTMAXT: 16137735bb0fSBill Fenner (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); 16147735bb0fSBill Fenner break; 16157735bb0fSBill Fenner case TP_INTMAXT: 16167735bb0fSBill Fenner (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); 1617efb7e53dSJordan K. Hubbard break; 1618efb7e53dSJordan K. Hubbard case T_DOUBLE: 161975239a01SPoul-Henning Kamp #ifndef NO_FLOATING_POINT 1620a387081cSDoug Rabson (*argtable) [n].doublearg = va_arg (ap, double); 162175239a01SPoul-Henning Kamp #endif 1622efb7e53dSJordan K. Hubbard break; 1623efb7e53dSJordan K. Hubbard case T_LONG_DOUBLE: 162475239a01SPoul-Henning Kamp #ifndef NO_FLOATING_POINT 1625a387081cSDoug Rabson (*argtable) [n].longdoublearg = va_arg (ap, long double); 1626a387081cSDoug Rabson #endif 162775239a01SPoul-Henning Kamp break; 1628efb7e53dSJordan K. Hubbard case TP_CHAR: 1629a387081cSDoug Rabson (*argtable) [n].pchararg = va_arg (ap, char *); 1630efb7e53dSJordan K. Hubbard break; 1631efb7e53dSJordan K. Hubbard case TP_VOID: 1632a387081cSDoug Rabson (*argtable) [n].pvoidarg = va_arg (ap, void *); 1633efb7e53dSJordan K. Hubbard break; 1634b9aac308STim J. Robbins case T_WINT: 1635b9aac308STim J. Robbins (*argtable) [n].wintarg = va_arg (ap, wint_t); 1636b9aac308STim J. Robbins break; 1637b9aac308STim J. Robbins case TP_WCHAR: 1638b9aac308STim J. Robbins (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); 1639b9aac308STim J. Robbins break; 1640efb7e53dSJordan K. Hubbard } 1641efb7e53dSJordan K. Hubbard } 1642efb7e53dSJordan K. Hubbard 1643e5abb5e6SDavid Schultz freetypes(&types); 1644efb7e53dSJordan K. Hubbard } 1645efb7e53dSJordan K. Hubbard 1646efb7e53dSJordan K. Hubbard /* 1647efb7e53dSJordan K. Hubbard * Increase the size of the type table. 1648efb7e53dSJordan K. Hubbard */ 1649efb7e53dSJordan K. Hubbard static void 1650e5abb5e6SDavid Schultz __grow_type_table(struct typetable *types) 1651efb7e53dSJordan K. Hubbard { 1652e5abb5e6SDavid Schultz enum typeid *const oldtable = types->table; 1653e5abb5e6SDavid Schultz const int oldsize = types->tablesize; 16547735bb0fSBill Fenner enum typeid *newtable; 1655ccc8c6c3STim J. Robbins int n, newsize = oldsize * 2; 1656efb7e53dSJordan K. Hubbard 1657e5abb5e6SDavid Schultz if (newsize < types->nextarg + 1) 1658e5abb5e6SDavid Schultz newsize = types->nextarg + 1; 165942cebaa5SArchie Cobbs if (oldsize == STATIC_ARG_TBL_SIZE) { 1660ccc8c6c3STim J. Robbins if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL) 166142cebaa5SArchie Cobbs abort(); /* XXX handle better */ 1662ccc8c6c3STim J. Robbins bcopy(oldtable, newtable, oldsize * sizeof(enum typeid)); 1663efb7e53dSJordan K. Hubbard } else { 1664ccc8c6c3STim J. Robbins newtable = reallocf(oldtable, newsize * sizeof(enum typeid)); 1665ccc8c6c3STim J. Robbins if (newtable == NULL) 166642cebaa5SArchie Cobbs abort(); /* XXX handle better */ 1667efb7e53dSJordan K. Hubbard } 1668ccc8c6c3STim J. Robbins for (n = oldsize; n < newsize; n++) 1669ccc8c6c3STim J. Robbins newtable[n] = T_UNUSED; 1670efb7e53dSJordan K. Hubbard 1671e5abb5e6SDavid Schultz types->table = newtable; 1672e5abb5e6SDavid Schultz types->tablesize = newsize; 1673efb7e53dSJordan K. Hubbard } 1674efb7e53dSJordan K. Hubbard 1675efb7e53dSJordan K. Hubbard 16768de9e897SDavid Schultz #ifndef NO_FLOATING_POINT 167758f0484fSRodney W. Grimes 167858f0484fSRodney W. Grimes static int 1679d201fe46SDaniel Eischen exponent(char *p0, int exp, int fmtch) 168058f0484fSRodney W. Grimes { 1681d201fe46SDaniel Eischen char *p, *t; 168238cac8f8SDavid Schultz char expbuf[MAXEXPDIG]; 168358f0484fSRodney W. Grimes 168458f0484fSRodney W. Grimes p = p0; 168558f0484fSRodney W. Grimes *p++ = fmtch; 168658f0484fSRodney W. Grimes if (exp < 0) { 168758f0484fSRodney W. Grimes exp = -exp; 168858f0484fSRodney W. Grimes *p++ = '-'; 168958f0484fSRodney W. Grimes } 169058f0484fSRodney W. Grimes else 169158f0484fSRodney W. Grimes *p++ = '+'; 169238cac8f8SDavid Schultz t = expbuf + MAXEXPDIG; 169358f0484fSRodney W. Grimes if (exp > 9) { 169458f0484fSRodney W. Grimes do { 169558f0484fSRodney W. Grimes *--t = to_char(exp % 10); 169658f0484fSRodney W. Grimes } while ((exp /= 10) > 9); 169758f0484fSRodney W. Grimes *--t = to_char(exp); 169838cac8f8SDavid Schultz for (; t < expbuf + MAXEXPDIG; *p++ = *t++); 169958f0484fSRodney W. Grimes } 170058f0484fSRodney W. Grimes else { 1701ebbad5ecSDavid Schultz /* 1702ebbad5ecSDavid Schultz * Exponents for decimal floating point conversions 1703ebbad5ecSDavid Schultz * (%[eEgG]) must be at least two characters long, 1704ebbad5ecSDavid Schultz * whereas exponents for hexadecimal conversions can 1705ebbad5ecSDavid Schultz * be only one character long. 1706ebbad5ecSDavid Schultz */ 1707ebbad5ecSDavid Schultz if (fmtch == 'e' || fmtch == 'E') 170858f0484fSRodney W. Grimes *p++ = '0'; 170958f0484fSRodney W. Grimes *p++ = to_char(exp); 171058f0484fSRodney W. Grimes } 171158f0484fSRodney W. Grimes return (p - p0); 171258f0484fSRodney W. Grimes } 17138de9e897SDavid Schultz #endif /* !NO_FLOATING_POINT */ 1714