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 5458f0484fSRodney W. Grimes #include <limits.h> 5558f0484fSRodney W. Grimes #include <stdio.h> 5658f0484fSRodney W. Grimes #include <stdlib.h> 5758f0484fSRodney W. Grimes #include <string.h> 5858f0484fSRodney W. Grimes 5958f0484fSRodney W. Grimes #if __STDC__ 6058f0484fSRodney W. Grimes #include <stdarg.h> 6158f0484fSRodney W. Grimes #else 6258f0484fSRodney W. Grimes #include <varargs.h> 6358f0484fSRodney W. Grimes #endif 64d201fe46SDaniel Eischen #include "un-namespace.h" 6558f0484fSRodney W. Grimes 66d201fe46SDaniel Eischen #include "libc_private.h" 6758f0484fSRodney W. Grimes #include "local.h" 6858f0484fSRodney W. Grimes #include "fvwrite.h" 6958f0484fSRodney W. Grimes 7058f0484fSRodney W. Grimes /* Define FLOATING_POINT to get floating point. */ 7158f0484fSRodney W. Grimes #define FLOATING_POINT 7258f0484fSRodney W. Grimes 73a387081cSDoug Rabson union arg { 74a387081cSDoug Rabson int intarg; 75a387081cSDoug Rabson unsigned int uintarg; 76a387081cSDoug Rabson long longarg; 77a387081cSDoug Rabson unsigned long ulongarg; 78a387081cSDoug Rabson quad_t quadarg; 79a387081cSDoug Rabson u_quad_t uquadarg; 80a387081cSDoug Rabson void *pvoidarg; 81a387081cSDoug Rabson char *pchararg; 82a387081cSDoug Rabson short *pshortarg; 83a387081cSDoug Rabson int *pintarg; 84a387081cSDoug Rabson long *plongarg; 85a387081cSDoug Rabson quad_t *pquadarg; 86a387081cSDoug Rabson #ifdef FLOATING_POINT 87a387081cSDoug Rabson double doublearg; 88a387081cSDoug Rabson long double longdoublearg; 89a387081cSDoug Rabson #endif 90a387081cSDoug Rabson }; 91a387081cSDoug Rabson 92ce51cf03SJames Raynard static int __sprint __P((FILE *, struct __suio *)); 936dac8ac9SKris Kennaway static int __sbprintf __P((FILE *, const char *, va_list)) __printflike(2, 0); 94ce51cf03SJames Raynard static char * __ultoa __P((u_long, char *, int, int, char *)); 95ce51cf03SJames Raynard static char * __uqtoa __P((u_quad_t, char *, int, int, char *)); 96a387081cSDoug Rabson static void __find_arguments __P((const char *, va_list, union arg **)); 97efb7e53dSJordan K. Hubbard static void __grow_type_table __P((int, unsigned char **, int *)); 98ce51cf03SJames Raynard 9958f0484fSRodney W. Grimes /* 10058f0484fSRodney W. Grimes * Flush out all the vectors defined by the given uio, 10158f0484fSRodney W. Grimes * then reset it so that it can be reused. 10258f0484fSRodney W. Grimes */ 10358f0484fSRodney W. Grimes static int 104d201fe46SDaniel Eischen __sprint(FILE *fp, struct __suio *uio) 10558f0484fSRodney W. Grimes { 106d201fe46SDaniel Eischen int err; 10758f0484fSRodney W. Grimes 10858f0484fSRodney W. Grimes if (uio->uio_resid == 0) { 10958f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 11058f0484fSRodney W. Grimes return (0); 11158f0484fSRodney W. Grimes } 11258f0484fSRodney W. Grimes err = __sfvwrite(fp, uio); 11358f0484fSRodney W. Grimes uio->uio_resid = 0; 11458f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 11558f0484fSRodney W. Grimes return (err); 11658f0484fSRodney W. Grimes } 11758f0484fSRodney W. Grimes 11858f0484fSRodney W. Grimes /* 11958f0484fSRodney W. Grimes * Helper function for `fprintf to unbuffered unix file': creates a 12058f0484fSRodney W. Grimes * temporary buffer. We only work on write-only files; this avoids 12158f0484fSRodney W. Grimes * worries about ungetc buffers and so forth. 12258f0484fSRodney W. Grimes */ 12358f0484fSRodney W. Grimes static int 124d201fe46SDaniel Eischen __sbprintf(FILE *fp, const char *fmt, va_list ap) 12558f0484fSRodney W. Grimes { 12658f0484fSRodney W. Grimes int ret; 12758f0484fSRodney W. Grimes FILE fake; 12858f0484fSRodney W. Grimes unsigned char buf[BUFSIZ]; 12958f0484fSRodney W. Grimes 13058f0484fSRodney W. Grimes /* copy the important variables */ 13158f0484fSRodney W. Grimes fake._flags = fp->_flags & ~__SNBF; 13258f0484fSRodney W. Grimes fake._file = fp->_file; 13358f0484fSRodney W. Grimes fake._cookie = fp->_cookie; 13458f0484fSRodney W. Grimes fake._write = fp->_write; 13558f0484fSRodney W. Grimes 13658f0484fSRodney W. Grimes /* set up the buffer */ 13758f0484fSRodney W. Grimes fake._bf._base = fake._p = buf; 13858f0484fSRodney W. Grimes fake._bf._size = fake._w = sizeof(buf); 13958f0484fSRodney W. Grimes fake._lbfsize = 0; /* not actually used, but Just In Case */ 14058f0484fSRodney W. Grimes 14158f0484fSRodney W. Grimes /* do the work, then copy any error status */ 142d201fe46SDaniel Eischen ret = __vfprintf(&fake, fmt, ap); 143d201fe46SDaniel Eischen if (ret >= 0 && __fflush(&fake)) 14458f0484fSRodney W. Grimes ret = EOF; 14558f0484fSRodney W. Grimes if (fake._flags & __SERR) 14658f0484fSRodney W. Grimes fp->_flags |= __SERR; 14758f0484fSRodney W. Grimes return (ret); 14858f0484fSRodney W. Grimes } 14958f0484fSRodney W. Grimes 15058f0484fSRodney W. Grimes /* 15158f0484fSRodney W. Grimes * Macros for converting digits to letters and vice versa 15258f0484fSRodney W. Grimes */ 15358f0484fSRodney W. Grimes #define to_digit(c) ((c) - '0') 15458f0484fSRodney W. Grimes #define is_digit(c) ((unsigned)to_digit(c) <= 9) 15558f0484fSRodney W. Grimes #define to_char(n) ((n) + '0') 15658f0484fSRodney W. Grimes 15758f0484fSRodney W. Grimes /* 15858f0484fSRodney W. Grimes * Convert an unsigned long to ASCII for printf purposes, returning 15958f0484fSRodney W. Grimes * a pointer to the first character of the string representation. 16058f0484fSRodney W. Grimes * Octal numbers can be forced to have a leading zero; hex numbers 16158f0484fSRodney W. Grimes * use the given digits. 16258f0484fSRodney W. Grimes */ 16358f0484fSRodney W. Grimes static char * 164d201fe46SDaniel Eischen __ultoa(u_long val, char *endp, int base, int octzero, char *xdigs) 16558f0484fSRodney W. Grimes { 16658f0484fSRodney W. Grimes register char *cp = endp; 16758f0484fSRodney W. Grimes register long sval; 16858f0484fSRodney W. Grimes 16958f0484fSRodney W. Grimes /* 17058f0484fSRodney W. Grimes * Handle the three cases separately, in the hope of getting 17158f0484fSRodney W. Grimes * better/faster code. 17258f0484fSRodney W. Grimes */ 17358f0484fSRodney W. Grimes switch (base) { 17458f0484fSRodney W. Grimes case 10: 17558f0484fSRodney W. Grimes if (val < 10) { /* many numbers are 1 digit */ 17658f0484fSRodney W. Grimes *--cp = to_char(val); 17758f0484fSRodney W. Grimes return (cp); 17858f0484fSRodney W. Grimes } 17958f0484fSRodney W. Grimes /* 18058f0484fSRodney W. Grimes * On many machines, unsigned arithmetic is harder than 18158f0484fSRodney W. Grimes * signed arithmetic, so we do at most one unsigned mod and 18258f0484fSRodney W. Grimes * divide; this is sufficient to reduce the range of 18358f0484fSRodney W. Grimes * the incoming value to where signed arithmetic works. 18458f0484fSRodney W. Grimes */ 18558f0484fSRodney W. Grimes if (val > LONG_MAX) { 18658f0484fSRodney W. Grimes *--cp = to_char(val % 10); 18758f0484fSRodney W. Grimes sval = val / 10; 18858f0484fSRodney W. Grimes } else 18958f0484fSRodney W. Grimes sval = val; 19058f0484fSRodney W. Grimes do { 19158f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 19258f0484fSRodney W. Grimes sval /= 10; 19358f0484fSRodney W. Grimes } while (sval != 0); 19458f0484fSRodney W. Grimes break; 19558f0484fSRodney W. Grimes 19658f0484fSRodney W. Grimes case 8: 19758f0484fSRodney W. Grimes do { 19858f0484fSRodney W. Grimes *--cp = to_char(val & 7); 19958f0484fSRodney W. Grimes val >>= 3; 20058f0484fSRodney W. Grimes } while (val); 20158f0484fSRodney W. Grimes if (octzero && *cp != '0') 20258f0484fSRodney W. Grimes *--cp = '0'; 20358f0484fSRodney W. Grimes break; 20458f0484fSRodney W. Grimes 20558f0484fSRodney W. Grimes case 16: 20658f0484fSRodney W. Grimes do { 20758f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 20858f0484fSRodney W. Grimes val >>= 4; 20958f0484fSRodney W. Grimes } while (val); 21058f0484fSRodney W. Grimes break; 21158f0484fSRodney W. Grimes 21258f0484fSRodney W. Grimes default: /* oops */ 21358f0484fSRodney W. Grimes abort(); 21458f0484fSRodney W. Grimes } 21558f0484fSRodney W. Grimes return (cp); 21658f0484fSRodney W. Grimes } 21758f0484fSRodney W. Grimes 21858f0484fSRodney W. Grimes /* Identical to __ultoa, but for quads. */ 21958f0484fSRodney W. Grimes static char * 220d201fe46SDaniel Eischen __uqtoa(u_quad_t val, char *endp, int base, int octzero, char *xdigs) 22158f0484fSRodney W. Grimes { 222d201fe46SDaniel Eischen char *cp = endp; 223d201fe46SDaniel Eischen quad_t sval; 22458f0484fSRodney W. Grimes 22558f0484fSRodney W. Grimes /* quick test for small values; __ultoa is typically much faster */ 22658f0484fSRodney W. Grimes /* (perhaps instead we should run until small, then call __ultoa?) */ 22758f0484fSRodney W. Grimes if (val <= ULONG_MAX) 22858f0484fSRodney W. Grimes return (__ultoa((u_long)val, endp, base, octzero, xdigs)); 22958f0484fSRodney W. Grimes switch (base) { 23058f0484fSRodney W. Grimes case 10: 23158f0484fSRodney W. Grimes if (val < 10) { 23258f0484fSRodney W. Grimes *--cp = to_char(val % 10); 23358f0484fSRodney W. Grimes return (cp); 23458f0484fSRodney W. Grimes } 23558f0484fSRodney W. Grimes if (val > QUAD_MAX) { 23658f0484fSRodney W. Grimes *--cp = to_char(val % 10); 23758f0484fSRodney W. Grimes sval = val / 10; 23858f0484fSRodney W. Grimes } else 23958f0484fSRodney W. Grimes sval = val; 24058f0484fSRodney W. Grimes do { 24158f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 24258f0484fSRodney W. Grimes sval /= 10; 24358f0484fSRodney W. Grimes } while (sval != 0); 24458f0484fSRodney W. Grimes break; 24558f0484fSRodney W. Grimes 24658f0484fSRodney W. Grimes case 8: 24758f0484fSRodney W. Grimes do { 24858f0484fSRodney W. Grimes *--cp = to_char(val & 7); 24958f0484fSRodney W. Grimes val >>= 3; 25058f0484fSRodney W. Grimes } while (val); 25158f0484fSRodney W. Grimes if (octzero && *cp != '0') 25258f0484fSRodney W. Grimes *--cp = '0'; 25358f0484fSRodney W. Grimes break; 25458f0484fSRodney W. Grimes 25558f0484fSRodney W. Grimes case 16: 25658f0484fSRodney W. Grimes do { 25758f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 25858f0484fSRodney W. Grimes val >>= 4; 25958f0484fSRodney W. Grimes } while (val); 26058f0484fSRodney W. Grimes break; 26158f0484fSRodney W. Grimes 26258f0484fSRodney W. Grimes default: 26358f0484fSRodney W. Grimes abort(); 26458f0484fSRodney W. Grimes } 26558f0484fSRodney W. Grimes return (cp); 26658f0484fSRodney W. Grimes } 26758f0484fSRodney W. Grimes 268d201fe46SDaniel Eischen /* 269d201fe46SDaniel Eischen * MT-safe version 270d201fe46SDaniel Eischen */ 271d201fe46SDaniel Eischen int 272d201fe46SDaniel Eischen vfprintf(FILE *fp, const char *fmt0, va_list ap) 273d201fe46SDaniel Eischen { 274d201fe46SDaniel Eischen int ret; 275d201fe46SDaniel Eischen 276d201fe46SDaniel Eischen FLOCKFILE(fp); 277d201fe46SDaniel Eischen ret = __vfprintf(fp, fmt0, ap); 278d201fe46SDaniel Eischen FUNLOCKFILE(fp); 279d201fe46SDaniel Eischen return (ret); 280d201fe46SDaniel Eischen } 281d201fe46SDaniel Eischen 28258f0484fSRodney W. Grimes #ifdef FLOATING_POINT 2839ad80ab5SAndrey A. Chernov #include <locale.h> 28458f0484fSRodney W. Grimes #include <math.h> 28558f0484fSRodney W. Grimes #include "floatio.h" 28658f0484fSRodney W. Grimes 28758f0484fSRodney W. Grimes #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ 28858f0484fSRodney W. Grimes #define DEFPREC 6 28958f0484fSRodney W. Grimes 2902ffc61baSTor Egge static char *cvt __P((double, int, int, char *, int *, int, int *, char **)); 29158f0484fSRodney W. Grimes static int exponent __P((char *, int, int)); 29258f0484fSRodney W. Grimes 29358f0484fSRodney W. Grimes #else /* no FLOATING_POINT */ 29458f0484fSRodney W. Grimes 29558f0484fSRodney W. Grimes #define BUF 68 29658f0484fSRodney W. Grimes 29758f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 29858f0484fSRodney W. Grimes 299efb7e53dSJordan K. Hubbard #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 30058f0484fSRodney W. Grimes 30158f0484fSRodney W. Grimes /* 30258f0484fSRodney W. Grimes * Flags used during conversion. 30358f0484fSRodney W. Grimes */ 30458f0484fSRodney W. Grimes #define ALT 0x001 /* alternate form */ 30558f0484fSRodney W. Grimes #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 30658f0484fSRodney W. Grimes #define LADJUST 0x004 /* left adjustment */ 3076a93659fSBruce Evans #define LONGDBL 0x008 /* long double */ 30858f0484fSRodney W. Grimes #define LONGINT 0x010 /* long integer */ 30958f0484fSRodney W. Grimes #define QUADINT 0x020 /* quad integer */ 31058f0484fSRodney W. Grimes #define SHORTINT 0x040 /* short integer */ 31158f0484fSRodney W. Grimes #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 31258f0484fSRodney W. Grimes #define FPT 0x100 /* Floating point number */ 313d201fe46SDaniel Eischen /* 314d201fe46SDaniel Eischen * Non-MT-safe version 315d201fe46SDaniel Eischen */ 31658f0484fSRodney W. Grimes int 317d201fe46SDaniel Eischen __vfprintf(FILE *fp, const char *fmt0, va_list ap) 31858f0484fSRodney W. Grimes { 319d201fe46SDaniel Eischen char *fmt; /* format string */ 320d201fe46SDaniel Eischen int ch; /* character from fmt */ 321d201fe46SDaniel Eischen int n, n2; /* handy integer (short term usage) */ 322d201fe46SDaniel Eischen char *cp; /* handy char pointer (short term usage) */ 323d201fe46SDaniel Eischen struct __siov *iovp; /* for PRINT macro */ 324d201fe46SDaniel Eischen int flags; /* flags as above */ 32558f0484fSRodney W. Grimes int ret; /* return value accumulator */ 32658f0484fSRodney W. Grimes int width; /* width from format (%8d), or 0 */ 32758f0484fSRodney W. Grimes int prec; /* precision from format (%.3d), or -1 */ 32858f0484fSRodney W. Grimes char sign; /* sign prefix (' ', '+', '-', or \0) */ 32958f0484fSRodney W. Grimes #ifdef FLOATING_POINT 3309ad80ab5SAndrey A. Chernov char *decimal_point = localeconv()->decimal_point; 33158f0484fSRodney W. Grimes char softsign; /* temporary negative sign for floats */ 33258f0484fSRodney W. Grimes double _double; /* double precision arguments %[eEfgG] */ 33358f0484fSRodney W. Grimes int expt; /* integer value of exponent */ 33458f0484fSRodney W. Grimes int expsize; /* character count for expstr */ 33558f0484fSRodney W. Grimes int ndig; /* actual number of digits returned by cvt */ 33658f0484fSRodney W. Grimes char expstr[7]; /* buffer for exponent string */ 3372ffc61baSTor Egge char *dtoaresult; /* buffer allocated by dtoa */ 33858f0484fSRodney W. Grimes #endif 33958f0484fSRodney W. Grimes u_long ulval; /* integer arguments %[diouxX] */ 34058f0484fSRodney W. Grimes u_quad_t uqval; /* %q integers */ 34158f0484fSRodney W. Grimes int base; /* base for [diouxX] conversion */ 34258f0484fSRodney W. Grimes int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 343261a532aSBill Fenner int realsz; /* field size expanded by dprec, sign, etc */ 34458f0484fSRodney W. Grimes int size; /* size of converted field or string */ 34592e88f87SAndrey A. Chernov int prsize; /* max size of printed field */ 34658f0484fSRodney W. Grimes char *xdigs; /* digits for [xX] conversion */ 34758f0484fSRodney W. Grimes #define NIOV 8 34858f0484fSRodney W. Grimes struct __suio uio; /* output information: summary */ 34958f0484fSRodney W. Grimes struct __siov iov[NIOV];/* ... and individual io vectors */ 35058f0484fSRodney W. Grimes char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 35158f0484fSRodney W. Grimes char ox[2]; /* space for 0x hex-prefix */ 352a387081cSDoug Rabson union arg *argtable; /* args, built due to positional arg */ 353a387081cSDoug Rabson union arg statargtable [STATIC_ARG_TBL_SIZE]; 354efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 355efb7e53dSJordan K. Hubbard va_list orgap; /* original argument pointer */ 35658f0484fSRodney W. Grimes 35758f0484fSRodney W. Grimes /* 35858f0484fSRodney W. Grimes * Choose PADSIZE to trade efficiency vs. size. If larger printf 35958f0484fSRodney W. Grimes * fields occur frequently, increase PADSIZE and make the initialisers 36058f0484fSRodney W. Grimes * below longer. 36158f0484fSRodney W. Grimes */ 36258f0484fSRodney W. Grimes #define PADSIZE 16 /* pad chunk size */ 36358f0484fSRodney W. Grimes static char blanks[PADSIZE] = 36458f0484fSRodney W. Grimes {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 36558f0484fSRodney W. Grimes static char zeroes[PADSIZE] = 36658f0484fSRodney W. Grimes {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 36758f0484fSRodney W. Grimes 36858f0484fSRodney W. Grimes /* 36958f0484fSRodney W. Grimes * BEWARE, these `goto error' on error, and PAD uses `n'. 37058f0484fSRodney W. Grimes */ 37158f0484fSRodney W. Grimes #define PRINT(ptr, len) { \ 37258f0484fSRodney W. Grimes iovp->iov_base = (ptr); \ 37358f0484fSRodney W. Grimes iovp->iov_len = (len); \ 37458f0484fSRodney W. Grimes uio.uio_resid += (len); \ 37558f0484fSRodney W. Grimes iovp++; \ 37658f0484fSRodney W. Grimes if (++uio.uio_iovcnt >= NIOV) { \ 37758f0484fSRodney W. Grimes if (__sprint(fp, &uio)) \ 37858f0484fSRodney W. Grimes goto error; \ 37958f0484fSRodney W. Grimes iovp = iov; \ 38058f0484fSRodney W. Grimes } \ 38158f0484fSRodney W. Grimes } 38258f0484fSRodney W. Grimes #define PAD(howmany, with) { \ 38358f0484fSRodney W. Grimes if ((n = (howmany)) > 0) { \ 38458f0484fSRodney W. Grimes while (n > PADSIZE) { \ 38558f0484fSRodney W. Grimes PRINT(with, PADSIZE); \ 38658f0484fSRodney W. Grimes n -= PADSIZE; \ 38758f0484fSRodney W. Grimes } \ 38858f0484fSRodney W. Grimes PRINT(with, n); \ 38958f0484fSRodney W. Grimes } \ 39058f0484fSRodney W. Grimes } 39158f0484fSRodney W. Grimes #define FLUSH() { \ 39258f0484fSRodney W. Grimes if (uio.uio_resid && __sprint(fp, &uio)) \ 39358f0484fSRodney W. Grimes goto error; \ 39458f0484fSRodney W. Grimes uio.uio_iovcnt = 0; \ 39558f0484fSRodney W. Grimes iovp = iov; \ 39658f0484fSRodney W. Grimes } 39758f0484fSRodney W. Grimes 39858f0484fSRodney W. Grimes /* 399efb7e53dSJordan K. Hubbard * Get the argument indexed by nextarg. If the argument table is 400efb7e53dSJordan K. Hubbard * built, use it to get the argument. If its not, get the next 401efb7e53dSJordan K. Hubbard * argument (and arguments must be gotten sequentially). 402efb7e53dSJordan K. Hubbard */ 403efb7e53dSJordan K. Hubbard #define GETARG(type) \ 404a387081cSDoug Rabson ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 405efb7e53dSJordan K. Hubbard (nextarg++, va_arg(ap, type))) 406efb7e53dSJordan K. Hubbard 407efb7e53dSJordan K. Hubbard /* 40858f0484fSRodney W. Grimes * To extend shorts properly, we need both signed and unsigned 40958f0484fSRodney W. Grimes * argument extraction methods. 41058f0484fSRodney W. Grimes */ 41158f0484fSRodney W. Grimes #define SARG() \ 412efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(long) : \ 413efb7e53dSJordan K. Hubbard flags&SHORTINT ? (long)(short)GETARG(int) : \ 414efb7e53dSJordan K. Hubbard (long)GETARG(int)) 41558f0484fSRodney W. Grimes #define UARG() \ 416efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(u_long) : \ 417efb7e53dSJordan K. Hubbard flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 418efb7e53dSJordan K. Hubbard (u_long)GETARG(u_int)) 419efb7e53dSJordan K. Hubbard 420efb7e53dSJordan K. Hubbard /* 421efb7e53dSJordan K. Hubbard * Get * arguments, including the form *nn$. Preserve the nextarg 422efb7e53dSJordan K. Hubbard * that the argument can be gotten once the type is determined. 423efb7e53dSJordan K. Hubbard */ 424efb7e53dSJordan K. Hubbard #define GETASTER(val) \ 425efb7e53dSJordan K. Hubbard n2 = 0; \ 426efb7e53dSJordan K. Hubbard cp = fmt; \ 427efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 428efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 429efb7e53dSJordan K. Hubbard cp++; \ 430efb7e53dSJordan K. Hubbard } \ 431efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 432efb7e53dSJordan K. Hubbard int hold = nextarg; \ 433efb7e53dSJordan K. Hubbard if (argtable == NULL) { \ 434efb7e53dSJordan K. Hubbard argtable = statargtable; \ 435efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, &argtable); \ 436efb7e53dSJordan K. Hubbard } \ 437efb7e53dSJordan K. Hubbard nextarg = n2; \ 438efb7e53dSJordan K. Hubbard val = GETARG (int); \ 439efb7e53dSJordan K. Hubbard nextarg = hold; \ 440efb7e53dSJordan K. Hubbard fmt = ++cp; \ 441efb7e53dSJordan K. Hubbard } else { \ 442efb7e53dSJordan K. Hubbard val = GETARG (int); \ 443efb7e53dSJordan K. Hubbard } 444efb7e53dSJordan K. Hubbard 44558f0484fSRodney W. Grimes 4462ffc61baSTor Egge #ifdef FLOATING_POINT 4472ffc61baSTor Egge dtoaresult = NULL; 4482ffc61baSTor Egge #endif 44958f0484fSRodney W. Grimes /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 450d201fe46SDaniel Eischen if (cantwrite(fp)) 45158f0484fSRodney W. Grimes return (EOF); 45258f0484fSRodney W. Grimes 45358f0484fSRodney W. Grimes /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 45458f0484fSRodney W. Grimes if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 455d201fe46SDaniel Eischen fp->_file >= 0) 45658f0484fSRodney W. Grimes return (__sbprintf(fp, fmt0, ap)); 45758f0484fSRodney W. Grimes 45858f0484fSRodney W. Grimes fmt = (char *)fmt0; 459efb7e53dSJordan K. Hubbard argtable = NULL; 460efb7e53dSJordan K. Hubbard nextarg = 1; 461efb7e53dSJordan K. Hubbard orgap = ap; 46258f0484fSRodney W. Grimes uio.uio_iov = iovp = iov; 46358f0484fSRodney W. Grimes uio.uio_resid = 0; 46458f0484fSRodney W. Grimes uio.uio_iovcnt = 0; 46558f0484fSRodney W. Grimes ret = 0; 46658f0484fSRodney W. Grimes 46758f0484fSRodney W. Grimes /* 46858f0484fSRodney W. Grimes * Scan the format for conversions (`%' character). 46958f0484fSRodney W. Grimes */ 47058f0484fSRodney W. Grimes for (;;) { 47158f0484fSRodney W. Grimes for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 47258f0484fSRodney W. Grimes /* void */; 47358f0484fSRodney W. Grimes if ((n = fmt - cp) != 0) { 474b250f248SAndrey A. Chernov if ((unsigned)ret + n > INT_MAX) { 47592e88f87SAndrey A. Chernov ret = EOF; 47692e88f87SAndrey A. Chernov goto error; 47792e88f87SAndrey A. Chernov } 47858f0484fSRodney W. Grimes PRINT(cp, n); 47958f0484fSRodney W. Grimes ret += n; 48058f0484fSRodney W. Grimes } 48158f0484fSRodney W. Grimes if (ch == '\0') 48258f0484fSRodney W. Grimes goto done; 48358f0484fSRodney W. Grimes fmt++; /* skip over '%' */ 48458f0484fSRodney W. Grimes 48558f0484fSRodney W. Grimes flags = 0; 48658f0484fSRodney W. Grimes dprec = 0; 48758f0484fSRodney W. Grimes width = 0; 48858f0484fSRodney W. Grimes prec = -1; 48958f0484fSRodney W. Grimes sign = '\0'; 49058f0484fSRodney W. Grimes 49158f0484fSRodney W. Grimes rflag: ch = *fmt++; 49258f0484fSRodney W. Grimes reswitch: switch (ch) { 49358f0484fSRodney W. Grimes case ' ': 49458f0484fSRodney W. Grimes /* 49558f0484fSRodney W. Grimes * ``If the space and + flags both appear, the space 49658f0484fSRodney W. Grimes * flag will be ignored.'' 49758f0484fSRodney W. Grimes * -- ANSI X3J11 49858f0484fSRodney W. Grimes */ 49958f0484fSRodney W. Grimes if (!sign) 50058f0484fSRodney W. Grimes sign = ' '; 50158f0484fSRodney W. Grimes goto rflag; 50258f0484fSRodney W. Grimes case '#': 50358f0484fSRodney W. Grimes flags |= ALT; 50458f0484fSRodney W. Grimes goto rflag; 50558f0484fSRodney W. Grimes case '*': 50658f0484fSRodney W. Grimes /* 50758f0484fSRodney W. Grimes * ``A negative field width argument is taken as a 50858f0484fSRodney W. Grimes * - flag followed by a positive field width.'' 50958f0484fSRodney W. Grimes * -- ANSI X3J11 51058f0484fSRodney W. Grimes * They don't exclude field widths read from args. 51158f0484fSRodney W. Grimes */ 512efb7e53dSJordan K. Hubbard GETASTER (width); 513efb7e53dSJordan K. Hubbard if (width >= 0) 51458f0484fSRodney W. Grimes goto rflag; 51558f0484fSRodney W. Grimes width = -width; 51658f0484fSRodney W. Grimes /* FALLTHROUGH */ 51758f0484fSRodney W. Grimes case '-': 51858f0484fSRodney W. Grimes flags |= LADJUST; 51958f0484fSRodney W. Grimes goto rflag; 52058f0484fSRodney W. Grimes case '+': 52158f0484fSRodney W. Grimes sign = '+'; 52258f0484fSRodney W. Grimes goto rflag; 52358f0484fSRodney W. Grimes case '.': 52458f0484fSRodney W. Grimes if ((ch = *fmt++) == '*') { 525efb7e53dSJordan K. Hubbard GETASTER (n); 52658f0484fSRodney W. Grimes prec = n < 0 ? -1 : n; 52758f0484fSRodney W. Grimes goto rflag; 52858f0484fSRodney W. Grimes } 52958f0484fSRodney W. Grimes n = 0; 53058f0484fSRodney W. Grimes while (is_digit(ch)) { 53158f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 53258f0484fSRodney W. Grimes ch = *fmt++; 53358f0484fSRodney W. Grimes } 53458f0484fSRodney W. Grimes prec = n < 0 ? -1 : n; 53558f0484fSRodney W. Grimes goto reswitch; 53658f0484fSRodney W. Grimes case '0': 53758f0484fSRodney W. Grimes /* 53858f0484fSRodney W. Grimes * ``Note that 0 is taken as a flag, not as the 53958f0484fSRodney W. Grimes * beginning of a field width.'' 54058f0484fSRodney W. Grimes * -- ANSI X3J11 54158f0484fSRodney W. Grimes */ 54258f0484fSRodney W. Grimes flags |= ZEROPAD; 54358f0484fSRodney W. Grimes goto rflag; 54458f0484fSRodney W. Grimes case '1': case '2': case '3': case '4': 54558f0484fSRodney W. Grimes case '5': case '6': case '7': case '8': case '9': 54658f0484fSRodney W. Grimes n = 0; 54758f0484fSRodney W. Grimes do { 54858f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 54958f0484fSRodney W. Grimes ch = *fmt++; 55058f0484fSRodney W. Grimes } while (is_digit(ch)); 551efb7e53dSJordan K. Hubbard if (ch == '$') { 552efb7e53dSJordan K. Hubbard nextarg = n; 553efb7e53dSJordan K. Hubbard if (argtable == NULL) { 554efb7e53dSJordan K. Hubbard argtable = statargtable; 555efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, 556efb7e53dSJordan K. Hubbard &argtable); 557efb7e53dSJordan K. Hubbard } 558efb7e53dSJordan K. Hubbard goto rflag; 559efb7e53dSJordan K. Hubbard } 56058f0484fSRodney W. Grimes width = n; 56158f0484fSRodney W. Grimes goto reswitch; 56258f0484fSRodney W. Grimes #ifdef FLOATING_POINT 56358f0484fSRodney W. Grimes case 'L': 56458f0484fSRodney W. Grimes flags |= LONGDBL; 56558f0484fSRodney W. Grimes goto rflag; 56658f0484fSRodney W. Grimes #endif 56758f0484fSRodney W. Grimes case 'h': 56858f0484fSRodney W. Grimes flags |= SHORTINT; 56958f0484fSRodney W. Grimes goto rflag; 57058f0484fSRodney W. Grimes case 'l': 57193263596SDoug Rabson if (flags & LONGINT) 57293263596SDoug Rabson flags |= QUADINT; 57393263596SDoug Rabson else 57458f0484fSRodney W. Grimes flags |= LONGINT; 57558f0484fSRodney W. Grimes goto rflag; 57658f0484fSRodney W. Grimes case 'q': 57758f0484fSRodney W. Grimes flags |= QUADINT; 57858f0484fSRodney W. Grimes goto rflag; 57958f0484fSRodney W. Grimes case 'c': 580efb7e53dSJordan K. Hubbard *(cp = buf) = GETARG(int); 58158f0484fSRodney W. Grimes size = 1; 58258f0484fSRodney W. Grimes sign = '\0'; 58358f0484fSRodney W. Grimes break; 58458f0484fSRodney W. Grimes case 'D': 58558f0484fSRodney W. Grimes flags |= LONGINT; 58658f0484fSRodney W. Grimes /*FALLTHROUGH*/ 58758f0484fSRodney W. Grimes case 'd': 58858f0484fSRodney W. Grimes case 'i': 58958f0484fSRodney W. Grimes if (flags & QUADINT) { 590efb7e53dSJordan K. Hubbard uqval = GETARG(quad_t); 59158f0484fSRodney W. Grimes if ((quad_t)uqval < 0) { 59258f0484fSRodney W. Grimes uqval = -uqval; 59358f0484fSRodney W. Grimes sign = '-'; 59458f0484fSRodney W. Grimes } 59558f0484fSRodney W. Grimes } else { 59658f0484fSRodney W. Grimes ulval = SARG(); 59758f0484fSRodney W. Grimes if ((long)ulval < 0) { 59858f0484fSRodney W. Grimes ulval = -ulval; 59958f0484fSRodney W. Grimes sign = '-'; 60058f0484fSRodney W. Grimes } 60158f0484fSRodney W. Grimes } 60258f0484fSRodney W. Grimes base = 10; 60358f0484fSRodney W. Grimes goto number; 60458f0484fSRodney W. Grimes #ifdef FLOATING_POINT 605d26be6f0SBruce Evans case 'e': 60658f0484fSRodney W. Grimes case 'E': 607d26be6f0SBruce Evans case 'f': 608d26be6f0SBruce Evans goto fp_begin; 60958f0484fSRodney W. Grimes case 'g': 61058f0484fSRodney W. Grimes case 'G': 611d26be6f0SBruce Evans if (prec == 0) 612d26be6f0SBruce Evans prec = 1; 613d26be6f0SBruce Evans fp_begin: if (prec == -1) 61458f0484fSRodney W. Grimes prec = DEFPREC; 615d26be6f0SBruce Evans if (flags & LONGDBL) 6166a93659fSBruce Evans /* XXX this loses precision. */ 617efb7e53dSJordan K. Hubbard _double = (double)GETARG(long double); 618d26be6f0SBruce Evans else 619efb7e53dSJordan K. Hubbard _double = GETARG(double); 62058f0484fSRodney W. Grimes /* do this before tricky precision changes */ 62158f0484fSRodney W. Grimes if (isinf(_double)) { 62258f0484fSRodney W. Grimes if (_double < 0) 62358f0484fSRodney W. Grimes sign = '-'; 62458f0484fSRodney W. Grimes cp = "Inf"; 62558f0484fSRodney W. Grimes size = 3; 62658f0484fSRodney W. Grimes break; 62758f0484fSRodney W. Grimes } 62858f0484fSRodney W. Grimes if (isnan(_double)) { 62958f0484fSRodney W. Grimes cp = "NaN"; 63058f0484fSRodney W. Grimes size = 3; 63158f0484fSRodney W. Grimes break; 63258f0484fSRodney W. Grimes } 63358f0484fSRodney W. Grimes flags |= FPT; 6342ffc61baSTor Egge if (dtoaresult != NULL) { 6352ffc61baSTor Egge free(dtoaresult); 6362ffc61baSTor Egge dtoaresult = NULL; 6372ffc61baSTor Egge } 63858f0484fSRodney W. Grimes cp = cvt(_double, prec, flags, &softsign, 6392ffc61baSTor Egge &expt, ch, &ndig, &dtoaresult); 64058f0484fSRodney W. Grimes if (ch == 'g' || ch == 'G') { 64158f0484fSRodney W. Grimes if (expt <= -4 || expt > prec) 64258f0484fSRodney W. Grimes ch = (ch == 'g') ? 'e' : 'E'; 64358f0484fSRodney W. Grimes else 64458f0484fSRodney W. Grimes ch = 'g'; 64558f0484fSRodney W. Grimes } 64658f0484fSRodney W. Grimes if (ch <= 'e') { /* 'e' or 'E' fmt */ 64758f0484fSRodney W. Grimes --expt; 64858f0484fSRodney W. Grimes expsize = exponent(expstr, expt, ch); 64958f0484fSRodney W. Grimes size = expsize + ndig; 65058f0484fSRodney W. Grimes if (ndig > 1 || flags & ALT) 65158f0484fSRodney W. Grimes ++size; 65258f0484fSRodney W. Grimes } else if (ch == 'f') { /* f fmt */ 65358f0484fSRodney W. Grimes if (expt > 0) { 65458f0484fSRodney W. Grimes size = expt; 65558f0484fSRodney W. Grimes if (prec || flags & ALT) 65658f0484fSRodney W. Grimes size += prec + 1; 65758f0484fSRodney W. Grimes } else /* "0.X" */ 65858f0484fSRodney W. Grimes size = prec + 2; 65958f0484fSRodney W. Grimes } else if (expt >= ndig) { /* fixed g fmt */ 66058f0484fSRodney W. Grimes size = expt; 66158f0484fSRodney W. Grimes if (flags & ALT) 66258f0484fSRodney W. Grimes ++size; 66358f0484fSRodney W. Grimes } else 66458f0484fSRodney W. Grimes size = ndig + (expt > 0 ? 66558f0484fSRodney W. Grimes 1 : 2 - expt); 66658f0484fSRodney W. Grimes 66758f0484fSRodney W. Grimes if (softsign) 66858f0484fSRodney W. Grimes sign = '-'; 66958f0484fSRodney W. Grimes break; 67058f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 67158f0484fSRodney W. Grimes case 'n': 67258f0484fSRodney W. Grimes if (flags & QUADINT) 6736e690ad4SAndrey A. Chernov *GETARG(quad_t *) = ret; 67458f0484fSRodney W. Grimes else if (flags & LONGINT) 6756e690ad4SAndrey A. Chernov *GETARG(long *) = ret; 67658f0484fSRodney W. Grimes else if (flags & SHORTINT) 6776e690ad4SAndrey A. Chernov *GETARG(short *) = ret; 67858f0484fSRodney W. Grimes else 6796e690ad4SAndrey A. Chernov *GETARG(int *) = ret; 68058f0484fSRodney W. Grimes continue; /* no output */ 68158f0484fSRodney W. Grimes case 'O': 68258f0484fSRodney W. Grimes flags |= LONGINT; 68358f0484fSRodney W. Grimes /*FALLTHROUGH*/ 68458f0484fSRodney W. Grimes case 'o': 68558f0484fSRodney W. Grimes if (flags & QUADINT) 686efb7e53dSJordan K. Hubbard uqval = GETARG(u_quad_t); 68758f0484fSRodney W. Grimes else 68858f0484fSRodney W. Grimes ulval = UARG(); 68958f0484fSRodney W. Grimes base = 8; 69058f0484fSRodney W. Grimes goto nosign; 69158f0484fSRodney W. Grimes case 'p': 69258f0484fSRodney W. Grimes /* 69358f0484fSRodney W. Grimes * ``The argument shall be a pointer to void. The 69458f0484fSRodney W. Grimes * value of the pointer is converted to a sequence 69558f0484fSRodney W. Grimes * of printable characters, in an implementation- 69658f0484fSRodney W. Grimes * defined manner.'' 69758f0484fSRodney W. Grimes * -- ANSI X3J11 69858f0484fSRodney W. Grimes */ 699efb7e53dSJordan K. Hubbard ulval = (u_long)GETARG(void *); 70058f0484fSRodney W. Grimes base = 16; 70158f0484fSRodney W. Grimes xdigs = "0123456789abcdef"; 70258f0484fSRodney W. Grimes flags = (flags & ~QUADINT) | HEXPREFIX; 70358f0484fSRodney W. Grimes ch = 'x'; 70458f0484fSRodney W. Grimes goto nosign; 70558f0484fSRodney W. Grimes case 's': 706efb7e53dSJordan K. Hubbard if ((cp = GETARG(char *)) == NULL) 70758f0484fSRodney W. Grimes cp = "(null)"; 70858f0484fSRodney W. Grimes if (prec >= 0) { 70958f0484fSRodney W. Grimes /* 71058f0484fSRodney W. Grimes * can't use strlen; can only look for the 71158f0484fSRodney W. Grimes * NUL in the first `prec' characters, and 71258f0484fSRodney W. Grimes * strlen() will go further. 71358f0484fSRodney W. Grimes */ 714ce51cf03SJames Raynard char *p = memchr(cp, 0, (size_t)prec); 71558f0484fSRodney W. Grimes 71658f0484fSRodney W. Grimes if (p != NULL) { 71758f0484fSRodney W. Grimes size = p - cp; 71858f0484fSRodney W. Grimes if (size > prec) 71958f0484fSRodney W. Grimes size = prec; 72058f0484fSRodney W. Grimes } else 72158f0484fSRodney W. Grimes size = prec; 72258f0484fSRodney W. Grimes } else 72358f0484fSRodney W. Grimes size = strlen(cp); 72458f0484fSRodney W. Grimes sign = '\0'; 72558f0484fSRodney W. Grimes break; 72658f0484fSRodney W. Grimes case 'U': 72758f0484fSRodney W. Grimes flags |= LONGINT; 72858f0484fSRodney W. Grimes /*FALLTHROUGH*/ 72958f0484fSRodney W. Grimes case 'u': 73058f0484fSRodney W. Grimes if (flags & QUADINT) 731efb7e53dSJordan K. Hubbard uqval = GETARG(u_quad_t); 73258f0484fSRodney W. Grimes else 73358f0484fSRodney W. Grimes ulval = UARG(); 73458f0484fSRodney W. Grimes base = 10; 73558f0484fSRodney W. Grimes goto nosign; 73658f0484fSRodney W. Grimes case 'X': 73758f0484fSRodney W. Grimes xdigs = "0123456789ABCDEF"; 73858f0484fSRodney W. Grimes goto hex; 73958f0484fSRodney W. Grimes case 'x': 74058f0484fSRodney W. Grimes xdigs = "0123456789abcdef"; 74158f0484fSRodney W. Grimes hex: if (flags & QUADINT) 742efb7e53dSJordan K. Hubbard uqval = GETARG(u_quad_t); 74358f0484fSRodney W. Grimes else 74458f0484fSRodney W. Grimes ulval = UARG(); 74558f0484fSRodney W. Grimes base = 16; 74658f0484fSRodney W. Grimes /* leading 0x/X only if non-zero */ 74758f0484fSRodney W. Grimes if (flags & ALT && 74858f0484fSRodney W. Grimes (flags & QUADINT ? uqval != 0 : ulval != 0)) 74958f0484fSRodney W. Grimes flags |= HEXPREFIX; 75058f0484fSRodney W. Grimes 75158f0484fSRodney W. Grimes /* unsigned conversions */ 75258f0484fSRodney W. Grimes nosign: sign = '\0'; 75358f0484fSRodney W. Grimes /* 75458f0484fSRodney W. Grimes * ``... diouXx conversions ... if a precision is 75558f0484fSRodney W. Grimes * specified, the 0 flag will be ignored.'' 75658f0484fSRodney W. Grimes * -- ANSI X3J11 75758f0484fSRodney W. Grimes */ 75858f0484fSRodney W. Grimes number: if ((dprec = prec) >= 0) 75958f0484fSRodney W. Grimes flags &= ~ZEROPAD; 76058f0484fSRodney W. Grimes 76158f0484fSRodney W. Grimes /* 76258f0484fSRodney W. Grimes * ``The result of converting a zero value with an 76358f0484fSRodney W. Grimes * explicit precision of zero is no characters.'' 76458f0484fSRodney W. Grimes * -- ANSI X3J11 76558f0484fSRodney W. Grimes */ 76658f0484fSRodney W. Grimes cp = buf + BUF; 76758f0484fSRodney W. Grimes if (flags & QUADINT) { 76858f0484fSRodney W. Grimes if (uqval != 0 || prec != 0) 76958f0484fSRodney W. Grimes cp = __uqtoa(uqval, cp, base, 77058f0484fSRodney W. Grimes flags & ALT, xdigs); 77158f0484fSRodney W. Grimes } else { 77258f0484fSRodney W. Grimes if (ulval != 0 || prec != 0) 77358f0484fSRodney W. Grimes cp = __ultoa(ulval, cp, base, 77458f0484fSRodney W. Grimes flags & ALT, xdigs); 77558f0484fSRodney W. Grimes } 77658f0484fSRodney W. Grimes size = buf + BUF - cp; 77758f0484fSRodney W. Grimes break; 77858f0484fSRodney W. Grimes default: /* "%?" prints ?, unless ? is NUL */ 77958f0484fSRodney W. Grimes if (ch == '\0') 78058f0484fSRodney W. Grimes goto done; 78158f0484fSRodney W. Grimes /* pretend it was %c with argument ch */ 78258f0484fSRodney W. Grimes cp = buf; 78358f0484fSRodney W. Grimes *cp = ch; 78458f0484fSRodney W. Grimes size = 1; 78558f0484fSRodney W. Grimes sign = '\0'; 78658f0484fSRodney W. Grimes break; 78758f0484fSRodney W. Grimes } 78858f0484fSRodney W. Grimes 78958f0484fSRodney W. Grimes /* 79058f0484fSRodney W. Grimes * All reasonable formats wind up here. At this point, `cp' 79158f0484fSRodney W. Grimes * points to a string which (if not flags&LADJUST) should be 79258f0484fSRodney W. Grimes * padded out to `width' places. If flags&ZEROPAD, it should 79358f0484fSRodney W. Grimes * first be prefixed by any sign or other prefix; otherwise, 79458f0484fSRodney W. Grimes * it should be blank padded before the prefix is emitted. 79558f0484fSRodney W. Grimes * After any left-hand padding and prefixing, emit zeroes 79658f0484fSRodney W. Grimes * required by a decimal [diouxX] precision, then print the 79758f0484fSRodney W. Grimes * string proper, then emit zeroes required by any leftover 79858f0484fSRodney W. Grimes * floating precision; finally, if LADJUST, pad with blanks. 79958f0484fSRodney W. Grimes * 80058f0484fSRodney W. Grimes * Compute actual size, so we know how much to pad. 801261a532aSBill Fenner * size excludes decimal prec; realsz includes it. 80258f0484fSRodney W. Grimes */ 803261a532aSBill Fenner realsz = dprec > size ? dprec : size; 80458f0484fSRodney W. Grimes if (sign) 805261a532aSBill Fenner realsz++; 80658f0484fSRodney W. Grimes else if (flags & HEXPREFIX) 807261a532aSBill Fenner realsz += 2; 80858f0484fSRodney W. Grimes 80992e88f87SAndrey A. Chernov prsize = width > realsz ? width : realsz; 810b250f248SAndrey A. Chernov if ((unsigned)ret + prsize > INT_MAX) { 81192e88f87SAndrey A. Chernov ret = EOF; 81292e88f87SAndrey A. Chernov goto error; 81392e88f87SAndrey A. Chernov } 81492e88f87SAndrey A. Chernov 81558f0484fSRodney W. Grimes /* right-adjusting blank padding */ 81658f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == 0) 81758f0484fSRodney W. Grimes PAD(width - realsz, blanks); 81858f0484fSRodney W. Grimes 81958f0484fSRodney W. Grimes /* prefix */ 82058f0484fSRodney W. Grimes if (sign) { 82158f0484fSRodney W. Grimes PRINT(&sign, 1); 82258f0484fSRodney W. Grimes } else if (flags & HEXPREFIX) { 82358f0484fSRodney W. Grimes ox[0] = '0'; 82458f0484fSRodney W. Grimes ox[1] = ch; 82558f0484fSRodney W. Grimes PRINT(ox, 2); 82658f0484fSRodney W. Grimes } 82758f0484fSRodney W. Grimes 82858f0484fSRodney W. Grimes /* right-adjusting zero padding */ 82958f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 83058f0484fSRodney W. Grimes PAD(width - realsz, zeroes); 83158f0484fSRodney W. Grimes 83258f0484fSRodney W. Grimes /* leading zeroes from decimal precision */ 833261a532aSBill Fenner PAD(dprec - size, zeroes); 83458f0484fSRodney W. Grimes 83558f0484fSRodney W. Grimes /* the string or number proper */ 83658f0484fSRodney W. Grimes #ifdef FLOATING_POINT 83758f0484fSRodney W. Grimes if ((flags & FPT) == 0) { 83858f0484fSRodney W. Grimes PRINT(cp, size); 83958f0484fSRodney W. Grimes } else { /* glue together f_p fragments */ 84058f0484fSRodney W. Grimes if (ch >= 'f') { /* 'f' or 'g' */ 84158f0484fSRodney W. Grimes if (_double == 0) { 84258f0484fSRodney W. Grimes /* kludge for __dtoa irregularity */ 84358f0484fSRodney W. Grimes PRINT("0", 1); 8449ad80ab5SAndrey A. Chernov if (expt < ndig || (flags & ALT) != 0) { 8459ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 84658f0484fSRodney W. Grimes PAD(ndig - 1, zeroes); 84758f0484fSRodney W. Grimes } 84858f0484fSRodney W. Grimes } else if (expt <= 0) { 8499ad80ab5SAndrey A. Chernov PRINT("0", 1); 8509ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 85158f0484fSRodney W. Grimes PAD(-expt, zeroes); 85258f0484fSRodney W. Grimes PRINT(cp, ndig); 85358f0484fSRodney W. Grimes } else if (expt >= ndig) { 85458f0484fSRodney W. Grimes PRINT(cp, ndig); 85558f0484fSRodney W. Grimes PAD(expt - ndig, zeroes); 85658f0484fSRodney W. Grimes if (flags & ALT) 8579ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 85858f0484fSRodney W. Grimes } else { 85958f0484fSRodney W. Grimes PRINT(cp, expt); 86058f0484fSRodney W. Grimes cp += expt; 8619ad80ab5SAndrey A. Chernov PRINT(decimal_point, 1); 86258f0484fSRodney W. Grimes PRINT(cp, ndig-expt); 86358f0484fSRodney W. Grimes } 86458f0484fSRodney W. Grimes } else { /* 'e' or 'E' */ 86558f0484fSRodney W. Grimes if (ndig > 1 || flags & ALT) { 86658f0484fSRodney W. Grimes ox[0] = *cp++; 8679ad80ab5SAndrey A. Chernov ox[1] = *decimal_point; 86858f0484fSRodney W. Grimes PRINT(ox, 2); 869918bed75SBruce Evans if (_double) { 87058f0484fSRodney W. Grimes PRINT(cp, ndig-1); 87158f0484fSRodney W. Grimes } else /* 0.[0..] */ 87258f0484fSRodney W. Grimes /* __dtoa irregularity */ 87358f0484fSRodney W. Grimes PAD(ndig - 1, zeroes); 87458f0484fSRodney W. Grimes } else /* XeYYY */ 87558f0484fSRodney W. Grimes PRINT(cp, 1); 87658f0484fSRodney W. Grimes PRINT(expstr, expsize); 87758f0484fSRodney W. Grimes } 87858f0484fSRodney W. Grimes } 87958f0484fSRodney W. Grimes #else 88058f0484fSRodney W. Grimes PRINT(cp, size); 88158f0484fSRodney W. Grimes #endif 88258f0484fSRodney W. Grimes /* left-adjusting padding (always blank) */ 88358f0484fSRodney W. Grimes if (flags & LADJUST) 88458f0484fSRodney W. Grimes PAD(width - realsz, blanks); 88558f0484fSRodney W. Grimes 88658f0484fSRodney W. Grimes /* finally, adjust ret */ 88792e88f87SAndrey A. Chernov ret += prsize; 88858f0484fSRodney W. Grimes 88958f0484fSRodney W. Grimes FLUSH(); /* copy out the I/O vectors */ 89058f0484fSRodney W. Grimes } 89158f0484fSRodney W. Grimes done: 89258f0484fSRodney W. Grimes FLUSH(); 89358f0484fSRodney W. Grimes error: 8942ffc61baSTor Egge #ifdef FLOATING_POINT 8952ffc61baSTor Egge if (dtoaresult != NULL) 8962ffc61baSTor Egge free(dtoaresult); 8972ffc61baSTor Egge #endif 898f70177e7SJulian Elischer if (__sferror(fp)) 899f70177e7SJulian Elischer ret = EOF; 900efb7e53dSJordan K. Hubbard if ((argtable != NULL) && (argtable != statargtable)) 901efb7e53dSJordan K. Hubbard free (argtable); 902f70177e7SJulian Elischer return (ret); 90358f0484fSRodney W. Grimes /* NOTREACHED */ 90458f0484fSRodney W. Grimes } 90558f0484fSRodney W. Grimes 906efb7e53dSJordan K. Hubbard /* 907efb7e53dSJordan K. Hubbard * Type ids for argument type table. 908efb7e53dSJordan K. Hubbard */ 909efb7e53dSJordan K. Hubbard #define T_UNUSED 0 910efb7e53dSJordan K. Hubbard #define T_SHORT 1 911efb7e53dSJordan K. Hubbard #define T_U_SHORT 2 912efb7e53dSJordan K. Hubbard #define TP_SHORT 3 913efb7e53dSJordan K. Hubbard #define T_INT 4 914efb7e53dSJordan K. Hubbard #define T_U_INT 5 915efb7e53dSJordan K. Hubbard #define TP_INT 6 916efb7e53dSJordan K. Hubbard #define T_LONG 7 917efb7e53dSJordan K. Hubbard #define T_U_LONG 8 918efb7e53dSJordan K. Hubbard #define TP_LONG 9 919efb7e53dSJordan K. Hubbard #define T_QUAD 10 920efb7e53dSJordan K. Hubbard #define T_U_QUAD 11 921efb7e53dSJordan K. Hubbard #define TP_QUAD 12 922efb7e53dSJordan K. Hubbard #define T_DOUBLE 13 923efb7e53dSJordan K. Hubbard #define T_LONG_DOUBLE 14 924efb7e53dSJordan K. Hubbard #define TP_CHAR 15 925efb7e53dSJordan K. Hubbard #define TP_VOID 16 926efb7e53dSJordan K. Hubbard 927efb7e53dSJordan K. Hubbard /* 928efb7e53dSJordan K. Hubbard * Find all arguments when a positional parameter is encountered. Returns a 929efb7e53dSJordan K. Hubbard * table, indexed by argument number, of pointers to each arguments. The 930efb7e53dSJordan K. Hubbard * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 93142cebaa5SArchie Cobbs * It will be replaces with a malloc-ed one if it overflows. 932efb7e53dSJordan K. Hubbard */ 933efb7e53dSJordan K. Hubbard static void 934a387081cSDoug Rabson __find_arguments (const char *fmt0, va_list ap, union arg **argtable) 935efb7e53dSJordan K. Hubbard { 936d201fe46SDaniel Eischen char *fmt; /* format string */ 937d201fe46SDaniel Eischen int ch; /* character from fmt */ 938d201fe46SDaniel Eischen int n, n2; /* handy integer (short term usage) */ 939d201fe46SDaniel Eischen char *cp; /* handy char pointer (short term usage) */ 940d201fe46SDaniel Eischen int flags; /* flags as above */ 941efb7e53dSJordan K. Hubbard int width; /* width from format (%8d), or 0 */ 942efb7e53dSJordan K. Hubbard unsigned char *typetable; /* table of types */ 943efb7e53dSJordan K. Hubbard unsigned char stattypetable [STATIC_ARG_TBL_SIZE]; 944efb7e53dSJordan K. Hubbard int tablesize; /* current size of type table */ 945efb7e53dSJordan K. Hubbard int tablemax; /* largest used index in table */ 946efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 947efb7e53dSJordan K. Hubbard 948efb7e53dSJordan K. Hubbard /* 949efb7e53dSJordan K. Hubbard * Add an argument type to the table, expanding if necessary. 950efb7e53dSJordan K. Hubbard */ 951efb7e53dSJordan K. Hubbard #define ADDTYPE(type) \ 952efb7e53dSJordan K. Hubbard ((nextarg >= tablesize) ? \ 953efb7e53dSJordan K. Hubbard __grow_type_table(nextarg, &typetable, &tablesize) : 0, \ 95442cebaa5SArchie Cobbs (nextarg > tablemax) ? tablemax = nextarg : 0, \ 95542cebaa5SArchie Cobbs typetable[nextarg++] = type) 956efb7e53dSJordan K. Hubbard 957efb7e53dSJordan K. Hubbard #define ADDSARG() \ 958efb7e53dSJordan K. Hubbard ((flags&LONGINT) ? ADDTYPE(T_LONG) : \ 959efb7e53dSJordan K. Hubbard ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT))) 960efb7e53dSJordan K. Hubbard 961efb7e53dSJordan K. Hubbard #define ADDUARG() \ 962efb7e53dSJordan K. Hubbard ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \ 963efb7e53dSJordan K. Hubbard ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT))) 964efb7e53dSJordan K. Hubbard 965efb7e53dSJordan K. Hubbard /* 966efb7e53dSJordan K. Hubbard * Add * arguments to the type array. 967efb7e53dSJordan K. Hubbard */ 968efb7e53dSJordan K. Hubbard #define ADDASTER() \ 969efb7e53dSJordan K. Hubbard n2 = 0; \ 970efb7e53dSJordan K. Hubbard cp = fmt; \ 971efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 972efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 973efb7e53dSJordan K. Hubbard cp++; \ 974efb7e53dSJordan K. Hubbard } \ 975efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 976efb7e53dSJordan K. Hubbard int hold = nextarg; \ 977efb7e53dSJordan K. Hubbard nextarg = n2; \ 978efb7e53dSJordan K. Hubbard ADDTYPE (T_INT); \ 979efb7e53dSJordan K. Hubbard nextarg = hold; \ 980efb7e53dSJordan K. Hubbard fmt = ++cp; \ 981efb7e53dSJordan K. Hubbard } else { \ 982efb7e53dSJordan K. Hubbard ADDTYPE (T_INT); \ 983efb7e53dSJordan K. Hubbard } 984efb7e53dSJordan K. Hubbard fmt = (char *)fmt0; 985efb7e53dSJordan K. Hubbard typetable = stattypetable; 986efb7e53dSJordan K. Hubbard tablesize = STATIC_ARG_TBL_SIZE; 987efb7e53dSJordan K. Hubbard tablemax = 0; 988efb7e53dSJordan K. Hubbard nextarg = 1; 989efb7e53dSJordan K. Hubbard memset (typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); 990efb7e53dSJordan K. Hubbard 991efb7e53dSJordan K. Hubbard /* 992efb7e53dSJordan K. Hubbard * Scan the format for conversions (`%' character). 993efb7e53dSJordan K. Hubbard */ 994efb7e53dSJordan K. Hubbard for (;;) { 995efb7e53dSJordan K. Hubbard for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 996efb7e53dSJordan K. Hubbard /* void */; 997efb7e53dSJordan K. Hubbard if (ch == '\0') 998efb7e53dSJordan K. Hubbard goto done; 999efb7e53dSJordan K. Hubbard fmt++; /* skip over '%' */ 1000efb7e53dSJordan K. Hubbard 1001efb7e53dSJordan K. Hubbard flags = 0; 1002efb7e53dSJordan K. Hubbard width = 0; 1003efb7e53dSJordan K. Hubbard 1004efb7e53dSJordan K. Hubbard rflag: ch = *fmt++; 1005efb7e53dSJordan K. Hubbard reswitch: switch (ch) { 1006efb7e53dSJordan K. Hubbard case ' ': 1007efb7e53dSJordan K. Hubbard case '#': 1008efb7e53dSJordan K. Hubbard goto rflag; 1009efb7e53dSJordan K. Hubbard case '*': 1010efb7e53dSJordan K. Hubbard ADDASTER (); 1011efb7e53dSJordan K. Hubbard goto rflag; 1012efb7e53dSJordan K. Hubbard case '-': 1013efb7e53dSJordan K. Hubbard case '+': 1014efb7e53dSJordan K. Hubbard goto rflag; 1015efb7e53dSJordan K. Hubbard case '.': 1016efb7e53dSJordan K. Hubbard if ((ch = *fmt++) == '*') { 1017efb7e53dSJordan K. Hubbard ADDASTER (); 1018efb7e53dSJordan K. Hubbard goto rflag; 1019efb7e53dSJordan K. Hubbard } 1020efb7e53dSJordan K. Hubbard while (is_digit(ch)) { 1021efb7e53dSJordan K. Hubbard ch = *fmt++; 1022efb7e53dSJordan K. Hubbard } 1023efb7e53dSJordan K. Hubbard goto reswitch; 1024efb7e53dSJordan K. Hubbard case '0': 1025efb7e53dSJordan K. Hubbard goto rflag; 1026efb7e53dSJordan K. Hubbard case '1': case '2': case '3': case '4': 1027efb7e53dSJordan K. Hubbard case '5': case '6': case '7': case '8': case '9': 1028efb7e53dSJordan K. Hubbard n = 0; 1029efb7e53dSJordan K. Hubbard do { 1030efb7e53dSJordan K. Hubbard n = 10 * n + to_digit(ch); 1031efb7e53dSJordan K. Hubbard ch = *fmt++; 1032efb7e53dSJordan K. Hubbard } while (is_digit(ch)); 1033efb7e53dSJordan K. Hubbard if (ch == '$') { 1034efb7e53dSJordan K. Hubbard nextarg = n; 1035efb7e53dSJordan K. Hubbard goto rflag; 1036efb7e53dSJordan K. Hubbard } 1037efb7e53dSJordan K. Hubbard width = n; 1038efb7e53dSJordan K. Hubbard goto reswitch; 1039efb7e53dSJordan K. Hubbard #ifdef FLOATING_POINT 1040efb7e53dSJordan K. Hubbard case 'L': 1041efb7e53dSJordan K. Hubbard flags |= LONGDBL; 1042efb7e53dSJordan K. Hubbard goto rflag; 1043efb7e53dSJordan K. Hubbard #endif 1044efb7e53dSJordan K. Hubbard case 'h': 1045efb7e53dSJordan K. Hubbard flags |= SHORTINT; 1046efb7e53dSJordan K. Hubbard goto rflag; 1047efb7e53dSJordan K. Hubbard case 'l': 104893263596SDoug Rabson if (flags & LONGINT) 104993263596SDoug Rabson flags |= QUADINT; 105093263596SDoug Rabson else 1051efb7e53dSJordan K. Hubbard flags |= LONGINT; 1052efb7e53dSJordan K. Hubbard goto rflag; 1053efb7e53dSJordan K. Hubbard case 'q': 1054efb7e53dSJordan K. Hubbard flags |= QUADINT; 1055efb7e53dSJordan K. Hubbard goto rflag; 1056efb7e53dSJordan K. Hubbard case 'c': 1057efb7e53dSJordan K. Hubbard ADDTYPE(T_INT); 1058efb7e53dSJordan K. Hubbard break; 1059efb7e53dSJordan K. Hubbard case 'D': 1060efb7e53dSJordan K. Hubbard flags |= LONGINT; 1061efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1062efb7e53dSJordan K. Hubbard case 'd': 1063efb7e53dSJordan K. Hubbard case 'i': 1064efb7e53dSJordan K. Hubbard if (flags & QUADINT) { 1065efb7e53dSJordan K. Hubbard ADDTYPE(T_QUAD); 1066efb7e53dSJordan K. Hubbard } else { 1067efb7e53dSJordan K. Hubbard ADDSARG(); 1068efb7e53dSJordan K. Hubbard } 1069efb7e53dSJordan K. Hubbard break; 1070efb7e53dSJordan K. Hubbard #ifdef FLOATING_POINT 1071efb7e53dSJordan K. Hubbard case 'e': 1072efb7e53dSJordan K. Hubbard case 'E': 1073efb7e53dSJordan K. Hubbard case 'f': 1074efb7e53dSJordan K. Hubbard case 'g': 1075efb7e53dSJordan K. Hubbard case 'G': 1076efb7e53dSJordan K. Hubbard if (flags & LONGDBL) 1077efb7e53dSJordan K. Hubbard ADDTYPE(T_LONG_DOUBLE); 1078efb7e53dSJordan K. Hubbard else 1079efb7e53dSJordan K. Hubbard ADDTYPE(T_DOUBLE); 1080efb7e53dSJordan K. Hubbard break; 1081efb7e53dSJordan K. Hubbard #endif /* FLOATING_POINT */ 1082efb7e53dSJordan K. Hubbard case 'n': 1083efb7e53dSJordan K. Hubbard if (flags & QUADINT) 1084efb7e53dSJordan K. Hubbard ADDTYPE(TP_QUAD); 1085efb7e53dSJordan K. Hubbard else if (flags & LONGINT) 1086efb7e53dSJordan K. Hubbard ADDTYPE(TP_LONG); 1087efb7e53dSJordan K. Hubbard else if (flags & SHORTINT) 1088efb7e53dSJordan K. Hubbard ADDTYPE(TP_SHORT); 1089efb7e53dSJordan K. Hubbard else 1090efb7e53dSJordan K. Hubbard ADDTYPE(TP_INT); 1091efb7e53dSJordan K. Hubbard continue; /* no output */ 1092efb7e53dSJordan K. Hubbard case 'O': 1093efb7e53dSJordan K. Hubbard flags |= LONGINT; 1094efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1095efb7e53dSJordan K. Hubbard case 'o': 1096efb7e53dSJordan K. Hubbard if (flags & QUADINT) 1097efb7e53dSJordan K. Hubbard ADDTYPE(T_U_QUAD); 1098efb7e53dSJordan K. Hubbard else 1099efb7e53dSJordan K. Hubbard ADDUARG(); 1100efb7e53dSJordan K. Hubbard break; 1101efb7e53dSJordan K. Hubbard case 'p': 1102efb7e53dSJordan K. Hubbard ADDTYPE(TP_VOID); 1103efb7e53dSJordan K. Hubbard break; 1104efb7e53dSJordan K. Hubbard case 's': 1105efb7e53dSJordan K. Hubbard ADDTYPE(TP_CHAR); 1106efb7e53dSJordan K. Hubbard break; 1107efb7e53dSJordan K. Hubbard case 'U': 1108efb7e53dSJordan K. Hubbard flags |= LONGINT; 1109efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1110efb7e53dSJordan K. Hubbard case 'u': 1111efb7e53dSJordan K. Hubbard if (flags & QUADINT) 1112efb7e53dSJordan K. Hubbard ADDTYPE(T_U_QUAD); 1113efb7e53dSJordan K. Hubbard else 1114efb7e53dSJordan K. Hubbard ADDUARG(); 1115efb7e53dSJordan K. Hubbard break; 1116efb7e53dSJordan K. Hubbard case 'X': 1117efb7e53dSJordan K. Hubbard case 'x': 1118efb7e53dSJordan K. Hubbard if (flags & QUADINT) 1119efb7e53dSJordan K. Hubbard ADDTYPE(T_U_QUAD); 1120efb7e53dSJordan K. Hubbard else 1121efb7e53dSJordan K. Hubbard ADDUARG(); 1122efb7e53dSJordan K. Hubbard break; 1123efb7e53dSJordan K. Hubbard default: /* "%?" prints ?, unless ? is NUL */ 1124efb7e53dSJordan K. Hubbard if (ch == '\0') 1125efb7e53dSJordan K. Hubbard goto done; 1126efb7e53dSJordan K. Hubbard break; 1127efb7e53dSJordan K. Hubbard } 1128efb7e53dSJordan K. Hubbard } 1129efb7e53dSJordan K. Hubbard done: 1130efb7e53dSJordan K. Hubbard /* 1131efb7e53dSJordan K. Hubbard * Build the argument table. 1132efb7e53dSJordan K. Hubbard */ 1133efb7e53dSJordan K. Hubbard if (tablemax >= STATIC_ARG_TBL_SIZE) { 1134a387081cSDoug Rabson *argtable = (union arg *) 1135a387081cSDoug Rabson malloc (sizeof (union arg) * (tablemax + 1)); 1136efb7e53dSJordan K. Hubbard } 1137efb7e53dSJordan K. Hubbard 1138a387081cSDoug Rabson (*argtable) [0].intarg = 0; 1139efb7e53dSJordan K. Hubbard for (n = 1; n <= tablemax; n++) { 1140efb7e53dSJordan K. Hubbard switch (typetable [n]) { 1141efb7e53dSJordan K. Hubbard case T_UNUSED: 1142a387081cSDoug Rabson (*argtable) [n].intarg = va_arg (ap, int); 1143efb7e53dSJordan K. Hubbard break; 1144efb7e53dSJordan K. Hubbard case T_SHORT: 1145a387081cSDoug Rabson (*argtable) [n].intarg = va_arg (ap, int); 1146efb7e53dSJordan K. Hubbard break; 1147efb7e53dSJordan K. Hubbard case T_U_SHORT: 1148a387081cSDoug Rabson (*argtable) [n].intarg = va_arg (ap, int); 1149efb7e53dSJordan K. Hubbard break; 1150efb7e53dSJordan K. Hubbard case TP_SHORT: 1151a387081cSDoug Rabson (*argtable) [n].pshortarg = va_arg (ap, short *); 1152efb7e53dSJordan K. Hubbard break; 1153efb7e53dSJordan K. Hubbard case T_INT: 1154a387081cSDoug Rabson (*argtable) [n].intarg = va_arg (ap, int); 1155efb7e53dSJordan K. Hubbard break; 1156efb7e53dSJordan K. Hubbard case T_U_INT: 1157a387081cSDoug Rabson (*argtable) [n].uintarg = va_arg (ap, unsigned int); 1158efb7e53dSJordan K. Hubbard break; 1159efb7e53dSJordan K. Hubbard case TP_INT: 1160a387081cSDoug Rabson (*argtable) [n].pintarg = va_arg (ap, int *); 1161efb7e53dSJordan K. Hubbard break; 1162efb7e53dSJordan K. Hubbard case T_LONG: 1163a387081cSDoug Rabson (*argtable) [n].longarg = va_arg (ap, long); 1164efb7e53dSJordan K. Hubbard break; 1165efb7e53dSJordan K. Hubbard case T_U_LONG: 1166a387081cSDoug Rabson (*argtable) [n].ulongarg = va_arg (ap, unsigned long); 1167efb7e53dSJordan K. Hubbard break; 1168efb7e53dSJordan K. Hubbard case TP_LONG: 1169a387081cSDoug Rabson (*argtable) [n].plongarg = va_arg (ap, long *); 1170efb7e53dSJordan K. Hubbard break; 1171efb7e53dSJordan K. Hubbard case T_QUAD: 1172a387081cSDoug Rabson (*argtable) [n].quadarg = va_arg (ap, quad_t); 1173efb7e53dSJordan K. Hubbard break; 1174efb7e53dSJordan K. Hubbard case T_U_QUAD: 1175a387081cSDoug Rabson (*argtable) [n].uquadarg = va_arg (ap, u_quad_t); 1176efb7e53dSJordan K. Hubbard break; 1177efb7e53dSJordan K. Hubbard case TP_QUAD: 1178a387081cSDoug Rabson (*argtable) [n].pquadarg = va_arg (ap, quad_t *); 1179efb7e53dSJordan K. Hubbard break; 1180a387081cSDoug Rabson #ifdef FLOATING_POINT 1181efb7e53dSJordan K. Hubbard case T_DOUBLE: 1182a387081cSDoug Rabson (*argtable) [n].doublearg = va_arg (ap, double); 1183efb7e53dSJordan K. Hubbard break; 1184efb7e53dSJordan K. Hubbard case T_LONG_DOUBLE: 1185a387081cSDoug Rabson (*argtable) [n].longdoublearg = va_arg (ap, long double); 1186efb7e53dSJordan K. Hubbard break; 1187a387081cSDoug Rabson #endif 1188efb7e53dSJordan K. Hubbard case TP_CHAR: 1189a387081cSDoug Rabson (*argtable) [n].pchararg = va_arg (ap, char *); 1190efb7e53dSJordan K. Hubbard break; 1191efb7e53dSJordan K. Hubbard case TP_VOID: 1192a387081cSDoug Rabson (*argtable) [n].pvoidarg = va_arg (ap, void *); 1193efb7e53dSJordan K. Hubbard break; 1194efb7e53dSJordan K. Hubbard } 1195efb7e53dSJordan K. Hubbard } 1196efb7e53dSJordan K. Hubbard 1197efb7e53dSJordan K. Hubbard if ((typetable != NULL) && (typetable != stattypetable)) 1198efb7e53dSJordan K. Hubbard free (typetable); 1199efb7e53dSJordan K. Hubbard } 1200efb7e53dSJordan K. Hubbard 1201efb7e53dSJordan K. Hubbard /* 1202efb7e53dSJordan K. Hubbard * Increase the size of the type table. 1203efb7e53dSJordan K. Hubbard */ 1204efb7e53dSJordan K. Hubbard static void 1205d201fe46SDaniel Eischen __grow_type_table (int nextarg, unsigned char **typetable, int *tablesize) 1206efb7e53dSJordan K. Hubbard { 120742cebaa5SArchie Cobbs unsigned char *const oldtable = *typetable; 120842cebaa5SArchie Cobbs const int oldsize = *tablesize; 120942cebaa5SArchie Cobbs unsigned char *newtable; 121042cebaa5SArchie Cobbs int newsize = oldsize * 2; 1211efb7e53dSJordan K. Hubbard 121242cebaa5SArchie Cobbs if (newsize < nextarg + 1) 121342cebaa5SArchie Cobbs newsize = nextarg + 1; 121442cebaa5SArchie Cobbs if (oldsize == STATIC_ARG_TBL_SIZE) { 121542cebaa5SArchie Cobbs if ((newtable = malloc(newsize)) == NULL) 121642cebaa5SArchie Cobbs abort(); /* XXX handle better */ 121742cebaa5SArchie Cobbs bcopy(oldtable, newtable, oldsize); 1218efb7e53dSJordan K. Hubbard } else { 121942cebaa5SArchie Cobbs if ((newtable = reallocf(oldtable, newsize)) == NULL) 122042cebaa5SArchie Cobbs abort(); /* XXX handle better */ 1221efb7e53dSJordan K. Hubbard } 122242cebaa5SArchie Cobbs memset(&newtable[oldsize], T_UNUSED, newsize - oldsize); 1223efb7e53dSJordan K. Hubbard 122442cebaa5SArchie Cobbs *typetable = newtable; 1225efb7e53dSJordan K. Hubbard *tablesize = newsize; 1226efb7e53dSJordan K. Hubbard } 1227efb7e53dSJordan K. Hubbard 1228efb7e53dSJordan K. Hubbard 122958f0484fSRodney W. Grimes #ifdef FLOATING_POINT 123058f0484fSRodney W. Grimes 12312ffc61baSTor Egge extern char *__dtoa __P((double, int, int, int *, int *, char **, char **)); 123258f0484fSRodney W. Grimes 123358f0484fSRodney W. Grimes static char * 1234d201fe46SDaniel Eischen cvt(double value, int ndigits, int flags, char *sign, int *decpt, 12352ffc61baSTor Egge int ch, int *length, char **dtoaresultp) 123658f0484fSRodney W. Grimes { 123758f0484fSRodney W. Grimes int mode, dsgn; 123858f0484fSRodney W. Grimes char *digits, *bp, *rve; 123958f0484fSRodney W. Grimes 124058f0484fSRodney W. Grimes if (ch == 'f') 1241d26be6f0SBruce Evans mode = 3; /* ndigits after the decimal point */ 124258f0484fSRodney W. Grimes else { 1243d26be6f0SBruce Evans /* 1244d26be6f0SBruce Evans * To obtain ndigits after the decimal point for the 'e' 1245d26be6f0SBruce Evans * and 'E' formats, round to ndigits + 1 significant 1246d26be6f0SBruce Evans * figures. 1247d26be6f0SBruce Evans */ 1248d26be6f0SBruce Evans if (ch == 'e' || ch == 'E') 1249d26be6f0SBruce Evans ndigits++; 1250d26be6f0SBruce Evans mode = 2; /* ndigits significant digits */ 125158f0484fSRodney W. Grimes } 125258f0484fSRodney W. Grimes if (value < 0) { 125358f0484fSRodney W. Grimes value = -value; 125458f0484fSRodney W. Grimes *sign = '-'; 125558f0484fSRodney W. Grimes } else 125658f0484fSRodney W. Grimes *sign = '\000'; 12572ffc61baSTor Egge digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve, 12582ffc61baSTor Egge dtoaresultp); 1259d26be6f0SBruce Evans if ((ch != 'g' && ch != 'G') || flags & ALT) { 1260d26be6f0SBruce Evans /* print trailing zeros */ 126158f0484fSRodney W. Grimes bp = digits + ndigits; 126258f0484fSRodney W. Grimes if (ch == 'f') { 126358f0484fSRodney W. Grimes if (*digits == '0' && value) 126458f0484fSRodney W. Grimes *decpt = -ndigits + 1; 126558f0484fSRodney W. Grimes bp += *decpt; 126658f0484fSRodney W. Grimes } 126758f0484fSRodney W. Grimes if (value == 0) /* kludge for __dtoa irregularity */ 126858f0484fSRodney W. Grimes rve = bp; 126958f0484fSRodney W. Grimes while (rve < bp) 127058f0484fSRodney W. Grimes *rve++ = '0'; 127158f0484fSRodney W. Grimes } 127258f0484fSRodney W. Grimes *length = rve - digits; 127358f0484fSRodney W. Grimes return (digits); 127458f0484fSRodney W. Grimes } 127558f0484fSRodney W. Grimes 127658f0484fSRodney W. Grimes static int 1277d201fe46SDaniel Eischen exponent(char *p0, int exp, int fmtch) 127858f0484fSRodney W. Grimes { 1279d201fe46SDaniel Eischen char *p, *t; 128058f0484fSRodney W. Grimes char expbuf[MAXEXP]; 128158f0484fSRodney W. Grimes 128258f0484fSRodney W. Grimes p = p0; 128358f0484fSRodney W. Grimes *p++ = fmtch; 128458f0484fSRodney W. Grimes if (exp < 0) { 128558f0484fSRodney W. Grimes exp = -exp; 128658f0484fSRodney W. Grimes *p++ = '-'; 128758f0484fSRodney W. Grimes } 128858f0484fSRodney W. Grimes else 128958f0484fSRodney W. Grimes *p++ = '+'; 129058f0484fSRodney W. Grimes t = expbuf + MAXEXP; 129158f0484fSRodney W. Grimes if (exp > 9) { 129258f0484fSRodney W. Grimes do { 129358f0484fSRodney W. Grimes *--t = to_char(exp % 10); 129458f0484fSRodney W. Grimes } while ((exp /= 10) > 9); 129558f0484fSRodney W. Grimes *--t = to_char(exp); 129658f0484fSRodney W. Grimes for (; t < expbuf + MAXEXP; *p++ = *t++); 129758f0484fSRodney W. Grimes } 129858f0484fSRodney W. Grimes else { 129958f0484fSRodney W. Grimes *p++ = '0'; 130058f0484fSRodney W. Grimes *p++ = to_char(exp); 130158f0484fSRodney W. Grimes } 130258f0484fSRodney W. Grimes return (p - p0); 130358f0484fSRodney W. Grimes } 130458f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 1305