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) 38ce51cf03SJames Raynard #if 0 3958f0484fSRodney W. Grimes static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; 40ce51cf03SJames Raynard #endif 41ce51cf03SJames Raynard static const char rcsid[] = 427f3dea24SPeter Wemm "$FreeBSD$"; 4358f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */ 4458f0484fSRodney W. Grimes 4558f0484fSRodney W. Grimes /* 4658f0484fSRodney W. Grimes * Actual printf innards. 4758f0484fSRodney W. Grimes * 4858f0484fSRodney W. Grimes * This code is large and complicated... 4958f0484fSRodney W. Grimes */ 5058f0484fSRodney W. Grimes 51d201fe46SDaniel Eischen #include "namespace.h" 5258f0484fSRodney W. Grimes #include <sys/types.h> 5358f0484fSRodney W. Grimes 547735bb0fSBill Fenner #include <ctype.h> 5558f0484fSRodney W. Grimes #include <limits.h> 567ae5c679SAlexey Zelkin #include <locale.h> 577735bb0fSBill Fenner #include <stddef.h> 587735bb0fSBill Fenner #include <stdint.h> 5958f0484fSRodney W. Grimes #include <stdio.h> 6058f0484fSRodney W. Grimes #include <stdlib.h> 6158f0484fSRodney W. Grimes #include <string.h> 6258f0484fSRodney W. Grimes 6358f0484fSRodney W. Grimes #if __STDC__ 6458f0484fSRodney W. Grimes #include <stdarg.h> 6558f0484fSRodney W. Grimes #else 6658f0484fSRodney W. Grimes #include <varargs.h> 6758f0484fSRodney W. Grimes #endif 68d201fe46SDaniel Eischen #include "un-namespace.h" 6958f0484fSRodney W. Grimes 70d201fe46SDaniel Eischen #include "libc_private.h" 7158f0484fSRodney W. Grimes #include "local.h" 7258f0484fSRodney W. Grimes #include "fvwrite.h" 7358f0484fSRodney W. Grimes 7458f0484fSRodney W. Grimes /* Define FLOATING_POINT to get floating point. */ 7558f0484fSRodney W. Grimes #define FLOATING_POINT 7658f0484fSRodney W. Grimes 77a387081cSDoug Rabson union arg { 78a387081cSDoug Rabson int intarg; 7918ca70d1SBruce Evans u_int uintarg; 80a387081cSDoug Rabson long longarg; 8118ca70d1SBruce Evans u_long ulongarg; 827735bb0fSBill Fenner long long longlongarg; 837735bb0fSBill Fenner unsigned long long ulonglongarg; 847735bb0fSBill Fenner ptrdiff_t ptrdiffarg; 857735bb0fSBill Fenner size_t sizearg; 867735bb0fSBill Fenner intmax_t intmaxarg; 877735bb0fSBill Fenner uintmax_t uintmaxarg; 88a387081cSDoug Rabson void *pvoidarg; 89a387081cSDoug Rabson char *pchararg; 907735bb0fSBill Fenner signed char *pschararg; 91a387081cSDoug Rabson short *pshortarg; 92a387081cSDoug Rabson int *pintarg; 93a387081cSDoug Rabson long *plongarg; 947735bb0fSBill Fenner long long *plonglongarg; 957735bb0fSBill Fenner ptrdiff_t *pptrdiffarg; 967735bb0fSBill Fenner size_t *psizearg; 977735bb0fSBill Fenner intmax_t *pintmaxarg; 98a387081cSDoug Rabson #ifdef FLOATING_POINT 99a387081cSDoug Rabson double doublearg; 100a387081cSDoug Rabson long double longdoublearg; 101a387081cSDoug Rabson #endif 102a387081cSDoug Rabson }; 103a387081cSDoug Rabson 1047735bb0fSBill Fenner /* 1057735bb0fSBill Fenner * Type ids for argument type table. 1067735bb0fSBill Fenner */ 1077735bb0fSBill Fenner enum typeid { 1087735bb0fSBill Fenner T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, 1097735bb0fSBill Fenner T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, 1107735bb0fSBill Fenner T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET, 1117735bb0fSBill Fenner T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, 1127735bb0fSBill Fenner T_DOUBLE, T_LONG_DOUBLE 1137735bb0fSBill Fenner }; 1147735bb0fSBill Fenner 115ce51cf03SJames Raynard static int __sprint __P((FILE *, struct __suio *)); 1166dac8ac9SKris Kennaway static int __sbprintf __P((FILE *, const char *, va_list)) __printflike(2, 0); 11798ee7635SAlexey Zelkin static char * __ujtoa __P((uintmax_t, char *, int, int, char *, int, char, const char *)); 11898ee7635SAlexey Zelkin static char * __ultoa __P((u_long, char *, int, int, char *, int, char, const char *)); 119a387081cSDoug Rabson static void __find_arguments __P((const char *, va_list, union arg **)); 1207735bb0fSBill Fenner static void __grow_type_table __P((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; 15858f0484fSRodney W. Grimes 15958f0484fSRodney W. Grimes /* set up the buffer */ 16058f0484fSRodney W. Grimes fake._bf._base = fake._p = buf; 16158f0484fSRodney W. Grimes fake._bf._size = fake._w = sizeof(buf); 16258f0484fSRodney W. Grimes fake._lbfsize = 0; /* not actually used, but Just In Case */ 16358f0484fSRodney W. Grimes 16458f0484fSRodney W. Grimes /* do the work, then copy any error status */ 165d201fe46SDaniel Eischen ret = __vfprintf(&fake, fmt, ap); 166d201fe46SDaniel Eischen if (ret >= 0 && __fflush(&fake)) 16758f0484fSRodney W. Grimes ret = EOF; 16858f0484fSRodney W. Grimes if (fake._flags & __SERR) 16958f0484fSRodney W. Grimes fp->_flags |= __SERR; 17058f0484fSRodney W. Grimes return (ret); 17158f0484fSRodney W. Grimes } 17258f0484fSRodney W. Grimes 17358f0484fSRodney W. Grimes /* 17458f0484fSRodney W. Grimes * Macros for converting digits to letters and vice versa 17558f0484fSRodney W. Grimes */ 17658f0484fSRodney W. Grimes #define to_digit(c) ((c) - '0') 17758f0484fSRodney W. Grimes #define is_digit(c) ((unsigned)to_digit(c) <= 9) 17858f0484fSRodney W. Grimes #define to_char(n) ((n) + '0') 17958f0484fSRodney W. Grimes 18058f0484fSRodney W. Grimes /* 18158f0484fSRodney W. Grimes * Convert an unsigned long to ASCII for printf purposes, returning 18258f0484fSRodney W. Grimes * a pointer to the first character of the string representation. 18358f0484fSRodney W. Grimes * Octal numbers can be forced to have a leading zero; hex numbers 18458f0484fSRodney W. Grimes * use the given digits. 18558f0484fSRodney W. Grimes */ 18658f0484fSRodney W. Grimes static char * 1877735bb0fSBill Fenner __ultoa(u_long val, char *endp, int base, int octzero, char *xdigs, 18898ee7635SAlexey Zelkin int needgrp, char thousep, const char *grp) 18958f0484fSRodney W. Grimes { 19058f0484fSRodney W. Grimes register char *cp = endp; 19158f0484fSRodney W. Grimes register long sval; 1927735bb0fSBill Fenner int ndig; 19358f0484fSRodney W. Grimes 19458f0484fSRodney W. Grimes /* 19558f0484fSRodney W. Grimes * Handle the three cases separately, in the hope of getting 19658f0484fSRodney W. Grimes * better/faster code. 19758f0484fSRodney W. Grimes */ 19858f0484fSRodney W. Grimes switch (base) { 19958f0484fSRodney W. Grimes case 10: 20058f0484fSRodney W. Grimes if (val < 10) { /* many numbers are 1 digit */ 20158f0484fSRodney W. Grimes *--cp = to_char(val); 20258f0484fSRodney W. Grimes return (cp); 20358f0484fSRodney W. Grimes } 2047735bb0fSBill Fenner ndig = 0; 20558f0484fSRodney W. Grimes /* 20658f0484fSRodney W. Grimes * On many machines, unsigned arithmetic is harder than 20758f0484fSRodney W. Grimes * signed arithmetic, so we do at most one unsigned mod and 20858f0484fSRodney W. Grimes * divide; this is sufficient to reduce the range of 20958f0484fSRodney W. Grimes * the incoming value to where signed arithmetic works. 21058f0484fSRodney W. Grimes */ 21158f0484fSRodney W. Grimes if (val > LONG_MAX) { 21258f0484fSRodney W. Grimes *--cp = to_char(val % 10); 2137735bb0fSBill Fenner ndig++; 21458f0484fSRodney W. Grimes sval = val / 10; 21558f0484fSRodney W. Grimes } else 21658f0484fSRodney W. Grimes sval = val; 21758f0484fSRodney W. Grimes do { 21858f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 21998ee7635SAlexey Zelkin ndig++; 22098ee7635SAlexey Zelkin /* 22198ee7635SAlexey Zelkin * If (*grp == CHAR_MAX) then no more grouping 22298ee7635SAlexey Zelkin * should be performed. 22398ee7635SAlexey Zelkin */ 22498ee7635SAlexey Zelkin if (needgrp && ndig == *grp && *grp != CHAR_MAX) { 22598ee7635SAlexey Zelkin *--cp = thousep; 2267735bb0fSBill Fenner ndig = 0; 22798ee7635SAlexey Zelkin /* 22898ee7635SAlexey Zelkin * If (*(grp+1) == '\0') then we have to 22998ee7635SAlexey Zelkin * use *grp character (last grouping rule) 23098ee7635SAlexey Zelkin * for all next cases 23198ee7635SAlexey Zelkin */ 23298ee7635SAlexey Zelkin if (*(grp+1) != '\0') grp++; 2337735bb0fSBill Fenner } 23458f0484fSRodney W. Grimes sval /= 10; 23558f0484fSRodney W. Grimes } while (sval != 0); 23658f0484fSRodney W. Grimes break; 23758f0484fSRodney W. Grimes 23858f0484fSRodney W. Grimes case 8: 23958f0484fSRodney W. Grimes do { 24058f0484fSRodney W. Grimes *--cp = to_char(val & 7); 24158f0484fSRodney W. Grimes val >>= 3; 24258f0484fSRodney W. Grimes } while (val); 24358f0484fSRodney W. Grimes if (octzero && *cp != '0') 24458f0484fSRodney W. Grimes *--cp = '0'; 24558f0484fSRodney W. Grimes break; 24658f0484fSRodney W. Grimes 24758f0484fSRodney W. Grimes case 16: 24858f0484fSRodney W. Grimes do { 24958f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 25058f0484fSRodney W. Grimes val >>= 4; 25158f0484fSRodney W. Grimes } while (val); 25258f0484fSRodney W. Grimes break; 25358f0484fSRodney W. Grimes 25458f0484fSRodney W. Grimes default: /* oops */ 25558f0484fSRodney W. Grimes abort(); 25658f0484fSRodney W. Grimes } 25758f0484fSRodney W. Grimes return (cp); 25858f0484fSRodney W. Grimes } 25958f0484fSRodney W. Grimes 2607735bb0fSBill Fenner /* Identical to __ultoa, but for intmax_t. */ 26158f0484fSRodney W. Grimes static char * 2627735bb0fSBill Fenner __ujtoa(uintmax_t val, char *endp, int base, int octzero, char *xdigs, 26398ee7635SAlexey Zelkin int needgrp, char thousep, const char *grp) 26458f0484fSRodney W. Grimes { 265d201fe46SDaniel Eischen char *cp = endp; 2667735bb0fSBill Fenner intmax_t sval; 2677735bb0fSBill Fenner int ndig; 26858f0484fSRodney W. Grimes 26958f0484fSRodney W. Grimes /* quick test for small values; __ultoa is typically much faster */ 27058f0484fSRodney W. Grimes /* (perhaps instead we should run until small, then call __ultoa?) */ 27158f0484fSRodney W. Grimes if (val <= ULONG_MAX) 2727735bb0fSBill Fenner return (__ultoa((u_long)val, endp, base, octzero, xdigs, 27398ee7635SAlexey Zelkin needgrp, thousep, grp)); 27458f0484fSRodney W. Grimes switch (base) { 27558f0484fSRodney W. Grimes case 10: 27658f0484fSRodney W. Grimes if (val < 10) { 27758f0484fSRodney W. Grimes *--cp = to_char(val % 10); 27858f0484fSRodney W. Grimes return (cp); 27958f0484fSRodney W. Grimes } 2807735bb0fSBill Fenner ndig = 0; 2817735bb0fSBill Fenner if (val > INTMAX_MAX) { 28258f0484fSRodney W. Grimes *--cp = to_char(val % 10); 2837735bb0fSBill Fenner ndig++; 28458f0484fSRodney W. Grimes sval = val / 10; 28558f0484fSRodney W. Grimes } else 28658f0484fSRodney W. Grimes sval = val; 28758f0484fSRodney W. Grimes do { 28858f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 28998ee7635SAlexey Zelkin ndig++; 29098ee7635SAlexey Zelkin /* 29198ee7635SAlexey Zelkin * If (*grp == CHAR_MAX) then no more grouping 29298ee7635SAlexey Zelkin * should be performed. 29398ee7635SAlexey Zelkin */ 29498ee7635SAlexey Zelkin if (needgrp && *grp != CHAR_MAX && ndig == *grp) { 29598ee7635SAlexey Zelkin *--cp = thousep; 2967735bb0fSBill Fenner ndig = 0; 29798ee7635SAlexey Zelkin /* 29898ee7635SAlexey Zelkin * If (*(grp+1) == '\0') then we have to 29998ee7635SAlexey Zelkin * use *grp character (last grouping rule) 30098ee7635SAlexey Zelkin * for all next cases 30198ee7635SAlexey Zelkin */ 30298ee7635SAlexey Zelkin if (*(grp+1) != '\0') grp++; 3037735bb0fSBill Fenner } 30458f0484fSRodney W. Grimes sval /= 10; 30558f0484fSRodney W. Grimes } while (sval != 0); 30658f0484fSRodney W. Grimes break; 30758f0484fSRodney W. Grimes 30858f0484fSRodney W. Grimes case 8: 30958f0484fSRodney W. Grimes do { 31058f0484fSRodney W. Grimes *--cp = to_char(val & 7); 31158f0484fSRodney W. Grimes val >>= 3; 31258f0484fSRodney W. Grimes } while (val); 31358f0484fSRodney W. Grimes if (octzero && *cp != '0') 31458f0484fSRodney W. Grimes *--cp = '0'; 31558f0484fSRodney W. Grimes break; 31658f0484fSRodney W. Grimes 31758f0484fSRodney W. Grimes case 16: 31858f0484fSRodney W. Grimes do { 31958f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 32058f0484fSRodney W. Grimes val >>= 4; 32158f0484fSRodney W. Grimes } while (val); 32258f0484fSRodney W. Grimes break; 32358f0484fSRodney W. Grimes 32458f0484fSRodney W. Grimes default: 32558f0484fSRodney W. Grimes abort(); 32658f0484fSRodney W. Grimes } 32758f0484fSRodney W. Grimes return (cp); 32858f0484fSRodney W. Grimes } 32958f0484fSRodney W. Grimes 330d201fe46SDaniel Eischen /* 331d201fe46SDaniel Eischen * MT-safe version 332d201fe46SDaniel Eischen */ 333d201fe46SDaniel Eischen int 334d201fe46SDaniel Eischen vfprintf(FILE *fp, const char *fmt0, va_list ap) 335d201fe46SDaniel Eischen { 336d201fe46SDaniel Eischen int ret; 337d201fe46SDaniel Eischen 338d201fe46SDaniel Eischen FLOCKFILE(fp); 339d201fe46SDaniel Eischen ret = __vfprintf(fp, fmt0, ap); 340d201fe46SDaniel Eischen FUNLOCKFILE(fp); 341d201fe46SDaniel Eischen return (ret); 342d201fe46SDaniel Eischen } 343d201fe46SDaniel Eischen 34458f0484fSRodney W. Grimes #ifdef FLOATING_POINT 34558f0484fSRodney W. Grimes #include <math.h> 34658f0484fSRodney W. Grimes #include "floatio.h" 34758f0484fSRodney W. Grimes 34898ee7635SAlexey Zelkin #define BUF ((MAXEXP*2)+MAXFRACT+1) /* + decimal point */ 34958f0484fSRodney W. Grimes #define DEFPREC 6 35058f0484fSRodney W. Grimes 3512ffc61baSTor Egge static char *cvt __P((double, int, int, char *, int *, int, int *, char **)); 35258f0484fSRodney W. Grimes static int exponent __P((char *, int, int)); 35358f0484fSRodney W. Grimes 35458f0484fSRodney W. Grimes #else /* no FLOATING_POINT */ 35558f0484fSRodney W. Grimes 35698ee7635SAlexey Zelkin #define BUF 136 35758f0484fSRodney W. Grimes 35858f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 35958f0484fSRodney W. Grimes 360efb7e53dSJordan K. Hubbard #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 36158f0484fSRodney W. Grimes 36258f0484fSRodney W. Grimes /* 36358f0484fSRodney W. Grimes * Flags used during conversion. 36458f0484fSRodney W. Grimes */ 36558f0484fSRodney W. Grimes #define ALT 0x001 /* alternate form */ 36658f0484fSRodney W. Grimes #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 36758f0484fSRodney W. Grimes #define LADJUST 0x004 /* left adjustment */ 3686a93659fSBruce Evans #define LONGDBL 0x008 /* long double */ 36958f0484fSRodney W. Grimes #define LONGINT 0x010 /* long integer */ 3707735bb0fSBill Fenner #define LLONGINT 0x020 /* long long integer */ 37158f0484fSRodney W. Grimes #define SHORTINT 0x040 /* short integer */ 37258f0484fSRodney W. Grimes #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 37358f0484fSRodney W. Grimes #define FPT 0x100 /* Floating point number */ 37498ee7635SAlexey Zelkin #define GROUPING 0x200 /* use grouping ("'" flag) */ 3757735bb0fSBill Fenner /* C99 additional size modifiers: */ 37698ee7635SAlexey Zelkin #define SIZET 0x400 /* size_t */ 37798ee7635SAlexey Zelkin #define PTRDIFFT 0x800 /* ptrdiff_t */ 37898ee7635SAlexey Zelkin #define INTMAXT 0x1000 /* intmax_t */ 37998ee7635SAlexey Zelkin #define CHARINT 0x2000 /* print char using int format */ 3807735bb0fSBill Fenner 381d201fe46SDaniel Eischen /* 382d201fe46SDaniel Eischen * Non-MT-safe version 383d201fe46SDaniel Eischen */ 38458f0484fSRodney W. Grimes int 385d201fe46SDaniel Eischen __vfprintf(FILE *fp, const char *fmt0, va_list ap) 38658f0484fSRodney W. Grimes { 387d201fe46SDaniel Eischen char *fmt; /* format string */ 388d201fe46SDaniel Eischen int ch; /* character from fmt */ 389d201fe46SDaniel Eischen int n, n2; /* handy integer (short term usage) */ 390d201fe46SDaniel Eischen char *cp; /* handy char pointer (short term usage) */ 391d201fe46SDaniel Eischen struct __siov *iovp; /* for PRINT macro */ 392d201fe46SDaniel Eischen int flags; /* flags as above */ 39358f0484fSRodney W. Grimes int ret; /* return value accumulator */ 39458f0484fSRodney W. Grimes int width; /* width from format (%8d), or 0 */ 39558f0484fSRodney W. Grimes int prec; /* precision from format (%.3d), or -1 */ 39658f0484fSRodney W. Grimes char sign; /* sign prefix (' ', '+', '-', or \0) */ 39798ee7635SAlexey Zelkin char thousands_sep; /* locale specific thousands separator */ 39898ee7635SAlexey Zelkin const char *grouping; /* locale specific numeric grouping rules */ 39958f0484fSRodney W. Grimes #ifdef FLOATING_POINT 4007ae5c679SAlexey Zelkin char *decimal_point; /* locale specific decimal point */ 40158f0484fSRodney W. Grimes char softsign; /* temporary negative sign for floats */ 40258f0484fSRodney W. Grimes double _double; /* double precision arguments %[eEfgG] */ 40358f0484fSRodney W. Grimes int expt; /* integer value of exponent */ 40458f0484fSRodney W. Grimes int expsize; /* character count for expstr */ 40558f0484fSRodney W. Grimes int ndig; /* actual number of digits returned by cvt */ 40658f0484fSRodney W. Grimes char expstr[7]; /* buffer for exponent string */ 4072ffc61baSTor Egge char *dtoaresult; /* buffer allocated by dtoa */ 40858f0484fSRodney W. Grimes #endif 40958f0484fSRodney W. Grimes u_long ulval; /* integer arguments %[diouxX] */ 4107735bb0fSBill Fenner uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ 41158f0484fSRodney W. Grimes int base; /* base for [diouxX] conversion */ 41258f0484fSRodney W. Grimes int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 413261a532aSBill Fenner int realsz; /* field size expanded by dprec, sign, etc */ 41458f0484fSRodney W. Grimes int size; /* size of converted field or string */ 41592e88f87SAndrey A. Chernov int prsize; /* max size of printed field */ 41658f0484fSRodney W. Grimes char *xdigs; /* digits for [xX] conversion */ 41758f0484fSRodney W. Grimes #define NIOV 8 41858f0484fSRodney W. Grimes struct __suio uio; /* output information: summary */ 41958f0484fSRodney W. Grimes struct __siov iov[NIOV];/* ... and individual io vectors */ 4207735bb0fSBill Fenner char buf[BUF]; /* space for %c, %[diouxX], %[eEfFgG] */ 42158f0484fSRodney W. Grimes char ox[2]; /* space for 0x hex-prefix */ 422a387081cSDoug Rabson union arg *argtable; /* args, built due to positional arg */ 423a387081cSDoug Rabson union arg statargtable [STATIC_ARG_TBL_SIZE]; 424efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 425efb7e53dSJordan K. Hubbard va_list orgap; /* original argument pointer */ 42658f0484fSRodney W. Grimes 42758f0484fSRodney W. Grimes /* 42858f0484fSRodney W. Grimes * Choose PADSIZE to trade efficiency vs. size. If larger printf 42958f0484fSRodney W. Grimes * fields occur frequently, increase PADSIZE and make the initialisers 43058f0484fSRodney W. Grimes * below longer. 43158f0484fSRodney W. Grimes */ 43258f0484fSRodney W. Grimes #define PADSIZE 16 /* pad chunk size */ 43358f0484fSRodney W. Grimes static char blanks[PADSIZE] = 43458f0484fSRodney W. Grimes {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 43558f0484fSRodney W. Grimes static char zeroes[PADSIZE] = 43658f0484fSRodney W. Grimes {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 43758f0484fSRodney W. Grimes 43858f0484fSRodney W. Grimes /* 43958f0484fSRodney W. Grimes * BEWARE, these `goto error' on error, and PAD uses `n'. 44058f0484fSRodney W. Grimes */ 44158f0484fSRodney W. Grimes #define PRINT(ptr, len) { \ 44258f0484fSRodney W. Grimes iovp->iov_base = (ptr); \ 44358f0484fSRodney W. Grimes iovp->iov_len = (len); \ 44458f0484fSRodney W. Grimes uio.uio_resid += (len); \ 44558f0484fSRodney W. Grimes iovp++; \ 44658f0484fSRodney W. Grimes if (++uio.uio_iovcnt >= NIOV) { \ 44758f0484fSRodney W. Grimes if (__sprint(fp, &uio)) \ 44858f0484fSRodney W. Grimes goto error; \ 44958f0484fSRodney W. Grimes iovp = iov; \ 45058f0484fSRodney W. Grimes } \ 45158f0484fSRodney W. Grimes } 45258f0484fSRodney W. Grimes #define PAD(howmany, with) { \ 45358f0484fSRodney W. Grimes if ((n = (howmany)) > 0) { \ 45458f0484fSRodney W. Grimes while (n > PADSIZE) { \ 45558f0484fSRodney W. Grimes PRINT(with, PADSIZE); \ 45658f0484fSRodney W. Grimes n -= PADSIZE; \ 45758f0484fSRodney W. Grimes } \ 45858f0484fSRodney W. Grimes PRINT(with, n); \ 45958f0484fSRodney W. Grimes } \ 46058f0484fSRodney W. Grimes } 46158f0484fSRodney W. Grimes #define FLUSH() { \ 46258f0484fSRodney W. Grimes if (uio.uio_resid && __sprint(fp, &uio)) \ 46358f0484fSRodney W. Grimes goto error; \ 46458f0484fSRodney W. Grimes uio.uio_iovcnt = 0; \ 46558f0484fSRodney W. Grimes iovp = iov; \ 46658f0484fSRodney W. Grimes } 46758f0484fSRodney W. Grimes 46858f0484fSRodney W. Grimes /* 469efb7e53dSJordan K. Hubbard * Get the argument indexed by nextarg. If the argument table is 470efb7e53dSJordan K. Hubbard * built, use it to get the argument. If its not, get the next 471efb7e53dSJordan K. Hubbard * argument (and arguments must be gotten sequentially). 472efb7e53dSJordan K. Hubbard */ 473efb7e53dSJordan K. Hubbard #define GETARG(type) \ 474a387081cSDoug Rabson ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 475efb7e53dSJordan K. Hubbard (nextarg++, va_arg(ap, type))) 476efb7e53dSJordan K. Hubbard 477efb7e53dSJordan K. Hubbard /* 47858f0484fSRodney W. Grimes * To extend shorts properly, we need both signed and unsigned 47958f0484fSRodney W. Grimes * argument extraction methods. 48058f0484fSRodney W. Grimes */ 48158f0484fSRodney W. Grimes #define SARG() \ 482efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(long) : \ 483efb7e53dSJordan K. Hubbard flags&SHORTINT ? (long)(short)GETARG(int) : \ 4847735bb0fSBill Fenner flags&CHARINT ? (long)(signed char)GETARG(int) : \ 485efb7e53dSJordan K. Hubbard (long)GETARG(int)) 48658f0484fSRodney W. Grimes #define UARG() \ 487efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(u_long) : \ 488efb7e53dSJordan K. Hubbard flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 4897735bb0fSBill Fenner flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ 490efb7e53dSJordan K. Hubbard (u_long)GETARG(u_int)) 4917735bb0fSBill Fenner #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) 4927735bb0fSBill Fenner #define SJARG() \ 4937735bb0fSBill Fenner (flags&INTMAXT ? GETARG(intmax_t) : \ 4947735bb0fSBill Fenner flags&SIZET ? (intmax_t)GETARG(size_t) : \ 4957735bb0fSBill Fenner flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ 4967735bb0fSBill Fenner (intmax_t)GETARG(long long)) 4977735bb0fSBill Fenner #define UJARG() \ 4987735bb0fSBill Fenner (flags&INTMAXT ? GETARG(uintmax_t) : \ 4997735bb0fSBill Fenner flags&SIZET ? (uintmax_t)GETARG(size_t) : \ 5007735bb0fSBill Fenner flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ 5017735bb0fSBill Fenner (uintmax_t)GETARG(unsigned long long)) 502efb7e53dSJordan K. Hubbard 503efb7e53dSJordan K. Hubbard /* 504efb7e53dSJordan K. Hubbard * Get * arguments, including the form *nn$. Preserve the nextarg 505efb7e53dSJordan K. Hubbard * that the argument can be gotten once the type is determined. 506efb7e53dSJordan K. Hubbard */ 507efb7e53dSJordan K. Hubbard #define GETASTER(val) \ 508efb7e53dSJordan K. Hubbard n2 = 0; \ 509efb7e53dSJordan K. Hubbard cp = fmt; \ 510efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 511efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 512efb7e53dSJordan K. Hubbard cp++; \ 513efb7e53dSJordan K. Hubbard } \ 514efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 515efb7e53dSJordan K. Hubbard int hold = nextarg; \ 516efb7e53dSJordan K. Hubbard if (argtable == NULL) { \ 517efb7e53dSJordan K. Hubbard argtable = statargtable; \ 518efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, &argtable); \ 519efb7e53dSJordan K. Hubbard } \ 520efb7e53dSJordan K. Hubbard nextarg = n2; \ 521efb7e53dSJordan K. Hubbard val = GETARG (int); \ 522efb7e53dSJordan K. Hubbard nextarg = hold; \ 523efb7e53dSJordan K. Hubbard fmt = ++cp; \ 524efb7e53dSJordan K. Hubbard } else { \ 525efb7e53dSJordan K. Hubbard val = GETARG (int); \ 526efb7e53dSJordan K. Hubbard } 527efb7e53dSJordan K. Hubbard 52858f0484fSRodney W. Grimes 52998ee7635SAlexey Zelkin thousands_sep = '\0'; 53098ee7635SAlexey Zelkin grouping = NULL; 5312ffc61baSTor Egge #ifdef FLOATING_POINT 5322ffc61baSTor Egge dtoaresult = NULL; 5337735bb0fSBill Fenner decimal_point = localeconv()->decimal_point; 5342ffc61baSTor Egge #endif 53558f0484fSRodney W. Grimes /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 536d201fe46SDaniel Eischen if (cantwrite(fp)) 53758f0484fSRodney W. Grimes return (EOF); 53858f0484fSRodney W. Grimes 53958f0484fSRodney W. Grimes /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 54058f0484fSRodney W. Grimes if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 541d201fe46SDaniel Eischen fp->_file >= 0) 54258f0484fSRodney W. Grimes return (__sbprintf(fp, fmt0, ap)); 54358f0484fSRodney W. Grimes 54458f0484fSRodney W. Grimes fmt = (char *)fmt0; 545efb7e53dSJordan K. Hubbard argtable = NULL; 546efb7e53dSJordan K. Hubbard nextarg = 1; 547efb7e53dSJordan K. Hubbard orgap = ap; 54858f0484fSRodney W. Grimes uio.uio_iov = iovp = iov; 54958f0484fSRodney W. Grimes uio.uio_resid = 0; 55058f0484fSRodney W. Grimes uio.uio_iovcnt = 0; 55158f0484fSRodney W. Grimes ret = 0; 55258f0484fSRodney W. Grimes 55358f0484fSRodney W. Grimes /* 55458f0484fSRodney W. Grimes * Scan the format for conversions (`%' character). 55558f0484fSRodney W. Grimes */ 55658f0484fSRodney W. Grimes for (;;) { 55758f0484fSRodney W. Grimes for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 55858f0484fSRodney W. Grimes /* void */; 55958f0484fSRodney W. Grimes if ((n = fmt - cp) != 0) { 560b250f248SAndrey A. Chernov if ((unsigned)ret + n > INT_MAX) { 56192e88f87SAndrey A. Chernov ret = EOF; 56292e88f87SAndrey A. Chernov goto error; 56392e88f87SAndrey A. Chernov } 56458f0484fSRodney W. Grimes PRINT(cp, n); 56558f0484fSRodney W. Grimes ret += n; 56658f0484fSRodney W. Grimes } 56758f0484fSRodney W. Grimes if (ch == '\0') 56858f0484fSRodney W. Grimes goto done; 56958f0484fSRodney W. Grimes fmt++; /* skip over '%' */ 57058f0484fSRodney W. Grimes 57158f0484fSRodney W. Grimes flags = 0; 57258f0484fSRodney W. Grimes dprec = 0; 57358f0484fSRodney W. Grimes width = 0; 57458f0484fSRodney W. Grimes prec = -1; 57558f0484fSRodney W. Grimes sign = '\0'; 57658f0484fSRodney W. Grimes 57758f0484fSRodney W. Grimes rflag: ch = *fmt++; 57858f0484fSRodney W. Grimes reswitch: switch (ch) { 57958f0484fSRodney W. Grimes case ' ': 58058f0484fSRodney W. Grimes /* 58158f0484fSRodney W. Grimes * ``If the space and + flags both appear, the space 58258f0484fSRodney W. Grimes * flag will be ignored.'' 58358f0484fSRodney W. Grimes * -- ANSI X3J11 58458f0484fSRodney W. Grimes */ 58558f0484fSRodney W. Grimes if (!sign) 58658f0484fSRodney W. Grimes sign = ' '; 58758f0484fSRodney W. Grimes goto rflag; 58858f0484fSRodney W. Grimes case '#': 58958f0484fSRodney W. Grimes flags |= ALT; 59058f0484fSRodney W. Grimes goto rflag; 59158f0484fSRodney W. Grimes case '*': 59258f0484fSRodney W. Grimes /* 59358f0484fSRodney W. Grimes * ``A negative field width argument is taken as a 59458f0484fSRodney W. Grimes * - flag followed by a positive field width.'' 59558f0484fSRodney W. Grimes * -- ANSI X3J11 59658f0484fSRodney W. Grimes * They don't exclude field widths read from args. 59758f0484fSRodney W. Grimes */ 598efb7e53dSJordan K. Hubbard GETASTER (width); 599efb7e53dSJordan K. Hubbard if (width >= 0) 60058f0484fSRodney W. Grimes goto rflag; 60158f0484fSRodney W. Grimes width = -width; 60258f0484fSRodney W. Grimes /* FALLTHROUGH */ 60358f0484fSRodney W. Grimes case '-': 60458f0484fSRodney W. Grimes flags |= LADJUST; 60558f0484fSRodney W. Grimes goto rflag; 60658f0484fSRodney W. Grimes case '+': 60758f0484fSRodney W. Grimes sign = '+'; 60858f0484fSRodney W. Grimes goto rflag; 6097735bb0fSBill Fenner case '\'': 61098ee7635SAlexey Zelkin flags |= GROUPING; 61198ee7635SAlexey Zelkin thousands_sep = *(localeconv()->thousands_sep); 61298ee7635SAlexey Zelkin grouping = localeconv()->grouping; 6137735bb0fSBill Fenner goto rflag; 61458f0484fSRodney W. Grimes case '.': 61558f0484fSRodney W. Grimes if ((ch = *fmt++) == '*') { 616efb7e53dSJordan K. Hubbard GETASTER (n); 61758f0484fSRodney W. Grimes prec = n < 0 ? -1 : n; 61858f0484fSRodney W. Grimes goto rflag; 61958f0484fSRodney W. Grimes } 62058f0484fSRodney W. Grimes n = 0; 62158f0484fSRodney W. Grimes while (is_digit(ch)) { 62258f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 62358f0484fSRodney W. Grimes ch = *fmt++; 62458f0484fSRodney W. Grimes } 62558f0484fSRodney W. Grimes prec = n < 0 ? -1 : n; 62658f0484fSRodney W. Grimes goto reswitch; 62758f0484fSRodney W. Grimes case '0': 62858f0484fSRodney W. Grimes /* 62958f0484fSRodney W. Grimes * ``Note that 0 is taken as a flag, not as the 63058f0484fSRodney W. Grimes * beginning of a field width.'' 63158f0484fSRodney W. Grimes * -- ANSI X3J11 63258f0484fSRodney W. Grimes */ 63358f0484fSRodney W. Grimes flags |= ZEROPAD; 63458f0484fSRodney W. Grimes goto rflag; 63558f0484fSRodney W. Grimes case '1': case '2': case '3': case '4': 63658f0484fSRodney W. Grimes case '5': case '6': case '7': case '8': case '9': 63758f0484fSRodney W. Grimes n = 0; 63858f0484fSRodney W. Grimes do { 63958f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 64058f0484fSRodney W. Grimes ch = *fmt++; 64158f0484fSRodney W. Grimes } while (is_digit(ch)); 642efb7e53dSJordan K. Hubbard if (ch == '$') { 643efb7e53dSJordan K. Hubbard nextarg = n; 644efb7e53dSJordan K. Hubbard if (argtable == NULL) { 645efb7e53dSJordan K. Hubbard argtable = statargtable; 646efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, 647efb7e53dSJordan K. Hubbard &argtable); 648efb7e53dSJordan K. Hubbard } 649efb7e53dSJordan K. Hubbard goto rflag; 650efb7e53dSJordan K. Hubbard } 65158f0484fSRodney W. Grimes width = n; 65258f0484fSRodney W. Grimes goto reswitch; 65358f0484fSRodney W. Grimes #ifdef FLOATING_POINT 65458f0484fSRodney W. Grimes case 'L': 65558f0484fSRodney W. Grimes flags |= LONGDBL; 65658f0484fSRodney W. Grimes goto rflag; 65758f0484fSRodney W. Grimes #endif 65858f0484fSRodney W. Grimes case 'h': 6597735bb0fSBill Fenner if (flags & SHORTINT) { 6607735bb0fSBill Fenner flags &= ~SHORTINT; 6617735bb0fSBill Fenner flags |= CHARINT; 6627735bb0fSBill Fenner } else 66358f0484fSRodney W. Grimes flags |= SHORTINT; 66458f0484fSRodney W. Grimes goto rflag; 6657735bb0fSBill Fenner case 'j': 6667735bb0fSBill Fenner flags |= INTMAXT; 6677735bb0fSBill Fenner goto rflag; 66858f0484fSRodney W. Grimes case 'l': 6697735bb0fSBill Fenner if (flags & LONGINT) { 6707735bb0fSBill Fenner flags &= ~LONGINT; 6717735bb0fSBill Fenner flags |= LLONGINT; 6727735bb0fSBill Fenner } else 67358f0484fSRodney W. Grimes flags |= LONGINT; 67458f0484fSRodney W. Grimes goto rflag; 67558f0484fSRodney W. Grimes case 'q': 6767735bb0fSBill Fenner flags |= LLONGINT; /* not necessarily */ 6777735bb0fSBill Fenner goto rflag; 6787735bb0fSBill Fenner case 't': 6797735bb0fSBill Fenner flags |= PTRDIFFT; 6807735bb0fSBill Fenner goto rflag; 6817735bb0fSBill Fenner case 'z': 6827735bb0fSBill Fenner flags |= SIZET; 68358f0484fSRodney W. Grimes goto rflag; 68458f0484fSRodney W. Grimes case 'c': 685efb7e53dSJordan K. Hubbard *(cp = buf) = GETARG(int); 68658f0484fSRodney W. Grimes size = 1; 68758f0484fSRodney W. Grimes sign = '\0'; 68858f0484fSRodney W. Grimes break; 68958f0484fSRodney W. Grimes case 'D': 69058f0484fSRodney W. Grimes flags |= LONGINT; 69158f0484fSRodney W. Grimes /*FALLTHROUGH*/ 69258f0484fSRodney W. Grimes case 'd': 69358f0484fSRodney W. Grimes case 'i': 6947735bb0fSBill Fenner if (flags & INTMAX_SIZE) { 6957735bb0fSBill Fenner ujval = SJARG(); 6967735bb0fSBill Fenner if ((intmax_t)ujval < 0) { 6977735bb0fSBill Fenner ujval = -ujval; 69858f0484fSRodney W. Grimes sign = '-'; 69958f0484fSRodney W. Grimes } 70058f0484fSRodney W. Grimes } else { 70158f0484fSRodney W. Grimes ulval = SARG(); 70258f0484fSRodney W. Grimes if ((long)ulval < 0) { 70358f0484fSRodney W. Grimes ulval = -ulval; 70458f0484fSRodney W. Grimes sign = '-'; 70558f0484fSRodney W. Grimes } 70658f0484fSRodney W. Grimes } 70758f0484fSRodney W. Grimes base = 10; 70858f0484fSRodney W. Grimes goto number; 70958f0484fSRodney W. Grimes #ifdef FLOATING_POINT 7107735bb0fSBill Fenner #ifdef HEXFLOAT 7117735bb0fSBill Fenner case 'a': 7127735bb0fSBill Fenner case 'A': 7137735bb0fSBill Fenner #endif 714d26be6f0SBruce Evans case 'e': 71558f0484fSRodney W. Grimes case 'E': 71698ee7635SAlexey Zelkin /* 71798ee7635SAlexey Zelkin * Grouping apply to %i, %d, %u, %f, %F, %g, %G 71898ee7635SAlexey Zelkin * conversion specifiers only. For other conversions 71998ee7635SAlexey Zelkin * behavior is undefined. 72098ee7635SAlexey Zelkin * -- POSIX 72198ee7635SAlexey Zelkin */ 72298ee7635SAlexey Zelkin flags &= ~GROUPING; 72398ee7635SAlexey Zelkin /*FALLTHROUGH*/ 724d26be6f0SBruce Evans case 'f': 7257735bb0fSBill Fenner case 'F': 726d26be6f0SBruce Evans goto fp_begin; 72758f0484fSRodney W. Grimes case 'g': 72858f0484fSRodney W. Grimes case 'G': 729d26be6f0SBruce Evans if (prec == 0) 730d26be6f0SBruce Evans prec = 1; 731d26be6f0SBruce Evans fp_begin: if (prec == -1) 73258f0484fSRodney W. Grimes prec = DEFPREC; 733d26be6f0SBruce Evans if (flags & LONGDBL) 7346a93659fSBruce Evans /* XXX this loses precision. */ 735efb7e53dSJordan K. Hubbard _double = (double)GETARG(long double); 736d26be6f0SBruce Evans else 737efb7e53dSJordan K. Hubbard _double = GETARG(double); 73858f0484fSRodney W. Grimes /* do this before tricky precision changes */ 73958f0484fSRodney W. Grimes if (isinf(_double)) { 74058f0484fSRodney W. Grimes if (_double < 0) 74158f0484fSRodney W. Grimes sign = '-'; 7427735bb0fSBill Fenner if (isupper(ch)) 7437735bb0fSBill Fenner cp = "INF"; 7447735bb0fSBill Fenner else 7457735bb0fSBill Fenner cp = "inf"; 74658f0484fSRodney W. Grimes size = 3; 74758f0484fSRodney W. Grimes break; 74858f0484fSRodney W. Grimes } 74958f0484fSRodney W. Grimes if (isnan(_double)) { 7507735bb0fSBill Fenner if (isupper(ch)) 7517735bb0fSBill Fenner cp = "NAN"; 7527735bb0fSBill Fenner else 7537735bb0fSBill Fenner cp = "nan"; 75458f0484fSRodney W. Grimes size = 3; 75558f0484fSRodney W. Grimes break; 75658f0484fSRodney W. Grimes } 75758f0484fSRodney W. Grimes flags |= FPT; 7582ffc61baSTor Egge if (dtoaresult != NULL) { 7592ffc61baSTor Egge free(dtoaresult); 7602ffc61baSTor Egge dtoaresult = NULL; 7612ffc61baSTor Egge } 76258f0484fSRodney W. Grimes cp = cvt(_double, prec, flags, &softsign, 7632ffc61baSTor Egge &expt, ch, &ndig, &dtoaresult); 76458f0484fSRodney W. Grimes if (ch == 'g' || ch == 'G') { 76558f0484fSRodney W. Grimes if (expt <= -4 || expt > prec) 76658f0484fSRodney W. Grimes ch = (ch == 'g') ? 'e' : 'E'; 76758f0484fSRodney W. Grimes else 76858f0484fSRodney W. Grimes ch = 'g'; 76958f0484fSRodney W. Grimes } 7707735bb0fSBill Fenner if (ch == 'e' || ch == 'E') { 77158f0484fSRodney W. Grimes --expt; 77258f0484fSRodney W. Grimes expsize = exponent(expstr, expt, ch); 77358f0484fSRodney W. Grimes size = expsize + ndig; 77458f0484fSRodney W. Grimes if (ndig > 1 || flags & ALT) 77558f0484fSRodney W. Grimes ++size; 7767735bb0fSBill Fenner } else if (ch == 'f' || ch == 'F') { 77758f0484fSRodney W. Grimes if (expt > 0) { 77858f0484fSRodney W. Grimes size = expt; 77958f0484fSRodney W. Grimes if (prec || flags & ALT) 78058f0484fSRodney W. Grimes size += prec + 1; 78158f0484fSRodney W. Grimes } else /* "0.X" */ 78258f0484fSRodney W. Grimes size = prec + 2; 78358f0484fSRodney W. Grimes } else if (expt >= ndig) { /* fixed g fmt */ 78458f0484fSRodney W. Grimes size = expt; 78558f0484fSRodney W. Grimes if (flags & ALT) 78658f0484fSRodney W. Grimes ++size; 78758f0484fSRodney W. Grimes } else 78858f0484fSRodney W. Grimes size = ndig + (expt > 0 ? 78958f0484fSRodney W. Grimes 1 : 2 - expt); 79058f0484fSRodney W. Grimes 79158f0484fSRodney W. Grimes if (softsign) 79258f0484fSRodney W. Grimes sign = '-'; 79358f0484fSRodney W. Grimes break; 79458f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 79558f0484fSRodney W. Grimes case 'n': 7967735bb0fSBill Fenner /* 7977735bb0fSBill Fenner * Assignment-like behavior is specified if the 7987735bb0fSBill Fenner * value overflows or is otherwise unrepresentable. 7997735bb0fSBill Fenner * C99 says to use `signed char' for %hhn conversions. 8007735bb0fSBill Fenner */ 8017735bb0fSBill Fenner if (flags & LLONGINT) 8027735bb0fSBill Fenner *GETARG(long long *) = ret; 8037735bb0fSBill Fenner else if (flags & SIZET) 8047735bb0fSBill Fenner *GETARG(ssize_t *) = (ssize_t)ret; 8057735bb0fSBill Fenner else if (flags & PTRDIFFT) 8067735bb0fSBill Fenner *GETARG(ptrdiff_t *) = ret; 8077735bb0fSBill Fenner else if (flags & INTMAXT) 8087735bb0fSBill Fenner *GETARG(intmax_t *) = ret; 80958f0484fSRodney W. Grimes else if (flags & LONGINT) 8106e690ad4SAndrey A. Chernov *GETARG(long *) = ret; 81158f0484fSRodney W. Grimes else if (flags & SHORTINT) 8126e690ad4SAndrey A. Chernov *GETARG(short *) = ret; 8137735bb0fSBill Fenner else if (flags & CHARINT) 8147735bb0fSBill Fenner *GETARG(signed char *) = ret; 81558f0484fSRodney W. Grimes else 8166e690ad4SAndrey A. Chernov *GETARG(int *) = ret; 81758f0484fSRodney W. Grimes continue; /* no output */ 81858f0484fSRodney W. Grimes case 'O': 81958f0484fSRodney W. Grimes flags |= LONGINT; 82058f0484fSRodney W. Grimes /*FALLTHROUGH*/ 82158f0484fSRodney W. Grimes case 'o': 8227735bb0fSBill Fenner if (flags & INTMAX_SIZE) 8237735bb0fSBill Fenner ujval = UJARG(); 82458f0484fSRodney W. Grimes else 82558f0484fSRodney W. Grimes ulval = UARG(); 82658f0484fSRodney W. Grimes base = 8; 82758f0484fSRodney W. Grimes goto nosign; 82858f0484fSRodney W. Grimes case 'p': 82958f0484fSRodney W. Grimes /* 83058f0484fSRodney W. Grimes * ``The argument shall be a pointer to void. The 83158f0484fSRodney W. Grimes * value of the pointer is converted to a sequence 83258f0484fSRodney W. Grimes * of printable characters, in an implementation- 83358f0484fSRodney W. Grimes * defined manner.'' 83458f0484fSRodney W. Grimes * -- ANSI X3J11 83558f0484fSRodney W. Grimes */ 8367735bb0fSBill Fenner ujval = (uintmax_t)(uintptr_t)GETARG(void *); 83758f0484fSRodney W. Grimes base = 16; 83858f0484fSRodney W. Grimes xdigs = "0123456789abcdef"; 8397735bb0fSBill Fenner flags = flags | INTMAXT | HEXPREFIX; 84058f0484fSRodney W. Grimes ch = 'x'; 84158f0484fSRodney W. Grimes goto nosign; 84258f0484fSRodney W. Grimes case 's': 843efb7e53dSJordan K. Hubbard if ((cp = GETARG(char *)) == NULL) 84458f0484fSRodney W. Grimes cp = "(null)"; 84558f0484fSRodney W. Grimes if (prec >= 0) { 84658f0484fSRodney W. Grimes /* 84758f0484fSRodney W. Grimes * can't use strlen; can only look for the 84858f0484fSRodney W. Grimes * NUL in the first `prec' characters, and 84958f0484fSRodney W. Grimes * strlen() will go further. 85058f0484fSRodney W. Grimes */ 851ce51cf03SJames Raynard char *p = memchr(cp, 0, (size_t)prec); 85258f0484fSRodney W. Grimes 85358f0484fSRodney W. Grimes if (p != NULL) { 85458f0484fSRodney W. Grimes size = p - cp; 85558f0484fSRodney W. Grimes if (size > prec) 85658f0484fSRodney W. Grimes size = prec; 85758f0484fSRodney W. Grimes } else 85858f0484fSRodney W. Grimes size = prec; 85958f0484fSRodney W. Grimes } else 86058f0484fSRodney W. Grimes size = strlen(cp); 86158f0484fSRodney W. Grimes sign = '\0'; 86258f0484fSRodney W. Grimes break; 86358f0484fSRodney W. Grimes case 'U': 86458f0484fSRodney W. Grimes flags |= LONGINT; 86558f0484fSRodney W. Grimes /*FALLTHROUGH*/ 86658f0484fSRodney W. Grimes case 'u': 8677735bb0fSBill Fenner if (flags & INTMAX_SIZE) 8687735bb0fSBill Fenner ujval = UJARG(); 86958f0484fSRodney W. Grimes else 87058f0484fSRodney W. Grimes ulval = UARG(); 87158f0484fSRodney W. Grimes base = 10; 87258f0484fSRodney W. Grimes goto nosign; 87358f0484fSRodney W. Grimes case 'X': 87458f0484fSRodney W. Grimes xdigs = "0123456789ABCDEF"; 87558f0484fSRodney W. Grimes goto hex; 87658f0484fSRodney W. Grimes case 'x': 87758f0484fSRodney W. Grimes xdigs = "0123456789abcdef"; 8787735bb0fSBill Fenner hex: 8797735bb0fSBill Fenner if (flags & INTMAX_SIZE) 8807735bb0fSBill Fenner ujval = UJARG(); 88158f0484fSRodney W. Grimes else 88258f0484fSRodney W. Grimes ulval = UARG(); 88358f0484fSRodney W. Grimes base = 16; 88458f0484fSRodney W. Grimes /* leading 0x/X only if non-zero */ 88558f0484fSRodney W. Grimes if (flags & ALT && 8867735bb0fSBill Fenner (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 88758f0484fSRodney W. Grimes flags |= HEXPREFIX; 88858f0484fSRodney W. Grimes 88998ee7635SAlexey Zelkin flags &= ~GROUPING; 89098ee7635SAlexey Zelkin 89158f0484fSRodney W. Grimes /* unsigned conversions */ 89258f0484fSRodney W. Grimes nosign: sign = '\0'; 89358f0484fSRodney W. Grimes /* 89458f0484fSRodney W. Grimes * ``... diouXx conversions ... if a precision is 89558f0484fSRodney W. Grimes * specified, the 0 flag will be ignored.'' 89658f0484fSRodney W. Grimes * -- ANSI X3J11 89758f0484fSRodney W. Grimes */ 89858f0484fSRodney W. Grimes number: if ((dprec = prec) >= 0) 89958f0484fSRodney W. Grimes flags &= ~ZEROPAD; 90058f0484fSRodney W. Grimes 90158f0484fSRodney W. Grimes /* 90258f0484fSRodney W. Grimes * ``The result of converting a zero value with an 90358f0484fSRodney W. Grimes * explicit precision of zero is no characters.'' 90458f0484fSRodney W. Grimes * -- ANSI X3J11 90558f0484fSRodney W. Grimes */ 90658f0484fSRodney W. Grimes cp = buf + BUF; 9077735bb0fSBill Fenner if (flags & INTMAX_SIZE) { 9087735bb0fSBill Fenner if (ujval != 0 || prec != 0) 9097735bb0fSBill Fenner cp = __ujtoa(ujval, cp, base, 91098ee7635SAlexey Zelkin flags & ALT, xdigs, 91198ee7635SAlexey Zelkin flags & GROUPING, thousands_sep, 91298ee7635SAlexey Zelkin grouping); 91358f0484fSRodney W. Grimes } else { 91458f0484fSRodney W. Grimes if (ulval != 0 || prec != 0) 91558f0484fSRodney W. Grimes cp = __ultoa(ulval, cp, base, 91698ee7635SAlexey Zelkin flags & ALT, xdigs, 91798ee7635SAlexey Zelkin flags & GROUPING, thousands_sep, 91898ee7635SAlexey Zelkin grouping); 91958f0484fSRodney W. Grimes } 92058f0484fSRodney W. Grimes size = buf + BUF - cp; 92158f0484fSRodney W. Grimes break; 92258f0484fSRodney W. Grimes default: /* "%?" prints ?, unless ? is NUL */ 92358f0484fSRodney W. Grimes if (ch == '\0') 92458f0484fSRodney W. Grimes goto done; 92558f0484fSRodney W. Grimes /* pretend it was %c with argument ch */ 92658f0484fSRodney W. Grimes cp = buf; 92758f0484fSRodney W. Grimes *cp = ch; 92858f0484fSRodney W. Grimes size = 1; 92958f0484fSRodney W. Grimes sign = '\0'; 93058f0484fSRodney W. Grimes break; 93158f0484fSRodney W. Grimes } 93258f0484fSRodney W. Grimes 93358f0484fSRodney W. Grimes /* 93458f0484fSRodney W. Grimes * All reasonable formats wind up here. At this point, `cp' 93558f0484fSRodney W. Grimes * points to a string which (if not flags&LADJUST) should be 93658f0484fSRodney W. Grimes * padded out to `width' places. If flags&ZEROPAD, it should 93758f0484fSRodney W. Grimes * first be prefixed by any sign or other prefix; otherwise, 93858f0484fSRodney W. Grimes * it should be blank padded before the prefix is emitted. 93958f0484fSRodney W. Grimes * After any left-hand padding and prefixing, emit zeroes 94058f0484fSRodney W. Grimes * required by a decimal [diouxX] precision, then print the 94158f0484fSRodney W. Grimes * string proper, then emit zeroes required by any leftover 94258f0484fSRodney W. Grimes * floating precision; finally, if LADJUST, pad with blanks. 94358f0484fSRodney W. Grimes * 94458f0484fSRodney W. Grimes * Compute actual size, so we know how much to pad. 945261a532aSBill Fenner * size excludes decimal prec; realsz includes it. 94658f0484fSRodney W. Grimes */ 947261a532aSBill Fenner realsz = dprec > size ? dprec : size; 94858f0484fSRodney W. Grimes if (sign) 949261a532aSBill Fenner realsz++; 95058f0484fSRodney W. Grimes else if (flags & HEXPREFIX) 951261a532aSBill Fenner realsz += 2; 95258f0484fSRodney W. Grimes 95392e88f87SAndrey A. Chernov prsize = width > realsz ? width : realsz; 954b250f248SAndrey A. Chernov if ((unsigned)ret + prsize > INT_MAX) { 95592e88f87SAndrey A. Chernov ret = EOF; 95692e88f87SAndrey A. Chernov goto error; 95792e88f87SAndrey A. Chernov } 95892e88f87SAndrey A. Chernov 95958f0484fSRodney W. Grimes /* right-adjusting blank padding */ 96058f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == 0) 96158f0484fSRodney W. Grimes PAD(width - realsz, blanks); 96258f0484fSRodney W. Grimes 96358f0484fSRodney W. Grimes /* prefix */ 96458f0484fSRodney W. Grimes if (sign) { 96558f0484fSRodney W. Grimes PRINT(&sign, 1); 96658f0484fSRodney W. Grimes } else if (flags & HEXPREFIX) { 96758f0484fSRodney W. Grimes ox[0] = '0'; 96858f0484fSRodney W. Grimes ox[1] = ch; 96958f0484fSRodney W. Grimes PRINT(ox, 2); 97058f0484fSRodney W. Grimes } 97158f0484fSRodney W. Grimes 97258f0484fSRodney W. Grimes /* right-adjusting zero padding */ 97358f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 97458f0484fSRodney W. Grimes PAD(width - realsz, zeroes); 97558f0484fSRodney W. Grimes 97658f0484fSRodney W. Grimes /* leading zeroes from decimal precision */ 977261a532aSBill Fenner PAD(dprec - size, zeroes); 97858f0484fSRodney W. Grimes 97958f0484fSRodney W. Grimes /* the string or number proper */ 98058f0484fSRodney W. Grimes #ifdef FLOATING_POINT 98158f0484fSRodney W. Grimes if ((flags & FPT) == 0) { 98258f0484fSRodney W. Grimes PRINT(cp, size); 98358f0484fSRodney W. Grimes } else { /* glue together f_p fragments */ 98458f0484fSRodney W. Grimes if (ch >= 'f') { /* 'f' or 'g' */ 98558f0484fSRodney W. Grimes if (_double == 0) { 98658f0484fSRodney W. Grimes /* kludge for __dtoa irregularity */ 98758f0484fSRodney W. Grimes PRINT("0", 1); 9889ad80ab5SAndrey A. Chernov if (expt < ndig || (flags & ALT) != 0) { 9899ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 99058f0484fSRodney W. Grimes PAD(ndig - 1, zeroes); 99158f0484fSRodney W. Grimes } 99258f0484fSRodney W. Grimes } else if (expt <= 0) { 9939ad80ab5SAndrey A. Chernov PRINT("0", 1); 9949ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 99558f0484fSRodney W. Grimes PAD(-expt, zeroes); 99658f0484fSRodney W. Grimes PRINT(cp, ndig); 99758f0484fSRodney W. Grimes } else if (expt >= ndig) { 99858f0484fSRodney W. Grimes PRINT(cp, ndig); 99958f0484fSRodney W. Grimes PAD(expt - ndig, zeroes); 100058f0484fSRodney W. Grimes if (flags & ALT) 10019ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 100258f0484fSRodney W. Grimes } else { 100358f0484fSRodney W. Grimes PRINT(cp, expt); 100458f0484fSRodney W. Grimes cp += expt; 10059ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 100658f0484fSRodney W. Grimes PRINT(cp, ndig-expt); 100758f0484fSRodney W. Grimes } 100858f0484fSRodney W. Grimes } else { /* 'e' or 'E' */ 100958f0484fSRodney W. Grimes if (ndig > 1 || flags & ALT) { 101058f0484fSRodney W. Grimes ox[0] = *cp++; 10119ad80ab5SAndrey A. Chernov ox[1] = *decimal_point; 101258f0484fSRodney W. Grimes PRINT(ox, 2); 1013918bed75SBruce Evans if (_double) { 101458f0484fSRodney W. Grimes PRINT(cp, ndig-1); 101558f0484fSRodney W. Grimes } else /* 0.[0..] */ 101658f0484fSRodney W. Grimes /* __dtoa irregularity */ 101758f0484fSRodney W. Grimes PAD(ndig - 1, zeroes); 101858f0484fSRodney W. Grimes } else /* XeYYY */ 101958f0484fSRodney W. Grimes PRINT(cp, 1); 102058f0484fSRodney W. Grimes PRINT(expstr, expsize); 102158f0484fSRodney W. Grimes } 102258f0484fSRodney W. Grimes } 102358f0484fSRodney W. Grimes #else 102458f0484fSRodney W. Grimes PRINT(cp, size); 102558f0484fSRodney W. Grimes #endif 102658f0484fSRodney W. Grimes /* left-adjusting padding (always blank) */ 102758f0484fSRodney W. Grimes if (flags & LADJUST) 102858f0484fSRodney W. Grimes PAD(width - realsz, blanks); 102958f0484fSRodney W. Grimes 103058f0484fSRodney W. Grimes /* finally, adjust ret */ 103192e88f87SAndrey A. Chernov ret += prsize; 103258f0484fSRodney W. Grimes 103358f0484fSRodney W. Grimes FLUSH(); /* copy out the I/O vectors */ 103458f0484fSRodney W. Grimes } 103558f0484fSRodney W. Grimes done: 103658f0484fSRodney W. Grimes FLUSH(); 103758f0484fSRodney W. Grimes error: 10382ffc61baSTor Egge #ifdef FLOATING_POINT 10392ffc61baSTor Egge if (dtoaresult != NULL) 10402ffc61baSTor Egge free(dtoaresult); 10412ffc61baSTor Egge #endif 1042f70177e7SJulian Elischer if (__sferror(fp)) 1043f70177e7SJulian Elischer ret = EOF; 1044efb7e53dSJordan K. Hubbard if ((argtable != NULL) && (argtable != statargtable)) 1045efb7e53dSJordan K. Hubbard free (argtable); 1046f70177e7SJulian Elischer return (ret); 104758f0484fSRodney W. Grimes /* NOTREACHED */ 104858f0484fSRodney W. Grimes } 104958f0484fSRodney W. Grimes 1050efb7e53dSJordan K. Hubbard /* 1051efb7e53dSJordan K. Hubbard * Find all arguments when a positional parameter is encountered. Returns a 1052efb7e53dSJordan K. Hubbard * table, indexed by argument number, of pointers to each arguments. The 1053efb7e53dSJordan K. Hubbard * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 105442cebaa5SArchie Cobbs * It will be replaces with a malloc-ed one if it overflows. 1055efb7e53dSJordan K. Hubbard */ 1056efb7e53dSJordan K. Hubbard static void 1057a387081cSDoug Rabson __find_arguments (const char *fmt0, va_list ap, union arg **argtable) 1058efb7e53dSJordan K. Hubbard { 1059d201fe46SDaniel Eischen char *fmt; /* format string */ 1060d201fe46SDaniel Eischen int ch; /* character from fmt */ 1061d201fe46SDaniel Eischen int n, n2; /* handy integer (short term usage) */ 1062d201fe46SDaniel Eischen char *cp; /* handy char pointer (short term usage) */ 1063d201fe46SDaniel Eischen int flags; /* flags as above */ 1064efb7e53dSJordan K. Hubbard int width; /* width from format (%8d), or 0 */ 10657735bb0fSBill Fenner enum typeid *typetable; /* table of types */ 10667735bb0fSBill Fenner enum typeid stattypetable [STATIC_ARG_TBL_SIZE]; 1067efb7e53dSJordan K. Hubbard int tablesize; /* current size of type table */ 1068efb7e53dSJordan K. Hubbard int tablemax; /* largest used index in table */ 1069efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 1070efb7e53dSJordan K. Hubbard 1071efb7e53dSJordan K. Hubbard /* 1072efb7e53dSJordan K. Hubbard * Add an argument type to the table, expanding if necessary. 1073efb7e53dSJordan K. Hubbard */ 1074efb7e53dSJordan K. Hubbard #define ADDTYPE(type) \ 1075efb7e53dSJordan K. Hubbard ((nextarg >= tablesize) ? \ 1076efb7e53dSJordan K. Hubbard __grow_type_table(nextarg, &typetable, &tablesize) : 0, \ 107742cebaa5SArchie Cobbs (nextarg > tablemax) ? tablemax = nextarg : 0, \ 107842cebaa5SArchie Cobbs typetable[nextarg++] = type) 1079efb7e53dSJordan K. Hubbard 1080efb7e53dSJordan K. Hubbard #define ADDSARG() \ 10817735bb0fSBill Fenner ((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \ 10827735bb0fSBill Fenner ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 10837735bb0fSBill Fenner ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 10847735bb0fSBill Fenner ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \ 10857735bb0fSBill Fenner ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT)))))) 1086efb7e53dSJordan K. Hubbard 1087efb7e53dSJordan K. Hubbard #define ADDUARG() \ 10887735bb0fSBill Fenner ((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \ 10897735bb0fSBill Fenner ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 10907735bb0fSBill Fenner ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 10917735bb0fSBill Fenner ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \ 10927735bb0fSBill Fenner ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT)))))) 1093efb7e53dSJordan K. Hubbard 1094efb7e53dSJordan K. Hubbard /* 1095efb7e53dSJordan K. Hubbard * Add * arguments to the type array. 1096efb7e53dSJordan K. Hubbard */ 1097efb7e53dSJordan K. Hubbard #define ADDASTER() \ 1098efb7e53dSJordan K. Hubbard n2 = 0; \ 1099efb7e53dSJordan K. Hubbard cp = fmt; \ 1100efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 1101efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 1102efb7e53dSJordan K. Hubbard cp++; \ 1103efb7e53dSJordan K. Hubbard } \ 1104efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 1105efb7e53dSJordan K. Hubbard int hold = nextarg; \ 1106efb7e53dSJordan K. Hubbard nextarg = n2; \ 1107efb7e53dSJordan K. Hubbard ADDTYPE (T_INT); \ 1108efb7e53dSJordan K. Hubbard nextarg = hold; \ 1109efb7e53dSJordan K. Hubbard fmt = ++cp; \ 1110efb7e53dSJordan K. Hubbard } else { \ 1111efb7e53dSJordan K. Hubbard ADDTYPE (T_INT); \ 1112efb7e53dSJordan K. Hubbard } 1113efb7e53dSJordan K. Hubbard fmt = (char *)fmt0; 1114efb7e53dSJordan K. Hubbard typetable = stattypetable; 1115efb7e53dSJordan K. Hubbard tablesize = STATIC_ARG_TBL_SIZE; 1116efb7e53dSJordan K. Hubbard tablemax = 0; 1117efb7e53dSJordan K. Hubbard nextarg = 1; 1118efb7e53dSJordan K. Hubbard memset (typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); 1119efb7e53dSJordan K. Hubbard 1120efb7e53dSJordan K. Hubbard /* 1121efb7e53dSJordan K. Hubbard * Scan the format for conversions (`%' character). 1122efb7e53dSJordan K. Hubbard */ 1123efb7e53dSJordan K. Hubbard for (;;) { 1124efb7e53dSJordan K. Hubbard for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 1125efb7e53dSJordan K. Hubbard /* void */; 1126efb7e53dSJordan K. Hubbard if (ch == '\0') 1127efb7e53dSJordan K. Hubbard goto done; 1128efb7e53dSJordan K. Hubbard fmt++; /* skip over '%' */ 1129efb7e53dSJordan K. Hubbard 1130efb7e53dSJordan K. Hubbard flags = 0; 1131efb7e53dSJordan K. Hubbard width = 0; 1132efb7e53dSJordan K. Hubbard 1133efb7e53dSJordan K. Hubbard rflag: ch = *fmt++; 1134efb7e53dSJordan K. Hubbard reswitch: switch (ch) { 1135efb7e53dSJordan K. Hubbard case ' ': 1136efb7e53dSJordan K. Hubbard case '#': 1137efb7e53dSJordan K. Hubbard goto rflag; 1138efb7e53dSJordan K. Hubbard case '*': 1139efb7e53dSJordan K. Hubbard ADDASTER (); 1140efb7e53dSJordan K. Hubbard goto rflag; 1141efb7e53dSJordan K. Hubbard case '-': 1142efb7e53dSJordan K. Hubbard case '+': 11437735bb0fSBill Fenner case '\'': 1144efb7e53dSJordan K. Hubbard goto rflag; 1145efb7e53dSJordan K. Hubbard case '.': 1146efb7e53dSJordan K. Hubbard if ((ch = *fmt++) == '*') { 1147efb7e53dSJordan K. Hubbard ADDASTER (); 1148efb7e53dSJordan K. Hubbard goto rflag; 1149efb7e53dSJordan K. Hubbard } 1150efb7e53dSJordan K. Hubbard while (is_digit(ch)) { 1151efb7e53dSJordan K. Hubbard ch = *fmt++; 1152efb7e53dSJordan K. Hubbard } 1153efb7e53dSJordan K. Hubbard goto reswitch; 1154efb7e53dSJordan K. Hubbard case '0': 1155efb7e53dSJordan K. Hubbard goto rflag; 1156efb7e53dSJordan K. Hubbard case '1': case '2': case '3': case '4': 1157efb7e53dSJordan K. Hubbard case '5': case '6': case '7': case '8': case '9': 1158efb7e53dSJordan K. Hubbard n = 0; 1159efb7e53dSJordan K. Hubbard do { 1160efb7e53dSJordan K. Hubbard n = 10 * n + to_digit(ch); 1161efb7e53dSJordan K. Hubbard ch = *fmt++; 1162efb7e53dSJordan K. Hubbard } while (is_digit(ch)); 1163efb7e53dSJordan K. Hubbard if (ch == '$') { 1164efb7e53dSJordan K. Hubbard nextarg = n; 1165efb7e53dSJordan K. Hubbard goto rflag; 1166efb7e53dSJordan K. Hubbard } 1167efb7e53dSJordan K. Hubbard width = n; 1168efb7e53dSJordan K. Hubbard goto reswitch; 1169efb7e53dSJordan K. Hubbard #ifdef FLOATING_POINT 1170efb7e53dSJordan K. Hubbard case 'L': 1171efb7e53dSJordan K. Hubbard flags |= LONGDBL; 1172efb7e53dSJordan K. Hubbard goto rflag; 1173efb7e53dSJordan K. Hubbard #endif 1174efb7e53dSJordan K. Hubbard case 'h': 11757735bb0fSBill Fenner if (flags & SHORTINT) { 11767735bb0fSBill Fenner flags &= ~SHORTINT; 11777735bb0fSBill Fenner flags |= CHARINT; 11787735bb0fSBill Fenner } else 1179efb7e53dSJordan K. Hubbard flags |= SHORTINT; 1180efb7e53dSJordan K. Hubbard goto rflag; 11817735bb0fSBill Fenner case 'j': 11827735bb0fSBill Fenner flags |= INTMAXT; 11837735bb0fSBill Fenner goto rflag; 1184efb7e53dSJordan K. Hubbard case 'l': 11857735bb0fSBill Fenner if (flags & LONGINT) { 11867735bb0fSBill Fenner flags &= ~LONGINT; 11877735bb0fSBill Fenner flags |= LLONGINT; 11887735bb0fSBill Fenner } else 1189efb7e53dSJordan K. Hubbard flags |= LONGINT; 1190efb7e53dSJordan K. Hubbard goto rflag; 1191efb7e53dSJordan K. Hubbard case 'q': 11927735bb0fSBill Fenner flags |= LLONGINT; /* not necessarily */ 11937735bb0fSBill Fenner goto rflag; 11947735bb0fSBill Fenner case 't': 11957735bb0fSBill Fenner flags |= PTRDIFFT; 11967735bb0fSBill Fenner goto rflag; 11977735bb0fSBill Fenner case 'z': 11987735bb0fSBill Fenner flags |= SIZET; 1199efb7e53dSJordan K. Hubbard goto rflag; 1200efb7e53dSJordan K. Hubbard case 'c': 1201efb7e53dSJordan K. Hubbard ADDTYPE(T_INT); 1202efb7e53dSJordan K. Hubbard break; 1203efb7e53dSJordan K. Hubbard case 'D': 1204efb7e53dSJordan K. Hubbard flags |= LONGINT; 1205efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1206efb7e53dSJordan K. Hubbard case 'd': 1207efb7e53dSJordan K. Hubbard case 'i': 1208efb7e53dSJordan K. Hubbard ADDSARG(); 1209efb7e53dSJordan K. Hubbard break; 1210efb7e53dSJordan K. Hubbard #ifdef FLOATING_POINT 12117735bb0fSBill Fenner #ifdef HEXFLOAT 12127735bb0fSBill Fenner case 'a': 12137735bb0fSBill Fenner case 'A': 12147735bb0fSBill Fenner #endif 1215efb7e53dSJordan K. Hubbard case 'e': 1216efb7e53dSJordan K. Hubbard case 'E': 1217efb7e53dSJordan K. Hubbard case 'f': 1218efb7e53dSJordan K. Hubbard case 'g': 1219efb7e53dSJordan K. Hubbard case 'G': 1220efb7e53dSJordan K. Hubbard if (flags & LONGDBL) 1221efb7e53dSJordan K. Hubbard ADDTYPE(T_LONG_DOUBLE); 1222efb7e53dSJordan K. Hubbard else 1223efb7e53dSJordan K. Hubbard ADDTYPE(T_DOUBLE); 1224efb7e53dSJordan K. Hubbard break; 1225efb7e53dSJordan K. Hubbard #endif /* FLOATING_POINT */ 1226efb7e53dSJordan K. Hubbard case 'n': 12277735bb0fSBill Fenner if (flags & INTMAXT) 12287735bb0fSBill Fenner ADDTYPE(TP_INTMAXT); 12297735bb0fSBill Fenner else if (flags & PTRDIFFT) 12307735bb0fSBill Fenner ADDTYPE(TP_PTRDIFFT); 12317735bb0fSBill Fenner else if (flags & SIZET) 12327735bb0fSBill Fenner ADDTYPE(TP_SIZET); 12337735bb0fSBill Fenner else if (flags & LLONGINT) 12347735bb0fSBill Fenner ADDTYPE(TP_LLONG); 1235efb7e53dSJordan K. Hubbard else if (flags & LONGINT) 1236efb7e53dSJordan K. Hubbard ADDTYPE(TP_LONG); 1237efb7e53dSJordan K. Hubbard else if (flags & SHORTINT) 1238efb7e53dSJordan K. Hubbard ADDTYPE(TP_SHORT); 12397735bb0fSBill Fenner else if (flags & CHARINT) 12407735bb0fSBill Fenner ADDTYPE(TP_SCHAR); 1241efb7e53dSJordan K. Hubbard else 1242efb7e53dSJordan K. Hubbard ADDTYPE(TP_INT); 1243efb7e53dSJordan K. Hubbard continue; /* no output */ 1244efb7e53dSJordan K. Hubbard case 'O': 1245efb7e53dSJordan K. Hubbard flags |= LONGINT; 1246efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1247efb7e53dSJordan K. Hubbard case 'o': 1248efb7e53dSJordan K. Hubbard ADDUARG(); 1249efb7e53dSJordan K. Hubbard break; 1250efb7e53dSJordan K. Hubbard case 'p': 1251efb7e53dSJordan K. Hubbard ADDTYPE(TP_VOID); 1252efb7e53dSJordan K. Hubbard break; 1253efb7e53dSJordan K. Hubbard case 's': 1254efb7e53dSJordan K. Hubbard ADDTYPE(TP_CHAR); 1255efb7e53dSJordan K. Hubbard break; 1256efb7e53dSJordan K. Hubbard case 'U': 1257efb7e53dSJordan K. Hubbard flags |= LONGINT; 1258efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1259efb7e53dSJordan K. Hubbard case 'u': 1260efb7e53dSJordan K. Hubbard case 'X': 1261efb7e53dSJordan K. Hubbard case 'x': 1262efb7e53dSJordan K. Hubbard ADDUARG(); 1263efb7e53dSJordan K. Hubbard break; 1264efb7e53dSJordan K. Hubbard default: /* "%?" prints ?, unless ? is NUL */ 1265efb7e53dSJordan K. Hubbard if (ch == '\0') 1266efb7e53dSJordan K. Hubbard goto done; 1267efb7e53dSJordan K. Hubbard break; 1268efb7e53dSJordan K. Hubbard } 1269efb7e53dSJordan K. Hubbard } 1270efb7e53dSJordan K. Hubbard done: 1271efb7e53dSJordan K. Hubbard /* 1272efb7e53dSJordan K. Hubbard * Build the argument table. 1273efb7e53dSJordan K. Hubbard */ 1274efb7e53dSJordan K. Hubbard if (tablemax >= STATIC_ARG_TBL_SIZE) { 1275a387081cSDoug Rabson *argtable = (union arg *) 1276a387081cSDoug Rabson malloc (sizeof (union arg) * (tablemax + 1)); 1277efb7e53dSJordan K. Hubbard } 1278efb7e53dSJordan K. Hubbard 1279a387081cSDoug Rabson (*argtable) [0].intarg = 0; 1280efb7e53dSJordan K. Hubbard for (n = 1; n <= tablemax; n++) { 1281efb7e53dSJordan K. Hubbard switch (typetable [n]) { 12827735bb0fSBill Fenner case T_UNUSED: /* whoops! */ 1283a387081cSDoug Rabson (*argtable) [n].intarg = va_arg (ap, int); 1284efb7e53dSJordan K. Hubbard break; 12857735bb0fSBill Fenner case TP_SCHAR: 12867735bb0fSBill Fenner (*argtable) [n].pschararg = va_arg (ap, signed char *); 1287efb7e53dSJordan K. Hubbard break; 1288efb7e53dSJordan K. Hubbard case TP_SHORT: 1289a387081cSDoug Rabson (*argtable) [n].pshortarg = va_arg (ap, short *); 1290efb7e53dSJordan K. Hubbard break; 1291efb7e53dSJordan K. Hubbard case T_INT: 1292a387081cSDoug Rabson (*argtable) [n].intarg = va_arg (ap, int); 1293efb7e53dSJordan K. Hubbard break; 1294efb7e53dSJordan K. Hubbard case T_U_INT: 1295a387081cSDoug Rabson (*argtable) [n].uintarg = va_arg (ap, unsigned int); 1296efb7e53dSJordan K. Hubbard break; 1297efb7e53dSJordan K. Hubbard case TP_INT: 1298a387081cSDoug Rabson (*argtable) [n].pintarg = va_arg (ap, int *); 1299efb7e53dSJordan K. Hubbard break; 1300efb7e53dSJordan K. Hubbard case T_LONG: 1301a387081cSDoug Rabson (*argtable) [n].longarg = va_arg (ap, long); 1302efb7e53dSJordan K. Hubbard break; 1303efb7e53dSJordan K. Hubbard case T_U_LONG: 1304a387081cSDoug Rabson (*argtable) [n].ulongarg = va_arg (ap, unsigned long); 1305efb7e53dSJordan K. Hubbard break; 1306efb7e53dSJordan K. Hubbard case TP_LONG: 1307a387081cSDoug Rabson (*argtable) [n].plongarg = va_arg (ap, long *); 1308efb7e53dSJordan K. Hubbard break; 13097735bb0fSBill Fenner case T_LLONG: 13107735bb0fSBill Fenner (*argtable) [n].longlongarg = va_arg (ap, long long); 1311efb7e53dSJordan K. Hubbard break; 13127735bb0fSBill Fenner case T_U_LLONG: 13137735bb0fSBill Fenner (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); 1314efb7e53dSJordan K. Hubbard break; 13157735bb0fSBill Fenner case TP_LLONG: 13167735bb0fSBill Fenner (*argtable) [n].plonglongarg = va_arg (ap, long long *); 13177735bb0fSBill Fenner break; 13187735bb0fSBill Fenner case T_PTRDIFFT: 13197735bb0fSBill Fenner (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); 13207735bb0fSBill Fenner break; 13217735bb0fSBill Fenner case TP_PTRDIFFT: 13227735bb0fSBill Fenner (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); 13237735bb0fSBill Fenner break; 13247735bb0fSBill Fenner case T_SIZET: 13257735bb0fSBill Fenner (*argtable) [n].sizearg = va_arg (ap, size_t); 13267735bb0fSBill Fenner break; 13277735bb0fSBill Fenner case TP_SIZET: 13287735bb0fSBill Fenner (*argtable) [n].psizearg = va_arg (ap, ssize_t *); 13297735bb0fSBill Fenner break; 13307735bb0fSBill Fenner case T_INTMAXT: 13317735bb0fSBill Fenner (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); 13327735bb0fSBill Fenner break; 13337735bb0fSBill Fenner case T_UINTMAXT: 13347735bb0fSBill Fenner (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); 13357735bb0fSBill Fenner break; 13367735bb0fSBill Fenner case TP_INTMAXT: 13377735bb0fSBill Fenner (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); 1338efb7e53dSJordan K. Hubbard break; 1339a387081cSDoug Rabson #ifdef FLOATING_POINT 1340efb7e53dSJordan K. Hubbard case T_DOUBLE: 1341a387081cSDoug Rabson (*argtable) [n].doublearg = va_arg (ap, double); 1342efb7e53dSJordan K. Hubbard break; 1343efb7e53dSJordan K. Hubbard case T_LONG_DOUBLE: 1344a387081cSDoug Rabson (*argtable) [n].longdoublearg = va_arg (ap, long double); 1345efb7e53dSJordan K. Hubbard break; 1346a387081cSDoug Rabson #endif 1347efb7e53dSJordan K. Hubbard case TP_CHAR: 1348a387081cSDoug Rabson (*argtable) [n].pchararg = va_arg (ap, char *); 1349efb7e53dSJordan K. Hubbard break; 1350efb7e53dSJordan K. Hubbard case TP_VOID: 1351a387081cSDoug Rabson (*argtable) [n].pvoidarg = va_arg (ap, void *); 1352efb7e53dSJordan K. Hubbard break; 1353efb7e53dSJordan K. Hubbard } 1354efb7e53dSJordan K. Hubbard } 1355efb7e53dSJordan K. Hubbard 1356efb7e53dSJordan K. Hubbard if ((typetable != NULL) && (typetable != stattypetable)) 1357efb7e53dSJordan K. Hubbard free (typetable); 1358efb7e53dSJordan K. Hubbard } 1359efb7e53dSJordan K. Hubbard 1360efb7e53dSJordan K. Hubbard /* 1361efb7e53dSJordan K. Hubbard * Increase the size of the type table. 1362efb7e53dSJordan K. Hubbard */ 1363efb7e53dSJordan K. Hubbard static void 13647735bb0fSBill Fenner __grow_type_table (int nextarg, enum typeid **typetable, int *tablesize) 1365efb7e53dSJordan K. Hubbard { 13667735bb0fSBill Fenner enum typeid *const oldtable = *typetable; 136742cebaa5SArchie Cobbs const int oldsize = *tablesize; 13687735bb0fSBill Fenner enum typeid *newtable; 136942cebaa5SArchie Cobbs int newsize = oldsize * 2; 1370efb7e53dSJordan K. Hubbard 137142cebaa5SArchie Cobbs if (newsize < nextarg + 1) 137242cebaa5SArchie Cobbs newsize = nextarg + 1; 137342cebaa5SArchie Cobbs if (oldsize == STATIC_ARG_TBL_SIZE) { 137442cebaa5SArchie Cobbs if ((newtable = malloc(newsize)) == NULL) 137542cebaa5SArchie Cobbs abort(); /* XXX handle better */ 137642cebaa5SArchie Cobbs bcopy(oldtable, newtable, oldsize); 1377efb7e53dSJordan K. Hubbard } else { 137842cebaa5SArchie Cobbs if ((newtable = reallocf(oldtable, newsize)) == NULL) 137942cebaa5SArchie Cobbs abort(); /* XXX handle better */ 1380efb7e53dSJordan K. Hubbard } 138142cebaa5SArchie Cobbs memset(&newtable[oldsize], T_UNUSED, newsize - oldsize); 1382efb7e53dSJordan K. Hubbard 138342cebaa5SArchie Cobbs *typetable = newtable; 1384efb7e53dSJordan K. Hubbard *tablesize = newsize; 1385efb7e53dSJordan K. Hubbard } 1386efb7e53dSJordan K. Hubbard 1387efb7e53dSJordan K. Hubbard 138858f0484fSRodney W. Grimes #ifdef FLOATING_POINT 138958f0484fSRodney W. Grimes 13902ffc61baSTor Egge extern char *__dtoa __P((double, int, int, int *, int *, char **, char **)); 139158f0484fSRodney W. Grimes 139258f0484fSRodney W. Grimes static char * 1393d201fe46SDaniel Eischen cvt(double value, int ndigits, int flags, char *sign, int *decpt, 13942ffc61baSTor Egge int ch, int *length, char **dtoaresultp) 139558f0484fSRodney W. Grimes { 139658f0484fSRodney W. Grimes int mode, dsgn; 139758f0484fSRodney W. Grimes char *digits, *bp, *rve; 139858f0484fSRodney W. Grimes 139958f0484fSRodney W. Grimes if (ch == 'f') 1400d26be6f0SBruce Evans mode = 3; /* ndigits after the decimal point */ 140158f0484fSRodney W. Grimes else { 1402d26be6f0SBruce Evans /* 1403d26be6f0SBruce Evans * To obtain ndigits after the decimal point for the 'e' 1404d26be6f0SBruce Evans * and 'E' formats, round to ndigits + 1 significant 1405d26be6f0SBruce Evans * figures. 1406d26be6f0SBruce Evans */ 1407d26be6f0SBruce Evans if (ch == 'e' || ch == 'E') 1408d26be6f0SBruce Evans ndigits++; 1409d26be6f0SBruce Evans mode = 2; /* ndigits significant digits */ 141058f0484fSRodney W. Grimes } 141158f0484fSRodney W. Grimes if (value < 0) { 141258f0484fSRodney W. Grimes value = -value; 141358f0484fSRodney W. Grimes *sign = '-'; 141458f0484fSRodney W. Grimes } else 141558f0484fSRodney W. Grimes *sign = '\000'; 14162ffc61baSTor Egge digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve, 14172ffc61baSTor Egge dtoaresultp); 1418d26be6f0SBruce Evans if ((ch != 'g' && ch != 'G') || flags & ALT) { 1419d26be6f0SBruce Evans /* print trailing zeros */ 142058f0484fSRodney W. Grimes bp = digits + ndigits; 142158f0484fSRodney W. Grimes if (ch == 'f') { 142258f0484fSRodney W. Grimes if (*digits == '0' && value) 142358f0484fSRodney W. Grimes *decpt = -ndigits + 1; 142458f0484fSRodney W. Grimes bp += *decpt; 142558f0484fSRodney W. Grimes } 142658f0484fSRodney W. Grimes if (value == 0) /* kludge for __dtoa irregularity */ 142758f0484fSRodney W. Grimes rve = bp; 142858f0484fSRodney W. Grimes while (rve < bp) 142958f0484fSRodney W. Grimes *rve++ = '0'; 143058f0484fSRodney W. Grimes } 143158f0484fSRodney W. Grimes *length = rve - digits; 143258f0484fSRodney W. Grimes return (digits); 143358f0484fSRodney W. Grimes } 143458f0484fSRodney W. Grimes 143558f0484fSRodney W. Grimes static int 1436d201fe46SDaniel Eischen exponent(char *p0, int exp, int fmtch) 143758f0484fSRodney W. Grimes { 1438d201fe46SDaniel Eischen char *p, *t; 143958f0484fSRodney W. Grimes char expbuf[MAXEXP]; 144058f0484fSRodney W. Grimes 144158f0484fSRodney W. Grimes p = p0; 144258f0484fSRodney W. Grimes *p++ = fmtch; 144358f0484fSRodney W. Grimes if (exp < 0) { 144458f0484fSRodney W. Grimes exp = -exp; 144558f0484fSRodney W. Grimes *p++ = '-'; 144658f0484fSRodney W. Grimes } 144758f0484fSRodney W. Grimes else 144858f0484fSRodney W. Grimes *p++ = '+'; 144958f0484fSRodney W. Grimes t = expbuf + MAXEXP; 145058f0484fSRodney W. Grimes if (exp > 9) { 145158f0484fSRodney W. Grimes do { 145258f0484fSRodney W. Grimes *--t = to_char(exp % 10); 145358f0484fSRodney W. Grimes } while ((exp /= 10) > 9); 145458f0484fSRodney W. Grimes *--t = to_char(exp); 145558f0484fSRodney W. Grimes for (; t < expbuf + MAXEXP; *p++ = *t++); 145658f0484fSRodney W. Grimes } 145758f0484fSRodney W. Grimes else { 145858f0484fSRodney W. Grimes *p++ = '0'; 145958f0484fSRodney W. Grimes *p++ = to_char(exp); 146058f0484fSRodney W. Grimes } 146158f0484fSRodney W. Grimes return (p - p0); 146258f0484fSRodney W. Grimes } 146358f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 1464