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); 1172e394b2fSAlexey Zelkin static char *__ujtoa __P((uintmax_t, char *, int, int, char *, int, 1182e394b2fSAlexey Zelkin char, const char *)); 1192e394b2fSAlexey Zelkin static char *__ultoa __P((u_long, char *, int, int, char *, int, 1202e394b2fSAlexey Zelkin char, const char *)); 121a387081cSDoug Rabson static void __find_arguments __P((const char *, va_list, union arg **)); 1227735bb0fSBill Fenner static void __grow_type_table __P((int, enum typeid **, int *)); 123ce51cf03SJames Raynard 12458f0484fSRodney W. Grimes /* 12558f0484fSRodney W. Grimes * Flush out all the vectors defined by the given uio, 12658f0484fSRodney W. Grimes * then reset it so that it can be reused. 12758f0484fSRodney W. Grimes */ 12858f0484fSRodney W. Grimes static int 129d201fe46SDaniel Eischen __sprint(FILE *fp, struct __suio *uio) 13058f0484fSRodney W. Grimes { 131d201fe46SDaniel Eischen int err; 13258f0484fSRodney W. Grimes 13358f0484fSRodney W. Grimes if (uio->uio_resid == 0) { 13458f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 13558f0484fSRodney W. Grimes return (0); 13658f0484fSRodney W. Grimes } 13758f0484fSRodney W. Grimes err = __sfvwrite(fp, uio); 13858f0484fSRodney W. Grimes uio->uio_resid = 0; 13958f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 14058f0484fSRodney W. Grimes return (err); 14158f0484fSRodney W. Grimes } 14258f0484fSRodney W. Grimes 14358f0484fSRodney W. Grimes /* 14458f0484fSRodney W. Grimes * Helper function for `fprintf to unbuffered unix file': creates a 14558f0484fSRodney W. Grimes * temporary buffer. We only work on write-only files; this avoids 14658f0484fSRodney W. Grimes * worries about ungetc buffers and so forth. 14758f0484fSRodney W. Grimes */ 14858f0484fSRodney W. Grimes static int 149d201fe46SDaniel Eischen __sbprintf(FILE *fp, const char *fmt, va_list ap) 15058f0484fSRodney W. Grimes { 15158f0484fSRodney W. Grimes int ret; 15258f0484fSRodney W. Grimes FILE fake; 15358f0484fSRodney W. Grimes unsigned char buf[BUFSIZ]; 15458f0484fSRodney W. Grimes 15558f0484fSRodney W. Grimes /* copy the important variables */ 15658f0484fSRodney W. Grimes fake._flags = fp->_flags & ~__SNBF; 15758f0484fSRodney W. Grimes fake._file = fp->_file; 15858f0484fSRodney W. Grimes fake._cookie = fp->_cookie; 15958f0484fSRodney W. Grimes fake._write = fp->_write; 16058f0484fSRodney W. Grimes 16158f0484fSRodney W. Grimes /* set up the buffer */ 16258f0484fSRodney W. Grimes fake._bf._base = fake._p = buf; 16358f0484fSRodney W. Grimes fake._bf._size = fake._w = sizeof(buf); 16458f0484fSRodney W. Grimes fake._lbfsize = 0; /* not actually used, but Just In Case */ 16558f0484fSRodney W. Grimes 16658f0484fSRodney W. Grimes /* do the work, then copy any error status */ 167d201fe46SDaniel Eischen ret = __vfprintf(&fake, fmt, ap); 168d201fe46SDaniel Eischen if (ret >= 0 && __fflush(&fake)) 16958f0484fSRodney W. Grimes ret = EOF; 17058f0484fSRodney W. Grimes if (fake._flags & __SERR) 17158f0484fSRodney W. Grimes fp->_flags |= __SERR; 17258f0484fSRodney W. Grimes return (ret); 17358f0484fSRodney W. Grimes } 17458f0484fSRodney W. Grimes 17558f0484fSRodney W. Grimes /* 17658f0484fSRodney W. Grimes * Macros for converting digits to letters and vice versa 17758f0484fSRodney W. Grimes */ 17858f0484fSRodney W. Grimes #define to_digit(c) ((c) - '0') 17958f0484fSRodney W. Grimes #define is_digit(c) ((unsigned)to_digit(c) <= 9) 18058f0484fSRodney W. Grimes #define to_char(n) ((n) + '0') 18158f0484fSRodney W. Grimes 18258f0484fSRodney W. Grimes /* 18358f0484fSRodney W. Grimes * Convert an unsigned long to ASCII for printf purposes, returning 18458f0484fSRodney W. Grimes * a pointer to the first character of the string representation. 18558f0484fSRodney W. Grimes * Octal numbers can be forced to have a leading zero; hex numbers 18658f0484fSRodney W. Grimes * use the given digits. 18758f0484fSRodney W. Grimes */ 18858f0484fSRodney W. Grimes static char * 1897735bb0fSBill Fenner __ultoa(u_long val, char *endp, int base, int octzero, char *xdigs, 19098ee7635SAlexey Zelkin int needgrp, char thousep, const char *grp) 19158f0484fSRodney W. Grimes { 19258f0484fSRodney W. Grimes register char *cp = endp; 19358f0484fSRodney W. Grimes register long sval; 1947735bb0fSBill Fenner int ndig; 19558f0484fSRodney W. Grimes 19658f0484fSRodney W. Grimes /* 19758f0484fSRodney W. Grimes * Handle the three cases separately, in the hope of getting 19858f0484fSRodney W. Grimes * better/faster code. 19958f0484fSRodney W. Grimes */ 20058f0484fSRodney W. Grimes switch (base) { 20158f0484fSRodney W. Grimes case 10: 20258f0484fSRodney W. Grimes if (val < 10) { /* many numbers are 1 digit */ 20358f0484fSRodney W. Grimes *--cp = to_char(val); 20458f0484fSRodney W. Grimes return (cp); 20558f0484fSRodney W. Grimes } 2067735bb0fSBill Fenner ndig = 0; 20758f0484fSRodney W. Grimes /* 20858f0484fSRodney W. Grimes * On many machines, unsigned arithmetic is harder than 20958f0484fSRodney W. Grimes * signed arithmetic, so we do at most one unsigned mod and 21058f0484fSRodney W. Grimes * divide; this is sufficient to reduce the range of 21158f0484fSRodney W. Grimes * the incoming value to where signed arithmetic works. 21258f0484fSRodney W. Grimes */ 21358f0484fSRodney W. Grimes if (val > LONG_MAX) { 21458f0484fSRodney W. Grimes *--cp = to_char(val % 10); 2157735bb0fSBill Fenner ndig++; 21658f0484fSRodney W. Grimes sval = val / 10; 21758f0484fSRodney W. Grimes } else 21858f0484fSRodney W. Grimes sval = val; 21958f0484fSRodney W. Grimes do { 22058f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 22198ee7635SAlexey Zelkin ndig++; 22298ee7635SAlexey Zelkin /* 22398ee7635SAlexey Zelkin * If (*grp == CHAR_MAX) then no more grouping 22498ee7635SAlexey Zelkin * should be performed. 22598ee7635SAlexey Zelkin */ 226243e90d6SAlexey Zelkin if (needgrp && ndig == *grp && *grp != CHAR_MAX 227243e90d6SAlexey Zelkin && sval > 9) { 22898ee7635SAlexey Zelkin *--cp = thousep; 2297735bb0fSBill Fenner ndig = 0; 23098ee7635SAlexey Zelkin /* 23198ee7635SAlexey Zelkin * If (*(grp+1) == '\0') then we have to 23298ee7635SAlexey Zelkin * use *grp character (last grouping rule) 23398ee7635SAlexey Zelkin * for all next cases 23498ee7635SAlexey Zelkin */ 2352e394b2fSAlexey Zelkin if (*(grp+1) != '\0') 2362e394b2fSAlexey Zelkin grp++; 2377735bb0fSBill Fenner } 23858f0484fSRodney W. Grimes sval /= 10; 23958f0484fSRodney W. Grimes } while (sval != 0); 24058f0484fSRodney W. Grimes break; 24158f0484fSRodney W. Grimes 24258f0484fSRodney W. Grimes case 8: 24358f0484fSRodney W. Grimes do { 24458f0484fSRodney W. Grimes *--cp = to_char(val & 7); 24558f0484fSRodney W. Grimes val >>= 3; 24658f0484fSRodney W. Grimes } while (val); 24758f0484fSRodney W. Grimes if (octzero && *cp != '0') 24858f0484fSRodney W. Grimes *--cp = '0'; 24958f0484fSRodney W. Grimes break; 25058f0484fSRodney W. Grimes 25158f0484fSRodney W. Grimes case 16: 25258f0484fSRodney W. Grimes do { 25358f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 25458f0484fSRodney W. Grimes val >>= 4; 25558f0484fSRodney W. Grimes } while (val); 25658f0484fSRodney W. Grimes break; 25758f0484fSRodney W. Grimes 25858f0484fSRodney W. Grimes default: /* oops */ 25958f0484fSRodney W. Grimes abort(); 26058f0484fSRodney W. Grimes } 26158f0484fSRodney W. Grimes return (cp); 26258f0484fSRodney W. Grimes } 26358f0484fSRodney W. Grimes 2647735bb0fSBill Fenner /* Identical to __ultoa, but for intmax_t. */ 26558f0484fSRodney W. Grimes static char * 2667735bb0fSBill Fenner __ujtoa(uintmax_t val, char *endp, int base, int octzero, char *xdigs, 26798ee7635SAlexey Zelkin int needgrp, char thousep, const char *grp) 26858f0484fSRodney W. Grimes { 269d201fe46SDaniel Eischen char *cp = endp; 2707735bb0fSBill Fenner intmax_t sval; 2717735bb0fSBill Fenner int ndig; 27258f0484fSRodney W. Grimes 27358f0484fSRodney W. Grimes /* quick test for small values; __ultoa is typically much faster */ 27458f0484fSRodney W. Grimes /* (perhaps instead we should run until small, then call __ultoa?) */ 27558f0484fSRodney W. Grimes if (val <= ULONG_MAX) 2767735bb0fSBill Fenner return (__ultoa((u_long)val, endp, base, octzero, xdigs, 27798ee7635SAlexey Zelkin needgrp, thousep, grp)); 27858f0484fSRodney W. Grimes switch (base) { 27958f0484fSRodney W. Grimes case 10: 28058f0484fSRodney W. Grimes if (val < 10) { 28158f0484fSRodney W. Grimes *--cp = to_char(val % 10); 28258f0484fSRodney W. Grimes return (cp); 28358f0484fSRodney W. Grimes } 2847735bb0fSBill Fenner ndig = 0; 2857735bb0fSBill Fenner if (val > INTMAX_MAX) { 28658f0484fSRodney W. Grimes *--cp = to_char(val % 10); 2877735bb0fSBill Fenner ndig++; 28858f0484fSRodney W. Grimes sval = val / 10; 28958f0484fSRodney W. Grimes } else 29058f0484fSRodney W. Grimes sval = val; 29158f0484fSRodney W. Grimes do { 29258f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 29398ee7635SAlexey Zelkin ndig++; 29498ee7635SAlexey Zelkin /* 29598ee7635SAlexey Zelkin * If (*grp == CHAR_MAX) then no more grouping 29698ee7635SAlexey Zelkin * should be performed. 29798ee7635SAlexey Zelkin */ 298243e90d6SAlexey Zelkin if (needgrp && *grp != CHAR_MAX && ndig == *grp 299243e90d6SAlexey Zelkin && sval > 9) { 30098ee7635SAlexey Zelkin *--cp = thousep; 3017735bb0fSBill Fenner ndig = 0; 30298ee7635SAlexey Zelkin /* 30398ee7635SAlexey Zelkin * If (*(grp+1) == '\0') then we have to 30498ee7635SAlexey Zelkin * use *grp character (last grouping rule) 30598ee7635SAlexey Zelkin * for all next cases 30698ee7635SAlexey Zelkin */ 3072e394b2fSAlexey Zelkin if (*(grp+1) != '\0') 3082e394b2fSAlexey Zelkin grp++; 3097735bb0fSBill Fenner } 31058f0484fSRodney W. Grimes sval /= 10; 31158f0484fSRodney W. Grimes } while (sval != 0); 31258f0484fSRodney W. Grimes break; 31358f0484fSRodney W. Grimes 31458f0484fSRodney W. Grimes case 8: 31558f0484fSRodney W. Grimes do { 31658f0484fSRodney W. Grimes *--cp = to_char(val & 7); 31758f0484fSRodney W. Grimes val >>= 3; 31858f0484fSRodney W. Grimes } while (val); 31958f0484fSRodney W. Grimes if (octzero && *cp != '0') 32058f0484fSRodney W. Grimes *--cp = '0'; 32158f0484fSRodney W. Grimes break; 32258f0484fSRodney W. Grimes 32358f0484fSRodney W. Grimes case 16: 32458f0484fSRodney W. Grimes do { 32558f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 32658f0484fSRodney W. Grimes val >>= 4; 32758f0484fSRodney W. Grimes } while (val); 32858f0484fSRodney W. Grimes break; 32958f0484fSRodney W. Grimes 33058f0484fSRodney W. Grimes default: 33158f0484fSRodney W. Grimes abort(); 33258f0484fSRodney W. Grimes } 33358f0484fSRodney W. Grimes return (cp); 33458f0484fSRodney W. Grimes } 33558f0484fSRodney W. Grimes 336d201fe46SDaniel Eischen /* 337d201fe46SDaniel Eischen * MT-safe version 338d201fe46SDaniel Eischen */ 339d201fe46SDaniel Eischen int 340d201fe46SDaniel Eischen vfprintf(FILE *fp, const char *fmt0, va_list ap) 341d201fe46SDaniel Eischen { 342d201fe46SDaniel Eischen int ret; 343d201fe46SDaniel Eischen 344d201fe46SDaniel Eischen FLOCKFILE(fp); 345d201fe46SDaniel Eischen ret = __vfprintf(fp, fmt0, ap); 346d201fe46SDaniel Eischen FUNLOCKFILE(fp); 347d201fe46SDaniel Eischen return (ret); 348d201fe46SDaniel Eischen } 349d201fe46SDaniel Eischen 35058f0484fSRodney W. Grimes #ifdef FLOATING_POINT 35158f0484fSRodney W. Grimes #include <math.h> 35258f0484fSRodney W. Grimes #include "floatio.h" 35358f0484fSRodney W. Grimes 35498ee7635SAlexey Zelkin #define BUF ((MAXEXP*2)+MAXFRACT+1) /* + decimal point */ 35558f0484fSRodney W. Grimes #define DEFPREC 6 35658f0484fSRodney W. Grimes 3572ffc61baSTor Egge static char *cvt __P((double, int, int, char *, int *, int, int *, char **)); 35858f0484fSRodney W. Grimes static int exponent __P((char *, int, int)); 35958f0484fSRodney W. Grimes 36058f0484fSRodney W. Grimes #else /* no FLOATING_POINT */ 36158f0484fSRodney W. Grimes 36298ee7635SAlexey Zelkin #define BUF 136 36358f0484fSRodney W. Grimes 36458f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 36558f0484fSRodney W. Grimes 366efb7e53dSJordan K. Hubbard #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 36758f0484fSRodney W. Grimes 36858f0484fSRodney W. Grimes /* 36958f0484fSRodney W. Grimes * Flags used during conversion. 37058f0484fSRodney W. Grimes */ 37158f0484fSRodney W. Grimes #define ALT 0x001 /* alternate form */ 37258f0484fSRodney W. Grimes #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 37358f0484fSRodney W. Grimes #define LADJUST 0x004 /* left adjustment */ 3746a93659fSBruce Evans #define LONGDBL 0x008 /* long double */ 37558f0484fSRodney W. Grimes #define LONGINT 0x010 /* long integer */ 3767735bb0fSBill Fenner #define LLONGINT 0x020 /* long long integer */ 37758f0484fSRodney W. Grimes #define SHORTINT 0x040 /* short integer */ 37858f0484fSRodney W. Grimes #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 37958f0484fSRodney W. Grimes #define FPT 0x100 /* Floating point number */ 38098ee7635SAlexey Zelkin #define GROUPING 0x200 /* use grouping ("'" flag) */ 3817735bb0fSBill Fenner /* C99 additional size modifiers: */ 38298ee7635SAlexey Zelkin #define SIZET 0x400 /* size_t */ 38398ee7635SAlexey Zelkin #define PTRDIFFT 0x800 /* ptrdiff_t */ 38498ee7635SAlexey Zelkin #define INTMAXT 0x1000 /* intmax_t */ 38598ee7635SAlexey Zelkin #define CHARINT 0x2000 /* print char using int format */ 3867735bb0fSBill Fenner 387d201fe46SDaniel Eischen /* 388d201fe46SDaniel Eischen * Non-MT-safe version 389d201fe46SDaniel Eischen */ 39058f0484fSRodney W. Grimes int 391d201fe46SDaniel Eischen __vfprintf(FILE *fp, const char *fmt0, va_list ap) 39258f0484fSRodney W. Grimes { 393d201fe46SDaniel Eischen char *fmt; /* format string */ 394d201fe46SDaniel Eischen int ch; /* character from fmt */ 395d201fe46SDaniel Eischen int n, n2; /* handy integer (short term usage) */ 396d201fe46SDaniel Eischen char *cp; /* handy char pointer (short term usage) */ 397d201fe46SDaniel Eischen struct __siov *iovp; /* for PRINT macro */ 398d201fe46SDaniel Eischen int flags; /* flags as above */ 39958f0484fSRodney W. Grimes int ret; /* return value accumulator */ 40058f0484fSRodney W. Grimes int width; /* width from format (%8d), or 0 */ 40158f0484fSRodney W. Grimes int prec; /* precision from format (%.3d), or -1 */ 40258f0484fSRodney W. Grimes char sign; /* sign prefix (' ', '+', '-', or \0) */ 40398ee7635SAlexey Zelkin char thousands_sep; /* locale specific thousands separator */ 40498ee7635SAlexey Zelkin const char *grouping; /* locale specific numeric grouping rules */ 40558f0484fSRodney W. Grimes #ifdef FLOATING_POINT 4067ae5c679SAlexey Zelkin char *decimal_point; /* locale specific decimal point */ 40758f0484fSRodney W. Grimes char softsign; /* temporary negative sign for floats */ 40858f0484fSRodney W. Grimes double _double; /* double precision arguments %[eEfgG] */ 40958f0484fSRodney W. Grimes int expt; /* integer value of exponent */ 41058f0484fSRodney W. Grimes int expsize; /* character count for expstr */ 41158f0484fSRodney W. Grimes int ndig; /* actual number of digits returned by cvt */ 41258f0484fSRodney W. Grimes char expstr[7]; /* buffer for exponent string */ 4132ffc61baSTor Egge char *dtoaresult; /* buffer allocated by dtoa */ 41458f0484fSRodney W. Grimes #endif 41558f0484fSRodney W. Grimes u_long ulval; /* integer arguments %[diouxX] */ 4167735bb0fSBill Fenner uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ 41758f0484fSRodney W. Grimes int base; /* base for [diouxX] conversion */ 41858f0484fSRodney W. Grimes int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 419261a532aSBill Fenner int realsz; /* field size expanded by dprec, sign, etc */ 42058f0484fSRodney W. Grimes int size; /* size of converted field or string */ 42192e88f87SAndrey A. Chernov int prsize; /* max size of printed field */ 42258f0484fSRodney W. Grimes char *xdigs; /* digits for [xX] conversion */ 42358f0484fSRodney W. Grimes #define NIOV 8 42458f0484fSRodney W. Grimes struct __suio uio; /* output information: summary */ 42558f0484fSRodney W. Grimes struct __siov iov[NIOV];/* ... and individual io vectors */ 4267735bb0fSBill Fenner char buf[BUF]; /* space for %c, %[diouxX], %[eEfFgG] */ 42758f0484fSRodney W. Grimes char ox[2]; /* space for 0x hex-prefix */ 428a387081cSDoug Rabson union arg *argtable; /* args, built due to positional arg */ 429a387081cSDoug Rabson union arg statargtable [STATIC_ARG_TBL_SIZE]; 430efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 431efb7e53dSJordan K. Hubbard va_list orgap; /* original argument pointer */ 43258f0484fSRodney W. Grimes 43358f0484fSRodney W. Grimes /* 43458f0484fSRodney W. Grimes * Choose PADSIZE to trade efficiency vs. size. If larger printf 43558f0484fSRodney W. Grimes * fields occur frequently, increase PADSIZE and make the initialisers 43658f0484fSRodney W. Grimes * below longer. 43758f0484fSRodney W. Grimes */ 43858f0484fSRodney W. Grimes #define PADSIZE 16 /* pad chunk size */ 43958f0484fSRodney W. Grimes static char blanks[PADSIZE] = 44058f0484fSRodney W. Grimes {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 44158f0484fSRodney W. Grimes static char zeroes[PADSIZE] = 44258f0484fSRodney W. Grimes {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 44358f0484fSRodney W. Grimes 44458f0484fSRodney W. Grimes /* 44558f0484fSRodney W. Grimes * BEWARE, these `goto error' on error, and PAD uses `n'. 44658f0484fSRodney W. Grimes */ 44758f0484fSRodney W. Grimes #define PRINT(ptr, len) { \ 44858f0484fSRodney W. Grimes iovp->iov_base = (ptr); \ 44958f0484fSRodney W. Grimes iovp->iov_len = (len); \ 45058f0484fSRodney W. Grimes uio.uio_resid += (len); \ 45158f0484fSRodney W. Grimes iovp++; \ 45258f0484fSRodney W. Grimes if (++uio.uio_iovcnt >= NIOV) { \ 45358f0484fSRodney W. Grimes if (__sprint(fp, &uio)) \ 45458f0484fSRodney W. Grimes goto error; \ 45558f0484fSRodney W. Grimes iovp = iov; \ 45658f0484fSRodney W. Grimes } \ 45758f0484fSRodney W. Grimes } 45858f0484fSRodney W. Grimes #define PAD(howmany, with) { \ 45958f0484fSRodney W. Grimes if ((n = (howmany)) > 0) { \ 46058f0484fSRodney W. Grimes while (n > PADSIZE) { \ 46158f0484fSRodney W. Grimes PRINT(with, PADSIZE); \ 46258f0484fSRodney W. Grimes n -= PADSIZE; \ 46358f0484fSRodney W. Grimes } \ 46458f0484fSRodney W. Grimes PRINT(with, n); \ 46558f0484fSRodney W. Grimes } \ 46658f0484fSRodney W. Grimes } 46758f0484fSRodney W. Grimes #define FLUSH() { \ 46858f0484fSRodney W. Grimes if (uio.uio_resid && __sprint(fp, &uio)) \ 46958f0484fSRodney W. Grimes goto error; \ 47058f0484fSRodney W. Grimes uio.uio_iovcnt = 0; \ 47158f0484fSRodney W. Grimes iovp = iov; \ 47258f0484fSRodney W. Grimes } 47358f0484fSRodney W. Grimes 47458f0484fSRodney W. Grimes /* 475efb7e53dSJordan K. Hubbard * Get the argument indexed by nextarg. If the argument table is 476efb7e53dSJordan K. Hubbard * built, use it to get the argument. If its not, get the next 477efb7e53dSJordan K. Hubbard * argument (and arguments must be gotten sequentially). 478efb7e53dSJordan K. Hubbard */ 479efb7e53dSJordan K. Hubbard #define GETARG(type) \ 480a387081cSDoug Rabson ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 481efb7e53dSJordan K. Hubbard (nextarg++, va_arg(ap, type))) 482efb7e53dSJordan K. Hubbard 483efb7e53dSJordan K. Hubbard /* 48458f0484fSRodney W. Grimes * To extend shorts properly, we need both signed and unsigned 48558f0484fSRodney W. Grimes * argument extraction methods. 48658f0484fSRodney W. Grimes */ 48758f0484fSRodney W. Grimes #define SARG() \ 488efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(long) : \ 489efb7e53dSJordan K. Hubbard flags&SHORTINT ? (long)(short)GETARG(int) : \ 4907735bb0fSBill Fenner flags&CHARINT ? (long)(signed char)GETARG(int) : \ 491efb7e53dSJordan K. Hubbard (long)GETARG(int)) 49258f0484fSRodney W. Grimes #define UARG() \ 493efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(u_long) : \ 494efb7e53dSJordan K. Hubbard flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 4957735bb0fSBill Fenner flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ 496efb7e53dSJordan K. Hubbard (u_long)GETARG(u_int)) 4977735bb0fSBill Fenner #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) 4987735bb0fSBill Fenner #define SJARG() \ 4997735bb0fSBill Fenner (flags&INTMAXT ? GETARG(intmax_t) : \ 5007735bb0fSBill Fenner flags&SIZET ? (intmax_t)GETARG(size_t) : \ 5017735bb0fSBill Fenner flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ 5027735bb0fSBill Fenner (intmax_t)GETARG(long long)) 5037735bb0fSBill Fenner #define UJARG() \ 5047735bb0fSBill Fenner (flags&INTMAXT ? GETARG(uintmax_t) : \ 5057735bb0fSBill Fenner flags&SIZET ? (uintmax_t)GETARG(size_t) : \ 5067735bb0fSBill Fenner flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ 5077735bb0fSBill Fenner (uintmax_t)GETARG(unsigned long long)) 508efb7e53dSJordan K. Hubbard 509efb7e53dSJordan K. Hubbard /* 510efb7e53dSJordan K. Hubbard * Get * arguments, including the form *nn$. Preserve the nextarg 511efb7e53dSJordan K. Hubbard * that the argument can be gotten once the type is determined. 512efb7e53dSJordan K. Hubbard */ 513efb7e53dSJordan K. Hubbard #define GETASTER(val) \ 514efb7e53dSJordan K. Hubbard n2 = 0; \ 515efb7e53dSJordan K. Hubbard cp = fmt; \ 516efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 517efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 518efb7e53dSJordan K. Hubbard cp++; \ 519efb7e53dSJordan K. Hubbard } \ 520efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 521efb7e53dSJordan K. Hubbard int hold = nextarg; \ 522efb7e53dSJordan K. Hubbard if (argtable == NULL) { \ 523efb7e53dSJordan K. Hubbard argtable = statargtable; \ 524efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, &argtable); \ 525efb7e53dSJordan K. Hubbard } \ 526efb7e53dSJordan K. Hubbard nextarg = n2; \ 527efb7e53dSJordan K. Hubbard val = GETARG (int); \ 528efb7e53dSJordan K. Hubbard nextarg = hold; \ 529efb7e53dSJordan K. Hubbard fmt = ++cp; \ 530efb7e53dSJordan K. Hubbard } else { \ 531efb7e53dSJordan K. Hubbard val = GETARG (int); \ 532efb7e53dSJordan K. Hubbard } 533efb7e53dSJordan K. Hubbard 53458f0484fSRodney W. Grimes 53598ee7635SAlexey Zelkin thousands_sep = '\0'; 53698ee7635SAlexey Zelkin grouping = NULL; 5372ffc61baSTor Egge #ifdef FLOATING_POINT 5382ffc61baSTor Egge dtoaresult = NULL; 5397735bb0fSBill Fenner decimal_point = localeconv()->decimal_point; 5402ffc61baSTor Egge #endif 54158f0484fSRodney W. Grimes /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 542d201fe46SDaniel Eischen if (cantwrite(fp)) 54358f0484fSRodney W. Grimes return (EOF); 54458f0484fSRodney W. Grimes 54558f0484fSRodney W. Grimes /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 54658f0484fSRodney W. Grimes if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 547d201fe46SDaniel Eischen fp->_file >= 0) 54858f0484fSRodney W. Grimes return (__sbprintf(fp, fmt0, ap)); 54958f0484fSRodney W. Grimes 55058f0484fSRodney W. Grimes fmt = (char *)fmt0; 551efb7e53dSJordan K. Hubbard argtable = NULL; 552efb7e53dSJordan K. Hubbard nextarg = 1; 553efb7e53dSJordan K. Hubbard orgap = ap; 55458f0484fSRodney W. Grimes uio.uio_iov = iovp = iov; 55558f0484fSRodney W. Grimes uio.uio_resid = 0; 55658f0484fSRodney W. Grimes uio.uio_iovcnt = 0; 55758f0484fSRodney W. Grimes ret = 0; 55858f0484fSRodney W. Grimes 55958f0484fSRodney W. Grimes /* 56058f0484fSRodney W. Grimes * Scan the format for conversions (`%' character). 56158f0484fSRodney W. Grimes */ 56258f0484fSRodney W. Grimes for (;;) { 56358f0484fSRodney W. Grimes for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 56458f0484fSRodney W. Grimes /* void */; 56558f0484fSRodney W. Grimes if ((n = fmt - cp) != 0) { 566b250f248SAndrey A. Chernov if ((unsigned)ret + n > INT_MAX) { 56792e88f87SAndrey A. Chernov ret = EOF; 56892e88f87SAndrey A. Chernov goto error; 56992e88f87SAndrey A. Chernov } 57058f0484fSRodney W. Grimes PRINT(cp, n); 57158f0484fSRodney W. Grimes ret += n; 57258f0484fSRodney W. Grimes } 57358f0484fSRodney W. Grimes if (ch == '\0') 57458f0484fSRodney W. Grimes goto done; 57558f0484fSRodney W. Grimes fmt++; /* skip over '%' */ 57658f0484fSRodney W. Grimes 57758f0484fSRodney W. Grimes flags = 0; 57858f0484fSRodney W. Grimes dprec = 0; 57958f0484fSRodney W. Grimes width = 0; 58058f0484fSRodney W. Grimes prec = -1; 58158f0484fSRodney W. Grimes sign = '\0'; 58258f0484fSRodney W. Grimes 58358f0484fSRodney W. Grimes rflag: ch = *fmt++; 58458f0484fSRodney W. Grimes reswitch: switch (ch) { 58558f0484fSRodney W. Grimes case ' ': 5862e394b2fSAlexey Zelkin /*- 58758f0484fSRodney W. Grimes * ``If the space and + flags both appear, the space 58858f0484fSRodney W. Grimes * flag will be ignored.'' 58958f0484fSRodney W. Grimes * -- ANSI X3J11 59058f0484fSRodney W. Grimes */ 59158f0484fSRodney W. Grimes if (!sign) 59258f0484fSRodney W. Grimes sign = ' '; 59358f0484fSRodney W. Grimes goto rflag; 59458f0484fSRodney W. Grimes case '#': 59558f0484fSRodney W. Grimes flags |= ALT; 59658f0484fSRodney W. Grimes goto rflag; 59758f0484fSRodney W. Grimes case '*': 5982e394b2fSAlexey Zelkin /*- 59958f0484fSRodney W. Grimes * ``A negative field width argument is taken as a 60058f0484fSRodney W. Grimes * - flag followed by a positive field width.'' 60158f0484fSRodney W. Grimes * -- ANSI X3J11 60258f0484fSRodney W. Grimes * They don't exclude field widths read from args. 60358f0484fSRodney W. Grimes */ 604efb7e53dSJordan K. Hubbard GETASTER (width); 605efb7e53dSJordan K. Hubbard if (width >= 0) 60658f0484fSRodney W. Grimes goto rflag; 60758f0484fSRodney W. Grimes width = -width; 60858f0484fSRodney W. Grimes /* FALLTHROUGH */ 60958f0484fSRodney W. Grimes case '-': 61058f0484fSRodney W. Grimes flags |= LADJUST; 61158f0484fSRodney W. Grimes goto rflag; 61258f0484fSRodney W. Grimes case '+': 61358f0484fSRodney W. Grimes sign = '+'; 61458f0484fSRodney W. Grimes goto rflag; 6157735bb0fSBill Fenner case '\'': 61698ee7635SAlexey Zelkin flags |= GROUPING; 61798ee7635SAlexey Zelkin thousands_sep = *(localeconv()->thousands_sep); 61898ee7635SAlexey Zelkin grouping = localeconv()->grouping; 6197735bb0fSBill Fenner goto rflag; 62058f0484fSRodney W. Grimes case '.': 62158f0484fSRodney W. Grimes if ((ch = *fmt++) == '*') { 622efb7e53dSJordan K. Hubbard GETASTER (n); 62358f0484fSRodney W. Grimes prec = n < 0 ? -1 : n; 62458f0484fSRodney W. Grimes goto rflag; 62558f0484fSRodney W. Grimes } 62658f0484fSRodney W. Grimes n = 0; 62758f0484fSRodney W. Grimes while (is_digit(ch)) { 62858f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 62958f0484fSRodney W. Grimes ch = *fmt++; 63058f0484fSRodney W. Grimes } 63158f0484fSRodney W. Grimes prec = n < 0 ? -1 : n; 63258f0484fSRodney W. Grimes goto reswitch; 63358f0484fSRodney W. Grimes case '0': 6342e394b2fSAlexey Zelkin /*- 63558f0484fSRodney W. Grimes * ``Note that 0 is taken as a flag, not as the 63658f0484fSRodney W. Grimes * beginning of a field width.'' 63758f0484fSRodney W. Grimes * -- ANSI X3J11 63858f0484fSRodney W. Grimes */ 63958f0484fSRodney W. Grimes flags |= ZEROPAD; 64058f0484fSRodney W. Grimes goto rflag; 64158f0484fSRodney W. Grimes case '1': case '2': case '3': case '4': 64258f0484fSRodney W. Grimes case '5': case '6': case '7': case '8': case '9': 64358f0484fSRodney W. Grimes n = 0; 64458f0484fSRodney W. Grimes do { 64558f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 64658f0484fSRodney W. Grimes ch = *fmt++; 64758f0484fSRodney W. Grimes } while (is_digit(ch)); 648efb7e53dSJordan K. Hubbard if (ch == '$') { 649efb7e53dSJordan K. Hubbard nextarg = n; 650efb7e53dSJordan K. Hubbard if (argtable == NULL) { 651efb7e53dSJordan K. Hubbard argtable = statargtable; 652efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, 653efb7e53dSJordan K. Hubbard &argtable); 654efb7e53dSJordan K. Hubbard } 655efb7e53dSJordan K. Hubbard goto rflag; 656efb7e53dSJordan K. Hubbard } 65758f0484fSRodney W. Grimes width = n; 65858f0484fSRodney W. Grimes goto reswitch; 65958f0484fSRodney W. Grimes #ifdef FLOATING_POINT 66058f0484fSRodney W. Grimes case 'L': 66158f0484fSRodney W. Grimes flags |= LONGDBL; 66258f0484fSRodney W. Grimes goto rflag; 66358f0484fSRodney W. Grimes #endif 66458f0484fSRodney W. Grimes case 'h': 6657735bb0fSBill Fenner if (flags & SHORTINT) { 6667735bb0fSBill Fenner flags &= ~SHORTINT; 6677735bb0fSBill Fenner flags |= CHARINT; 6687735bb0fSBill Fenner } else 66958f0484fSRodney W. Grimes flags |= SHORTINT; 67058f0484fSRodney W. Grimes goto rflag; 6717735bb0fSBill Fenner case 'j': 6727735bb0fSBill Fenner flags |= INTMAXT; 6737735bb0fSBill Fenner goto rflag; 67458f0484fSRodney W. Grimes case 'l': 6757735bb0fSBill Fenner if (flags & LONGINT) { 6767735bb0fSBill Fenner flags &= ~LONGINT; 6777735bb0fSBill Fenner flags |= LLONGINT; 6787735bb0fSBill Fenner } else 67958f0484fSRodney W. Grimes flags |= LONGINT; 68058f0484fSRodney W. Grimes goto rflag; 68158f0484fSRodney W. Grimes case 'q': 6827735bb0fSBill Fenner flags |= LLONGINT; /* not necessarily */ 6837735bb0fSBill Fenner goto rflag; 6847735bb0fSBill Fenner case 't': 6857735bb0fSBill Fenner flags |= PTRDIFFT; 6867735bb0fSBill Fenner goto rflag; 6877735bb0fSBill Fenner case 'z': 6887735bb0fSBill Fenner flags |= SIZET; 68958f0484fSRodney W. Grimes goto rflag; 69058f0484fSRodney W. Grimes case 'c': 691efb7e53dSJordan K. Hubbard *(cp = buf) = GETARG(int); 69258f0484fSRodney W. Grimes size = 1; 69358f0484fSRodney W. Grimes sign = '\0'; 69458f0484fSRodney W. Grimes break; 69558f0484fSRodney W. Grimes case 'D': 69658f0484fSRodney W. Grimes flags |= LONGINT; 69758f0484fSRodney W. Grimes /*FALLTHROUGH*/ 69858f0484fSRodney W. Grimes case 'd': 69958f0484fSRodney W. Grimes case 'i': 7007735bb0fSBill Fenner if (flags & INTMAX_SIZE) { 7017735bb0fSBill Fenner ujval = SJARG(); 7027735bb0fSBill Fenner if ((intmax_t)ujval < 0) { 7037735bb0fSBill Fenner ujval = -ujval; 70458f0484fSRodney W. Grimes sign = '-'; 70558f0484fSRodney W. Grimes } 70658f0484fSRodney W. Grimes } else { 70758f0484fSRodney W. Grimes ulval = SARG(); 70858f0484fSRodney W. Grimes if ((long)ulval < 0) { 70958f0484fSRodney W. Grimes ulval = -ulval; 71058f0484fSRodney W. Grimes sign = '-'; 71158f0484fSRodney W. Grimes } 71258f0484fSRodney W. Grimes } 71358f0484fSRodney W. Grimes base = 10; 71458f0484fSRodney W. Grimes goto number; 71558f0484fSRodney W. Grimes #ifdef FLOATING_POINT 7167735bb0fSBill Fenner #ifdef HEXFLOAT 7177735bb0fSBill Fenner case 'a': 7187735bb0fSBill Fenner case 'A': 7197735bb0fSBill Fenner #endif 720d26be6f0SBruce Evans case 'e': 72158f0484fSRodney W. Grimes case 'E': 7222e394b2fSAlexey Zelkin /*- 72398ee7635SAlexey Zelkin * Grouping apply to %i, %d, %u, %f, %F, %g, %G 72498ee7635SAlexey Zelkin * conversion specifiers only. For other conversions 72598ee7635SAlexey Zelkin * behavior is undefined. 72698ee7635SAlexey Zelkin * -- POSIX 72798ee7635SAlexey Zelkin */ 72898ee7635SAlexey Zelkin flags &= ~GROUPING; 72998ee7635SAlexey Zelkin /*FALLTHROUGH*/ 730d26be6f0SBruce Evans case 'f': 7317735bb0fSBill Fenner case 'F': 732d26be6f0SBruce Evans goto fp_begin; 73358f0484fSRodney W. Grimes case 'g': 73458f0484fSRodney W. Grimes case 'G': 735d26be6f0SBruce Evans if (prec == 0) 736d26be6f0SBruce Evans prec = 1; 737d26be6f0SBruce Evans fp_begin: if (prec == -1) 73858f0484fSRodney W. Grimes prec = DEFPREC; 739d26be6f0SBruce Evans if (flags & LONGDBL) 7406a93659fSBruce Evans /* XXX this loses precision. */ 741efb7e53dSJordan K. Hubbard _double = (double)GETARG(long double); 742d26be6f0SBruce Evans else 743efb7e53dSJordan K. Hubbard _double = GETARG(double); 74458f0484fSRodney W. Grimes /* do this before tricky precision changes */ 74558f0484fSRodney W. Grimes if (isinf(_double)) { 74658f0484fSRodney W. Grimes if (_double < 0) 74758f0484fSRodney W. Grimes sign = '-'; 7487735bb0fSBill Fenner if (isupper(ch)) 7497735bb0fSBill Fenner cp = "INF"; 7507735bb0fSBill Fenner else 7517735bb0fSBill Fenner cp = "inf"; 75258f0484fSRodney W. Grimes size = 3; 75358f0484fSRodney W. Grimes break; 75458f0484fSRodney W. Grimes } 75558f0484fSRodney W. Grimes if (isnan(_double)) { 7567735bb0fSBill Fenner if (isupper(ch)) 7577735bb0fSBill Fenner cp = "NAN"; 7587735bb0fSBill Fenner else 7597735bb0fSBill Fenner cp = "nan"; 76058f0484fSRodney W. Grimes size = 3; 76158f0484fSRodney W. Grimes break; 76258f0484fSRodney W. Grimes } 76358f0484fSRodney W. Grimes flags |= FPT; 7642ffc61baSTor Egge if (dtoaresult != NULL) { 7652ffc61baSTor Egge free(dtoaresult); 7662ffc61baSTor Egge dtoaresult = NULL; 7672ffc61baSTor Egge } 76858f0484fSRodney W. Grimes cp = cvt(_double, prec, flags, &softsign, 7692ffc61baSTor Egge &expt, ch, &ndig, &dtoaresult); 77058f0484fSRodney W. Grimes if (ch == 'g' || ch == 'G') { 77158f0484fSRodney W. Grimes if (expt <= -4 || expt > prec) 77258f0484fSRodney W. Grimes ch = (ch == 'g') ? 'e' : 'E'; 77358f0484fSRodney W. Grimes else 77458f0484fSRodney W. Grimes ch = 'g'; 77558f0484fSRodney W. Grimes } 7767735bb0fSBill Fenner if (ch == 'e' || ch == 'E') { 77758f0484fSRodney W. Grimes --expt; 77858f0484fSRodney W. Grimes expsize = exponent(expstr, expt, ch); 77958f0484fSRodney W. Grimes size = expsize + ndig; 78058f0484fSRodney W. Grimes if (ndig > 1 || flags & ALT) 78158f0484fSRodney W. Grimes ++size; 7827735bb0fSBill Fenner } else if (ch == 'f' || ch == 'F') { 78358f0484fSRodney W. Grimes if (expt > 0) { 78458f0484fSRodney W. Grimes size = expt; 78558f0484fSRodney W. Grimes if (prec || flags & ALT) 78658f0484fSRodney W. Grimes size += prec + 1; 78758f0484fSRodney W. Grimes } else /* "0.X" */ 78858f0484fSRodney W. Grimes size = prec + 2; 78958f0484fSRodney W. Grimes } else if (expt >= ndig) { /* fixed g fmt */ 79058f0484fSRodney W. Grimes size = expt; 79158f0484fSRodney W. Grimes if (flags & ALT) 79258f0484fSRodney W. Grimes ++size; 79358f0484fSRodney W. Grimes } else 79458f0484fSRodney W. Grimes size = ndig + (expt > 0 ? 79558f0484fSRodney W. Grimes 1 : 2 - expt); 79658f0484fSRodney W. Grimes 79758f0484fSRodney W. Grimes if (softsign) 79858f0484fSRodney W. Grimes sign = '-'; 79958f0484fSRodney W. Grimes break; 80058f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 80158f0484fSRodney W. Grimes case 'n': 8027735bb0fSBill Fenner /* 8037735bb0fSBill Fenner * Assignment-like behavior is specified if the 8047735bb0fSBill Fenner * value overflows or is otherwise unrepresentable. 8057735bb0fSBill Fenner * C99 says to use `signed char' for %hhn conversions. 8067735bb0fSBill Fenner */ 8077735bb0fSBill Fenner if (flags & LLONGINT) 8087735bb0fSBill Fenner *GETARG(long long *) = ret; 8097735bb0fSBill Fenner else if (flags & SIZET) 8107735bb0fSBill Fenner *GETARG(ssize_t *) = (ssize_t)ret; 8117735bb0fSBill Fenner else if (flags & PTRDIFFT) 8127735bb0fSBill Fenner *GETARG(ptrdiff_t *) = ret; 8137735bb0fSBill Fenner else if (flags & INTMAXT) 8147735bb0fSBill Fenner *GETARG(intmax_t *) = ret; 81558f0484fSRodney W. Grimes else if (flags & LONGINT) 8166e690ad4SAndrey A. Chernov *GETARG(long *) = ret; 81758f0484fSRodney W. Grimes else if (flags & SHORTINT) 8186e690ad4SAndrey A. Chernov *GETARG(short *) = ret; 8197735bb0fSBill Fenner else if (flags & CHARINT) 8207735bb0fSBill Fenner *GETARG(signed char *) = ret; 82158f0484fSRodney W. Grimes else 8226e690ad4SAndrey A. Chernov *GETARG(int *) = ret; 82358f0484fSRodney W. Grimes continue; /* no output */ 82458f0484fSRodney W. Grimes case 'O': 82558f0484fSRodney W. Grimes flags |= LONGINT; 82658f0484fSRodney W. Grimes /*FALLTHROUGH*/ 82758f0484fSRodney W. Grimes case 'o': 8287735bb0fSBill Fenner if (flags & INTMAX_SIZE) 8297735bb0fSBill Fenner ujval = UJARG(); 83058f0484fSRodney W. Grimes else 83158f0484fSRodney W. Grimes ulval = UARG(); 83258f0484fSRodney W. Grimes base = 8; 83358f0484fSRodney W. Grimes goto nosign; 83458f0484fSRodney W. Grimes case 'p': 8352e394b2fSAlexey Zelkin /*- 83658f0484fSRodney W. Grimes * ``The argument shall be a pointer to void. The 83758f0484fSRodney W. Grimes * value of the pointer is converted to a sequence 83858f0484fSRodney W. Grimes * of printable characters, in an implementation- 83958f0484fSRodney W. Grimes * defined manner.'' 84058f0484fSRodney W. Grimes * -- ANSI X3J11 84158f0484fSRodney W. Grimes */ 8427735bb0fSBill Fenner ujval = (uintmax_t)(uintptr_t)GETARG(void *); 84358f0484fSRodney W. Grimes base = 16; 84458f0484fSRodney W. Grimes xdigs = "0123456789abcdef"; 8457735bb0fSBill Fenner flags = flags | INTMAXT | HEXPREFIX; 84658f0484fSRodney W. Grimes ch = 'x'; 84758f0484fSRodney W. Grimes goto nosign; 84858f0484fSRodney W. Grimes case 's': 849efb7e53dSJordan K. Hubbard if ((cp = GETARG(char *)) == NULL) 85058f0484fSRodney W. Grimes cp = "(null)"; 85158f0484fSRodney W. Grimes if (prec >= 0) { 85258f0484fSRodney W. Grimes /* 85358f0484fSRodney W. Grimes * can't use strlen; can only look for the 85458f0484fSRodney W. Grimes * NUL in the first `prec' characters, and 85558f0484fSRodney W. Grimes * strlen() will go further. 85658f0484fSRodney W. Grimes */ 857ce51cf03SJames Raynard char *p = memchr(cp, 0, (size_t)prec); 85858f0484fSRodney W. Grimes 85958f0484fSRodney W. Grimes if (p != NULL) { 86058f0484fSRodney W. Grimes size = p - cp; 86158f0484fSRodney W. Grimes if (size > prec) 86258f0484fSRodney W. Grimes size = prec; 86358f0484fSRodney W. Grimes } else 86458f0484fSRodney W. Grimes size = prec; 86558f0484fSRodney W. Grimes } else 86658f0484fSRodney W. Grimes size = strlen(cp); 86758f0484fSRodney W. Grimes sign = '\0'; 86858f0484fSRodney W. Grimes break; 86958f0484fSRodney W. Grimes case 'U': 87058f0484fSRodney W. Grimes flags |= LONGINT; 87158f0484fSRodney W. Grimes /*FALLTHROUGH*/ 87258f0484fSRodney W. Grimes case 'u': 8737735bb0fSBill Fenner if (flags & INTMAX_SIZE) 8747735bb0fSBill Fenner ujval = UJARG(); 87558f0484fSRodney W. Grimes else 87658f0484fSRodney W. Grimes ulval = UARG(); 87758f0484fSRodney W. Grimes base = 10; 87858f0484fSRodney W. Grimes goto nosign; 87958f0484fSRodney W. Grimes case 'X': 88058f0484fSRodney W. Grimes xdigs = "0123456789ABCDEF"; 88158f0484fSRodney W. Grimes goto hex; 88258f0484fSRodney W. Grimes case 'x': 88358f0484fSRodney W. Grimes xdigs = "0123456789abcdef"; 8847735bb0fSBill Fenner hex: 8857735bb0fSBill Fenner if (flags & INTMAX_SIZE) 8867735bb0fSBill Fenner ujval = UJARG(); 88758f0484fSRodney W. Grimes else 88858f0484fSRodney W. Grimes ulval = UARG(); 88958f0484fSRodney W. Grimes base = 16; 89058f0484fSRodney W. Grimes /* leading 0x/X only if non-zero */ 89158f0484fSRodney W. Grimes if (flags & ALT && 8927735bb0fSBill Fenner (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) 89358f0484fSRodney W. Grimes flags |= HEXPREFIX; 89458f0484fSRodney W. Grimes 89598ee7635SAlexey Zelkin flags &= ~GROUPING; 89658f0484fSRodney W. Grimes /* unsigned conversions */ 89758f0484fSRodney W. Grimes nosign: sign = '\0'; 8982e394b2fSAlexey Zelkin /*- 89958f0484fSRodney W. Grimes * ``... diouXx conversions ... if a precision is 90058f0484fSRodney W. Grimes * specified, the 0 flag will be ignored.'' 90158f0484fSRodney W. Grimes * -- ANSI X3J11 90258f0484fSRodney W. Grimes */ 90358f0484fSRodney W. Grimes number: if ((dprec = prec) >= 0) 90458f0484fSRodney W. Grimes flags &= ~ZEROPAD; 90558f0484fSRodney W. Grimes 9062e394b2fSAlexey Zelkin /*- 90758f0484fSRodney W. Grimes * ``The result of converting a zero value with an 90858f0484fSRodney W. Grimes * explicit precision of zero is no characters.'' 90958f0484fSRodney W. Grimes * -- ANSI X3J11 91058f0484fSRodney W. Grimes */ 91158f0484fSRodney W. Grimes cp = buf + BUF; 9127735bb0fSBill Fenner if (flags & INTMAX_SIZE) { 9137735bb0fSBill Fenner if (ujval != 0 || prec != 0) 9147735bb0fSBill Fenner cp = __ujtoa(ujval, cp, base, 91598ee7635SAlexey Zelkin flags & ALT, xdigs, 91698ee7635SAlexey Zelkin flags & GROUPING, thousands_sep, 91798ee7635SAlexey Zelkin grouping); 91858f0484fSRodney W. Grimes } else { 91958f0484fSRodney W. Grimes if (ulval != 0 || prec != 0) 92058f0484fSRodney W. Grimes cp = __ultoa(ulval, cp, base, 92198ee7635SAlexey Zelkin flags & ALT, xdigs, 92298ee7635SAlexey Zelkin flags & GROUPING, thousands_sep, 92398ee7635SAlexey Zelkin grouping); 92458f0484fSRodney W. Grimes } 92558f0484fSRodney W. Grimes size = buf + BUF - cp; 92658f0484fSRodney W. Grimes break; 92758f0484fSRodney W. Grimes default: /* "%?" prints ?, unless ? is NUL */ 92858f0484fSRodney W. Grimes if (ch == '\0') 92958f0484fSRodney W. Grimes goto done; 93058f0484fSRodney W. Grimes /* pretend it was %c with argument ch */ 93158f0484fSRodney W. Grimes cp = buf; 93258f0484fSRodney W. Grimes *cp = ch; 93358f0484fSRodney W. Grimes size = 1; 93458f0484fSRodney W. Grimes sign = '\0'; 93558f0484fSRodney W. Grimes break; 93658f0484fSRodney W. Grimes } 93758f0484fSRodney W. Grimes 93858f0484fSRodney W. Grimes /* 93958f0484fSRodney W. Grimes * All reasonable formats wind up here. At this point, `cp' 94058f0484fSRodney W. Grimes * points to a string which (if not flags&LADJUST) should be 94158f0484fSRodney W. Grimes * padded out to `width' places. If flags&ZEROPAD, it should 94258f0484fSRodney W. Grimes * first be prefixed by any sign or other prefix; otherwise, 94358f0484fSRodney W. Grimes * it should be blank padded before the prefix is emitted. 94458f0484fSRodney W. Grimes * After any left-hand padding and prefixing, emit zeroes 94558f0484fSRodney W. Grimes * required by a decimal [diouxX] precision, then print the 94658f0484fSRodney W. Grimes * string proper, then emit zeroes required by any leftover 94758f0484fSRodney W. Grimes * floating precision; finally, if LADJUST, pad with blanks. 94858f0484fSRodney W. Grimes * 94958f0484fSRodney W. Grimes * Compute actual size, so we know how much to pad. 950261a532aSBill Fenner * size excludes decimal prec; realsz includes it. 95158f0484fSRodney W. Grimes */ 952261a532aSBill Fenner realsz = dprec > size ? dprec : size; 95358f0484fSRodney W. Grimes if (sign) 954261a532aSBill Fenner realsz++; 95558f0484fSRodney W. Grimes else if (flags & HEXPREFIX) 956261a532aSBill Fenner realsz += 2; 95758f0484fSRodney W. Grimes 95892e88f87SAndrey A. Chernov prsize = width > realsz ? width : realsz; 959b250f248SAndrey A. Chernov if ((unsigned)ret + prsize > INT_MAX) { 96092e88f87SAndrey A. Chernov ret = EOF; 96192e88f87SAndrey A. Chernov goto error; 96292e88f87SAndrey A. Chernov } 96392e88f87SAndrey A. Chernov 96458f0484fSRodney W. Grimes /* right-adjusting blank padding */ 96558f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == 0) 96658f0484fSRodney W. Grimes PAD(width - realsz, blanks); 96758f0484fSRodney W. Grimes 96858f0484fSRodney W. Grimes /* prefix */ 96958f0484fSRodney W. Grimes if (sign) { 97058f0484fSRodney W. Grimes PRINT(&sign, 1); 97158f0484fSRodney W. Grimes } else if (flags & HEXPREFIX) { 97258f0484fSRodney W. Grimes ox[0] = '0'; 97358f0484fSRodney W. Grimes ox[1] = ch; 97458f0484fSRodney W. Grimes PRINT(ox, 2); 97558f0484fSRodney W. Grimes } 97658f0484fSRodney W. Grimes 97758f0484fSRodney W. Grimes /* right-adjusting zero padding */ 97858f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 97958f0484fSRodney W. Grimes PAD(width - realsz, zeroes); 98058f0484fSRodney W. Grimes 98158f0484fSRodney W. Grimes /* leading zeroes from decimal precision */ 982261a532aSBill Fenner PAD(dprec - size, zeroes); 98358f0484fSRodney W. Grimes 98458f0484fSRodney W. Grimes /* the string or number proper */ 98558f0484fSRodney W. Grimes #ifdef FLOATING_POINT 98658f0484fSRodney W. Grimes if ((flags & FPT) == 0) { 98758f0484fSRodney W. Grimes PRINT(cp, size); 98858f0484fSRodney W. Grimes } else { /* glue together f_p fragments */ 98958f0484fSRodney W. Grimes if (ch >= 'f') { /* 'f' or 'g' */ 99058f0484fSRodney W. Grimes if (_double == 0) { 99158f0484fSRodney W. Grimes /* kludge for __dtoa irregularity */ 99258f0484fSRodney W. Grimes PRINT("0", 1); 9939ad80ab5SAndrey A. Chernov if (expt < ndig || (flags & ALT) != 0) { 9949ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 99558f0484fSRodney W. Grimes PAD(ndig - 1, zeroes); 99658f0484fSRodney W. Grimes } 99758f0484fSRodney W. Grimes } else if (expt <= 0) { 9989ad80ab5SAndrey A. Chernov PRINT("0", 1); 9999ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 100058f0484fSRodney W. Grimes PAD(-expt, zeroes); 100158f0484fSRodney W. Grimes PRINT(cp, ndig); 100258f0484fSRodney W. Grimes } else if (expt >= ndig) { 100358f0484fSRodney W. Grimes PRINT(cp, ndig); 100458f0484fSRodney W. Grimes PAD(expt - ndig, zeroes); 100558f0484fSRodney W. Grimes if (flags & ALT) 10069ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 100758f0484fSRodney W. Grimes } else { 100858f0484fSRodney W. Grimes PRINT(cp, expt); 100958f0484fSRodney W. Grimes cp += expt; 10109ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 101158f0484fSRodney W. Grimes PRINT(cp, ndig-expt); 101258f0484fSRodney W. Grimes } 101358f0484fSRodney W. Grimes } else { /* 'e' or 'E' */ 101458f0484fSRodney W. Grimes if (ndig > 1 || flags & ALT) { 101558f0484fSRodney W. Grimes ox[0] = *cp++; 10169ad80ab5SAndrey A. Chernov ox[1] = *decimal_point; 101758f0484fSRodney W. Grimes PRINT(ox, 2); 1018918bed75SBruce Evans if (_double) { 101958f0484fSRodney W. Grimes PRINT(cp, ndig-1); 102058f0484fSRodney W. Grimes } else /* 0.[0..] */ 102158f0484fSRodney W. Grimes /* __dtoa irregularity */ 102258f0484fSRodney W. Grimes PAD(ndig - 1, zeroes); 102358f0484fSRodney W. Grimes } else /* XeYYY */ 102458f0484fSRodney W. Grimes PRINT(cp, 1); 102558f0484fSRodney W. Grimes PRINT(expstr, expsize); 102658f0484fSRodney W. Grimes } 102758f0484fSRodney W. Grimes } 102858f0484fSRodney W. Grimes #else 102958f0484fSRodney W. Grimes PRINT(cp, size); 103058f0484fSRodney W. Grimes #endif 103158f0484fSRodney W. Grimes /* left-adjusting padding (always blank) */ 103258f0484fSRodney W. Grimes if (flags & LADJUST) 103358f0484fSRodney W. Grimes PAD(width - realsz, blanks); 103458f0484fSRodney W. Grimes 103558f0484fSRodney W. Grimes /* finally, adjust ret */ 103692e88f87SAndrey A. Chernov ret += prsize; 103758f0484fSRodney W. Grimes 103858f0484fSRodney W. Grimes FLUSH(); /* copy out the I/O vectors */ 103958f0484fSRodney W. Grimes } 104058f0484fSRodney W. Grimes done: 104158f0484fSRodney W. Grimes FLUSH(); 104258f0484fSRodney W. Grimes error: 10432ffc61baSTor Egge #ifdef FLOATING_POINT 10442ffc61baSTor Egge if (dtoaresult != NULL) 10452ffc61baSTor Egge free(dtoaresult); 10462ffc61baSTor Egge #endif 1047f70177e7SJulian Elischer if (__sferror(fp)) 1048f70177e7SJulian Elischer ret = EOF; 1049efb7e53dSJordan K. Hubbard if ((argtable != NULL) && (argtable != statargtable)) 1050efb7e53dSJordan K. Hubbard free (argtable); 1051f70177e7SJulian Elischer return (ret); 105258f0484fSRodney W. Grimes /* NOTREACHED */ 105358f0484fSRodney W. Grimes } 105458f0484fSRodney W. Grimes 1055efb7e53dSJordan K. Hubbard /* 1056efb7e53dSJordan K. Hubbard * Find all arguments when a positional parameter is encountered. Returns a 1057efb7e53dSJordan K. Hubbard * table, indexed by argument number, of pointers to each arguments. The 1058efb7e53dSJordan K. Hubbard * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 105942cebaa5SArchie Cobbs * It will be replaces with a malloc-ed one if it overflows. 1060efb7e53dSJordan K. Hubbard */ 1061efb7e53dSJordan K. Hubbard static void 1062a387081cSDoug Rabson __find_arguments (const char *fmt0, va_list ap, union arg **argtable) 1063efb7e53dSJordan K. Hubbard { 1064d201fe46SDaniel Eischen char *fmt; /* format string */ 1065d201fe46SDaniel Eischen int ch; /* character from fmt */ 1066d201fe46SDaniel Eischen int n, n2; /* handy integer (short term usage) */ 1067d201fe46SDaniel Eischen char *cp; /* handy char pointer (short term usage) */ 1068d201fe46SDaniel Eischen int flags; /* flags as above */ 1069efb7e53dSJordan K. Hubbard int width; /* width from format (%8d), or 0 */ 10707735bb0fSBill Fenner enum typeid *typetable; /* table of types */ 10717735bb0fSBill Fenner enum typeid stattypetable [STATIC_ARG_TBL_SIZE]; 1072efb7e53dSJordan K. Hubbard int tablesize; /* current size of type table */ 1073efb7e53dSJordan K. Hubbard int tablemax; /* largest used index in table */ 1074efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 1075efb7e53dSJordan K. Hubbard 1076efb7e53dSJordan K. Hubbard /* 1077efb7e53dSJordan K. Hubbard * Add an argument type to the table, expanding if necessary. 1078efb7e53dSJordan K. Hubbard */ 1079efb7e53dSJordan K. Hubbard #define ADDTYPE(type) \ 1080efb7e53dSJordan K. Hubbard ((nextarg >= tablesize) ? \ 1081efb7e53dSJordan K. Hubbard __grow_type_table(nextarg, &typetable, &tablesize) : 0, \ 108242cebaa5SArchie Cobbs (nextarg > tablemax) ? tablemax = nextarg : 0, \ 108342cebaa5SArchie Cobbs typetable[nextarg++] = type) 1084efb7e53dSJordan K. Hubbard 1085efb7e53dSJordan K. Hubbard #define ADDSARG() \ 10867735bb0fSBill Fenner ((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \ 10877735bb0fSBill Fenner ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 10887735bb0fSBill Fenner ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 10897735bb0fSBill Fenner ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \ 10907735bb0fSBill Fenner ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT)))))) 1091efb7e53dSJordan K. Hubbard 1092efb7e53dSJordan K. Hubbard #define ADDUARG() \ 10937735bb0fSBill Fenner ((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \ 10947735bb0fSBill Fenner ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ 10957735bb0fSBill Fenner ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ 10967735bb0fSBill Fenner ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \ 10977735bb0fSBill Fenner ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT)))))) 1098efb7e53dSJordan K. Hubbard 1099efb7e53dSJordan K. Hubbard /* 1100efb7e53dSJordan K. Hubbard * Add * arguments to the type array. 1101efb7e53dSJordan K. Hubbard */ 1102efb7e53dSJordan K. Hubbard #define ADDASTER() \ 1103efb7e53dSJordan K. Hubbard n2 = 0; \ 1104efb7e53dSJordan K. Hubbard cp = fmt; \ 1105efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 1106efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 1107efb7e53dSJordan K. Hubbard cp++; \ 1108efb7e53dSJordan K. Hubbard } \ 1109efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 1110efb7e53dSJordan K. Hubbard int hold = nextarg; \ 1111efb7e53dSJordan K. Hubbard nextarg = n2; \ 1112efb7e53dSJordan K. Hubbard ADDTYPE (T_INT); \ 1113efb7e53dSJordan K. Hubbard nextarg = hold; \ 1114efb7e53dSJordan K. Hubbard fmt = ++cp; \ 1115efb7e53dSJordan K. Hubbard } else { \ 1116efb7e53dSJordan K. Hubbard ADDTYPE (T_INT); \ 1117efb7e53dSJordan K. Hubbard } 1118efb7e53dSJordan K. Hubbard fmt = (char *)fmt0; 1119efb7e53dSJordan K. Hubbard typetable = stattypetable; 1120efb7e53dSJordan K. Hubbard tablesize = STATIC_ARG_TBL_SIZE; 1121efb7e53dSJordan K. Hubbard tablemax = 0; 1122efb7e53dSJordan K. Hubbard nextarg = 1; 1123efb7e53dSJordan K. Hubbard memset (typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); 1124efb7e53dSJordan K. Hubbard 1125efb7e53dSJordan K. Hubbard /* 1126efb7e53dSJordan K. Hubbard * Scan the format for conversions (`%' character). 1127efb7e53dSJordan K. Hubbard */ 1128efb7e53dSJordan K. Hubbard for (;;) { 1129efb7e53dSJordan K. Hubbard for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 1130efb7e53dSJordan K. Hubbard /* void */; 1131efb7e53dSJordan K. Hubbard if (ch == '\0') 1132efb7e53dSJordan K. Hubbard goto done; 1133efb7e53dSJordan K. Hubbard fmt++; /* skip over '%' */ 1134efb7e53dSJordan K. Hubbard 1135efb7e53dSJordan K. Hubbard flags = 0; 1136efb7e53dSJordan K. Hubbard width = 0; 1137efb7e53dSJordan K. Hubbard 1138efb7e53dSJordan K. Hubbard rflag: ch = *fmt++; 1139efb7e53dSJordan K. Hubbard reswitch: switch (ch) { 1140efb7e53dSJordan K. Hubbard case ' ': 1141efb7e53dSJordan K. Hubbard case '#': 1142efb7e53dSJordan K. Hubbard goto rflag; 1143efb7e53dSJordan K. Hubbard case '*': 1144efb7e53dSJordan K. Hubbard ADDASTER (); 1145efb7e53dSJordan K. Hubbard goto rflag; 1146efb7e53dSJordan K. Hubbard case '-': 1147efb7e53dSJordan K. Hubbard case '+': 11487735bb0fSBill Fenner case '\'': 1149efb7e53dSJordan K. Hubbard goto rflag; 1150efb7e53dSJordan K. Hubbard case '.': 1151efb7e53dSJordan K. Hubbard if ((ch = *fmt++) == '*') { 1152efb7e53dSJordan K. Hubbard ADDASTER (); 1153efb7e53dSJordan K. Hubbard goto rflag; 1154efb7e53dSJordan K. Hubbard } 1155efb7e53dSJordan K. Hubbard while (is_digit(ch)) { 1156efb7e53dSJordan K. Hubbard ch = *fmt++; 1157efb7e53dSJordan K. Hubbard } 1158efb7e53dSJordan K. Hubbard goto reswitch; 1159efb7e53dSJordan K. Hubbard case '0': 1160efb7e53dSJordan K. Hubbard goto rflag; 1161efb7e53dSJordan K. Hubbard case '1': case '2': case '3': case '4': 1162efb7e53dSJordan K. Hubbard case '5': case '6': case '7': case '8': case '9': 1163efb7e53dSJordan K. Hubbard n = 0; 1164efb7e53dSJordan K. Hubbard do { 1165efb7e53dSJordan K. Hubbard n = 10 * n + to_digit(ch); 1166efb7e53dSJordan K. Hubbard ch = *fmt++; 1167efb7e53dSJordan K. Hubbard } while (is_digit(ch)); 1168efb7e53dSJordan K. Hubbard if (ch == '$') { 1169efb7e53dSJordan K. Hubbard nextarg = n; 1170efb7e53dSJordan K. Hubbard goto rflag; 1171efb7e53dSJordan K. Hubbard } 1172efb7e53dSJordan K. Hubbard width = n; 1173efb7e53dSJordan K. Hubbard goto reswitch; 1174efb7e53dSJordan K. Hubbard #ifdef FLOATING_POINT 1175efb7e53dSJordan K. Hubbard case 'L': 1176efb7e53dSJordan K. Hubbard flags |= LONGDBL; 1177efb7e53dSJordan K. Hubbard goto rflag; 1178efb7e53dSJordan K. Hubbard #endif 1179efb7e53dSJordan K. Hubbard case 'h': 11807735bb0fSBill Fenner if (flags & SHORTINT) { 11817735bb0fSBill Fenner flags &= ~SHORTINT; 11827735bb0fSBill Fenner flags |= CHARINT; 11837735bb0fSBill Fenner } else 1184efb7e53dSJordan K. Hubbard flags |= SHORTINT; 1185efb7e53dSJordan K. Hubbard goto rflag; 11867735bb0fSBill Fenner case 'j': 11877735bb0fSBill Fenner flags |= INTMAXT; 11887735bb0fSBill Fenner goto rflag; 1189efb7e53dSJordan K. Hubbard case 'l': 11907735bb0fSBill Fenner if (flags & LONGINT) { 11917735bb0fSBill Fenner flags &= ~LONGINT; 11927735bb0fSBill Fenner flags |= LLONGINT; 11937735bb0fSBill Fenner } else 1194efb7e53dSJordan K. Hubbard flags |= LONGINT; 1195efb7e53dSJordan K. Hubbard goto rflag; 1196efb7e53dSJordan K. Hubbard case 'q': 11977735bb0fSBill Fenner flags |= LLONGINT; /* not necessarily */ 11987735bb0fSBill Fenner goto rflag; 11997735bb0fSBill Fenner case 't': 12007735bb0fSBill Fenner flags |= PTRDIFFT; 12017735bb0fSBill Fenner goto rflag; 12027735bb0fSBill Fenner case 'z': 12037735bb0fSBill Fenner flags |= SIZET; 1204efb7e53dSJordan K. Hubbard goto rflag; 1205efb7e53dSJordan K. Hubbard case 'c': 1206efb7e53dSJordan K. Hubbard ADDTYPE(T_INT); 1207efb7e53dSJordan K. Hubbard break; 1208efb7e53dSJordan K. Hubbard case 'D': 1209efb7e53dSJordan K. Hubbard flags |= LONGINT; 1210efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1211efb7e53dSJordan K. Hubbard case 'd': 1212efb7e53dSJordan K. Hubbard case 'i': 1213efb7e53dSJordan K. Hubbard ADDSARG(); 1214efb7e53dSJordan K. Hubbard break; 1215efb7e53dSJordan K. Hubbard #ifdef FLOATING_POINT 12167735bb0fSBill Fenner #ifdef HEXFLOAT 12177735bb0fSBill Fenner case 'a': 12187735bb0fSBill Fenner case 'A': 12197735bb0fSBill Fenner #endif 1220efb7e53dSJordan K. Hubbard case 'e': 1221efb7e53dSJordan K. Hubbard case 'E': 1222efb7e53dSJordan K. Hubbard case 'f': 1223efb7e53dSJordan K. Hubbard case 'g': 1224efb7e53dSJordan K. Hubbard case 'G': 1225efb7e53dSJordan K. Hubbard if (flags & LONGDBL) 1226efb7e53dSJordan K. Hubbard ADDTYPE(T_LONG_DOUBLE); 1227efb7e53dSJordan K. Hubbard else 1228efb7e53dSJordan K. Hubbard ADDTYPE(T_DOUBLE); 1229efb7e53dSJordan K. Hubbard break; 1230efb7e53dSJordan K. Hubbard #endif /* FLOATING_POINT */ 1231efb7e53dSJordan K. Hubbard case 'n': 12327735bb0fSBill Fenner if (flags & INTMAXT) 12337735bb0fSBill Fenner ADDTYPE(TP_INTMAXT); 12347735bb0fSBill Fenner else if (flags & PTRDIFFT) 12357735bb0fSBill Fenner ADDTYPE(TP_PTRDIFFT); 12367735bb0fSBill Fenner else if (flags & SIZET) 12377735bb0fSBill Fenner ADDTYPE(TP_SIZET); 12387735bb0fSBill Fenner else if (flags & LLONGINT) 12397735bb0fSBill Fenner ADDTYPE(TP_LLONG); 1240efb7e53dSJordan K. Hubbard else if (flags & LONGINT) 1241efb7e53dSJordan K. Hubbard ADDTYPE(TP_LONG); 1242efb7e53dSJordan K. Hubbard else if (flags & SHORTINT) 1243efb7e53dSJordan K. Hubbard ADDTYPE(TP_SHORT); 12447735bb0fSBill Fenner else if (flags & CHARINT) 12457735bb0fSBill Fenner ADDTYPE(TP_SCHAR); 1246efb7e53dSJordan K. Hubbard else 1247efb7e53dSJordan K. Hubbard ADDTYPE(TP_INT); 1248efb7e53dSJordan K. Hubbard continue; /* no output */ 1249efb7e53dSJordan K. Hubbard case 'O': 1250efb7e53dSJordan K. Hubbard flags |= LONGINT; 1251efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1252efb7e53dSJordan K. Hubbard case 'o': 1253efb7e53dSJordan K. Hubbard ADDUARG(); 1254efb7e53dSJordan K. Hubbard break; 1255efb7e53dSJordan K. Hubbard case 'p': 1256efb7e53dSJordan K. Hubbard ADDTYPE(TP_VOID); 1257efb7e53dSJordan K. Hubbard break; 1258efb7e53dSJordan K. Hubbard case 's': 1259efb7e53dSJordan K. Hubbard ADDTYPE(TP_CHAR); 1260efb7e53dSJordan K. Hubbard break; 1261efb7e53dSJordan K. Hubbard case 'U': 1262efb7e53dSJordan K. Hubbard flags |= LONGINT; 1263efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1264efb7e53dSJordan K. Hubbard case 'u': 1265efb7e53dSJordan K. Hubbard case 'X': 1266efb7e53dSJordan K. Hubbard case 'x': 1267efb7e53dSJordan K. Hubbard ADDUARG(); 1268efb7e53dSJordan K. Hubbard break; 1269efb7e53dSJordan K. Hubbard default: /* "%?" prints ?, unless ? is NUL */ 1270efb7e53dSJordan K. Hubbard if (ch == '\0') 1271efb7e53dSJordan K. Hubbard goto done; 1272efb7e53dSJordan K. Hubbard break; 1273efb7e53dSJordan K. Hubbard } 1274efb7e53dSJordan K. Hubbard } 1275efb7e53dSJordan K. Hubbard done: 1276efb7e53dSJordan K. Hubbard /* 1277efb7e53dSJordan K. Hubbard * Build the argument table. 1278efb7e53dSJordan K. Hubbard */ 1279efb7e53dSJordan K. Hubbard if (tablemax >= STATIC_ARG_TBL_SIZE) { 1280a387081cSDoug Rabson *argtable = (union arg *) 1281a387081cSDoug Rabson malloc (sizeof (union arg) * (tablemax + 1)); 1282efb7e53dSJordan K. Hubbard } 1283efb7e53dSJordan K. Hubbard 1284a387081cSDoug Rabson (*argtable) [0].intarg = 0; 1285efb7e53dSJordan K. Hubbard for (n = 1; n <= tablemax; n++) { 1286efb7e53dSJordan K. Hubbard switch (typetable [n]) { 12877735bb0fSBill Fenner case T_UNUSED: /* whoops! */ 1288a387081cSDoug Rabson (*argtable) [n].intarg = va_arg (ap, int); 1289efb7e53dSJordan K. Hubbard break; 12907735bb0fSBill Fenner case TP_SCHAR: 12917735bb0fSBill Fenner (*argtable) [n].pschararg = va_arg (ap, signed char *); 1292efb7e53dSJordan K. Hubbard break; 1293efb7e53dSJordan K. Hubbard case TP_SHORT: 1294a387081cSDoug Rabson (*argtable) [n].pshortarg = va_arg (ap, short *); 1295efb7e53dSJordan K. Hubbard break; 1296efb7e53dSJordan K. Hubbard case T_INT: 1297a387081cSDoug Rabson (*argtable) [n].intarg = va_arg (ap, int); 1298efb7e53dSJordan K. Hubbard break; 1299efb7e53dSJordan K. Hubbard case T_U_INT: 1300a387081cSDoug Rabson (*argtable) [n].uintarg = va_arg (ap, unsigned int); 1301efb7e53dSJordan K. Hubbard break; 1302efb7e53dSJordan K. Hubbard case TP_INT: 1303a387081cSDoug Rabson (*argtable) [n].pintarg = va_arg (ap, int *); 1304efb7e53dSJordan K. Hubbard break; 1305efb7e53dSJordan K. Hubbard case T_LONG: 1306a387081cSDoug Rabson (*argtable) [n].longarg = va_arg (ap, long); 1307efb7e53dSJordan K. Hubbard break; 1308efb7e53dSJordan K. Hubbard case T_U_LONG: 1309a387081cSDoug Rabson (*argtable) [n].ulongarg = va_arg (ap, unsigned long); 1310efb7e53dSJordan K. Hubbard break; 1311efb7e53dSJordan K. Hubbard case TP_LONG: 1312a387081cSDoug Rabson (*argtable) [n].plongarg = va_arg (ap, long *); 1313efb7e53dSJordan K. Hubbard break; 13147735bb0fSBill Fenner case T_LLONG: 13157735bb0fSBill Fenner (*argtable) [n].longlongarg = va_arg (ap, long long); 1316efb7e53dSJordan K. Hubbard break; 13177735bb0fSBill Fenner case T_U_LLONG: 13187735bb0fSBill Fenner (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); 1319efb7e53dSJordan K. Hubbard break; 13207735bb0fSBill Fenner case TP_LLONG: 13217735bb0fSBill Fenner (*argtable) [n].plonglongarg = va_arg (ap, long long *); 13227735bb0fSBill Fenner break; 13237735bb0fSBill Fenner case T_PTRDIFFT: 13247735bb0fSBill Fenner (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); 13257735bb0fSBill Fenner break; 13267735bb0fSBill Fenner case TP_PTRDIFFT: 13277735bb0fSBill Fenner (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); 13287735bb0fSBill Fenner break; 13297735bb0fSBill Fenner case T_SIZET: 13307735bb0fSBill Fenner (*argtable) [n].sizearg = va_arg (ap, size_t); 13317735bb0fSBill Fenner break; 13327735bb0fSBill Fenner case TP_SIZET: 13337735bb0fSBill Fenner (*argtable) [n].psizearg = va_arg (ap, ssize_t *); 13347735bb0fSBill Fenner break; 13357735bb0fSBill Fenner case T_INTMAXT: 13367735bb0fSBill Fenner (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); 13377735bb0fSBill Fenner break; 13387735bb0fSBill Fenner case T_UINTMAXT: 13397735bb0fSBill Fenner (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); 13407735bb0fSBill Fenner break; 13417735bb0fSBill Fenner case TP_INTMAXT: 13427735bb0fSBill Fenner (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); 1343efb7e53dSJordan K. Hubbard break; 1344a387081cSDoug Rabson #ifdef FLOATING_POINT 1345efb7e53dSJordan K. Hubbard case T_DOUBLE: 1346a387081cSDoug Rabson (*argtable) [n].doublearg = va_arg (ap, double); 1347efb7e53dSJordan K. Hubbard break; 1348efb7e53dSJordan K. Hubbard case T_LONG_DOUBLE: 1349a387081cSDoug Rabson (*argtable) [n].longdoublearg = va_arg (ap, long double); 1350efb7e53dSJordan K. Hubbard break; 1351a387081cSDoug Rabson #endif 1352efb7e53dSJordan K. Hubbard case TP_CHAR: 1353a387081cSDoug Rabson (*argtable) [n].pchararg = va_arg (ap, char *); 1354efb7e53dSJordan K. Hubbard break; 1355efb7e53dSJordan K. Hubbard case TP_VOID: 1356a387081cSDoug Rabson (*argtable) [n].pvoidarg = va_arg (ap, void *); 1357efb7e53dSJordan K. Hubbard break; 1358efb7e53dSJordan K. Hubbard } 1359efb7e53dSJordan K. Hubbard } 1360efb7e53dSJordan K. Hubbard 1361efb7e53dSJordan K. Hubbard if ((typetable != NULL) && (typetable != stattypetable)) 1362efb7e53dSJordan K. Hubbard free (typetable); 1363efb7e53dSJordan K. Hubbard } 1364efb7e53dSJordan K. Hubbard 1365efb7e53dSJordan K. Hubbard /* 1366efb7e53dSJordan K. Hubbard * Increase the size of the type table. 1367efb7e53dSJordan K. Hubbard */ 1368efb7e53dSJordan K. Hubbard static void 13697735bb0fSBill Fenner __grow_type_table (int nextarg, enum typeid **typetable, int *tablesize) 1370efb7e53dSJordan K. Hubbard { 13717735bb0fSBill Fenner enum typeid *const oldtable = *typetable; 137242cebaa5SArchie Cobbs const int oldsize = *tablesize; 13737735bb0fSBill Fenner enum typeid *newtable; 137442cebaa5SArchie Cobbs int newsize = oldsize * 2; 1375efb7e53dSJordan K. Hubbard 137642cebaa5SArchie Cobbs if (newsize < nextarg + 1) 137742cebaa5SArchie Cobbs newsize = nextarg + 1; 137842cebaa5SArchie Cobbs if (oldsize == STATIC_ARG_TBL_SIZE) { 137942cebaa5SArchie Cobbs if ((newtable = malloc(newsize)) == NULL) 138042cebaa5SArchie Cobbs abort(); /* XXX handle better */ 138142cebaa5SArchie Cobbs bcopy(oldtable, newtable, oldsize); 1382efb7e53dSJordan K. Hubbard } else { 138342cebaa5SArchie Cobbs if ((newtable = reallocf(oldtable, newsize)) == NULL) 138442cebaa5SArchie Cobbs abort(); /* XXX handle better */ 1385efb7e53dSJordan K. Hubbard } 138642cebaa5SArchie Cobbs memset(&newtable[oldsize], T_UNUSED, newsize - oldsize); 1387efb7e53dSJordan K. Hubbard 138842cebaa5SArchie Cobbs *typetable = newtable; 1389efb7e53dSJordan K. Hubbard *tablesize = newsize; 1390efb7e53dSJordan K. Hubbard } 1391efb7e53dSJordan K. Hubbard 1392efb7e53dSJordan K. Hubbard 139358f0484fSRodney W. Grimes #ifdef FLOATING_POINT 139458f0484fSRodney W. Grimes 13952ffc61baSTor Egge extern char *__dtoa __P((double, int, int, int *, int *, char **, char **)); 139658f0484fSRodney W. Grimes 139758f0484fSRodney W. Grimes static char * 1398d201fe46SDaniel Eischen cvt(double value, int ndigits, int flags, char *sign, int *decpt, 13992ffc61baSTor Egge int ch, int *length, char **dtoaresultp) 140058f0484fSRodney W. Grimes { 140158f0484fSRodney W. Grimes int mode, dsgn; 140258f0484fSRodney W. Grimes char *digits, *bp, *rve; 140358f0484fSRodney W. Grimes 140458f0484fSRodney W. Grimes if (ch == 'f') 1405d26be6f0SBruce Evans mode = 3; /* ndigits after the decimal point */ 140658f0484fSRodney W. Grimes else { 1407d26be6f0SBruce Evans /* 1408d26be6f0SBruce Evans * To obtain ndigits after the decimal point for the 'e' 1409d26be6f0SBruce Evans * and 'E' formats, round to ndigits + 1 significant 1410d26be6f0SBruce Evans * figures. 1411d26be6f0SBruce Evans */ 1412d26be6f0SBruce Evans if (ch == 'e' || ch == 'E') 1413d26be6f0SBruce Evans ndigits++; 1414d26be6f0SBruce Evans mode = 2; /* ndigits significant digits */ 141558f0484fSRodney W. Grimes } 141658f0484fSRodney W. Grimes if (value < 0) { 141758f0484fSRodney W. Grimes value = -value; 141858f0484fSRodney W. Grimes *sign = '-'; 141958f0484fSRodney W. Grimes } else 142058f0484fSRodney W. Grimes *sign = '\000'; 14212ffc61baSTor Egge digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve, 14222ffc61baSTor Egge dtoaresultp); 1423d26be6f0SBruce Evans if ((ch != 'g' && ch != 'G') || flags & ALT) { 1424d26be6f0SBruce Evans /* print trailing zeros */ 142558f0484fSRodney W. Grimes bp = digits + ndigits; 142658f0484fSRodney W. Grimes if (ch == 'f') { 142758f0484fSRodney W. Grimes if (*digits == '0' && value) 142858f0484fSRodney W. Grimes *decpt = -ndigits + 1; 142958f0484fSRodney W. Grimes bp += *decpt; 143058f0484fSRodney W. Grimes } 143158f0484fSRodney W. Grimes if (value == 0) /* kludge for __dtoa irregularity */ 143258f0484fSRodney W. Grimes rve = bp; 143358f0484fSRodney W. Grimes while (rve < bp) 143458f0484fSRodney W. Grimes *rve++ = '0'; 143558f0484fSRodney W. Grimes } 143658f0484fSRodney W. Grimes *length = rve - digits; 143758f0484fSRodney W. Grimes return (digits); 143858f0484fSRodney W. Grimes } 143958f0484fSRodney W. Grimes 144058f0484fSRodney W. Grimes static int 1441d201fe46SDaniel Eischen exponent(char *p0, int exp, int fmtch) 144258f0484fSRodney W. Grimes { 1443d201fe46SDaniel Eischen char *p, *t; 144458f0484fSRodney W. Grimes char expbuf[MAXEXP]; 144558f0484fSRodney W. Grimes 144658f0484fSRodney W. Grimes p = p0; 144758f0484fSRodney W. Grimes *p++ = fmtch; 144858f0484fSRodney W. Grimes if (exp < 0) { 144958f0484fSRodney W. Grimes exp = -exp; 145058f0484fSRodney W. Grimes *p++ = '-'; 145158f0484fSRodney W. Grimes } 145258f0484fSRodney W. Grimes else 145358f0484fSRodney W. Grimes *p++ = '+'; 145458f0484fSRodney W. Grimes t = expbuf + MAXEXP; 145558f0484fSRodney W. Grimes if (exp > 9) { 145658f0484fSRodney W. Grimes do { 145758f0484fSRodney W. Grimes *--t = to_char(exp % 10); 145858f0484fSRodney W. Grimes } while ((exp /= 10) > 9); 145958f0484fSRodney W. Grimes *--t = to_char(exp); 146058f0484fSRodney W. Grimes for (; t < expbuf + MAXEXP; *p++ = *t++); 146158f0484fSRodney W. Grimes } 146258f0484fSRodney W. Grimes else { 146358f0484fSRodney W. Grimes *p++ = '0'; 146458f0484fSRodney W. Grimes *p++ = to_char(exp); 146558f0484fSRodney W. Grimes } 146658f0484fSRodney W. Grimes return (p - p0); 146758f0484fSRodney W. Grimes } 146858f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 1469