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[] = 4292e88f87SAndrey A. Chernov "$Id: vfprintf.c,v 1.15 1997/12/24 23:02:43 ache Exp $"; 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 5158f0484fSRodney W. Grimes #include <sys/types.h> 5258f0484fSRodney W. Grimes 5358f0484fSRodney W. Grimes #include <limits.h> 5458f0484fSRodney W. Grimes #include <stdio.h> 5558f0484fSRodney W. Grimes #include <stdlib.h> 5658f0484fSRodney W. Grimes #include <string.h> 5758f0484fSRodney W. Grimes 5858f0484fSRodney W. Grimes #if __STDC__ 5958f0484fSRodney W. Grimes #include <stdarg.h> 6058f0484fSRodney W. Grimes #else 6158f0484fSRodney W. Grimes #include <varargs.h> 6258f0484fSRodney W. Grimes #endif 6358f0484fSRodney W. Grimes 6458f0484fSRodney W. Grimes #include "local.h" 6558f0484fSRodney W. Grimes #include "fvwrite.h" 66f70177e7SJulian Elischer #ifdef _THREAD_SAFE 67f70177e7SJulian Elischer #include <pthread.h> 68f70177e7SJulian Elischer #include "pthread_private.h" 69f70177e7SJulian Elischer #endif 7058f0484fSRodney W. Grimes 7158f0484fSRodney W. Grimes /* Define FLOATING_POINT to get floating point. */ 7258f0484fSRodney W. Grimes #define FLOATING_POINT 7358f0484fSRodney W. Grimes 74ce51cf03SJames Raynard static int __sprint __P((FILE *, struct __suio *)); 75ce51cf03SJames Raynard static int __sbprintf __P((FILE *, const char *, va_list)); 76ce51cf03SJames Raynard static char * __ultoa __P((u_long, char *, int, int, char *)); 77ce51cf03SJames Raynard static char * __uqtoa __P((u_quad_t, char *, int, int, char *)); 78efb7e53dSJordan K. Hubbard static void __find_arguments __P((const char *, va_list, void ***)); 79efb7e53dSJordan K. Hubbard static void __grow_type_table __P((int, unsigned char **, int *)); 80ce51cf03SJames Raynard 8158f0484fSRodney W. Grimes /* 8258f0484fSRodney W. Grimes * Flush out all the vectors defined by the given uio, 8358f0484fSRodney W. Grimes * then reset it so that it can be reused. 8458f0484fSRodney W. Grimes */ 8558f0484fSRodney W. Grimes static int 8658f0484fSRodney W. Grimes __sprint(fp, uio) 8758f0484fSRodney W. Grimes FILE *fp; 8858f0484fSRodney W. Grimes register struct __suio *uio; 8958f0484fSRodney W. Grimes { 9058f0484fSRodney W. Grimes register int err; 9158f0484fSRodney W. Grimes 9258f0484fSRodney W. Grimes if (uio->uio_resid == 0) { 9358f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 9458f0484fSRodney W. Grimes return (0); 9558f0484fSRodney W. Grimes } 9658f0484fSRodney W. Grimes err = __sfvwrite(fp, uio); 9758f0484fSRodney W. Grimes uio->uio_resid = 0; 9858f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 9958f0484fSRodney W. Grimes return (err); 10058f0484fSRodney W. Grimes } 10158f0484fSRodney W. Grimes 10258f0484fSRodney W. Grimes /* 10358f0484fSRodney W. Grimes * Helper function for `fprintf to unbuffered unix file': creates a 10458f0484fSRodney W. Grimes * temporary buffer. We only work on write-only files; this avoids 10558f0484fSRodney W. Grimes * worries about ungetc buffers and so forth. 10658f0484fSRodney W. Grimes */ 10758f0484fSRodney W. Grimes static int 10858f0484fSRodney W. Grimes __sbprintf(fp, fmt, ap) 10958f0484fSRodney W. Grimes register FILE *fp; 11058f0484fSRodney W. Grimes const char *fmt; 11158f0484fSRodney W. Grimes va_list ap; 11258f0484fSRodney W. Grimes { 11358f0484fSRodney W. Grimes int ret; 11458f0484fSRodney W. Grimes FILE fake; 11558f0484fSRodney W. Grimes unsigned char buf[BUFSIZ]; 11658f0484fSRodney W. Grimes 11758f0484fSRodney W. Grimes /* copy the important variables */ 11858f0484fSRodney W. Grimes fake._flags = fp->_flags & ~__SNBF; 11958f0484fSRodney W. Grimes fake._file = fp->_file; 12058f0484fSRodney W. Grimes fake._cookie = fp->_cookie; 12158f0484fSRodney W. Grimes fake._write = fp->_write; 12258f0484fSRodney W. Grimes 12358f0484fSRodney W. Grimes /* set up the buffer */ 12458f0484fSRodney W. Grimes fake._bf._base = fake._p = buf; 12558f0484fSRodney W. Grimes fake._bf._size = fake._w = sizeof(buf); 12658f0484fSRodney W. Grimes fake._lbfsize = 0; /* not actually used, but Just In Case */ 12758f0484fSRodney W. Grimes 12858f0484fSRodney W. Grimes /* do the work, then copy any error status */ 12958f0484fSRodney W. Grimes ret = vfprintf(&fake, fmt, ap); 13058f0484fSRodney W. Grimes if (ret >= 0 && fflush(&fake)) 13158f0484fSRodney W. Grimes ret = EOF; 13258f0484fSRodney W. Grimes if (fake._flags & __SERR) 13358f0484fSRodney W. Grimes fp->_flags |= __SERR; 13458f0484fSRodney W. Grimes return (ret); 13558f0484fSRodney W. Grimes } 13658f0484fSRodney W. Grimes 13758f0484fSRodney W. Grimes /* 13858f0484fSRodney W. Grimes * Macros for converting digits to letters and vice versa 13958f0484fSRodney W. Grimes */ 14058f0484fSRodney W. Grimes #define to_digit(c) ((c) - '0') 14158f0484fSRodney W. Grimes #define is_digit(c) ((unsigned)to_digit(c) <= 9) 14258f0484fSRodney W. Grimes #define to_char(n) ((n) + '0') 14358f0484fSRodney W. Grimes 14458f0484fSRodney W. Grimes /* 14558f0484fSRodney W. Grimes * Convert an unsigned long to ASCII for printf purposes, returning 14658f0484fSRodney W. Grimes * a pointer to the first character of the string representation. 14758f0484fSRodney W. Grimes * Octal numbers can be forced to have a leading zero; hex numbers 14858f0484fSRodney W. Grimes * use the given digits. 14958f0484fSRodney W. Grimes */ 15058f0484fSRodney W. Grimes static char * 15158f0484fSRodney W. Grimes __ultoa(val, endp, base, octzero, xdigs) 15258f0484fSRodney W. Grimes register u_long val; 15358f0484fSRodney W. Grimes char *endp; 15458f0484fSRodney W. Grimes int base, octzero; 15558f0484fSRodney W. Grimes char *xdigs; 15658f0484fSRodney W. Grimes { 15758f0484fSRodney W. Grimes register char *cp = endp; 15858f0484fSRodney W. Grimes register long sval; 15958f0484fSRodney W. Grimes 16058f0484fSRodney W. Grimes /* 16158f0484fSRodney W. Grimes * Handle the three cases separately, in the hope of getting 16258f0484fSRodney W. Grimes * better/faster code. 16358f0484fSRodney W. Grimes */ 16458f0484fSRodney W. Grimes switch (base) { 16558f0484fSRodney W. Grimes case 10: 16658f0484fSRodney W. Grimes if (val < 10) { /* many numbers are 1 digit */ 16758f0484fSRodney W. Grimes *--cp = to_char(val); 16858f0484fSRodney W. Grimes return (cp); 16958f0484fSRodney W. Grimes } 17058f0484fSRodney W. Grimes /* 17158f0484fSRodney W. Grimes * On many machines, unsigned arithmetic is harder than 17258f0484fSRodney W. Grimes * signed arithmetic, so we do at most one unsigned mod and 17358f0484fSRodney W. Grimes * divide; this is sufficient to reduce the range of 17458f0484fSRodney W. Grimes * the incoming value to where signed arithmetic works. 17558f0484fSRodney W. Grimes */ 17658f0484fSRodney W. Grimes if (val > LONG_MAX) { 17758f0484fSRodney W. Grimes *--cp = to_char(val % 10); 17858f0484fSRodney W. Grimes sval = val / 10; 17958f0484fSRodney W. Grimes } else 18058f0484fSRodney W. Grimes sval = val; 18158f0484fSRodney W. Grimes do { 18258f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 18358f0484fSRodney W. Grimes sval /= 10; 18458f0484fSRodney W. Grimes } while (sval != 0); 18558f0484fSRodney W. Grimes break; 18658f0484fSRodney W. Grimes 18758f0484fSRodney W. Grimes case 8: 18858f0484fSRodney W. Grimes do { 18958f0484fSRodney W. Grimes *--cp = to_char(val & 7); 19058f0484fSRodney W. Grimes val >>= 3; 19158f0484fSRodney W. Grimes } while (val); 19258f0484fSRodney W. Grimes if (octzero && *cp != '0') 19358f0484fSRodney W. Grimes *--cp = '0'; 19458f0484fSRodney W. Grimes break; 19558f0484fSRodney W. Grimes 19658f0484fSRodney W. Grimes case 16: 19758f0484fSRodney W. Grimes do { 19858f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 19958f0484fSRodney W. Grimes val >>= 4; 20058f0484fSRodney W. Grimes } while (val); 20158f0484fSRodney W. Grimes break; 20258f0484fSRodney W. Grimes 20358f0484fSRodney W. Grimes default: /* oops */ 20458f0484fSRodney W. Grimes abort(); 20558f0484fSRodney W. Grimes } 20658f0484fSRodney W. Grimes return (cp); 20758f0484fSRodney W. Grimes } 20858f0484fSRodney W. Grimes 20958f0484fSRodney W. Grimes /* Identical to __ultoa, but for quads. */ 21058f0484fSRodney W. Grimes static char * 21158f0484fSRodney W. Grimes __uqtoa(val, endp, base, octzero, xdigs) 21258f0484fSRodney W. Grimes register u_quad_t val; 21358f0484fSRodney W. Grimes char *endp; 21458f0484fSRodney W. Grimes int base, octzero; 21558f0484fSRodney W. Grimes char *xdigs; 21658f0484fSRodney W. Grimes { 21758f0484fSRodney W. Grimes register char *cp = endp; 21858f0484fSRodney W. Grimes register quad_t sval; 21958f0484fSRodney W. Grimes 22058f0484fSRodney W. Grimes /* quick test for small values; __ultoa is typically much faster */ 22158f0484fSRodney W. Grimes /* (perhaps instead we should run until small, then call __ultoa?) */ 22258f0484fSRodney W. Grimes if (val <= ULONG_MAX) 22358f0484fSRodney W. Grimes return (__ultoa((u_long)val, endp, base, octzero, xdigs)); 22458f0484fSRodney W. Grimes switch (base) { 22558f0484fSRodney W. Grimes case 10: 22658f0484fSRodney W. Grimes if (val < 10) { 22758f0484fSRodney W. Grimes *--cp = to_char(val % 10); 22858f0484fSRodney W. Grimes return (cp); 22958f0484fSRodney W. Grimes } 23058f0484fSRodney W. Grimes if (val > QUAD_MAX) { 23158f0484fSRodney W. Grimes *--cp = to_char(val % 10); 23258f0484fSRodney W. Grimes sval = val / 10; 23358f0484fSRodney W. Grimes } else 23458f0484fSRodney W. Grimes sval = val; 23558f0484fSRodney W. Grimes do { 23658f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 23758f0484fSRodney W. Grimes sval /= 10; 23858f0484fSRodney W. Grimes } while (sval != 0); 23958f0484fSRodney W. Grimes break; 24058f0484fSRodney W. Grimes 24158f0484fSRodney W. Grimes case 8: 24258f0484fSRodney W. Grimes do { 24358f0484fSRodney W. Grimes *--cp = to_char(val & 7); 24458f0484fSRodney W. Grimes val >>= 3; 24558f0484fSRodney W. Grimes } while (val); 24658f0484fSRodney W. Grimes if (octzero && *cp != '0') 24758f0484fSRodney W. Grimes *--cp = '0'; 24858f0484fSRodney W. Grimes break; 24958f0484fSRodney W. Grimes 25058f0484fSRodney W. Grimes case 16: 25158f0484fSRodney W. Grimes do { 25258f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 25358f0484fSRodney W. Grimes val >>= 4; 25458f0484fSRodney W. Grimes } while (val); 25558f0484fSRodney W. Grimes break; 25658f0484fSRodney W. Grimes 25758f0484fSRodney W. Grimes default: 25858f0484fSRodney W. Grimes abort(); 25958f0484fSRodney W. Grimes } 26058f0484fSRodney W. Grimes return (cp); 26158f0484fSRodney W. Grimes } 26258f0484fSRodney W. Grimes 26358f0484fSRodney W. Grimes #ifdef FLOATING_POINT 26458f0484fSRodney W. Grimes #include <math.h> 26558f0484fSRodney W. Grimes #include "floatio.h" 26658f0484fSRodney W. Grimes 26758f0484fSRodney W. Grimes #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ 26858f0484fSRodney W. Grimes #define DEFPREC 6 26958f0484fSRodney W. Grimes 27058f0484fSRodney W. Grimes static char *cvt __P((double, int, int, char *, int *, int, int *)); 27158f0484fSRodney W. Grimes static int exponent __P((char *, int, int)); 27258f0484fSRodney W. Grimes 27358f0484fSRodney W. Grimes #else /* no FLOATING_POINT */ 27458f0484fSRodney W. Grimes 27558f0484fSRodney W. Grimes #define BUF 68 27658f0484fSRodney W. Grimes 27758f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 27858f0484fSRodney W. Grimes 279efb7e53dSJordan K. Hubbard #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 28058f0484fSRodney W. Grimes 28158f0484fSRodney W. Grimes /* 28258f0484fSRodney W. Grimes * Flags used during conversion. 28358f0484fSRodney W. Grimes */ 28458f0484fSRodney W. Grimes #define ALT 0x001 /* alternate form */ 28558f0484fSRodney W. Grimes #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 28658f0484fSRodney W. Grimes #define LADJUST 0x004 /* left adjustment */ 2876a93659fSBruce Evans #define LONGDBL 0x008 /* long double */ 28858f0484fSRodney W. Grimes #define LONGINT 0x010 /* long integer */ 28958f0484fSRodney W. Grimes #define QUADINT 0x020 /* quad integer */ 29058f0484fSRodney W. Grimes #define SHORTINT 0x040 /* short integer */ 29158f0484fSRodney W. Grimes #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 29258f0484fSRodney W. Grimes #define FPT 0x100 /* Floating point number */ 29358f0484fSRodney W. Grimes int 29458f0484fSRodney W. Grimes vfprintf(fp, fmt0, ap) 29558f0484fSRodney W. Grimes FILE *fp; 29658f0484fSRodney W. Grimes const char *fmt0; 29758f0484fSRodney W. Grimes va_list ap; 29858f0484fSRodney W. Grimes { 29958f0484fSRodney W. Grimes register char *fmt; /* format string */ 30058f0484fSRodney W. Grimes register int ch; /* character from fmt */ 301efb7e53dSJordan K. Hubbard register int n, n2; /* handy integer (short term usage) */ 30258f0484fSRodney W. Grimes register char *cp; /* handy char pointer (short term usage) */ 30358f0484fSRodney W. Grimes register struct __siov *iovp;/* for PRINT macro */ 30458f0484fSRodney W. Grimes register int flags; /* flags as above */ 30558f0484fSRodney W. Grimes int ret; /* return value accumulator */ 30658f0484fSRodney W. Grimes int width; /* width from format (%8d), or 0 */ 30758f0484fSRodney W. Grimes int prec; /* precision from format (%.3d), or -1 */ 30858f0484fSRodney W. Grimes char sign; /* sign prefix (' ', '+', '-', or \0) */ 30958f0484fSRodney W. Grimes #ifdef FLOATING_POINT 31058f0484fSRodney W. Grimes char softsign; /* temporary negative sign for floats */ 31158f0484fSRodney W. Grimes double _double; /* double precision arguments %[eEfgG] */ 31258f0484fSRodney W. Grimes int expt; /* integer value of exponent */ 31358f0484fSRodney W. Grimes int expsize; /* character count for expstr */ 31458f0484fSRodney W. Grimes int ndig; /* actual number of digits returned by cvt */ 31558f0484fSRodney W. Grimes char expstr[7]; /* buffer for exponent string */ 31658f0484fSRodney W. Grimes #endif 31758f0484fSRodney W. Grimes u_long ulval; /* integer arguments %[diouxX] */ 31858f0484fSRodney W. Grimes u_quad_t uqval; /* %q integers */ 31958f0484fSRodney W. Grimes int base; /* base for [diouxX] conversion */ 32058f0484fSRodney W. Grimes int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 321261a532aSBill Fenner int realsz; /* field size expanded by dprec, sign, etc */ 32258f0484fSRodney W. Grimes int size; /* size of converted field or string */ 32392e88f87SAndrey A. Chernov int prsize; /* max size of printed field */ 32458f0484fSRodney W. Grimes char *xdigs; /* digits for [xX] conversion */ 32558f0484fSRodney W. Grimes #define NIOV 8 32658f0484fSRodney W. Grimes struct __suio uio; /* output information: summary */ 32758f0484fSRodney W. Grimes struct __siov iov[NIOV];/* ... and individual io vectors */ 32858f0484fSRodney W. Grimes char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 32958f0484fSRodney W. Grimes char ox[2]; /* space for 0x hex-prefix */ 330efb7e53dSJordan K. Hubbard void **argtable; /* args, built due to positional arg */ 331efb7e53dSJordan K. Hubbard void *statargtable [STATIC_ARG_TBL_SIZE]; 332efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 333efb7e53dSJordan K. Hubbard va_list orgap; /* original argument pointer */ 33458f0484fSRodney W. Grimes 33558f0484fSRodney W. Grimes /* 33658f0484fSRodney W. Grimes * Choose PADSIZE to trade efficiency vs. size. If larger printf 33758f0484fSRodney W. Grimes * fields occur frequently, increase PADSIZE and make the initialisers 33858f0484fSRodney W. Grimes * below longer. 33958f0484fSRodney W. Grimes */ 34058f0484fSRodney W. Grimes #define PADSIZE 16 /* pad chunk size */ 34158f0484fSRodney W. Grimes static char blanks[PADSIZE] = 34258f0484fSRodney W. Grimes {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 34358f0484fSRodney W. Grimes static char zeroes[PADSIZE] = 34458f0484fSRodney W. Grimes {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 34558f0484fSRodney W. Grimes 34658f0484fSRodney W. Grimes /* 34758f0484fSRodney W. Grimes * BEWARE, these `goto error' on error, and PAD uses `n'. 34858f0484fSRodney W. Grimes */ 34958f0484fSRodney W. Grimes #define PRINT(ptr, len) { \ 35058f0484fSRodney W. Grimes iovp->iov_base = (ptr); \ 35158f0484fSRodney W. Grimes iovp->iov_len = (len); \ 35258f0484fSRodney W. Grimes uio.uio_resid += (len); \ 35358f0484fSRodney W. Grimes iovp++; \ 35458f0484fSRodney W. Grimes if (++uio.uio_iovcnt >= NIOV) { \ 35558f0484fSRodney W. Grimes if (__sprint(fp, &uio)) \ 35658f0484fSRodney W. Grimes goto error; \ 35758f0484fSRodney W. Grimes iovp = iov; \ 35858f0484fSRodney W. Grimes } \ 35958f0484fSRodney W. Grimes } 36058f0484fSRodney W. Grimes #define PAD(howmany, with) { \ 36158f0484fSRodney W. Grimes if ((n = (howmany)) > 0) { \ 36258f0484fSRodney W. Grimes while (n > PADSIZE) { \ 36358f0484fSRodney W. Grimes PRINT(with, PADSIZE); \ 36458f0484fSRodney W. Grimes n -= PADSIZE; \ 36558f0484fSRodney W. Grimes } \ 36658f0484fSRodney W. Grimes PRINT(with, n); \ 36758f0484fSRodney W. Grimes } \ 36858f0484fSRodney W. Grimes } 36958f0484fSRodney W. Grimes #define FLUSH() { \ 37058f0484fSRodney W. Grimes if (uio.uio_resid && __sprint(fp, &uio)) \ 37158f0484fSRodney W. Grimes goto error; \ 37258f0484fSRodney W. Grimes uio.uio_iovcnt = 0; \ 37358f0484fSRodney W. Grimes iovp = iov; \ 37458f0484fSRodney W. Grimes } 37558f0484fSRodney W. Grimes 37658f0484fSRodney W. Grimes /* 377efb7e53dSJordan K. Hubbard * Get the argument indexed by nextarg. If the argument table is 378efb7e53dSJordan K. Hubbard * built, use it to get the argument. If its not, get the next 379efb7e53dSJordan K. Hubbard * argument (and arguments must be gotten sequentially). 380efb7e53dSJordan K. Hubbard */ 381efb7e53dSJordan K. Hubbard #define GETARG(type) \ 382efb7e53dSJordan K. Hubbard ((argtable != NULL) ? *((type*)(argtable[nextarg++])) : \ 383efb7e53dSJordan K. Hubbard (nextarg++, va_arg(ap, type))) 384efb7e53dSJordan K. Hubbard 385efb7e53dSJordan K. Hubbard /* 38658f0484fSRodney W. Grimes * To extend shorts properly, we need both signed and unsigned 38758f0484fSRodney W. Grimes * argument extraction methods. 38858f0484fSRodney W. Grimes */ 38958f0484fSRodney W. Grimes #define SARG() \ 390efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(long) : \ 391efb7e53dSJordan K. Hubbard flags&SHORTINT ? (long)(short)GETARG(int) : \ 392efb7e53dSJordan K. Hubbard (long)GETARG(int)) 39358f0484fSRodney W. Grimes #define UARG() \ 394efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(u_long) : \ 395efb7e53dSJordan K. Hubbard flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 396efb7e53dSJordan K. Hubbard (u_long)GETARG(u_int)) 397efb7e53dSJordan K. Hubbard 398efb7e53dSJordan K. Hubbard /* 399efb7e53dSJordan K. Hubbard * Get * arguments, including the form *nn$. Preserve the nextarg 400efb7e53dSJordan K. Hubbard * that the argument can be gotten once the type is determined. 401efb7e53dSJordan K. Hubbard */ 402efb7e53dSJordan K. Hubbard #define GETASTER(val) \ 403efb7e53dSJordan K. Hubbard n2 = 0; \ 404efb7e53dSJordan K. Hubbard cp = fmt; \ 405efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 406efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 407efb7e53dSJordan K. Hubbard cp++; \ 408efb7e53dSJordan K. Hubbard } \ 409efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 410efb7e53dSJordan K. Hubbard int hold = nextarg; \ 411efb7e53dSJordan K. Hubbard if (argtable == NULL) { \ 412efb7e53dSJordan K. Hubbard argtable = statargtable; \ 413efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, &argtable); \ 414efb7e53dSJordan K. Hubbard } \ 415efb7e53dSJordan K. Hubbard nextarg = n2; \ 416efb7e53dSJordan K. Hubbard val = GETARG (int); \ 417efb7e53dSJordan K. Hubbard nextarg = hold; \ 418efb7e53dSJordan K. Hubbard fmt = ++cp; \ 419efb7e53dSJordan K. Hubbard } else { \ 420efb7e53dSJordan K. Hubbard val = GETARG (int); \ 421efb7e53dSJordan K. Hubbard } 422efb7e53dSJordan K. Hubbard 42358f0484fSRodney W. Grimes 424f70177e7SJulian Elischer #ifdef _THREAD_SAFE 425f70177e7SJulian Elischer _thread_flockfile(fp,__FILE__,__LINE__); 426f70177e7SJulian Elischer #endif 42758f0484fSRodney W. Grimes /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 428f70177e7SJulian Elischer if (cantwrite(fp)) { 429f70177e7SJulian Elischer #ifdef _THREAD_SAFE 430f70177e7SJulian Elischer _thread_funlockfile(fp); 431f70177e7SJulian Elischer #endif 43258f0484fSRodney W. Grimes return (EOF); 433f70177e7SJulian Elischer } 43458f0484fSRodney W. Grimes 43558f0484fSRodney W. Grimes /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 43658f0484fSRodney W. Grimes if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 437f70177e7SJulian Elischer fp->_file >= 0) { 438f70177e7SJulian Elischer #ifdef _THREAD_SAFE 439f70177e7SJulian Elischer _thread_funlockfile(fp); 440f70177e7SJulian Elischer #endif 44158f0484fSRodney W. Grimes return (__sbprintf(fp, fmt0, ap)); 442f70177e7SJulian Elischer } 44358f0484fSRodney W. Grimes 44458f0484fSRodney W. Grimes fmt = (char *)fmt0; 445efb7e53dSJordan K. Hubbard argtable = NULL; 446efb7e53dSJordan K. Hubbard nextarg = 1; 447efb7e53dSJordan K. Hubbard orgap = ap; 44858f0484fSRodney W. Grimes uio.uio_iov = iovp = iov; 44958f0484fSRodney W. Grimes uio.uio_resid = 0; 45058f0484fSRodney W. Grimes uio.uio_iovcnt = 0; 45158f0484fSRodney W. Grimes ret = 0; 45258f0484fSRodney W. Grimes 45358f0484fSRodney W. Grimes /* 45458f0484fSRodney W. Grimes * Scan the format for conversions (`%' character). 45558f0484fSRodney W. Grimes */ 45658f0484fSRodney W. Grimes for (;;) { 45758f0484fSRodney W. Grimes for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 45858f0484fSRodney W. Grimes /* void */; 45958f0484fSRodney W. Grimes if ((n = fmt - cp) != 0) { 46092e88f87SAndrey A. Chernov if ((size_t)ret + n > INT_MAX) { 46192e88f87SAndrey A. Chernov ret = EOF; 46292e88f87SAndrey A. Chernov goto error; 46392e88f87SAndrey A. Chernov } 46458f0484fSRodney W. Grimes PRINT(cp, n); 46558f0484fSRodney W. Grimes ret += n; 46658f0484fSRodney W. Grimes } 46758f0484fSRodney W. Grimes if (ch == '\0') 46858f0484fSRodney W. Grimes goto done; 46958f0484fSRodney W. Grimes fmt++; /* skip over '%' */ 47058f0484fSRodney W. Grimes 47158f0484fSRodney W. Grimes flags = 0; 47258f0484fSRodney W. Grimes dprec = 0; 47358f0484fSRodney W. Grimes width = 0; 47458f0484fSRodney W. Grimes prec = -1; 47558f0484fSRodney W. Grimes sign = '\0'; 47658f0484fSRodney W. Grimes 47758f0484fSRodney W. Grimes rflag: ch = *fmt++; 47858f0484fSRodney W. Grimes reswitch: switch (ch) { 47958f0484fSRodney W. Grimes case ' ': 48058f0484fSRodney W. Grimes /* 48158f0484fSRodney W. Grimes * ``If the space and + flags both appear, the space 48258f0484fSRodney W. Grimes * flag will be ignored.'' 48358f0484fSRodney W. Grimes * -- ANSI X3J11 48458f0484fSRodney W. Grimes */ 48558f0484fSRodney W. Grimes if (!sign) 48658f0484fSRodney W. Grimes sign = ' '; 48758f0484fSRodney W. Grimes goto rflag; 48858f0484fSRodney W. Grimes case '#': 48958f0484fSRodney W. Grimes flags |= ALT; 49058f0484fSRodney W. Grimes goto rflag; 49158f0484fSRodney W. Grimes case '*': 49258f0484fSRodney W. Grimes /* 49358f0484fSRodney W. Grimes * ``A negative field width argument is taken as a 49458f0484fSRodney W. Grimes * - flag followed by a positive field width.'' 49558f0484fSRodney W. Grimes * -- ANSI X3J11 49658f0484fSRodney W. Grimes * They don't exclude field widths read from args. 49758f0484fSRodney W. Grimes */ 498efb7e53dSJordan K. Hubbard GETASTER (width); 499efb7e53dSJordan K. Hubbard if (width >= 0) 50058f0484fSRodney W. Grimes goto rflag; 50158f0484fSRodney W. Grimes width = -width; 50258f0484fSRodney W. Grimes /* FALLTHROUGH */ 50358f0484fSRodney W. Grimes case '-': 50458f0484fSRodney W. Grimes flags |= LADJUST; 50558f0484fSRodney W. Grimes goto rflag; 50658f0484fSRodney W. Grimes case '+': 50758f0484fSRodney W. Grimes sign = '+'; 50858f0484fSRodney W. Grimes goto rflag; 50958f0484fSRodney W. Grimes case '.': 51058f0484fSRodney W. Grimes if ((ch = *fmt++) == '*') { 511efb7e53dSJordan K. Hubbard GETASTER (n); 51258f0484fSRodney W. Grimes prec = n < 0 ? -1 : n; 51358f0484fSRodney W. Grimes goto rflag; 51458f0484fSRodney W. Grimes } 51558f0484fSRodney W. Grimes n = 0; 51658f0484fSRodney W. Grimes while (is_digit(ch)) { 51758f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 51858f0484fSRodney W. Grimes ch = *fmt++; 51958f0484fSRodney W. Grimes } 52058f0484fSRodney W. Grimes prec = n < 0 ? -1 : n; 52158f0484fSRodney W. Grimes goto reswitch; 52258f0484fSRodney W. Grimes case '0': 52358f0484fSRodney W. Grimes /* 52458f0484fSRodney W. Grimes * ``Note that 0 is taken as a flag, not as the 52558f0484fSRodney W. Grimes * beginning of a field width.'' 52658f0484fSRodney W. Grimes * -- ANSI X3J11 52758f0484fSRodney W. Grimes */ 52858f0484fSRodney W. Grimes flags |= ZEROPAD; 52958f0484fSRodney W. Grimes goto rflag; 53058f0484fSRodney W. Grimes case '1': case '2': case '3': case '4': 53158f0484fSRodney W. Grimes case '5': case '6': case '7': case '8': case '9': 53258f0484fSRodney W. Grimes n = 0; 53358f0484fSRodney W. Grimes do { 53458f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 53558f0484fSRodney W. Grimes ch = *fmt++; 53658f0484fSRodney W. Grimes } while (is_digit(ch)); 537efb7e53dSJordan K. Hubbard if (ch == '$') { 538efb7e53dSJordan K. Hubbard nextarg = n; 539efb7e53dSJordan K. Hubbard if (argtable == NULL) { 540efb7e53dSJordan K. Hubbard argtable = statargtable; 541efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, 542efb7e53dSJordan K. Hubbard &argtable); 543efb7e53dSJordan K. Hubbard } 544efb7e53dSJordan K. Hubbard goto rflag; 545efb7e53dSJordan K. Hubbard } 54658f0484fSRodney W. Grimes width = n; 54758f0484fSRodney W. Grimes goto reswitch; 54858f0484fSRodney W. Grimes #ifdef FLOATING_POINT 54958f0484fSRodney W. Grimes case 'L': 55058f0484fSRodney W. Grimes flags |= LONGDBL; 55158f0484fSRodney W. Grimes goto rflag; 55258f0484fSRodney W. Grimes #endif 55358f0484fSRodney W. Grimes case 'h': 55458f0484fSRodney W. Grimes flags |= SHORTINT; 55558f0484fSRodney W. Grimes goto rflag; 55658f0484fSRodney W. Grimes case 'l': 55758f0484fSRodney W. Grimes flags |= LONGINT; 55858f0484fSRodney W. Grimes goto rflag; 55958f0484fSRodney W. Grimes case 'q': 56058f0484fSRodney W. Grimes flags |= QUADINT; 56158f0484fSRodney W. Grimes goto rflag; 56258f0484fSRodney W. Grimes case 'c': 563efb7e53dSJordan K. Hubbard *(cp = buf) = GETARG(int); 56458f0484fSRodney W. Grimes size = 1; 56558f0484fSRodney W. Grimes sign = '\0'; 56658f0484fSRodney W. Grimes break; 56758f0484fSRodney W. Grimes case 'D': 56858f0484fSRodney W. Grimes flags |= LONGINT; 56958f0484fSRodney W. Grimes /*FALLTHROUGH*/ 57058f0484fSRodney W. Grimes case 'd': 57158f0484fSRodney W. Grimes case 'i': 57258f0484fSRodney W. Grimes if (flags & QUADINT) { 573efb7e53dSJordan K. Hubbard uqval = GETARG(quad_t); 57458f0484fSRodney W. Grimes if ((quad_t)uqval < 0) { 57558f0484fSRodney W. Grimes uqval = -uqval; 57658f0484fSRodney W. Grimes sign = '-'; 57758f0484fSRodney W. Grimes } 57858f0484fSRodney W. Grimes } else { 57958f0484fSRodney W. Grimes ulval = SARG(); 58058f0484fSRodney W. Grimes if ((long)ulval < 0) { 58158f0484fSRodney W. Grimes ulval = -ulval; 58258f0484fSRodney W. Grimes sign = '-'; 58358f0484fSRodney W. Grimes } 58458f0484fSRodney W. Grimes } 58558f0484fSRodney W. Grimes base = 10; 58658f0484fSRodney W. Grimes goto number; 58758f0484fSRodney W. Grimes #ifdef FLOATING_POINT 588d26be6f0SBruce Evans case 'e': 58958f0484fSRodney W. Grimes case 'E': 590d26be6f0SBruce Evans case 'f': 591d26be6f0SBruce Evans goto fp_begin; 59258f0484fSRodney W. Grimes case 'g': 59358f0484fSRodney W. Grimes case 'G': 594d26be6f0SBruce Evans if (prec == 0) 595d26be6f0SBruce Evans prec = 1; 596d26be6f0SBruce Evans fp_begin: if (prec == -1) 59758f0484fSRodney W. Grimes prec = DEFPREC; 598d26be6f0SBruce Evans if (flags & LONGDBL) 5996a93659fSBruce Evans /* XXX this loses precision. */ 600efb7e53dSJordan K. Hubbard _double = (double)GETARG(long double); 601d26be6f0SBruce Evans else 602efb7e53dSJordan K. Hubbard _double = GETARG(double); 60358f0484fSRodney W. Grimes /* do this before tricky precision changes */ 60458f0484fSRodney W. Grimes if (isinf(_double)) { 60558f0484fSRodney W. Grimes if (_double < 0) 60658f0484fSRodney W. Grimes sign = '-'; 60758f0484fSRodney W. Grimes cp = "Inf"; 60858f0484fSRodney W. Grimes size = 3; 60958f0484fSRodney W. Grimes break; 61058f0484fSRodney W. Grimes } 61158f0484fSRodney W. Grimes if (isnan(_double)) { 61258f0484fSRodney W. Grimes cp = "NaN"; 61358f0484fSRodney W. Grimes size = 3; 61458f0484fSRodney W. Grimes break; 61558f0484fSRodney W. Grimes } 61658f0484fSRodney W. Grimes flags |= FPT; 61758f0484fSRodney W. Grimes cp = cvt(_double, prec, flags, &softsign, 61858f0484fSRodney W. Grimes &expt, ch, &ndig); 61958f0484fSRodney W. Grimes if (ch == 'g' || ch == 'G') { 62058f0484fSRodney W. Grimes if (expt <= -4 || expt > prec) 62158f0484fSRodney W. Grimes ch = (ch == 'g') ? 'e' : 'E'; 62258f0484fSRodney W. Grimes else 62358f0484fSRodney W. Grimes ch = 'g'; 62458f0484fSRodney W. Grimes } 62558f0484fSRodney W. Grimes if (ch <= 'e') { /* 'e' or 'E' fmt */ 62658f0484fSRodney W. Grimes --expt; 62758f0484fSRodney W. Grimes expsize = exponent(expstr, expt, ch); 62858f0484fSRodney W. Grimes size = expsize + ndig; 62958f0484fSRodney W. Grimes if (ndig > 1 || flags & ALT) 63058f0484fSRodney W. Grimes ++size; 63158f0484fSRodney W. Grimes } else if (ch == 'f') { /* f fmt */ 63258f0484fSRodney W. Grimes if (expt > 0) { 63358f0484fSRodney W. Grimes size = expt; 63458f0484fSRodney W. Grimes if (prec || flags & ALT) 63558f0484fSRodney W. Grimes size += prec + 1; 63658f0484fSRodney W. Grimes } else /* "0.X" */ 63758f0484fSRodney W. Grimes size = prec + 2; 63858f0484fSRodney W. Grimes } else if (expt >= ndig) { /* fixed g fmt */ 63958f0484fSRodney W. Grimes size = expt; 64058f0484fSRodney W. Grimes if (flags & ALT) 64158f0484fSRodney W. Grimes ++size; 64258f0484fSRodney W. Grimes } else 64358f0484fSRodney W. Grimes size = ndig + (expt > 0 ? 64458f0484fSRodney W. Grimes 1 : 2 - expt); 64558f0484fSRodney W. Grimes 64658f0484fSRodney W. Grimes if (softsign) 64758f0484fSRodney W. Grimes sign = '-'; 64858f0484fSRodney W. Grimes break; 64958f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 65058f0484fSRodney W. Grimes case 'n': 65158f0484fSRodney W. Grimes if (flags & QUADINT) 6526e690ad4SAndrey A. Chernov *GETARG(quad_t *) = ret; 65358f0484fSRodney W. Grimes else if (flags & LONGINT) 6546e690ad4SAndrey A. Chernov *GETARG(long *) = ret; 65558f0484fSRodney W. Grimes else if (flags & SHORTINT) 6566e690ad4SAndrey A. Chernov *GETARG(short *) = ret; 65758f0484fSRodney W. Grimes else 6586e690ad4SAndrey A. Chernov *GETARG(int *) = ret; 65958f0484fSRodney W. Grimes continue; /* no output */ 66058f0484fSRodney W. Grimes case 'O': 66158f0484fSRodney W. Grimes flags |= LONGINT; 66258f0484fSRodney W. Grimes /*FALLTHROUGH*/ 66358f0484fSRodney W. Grimes case 'o': 66458f0484fSRodney W. Grimes if (flags & QUADINT) 665efb7e53dSJordan K. Hubbard uqval = GETARG(u_quad_t); 66658f0484fSRodney W. Grimes else 66758f0484fSRodney W. Grimes ulval = UARG(); 66858f0484fSRodney W. Grimes base = 8; 66958f0484fSRodney W. Grimes goto nosign; 67058f0484fSRodney W. Grimes case 'p': 67158f0484fSRodney W. Grimes /* 67258f0484fSRodney W. Grimes * ``The argument shall be a pointer to void. The 67358f0484fSRodney W. Grimes * value of the pointer is converted to a sequence 67458f0484fSRodney W. Grimes * of printable characters, in an implementation- 67558f0484fSRodney W. Grimes * defined manner.'' 67658f0484fSRodney W. Grimes * -- ANSI X3J11 67758f0484fSRodney W. Grimes */ 678efb7e53dSJordan K. Hubbard ulval = (u_long)GETARG(void *); 67958f0484fSRodney W. Grimes base = 16; 68058f0484fSRodney W. Grimes xdigs = "0123456789abcdef"; 68158f0484fSRodney W. Grimes flags = (flags & ~QUADINT) | HEXPREFIX; 68258f0484fSRodney W. Grimes ch = 'x'; 68358f0484fSRodney W. Grimes goto nosign; 68458f0484fSRodney W. Grimes case 's': 685efb7e53dSJordan K. Hubbard if ((cp = GETARG(char *)) == NULL) 68658f0484fSRodney W. Grimes cp = "(null)"; 68758f0484fSRodney W. Grimes if (prec >= 0) { 68858f0484fSRodney W. Grimes /* 68958f0484fSRodney W. Grimes * can't use strlen; can only look for the 69058f0484fSRodney W. Grimes * NUL in the first `prec' characters, and 69158f0484fSRodney W. Grimes * strlen() will go further. 69258f0484fSRodney W. Grimes */ 693ce51cf03SJames Raynard char *p = memchr(cp, 0, (size_t)prec); 69458f0484fSRodney W. Grimes 69558f0484fSRodney W. Grimes if (p != NULL) { 69658f0484fSRodney W. Grimes size = p - cp; 69758f0484fSRodney W. Grimes if (size > prec) 69858f0484fSRodney W. Grimes size = prec; 69958f0484fSRodney W. Grimes } else 70058f0484fSRodney W. Grimes size = prec; 70158f0484fSRodney W. Grimes } else 70258f0484fSRodney W. Grimes size = strlen(cp); 70358f0484fSRodney W. Grimes sign = '\0'; 70458f0484fSRodney W. Grimes break; 70558f0484fSRodney W. Grimes case 'U': 70658f0484fSRodney W. Grimes flags |= LONGINT; 70758f0484fSRodney W. Grimes /*FALLTHROUGH*/ 70858f0484fSRodney W. Grimes case 'u': 70958f0484fSRodney W. Grimes if (flags & QUADINT) 710efb7e53dSJordan K. Hubbard uqval = GETARG(u_quad_t); 71158f0484fSRodney W. Grimes else 71258f0484fSRodney W. Grimes ulval = UARG(); 71358f0484fSRodney W. Grimes base = 10; 71458f0484fSRodney W. Grimes goto nosign; 71558f0484fSRodney W. Grimes case 'X': 71658f0484fSRodney W. Grimes xdigs = "0123456789ABCDEF"; 71758f0484fSRodney W. Grimes goto hex; 71858f0484fSRodney W. Grimes case 'x': 71958f0484fSRodney W. Grimes xdigs = "0123456789abcdef"; 72058f0484fSRodney W. Grimes hex: if (flags & QUADINT) 721efb7e53dSJordan K. Hubbard uqval = GETARG(u_quad_t); 72258f0484fSRodney W. Grimes else 72358f0484fSRodney W. Grimes ulval = UARG(); 72458f0484fSRodney W. Grimes base = 16; 72558f0484fSRodney W. Grimes /* leading 0x/X only if non-zero */ 72658f0484fSRodney W. Grimes if (flags & ALT && 72758f0484fSRodney W. Grimes (flags & QUADINT ? uqval != 0 : ulval != 0)) 72858f0484fSRodney W. Grimes flags |= HEXPREFIX; 72958f0484fSRodney W. Grimes 73058f0484fSRodney W. Grimes /* unsigned conversions */ 73158f0484fSRodney W. Grimes nosign: sign = '\0'; 73258f0484fSRodney W. Grimes /* 73358f0484fSRodney W. Grimes * ``... diouXx conversions ... if a precision is 73458f0484fSRodney W. Grimes * specified, the 0 flag will be ignored.'' 73558f0484fSRodney W. Grimes * -- ANSI X3J11 73658f0484fSRodney W. Grimes */ 73758f0484fSRodney W. Grimes number: if ((dprec = prec) >= 0) 73858f0484fSRodney W. Grimes flags &= ~ZEROPAD; 73958f0484fSRodney W. Grimes 74058f0484fSRodney W. Grimes /* 74158f0484fSRodney W. Grimes * ``The result of converting a zero value with an 74258f0484fSRodney W. Grimes * explicit precision of zero is no characters.'' 74358f0484fSRodney W. Grimes * -- ANSI X3J11 74458f0484fSRodney W. Grimes */ 74558f0484fSRodney W. Grimes cp = buf + BUF; 74658f0484fSRodney W. Grimes if (flags & QUADINT) { 74758f0484fSRodney W. Grimes if (uqval != 0 || prec != 0) 74858f0484fSRodney W. Grimes cp = __uqtoa(uqval, cp, base, 74958f0484fSRodney W. Grimes flags & ALT, xdigs); 75058f0484fSRodney W. Grimes } else { 75158f0484fSRodney W. Grimes if (ulval != 0 || prec != 0) 75258f0484fSRodney W. Grimes cp = __ultoa(ulval, cp, base, 75358f0484fSRodney W. Grimes flags & ALT, xdigs); 75458f0484fSRodney W. Grimes } 75558f0484fSRodney W. Grimes size = buf + BUF - cp; 75658f0484fSRodney W. Grimes break; 75758f0484fSRodney W. Grimes default: /* "%?" prints ?, unless ? is NUL */ 75858f0484fSRodney W. Grimes if (ch == '\0') 75958f0484fSRodney W. Grimes goto done; 76058f0484fSRodney W. Grimes /* pretend it was %c with argument ch */ 76158f0484fSRodney W. Grimes cp = buf; 76258f0484fSRodney W. Grimes *cp = ch; 76358f0484fSRodney W. Grimes size = 1; 76458f0484fSRodney W. Grimes sign = '\0'; 76558f0484fSRodney W. Grimes break; 76658f0484fSRodney W. Grimes } 76758f0484fSRodney W. Grimes 76858f0484fSRodney W. Grimes /* 76958f0484fSRodney W. Grimes * All reasonable formats wind up here. At this point, `cp' 77058f0484fSRodney W. Grimes * points to a string which (if not flags&LADJUST) should be 77158f0484fSRodney W. Grimes * padded out to `width' places. If flags&ZEROPAD, it should 77258f0484fSRodney W. Grimes * first be prefixed by any sign or other prefix; otherwise, 77358f0484fSRodney W. Grimes * it should be blank padded before the prefix is emitted. 77458f0484fSRodney W. Grimes * After any left-hand padding and prefixing, emit zeroes 77558f0484fSRodney W. Grimes * required by a decimal [diouxX] precision, then print the 77658f0484fSRodney W. Grimes * string proper, then emit zeroes required by any leftover 77758f0484fSRodney W. Grimes * floating precision; finally, if LADJUST, pad with blanks. 77858f0484fSRodney W. Grimes * 77958f0484fSRodney W. Grimes * Compute actual size, so we know how much to pad. 780261a532aSBill Fenner * size excludes decimal prec; realsz includes it. 78158f0484fSRodney W. Grimes */ 782261a532aSBill Fenner realsz = dprec > size ? dprec : size; 78358f0484fSRodney W. Grimes if (sign) 784261a532aSBill Fenner realsz++; 78558f0484fSRodney W. Grimes else if (flags & HEXPREFIX) 786261a532aSBill Fenner realsz += 2; 78758f0484fSRodney W. Grimes 78892e88f87SAndrey A. Chernov prsize = width > realsz ? width : realsz; 78992e88f87SAndrey A. Chernov if ((size_t)ret + prsize > INT_MAX) { 79092e88f87SAndrey A. Chernov ret = EOF; 79192e88f87SAndrey A. Chernov goto error; 79292e88f87SAndrey A. Chernov } 79392e88f87SAndrey A. Chernov 79458f0484fSRodney W. Grimes /* right-adjusting blank padding */ 79558f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == 0) 79658f0484fSRodney W. Grimes PAD(width - realsz, blanks); 79758f0484fSRodney W. Grimes 79858f0484fSRodney W. Grimes /* prefix */ 79958f0484fSRodney W. Grimes if (sign) { 80058f0484fSRodney W. Grimes PRINT(&sign, 1); 80158f0484fSRodney W. Grimes } else if (flags & HEXPREFIX) { 80258f0484fSRodney W. Grimes ox[0] = '0'; 80358f0484fSRodney W. Grimes ox[1] = ch; 80458f0484fSRodney W. Grimes PRINT(ox, 2); 80558f0484fSRodney W. Grimes } 80658f0484fSRodney W. Grimes 80758f0484fSRodney W. Grimes /* right-adjusting zero padding */ 80858f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 80958f0484fSRodney W. Grimes PAD(width - realsz, zeroes); 81058f0484fSRodney W. Grimes 81158f0484fSRodney W. Grimes /* leading zeroes from decimal precision */ 812261a532aSBill Fenner PAD(dprec - size, zeroes); 81358f0484fSRodney W. Grimes 81458f0484fSRodney W. Grimes /* the string or number proper */ 81558f0484fSRodney W. Grimes #ifdef FLOATING_POINT 81658f0484fSRodney W. Grimes if ((flags & FPT) == 0) { 81758f0484fSRodney W. Grimes PRINT(cp, size); 81858f0484fSRodney W. Grimes } else { /* glue together f_p fragments */ 81958f0484fSRodney W. Grimes if (ch >= 'f') { /* 'f' or 'g' */ 82058f0484fSRodney W. Grimes if (_double == 0) { 82158f0484fSRodney W. Grimes /* kludge for __dtoa irregularity */ 822ffe57f1aSBruce Evans if (expt >= ndig && 823ffe57f1aSBruce Evans (flags & ALT) == 0) { 82458f0484fSRodney W. Grimes PRINT("0", 1); 82558f0484fSRodney W. Grimes } else { 82658f0484fSRodney W. Grimes PRINT("0.", 2); 82758f0484fSRodney W. Grimes PAD(ndig - 1, zeroes); 82858f0484fSRodney W. Grimes } 82958f0484fSRodney W. Grimes } else if (expt <= 0) { 83058f0484fSRodney W. Grimes PRINT("0.", 2); 83158f0484fSRodney W. Grimes PAD(-expt, zeroes); 83258f0484fSRodney W. Grimes PRINT(cp, ndig); 83358f0484fSRodney W. Grimes } else if (expt >= ndig) { 83458f0484fSRodney W. Grimes PRINT(cp, ndig); 83558f0484fSRodney W. Grimes PAD(expt - ndig, zeroes); 83658f0484fSRodney W. Grimes if (flags & ALT) 83758f0484fSRodney W. Grimes PRINT(".", 1); 83858f0484fSRodney W. Grimes } else { 83958f0484fSRodney W. Grimes PRINT(cp, expt); 84058f0484fSRodney W. Grimes cp += expt; 84158f0484fSRodney W. Grimes PRINT(".", 1); 84258f0484fSRodney W. Grimes PRINT(cp, ndig-expt); 84358f0484fSRodney W. Grimes } 84458f0484fSRodney W. Grimes } else { /* 'e' or 'E' */ 84558f0484fSRodney W. Grimes if (ndig > 1 || flags & ALT) { 84658f0484fSRodney W. Grimes ox[0] = *cp++; 84758f0484fSRodney W. Grimes ox[1] = '.'; 84858f0484fSRodney W. Grimes PRINT(ox, 2); 849918bed75SBruce Evans if (_double) { 85058f0484fSRodney W. Grimes PRINT(cp, ndig-1); 85158f0484fSRodney W. Grimes } else /* 0.[0..] */ 85258f0484fSRodney W. Grimes /* __dtoa irregularity */ 85358f0484fSRodney W. Grimes PAD(ndig - 1, zeroes); 85458f0484fSRodney W. Grimes } else /* XeYYY */ 85558f0484fSRodney W. Grimes PRINT(cp, 1); 85658f0484fSRodney W. Grimes PRINT(expstr, expsize); 85758f0484fSRodney W. Grimes } 85858f0484fSRodney W. Grimes } 85958f0484fSRodney W. Grimes #else 86058f0484fSRodney W. Grimes PRINT(cp, size); 86158f0484fSRodney W. Grimes #endif 86258f0484fSRodney W. Grimes /* left-adjusting padding (always blank) */ 86358f0484fSRodney W. Grimes if (flags & LADJUST) 86458f0484fSRodney W. Grimes PAD(width - realsz, blanks); 86558f0484fSRodney W. Grimes 86658f0484fSRodney W. Grimes /* finally, adjust ret */ 86792e88f87SAndrey A. Chernov ret += prsize; 86858f0484fSRodney W. Grimes 86958f0484fSRodney W. Grimes FLUSH(); /* copy out the I/O vectors */ 87058f0484fSRodney W. Grimes } 87158f0484fSRodney W. Grimes done: 87258f0484fSRodney W. Grimes FLUSH(); 87358f0484fSRodney W. Grimes error: 874f70177e7SJulian Elischer if (__sferror(fp)) 875f70177e7SJulian Elischer ret = EOF; 876f70177e7SJulian Elischer #ifdef _THREAD_SAFE 877f70177e7SJulian Elischer _thread_funlockfile(fp); 878f70177e7SJulian Elischer #endif 879efb7e53dSJordan K. Hubbard if ((argtable != NULL) && (argtable != statargtable)) 880efb7e53dSJordan K. Hubbard free (argtable); 881f70177e7SJulian Elischer return (ret); 88258f0484fSRodney W. Grimes /* NOTREACHED */ 88358f0484fSRodney W. Grimes } 88458f0484fSRodney W. Grimes 885efb7e53dSJordan K. Hubbard /* 886efb7e53dSJordan K. Hubbard * Type ids for argument type table. 887efb7e53dSJordan K. Hubbard */ 888efb7e53dSJordan K. Hubbard #define T_UNUSED 0 889efb7e53dSJordan K. Hubbard #define T_SHORT 1 890efb7e53dSJordan K. Hubbard #define T_U_SHORT 2 891efb7e53dSJordan K. Hubbard #define TP_SHORT 3 892efb7e53dSJordan K. Hubbard #define T_INT 4 893efb7e53dSJordan K. Hubbard #define T_U_INT 5 894efb7e53dSJordan K. Hubbard #define TP_INT 6 895efb7e53dSJordan K. Hubbard #define T_LONG 7 896efb7e53dSJordan K. Hubbard #define T_U_LONG 8 897efb7e53dSJordan K. Hubbard #define TP_LONG 9 898efb7e53dSJordan K. Hubbard #define T_QUAD 10 899efb7e53dSJordan K. Hubbard #define T_U_QUAD 11 900efb7e53dSJordan K. Hubbard #define TP_QUAD 12 901efb7e53dSJordan K. Hubbard #define T_DOUBLE 13 902efb7e53dSJordan K. Hubbard #define T_LONG_DOUBLE 14 903efb7e53dSJordan K. Hubbard #define TP_CHAR 15 904efb7e53dSJordan K. Hubbard #define TP_VOID 16 905efb7e53dSJordan K. Hubbard 906efb7e53dSJordan K. Hubbard /* 907efb7e53dSJordan K. Hubbard * Find all arguments when a positional parameter is encountered. Returns a 908efb7e53dSJordan K. Hubbard * table, indexed by argument number, of pointers to each arguments. The 909efb7e53dSJordan K. Hubbard * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 910efb7e53dSJordan K. Hubbard * It will be replaces with a malloc-ed on if it overflows. 911efb7e53dSJordan K. Hubbard */ 912efb7e53dSJordan K. Hubbard static void 913efb7e53dSJordan K. Hubbard __find_arguments (fmt0, ap, argtable) 914efb7e53dSJordan K. Hubbard const char *fmt0; 915efb7e53dSJordan K. Hubbard va_list ap; 916efb7e53dSJordan K. Hubbard void ***argtable; 917efb7e53dSJordan K. Hubbard { 918efb7e53dSJordan K. Hubbard register char *fmt; /* format string */ 919efb7e53dSJordan K. Hubbard register int ch; /* character from fmt */ 920efb7e53dSJordan K. Hubbard register int n, n2; /* handy integer (short term usage) */ 921efb7e53dSJordan K. Hubbard register char *cp; /* handy char pointer (short term usage) */ 922efb7e53dSJordan K. Hubbard register int flags; /* flags as above */ 923efb7e53dSJordan K. Hubbard int width; /* width from format (%8d), or 0 */ 924efb7e53dSJordan K. Hubbard unsigned char *typetable; /* table of types */ 925efb7e53dSJordan K. Hubbard unsigned char stattypetable [STATIC_ARG_TBL_SIZE]; 926efb7e53dSJordan K. Hubbard int tablesize; /* current size of type table */ 927efb7e53dSJordan K. Hubbard int tablemax; /* largest used index in table */ 928efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 929efb7e53dSJordan K. Hubbard 930efb7e53dSJordan K. Hubbard /* 931efb7e53dSJordan K. Hubbard * Add an argument type to the table, expanding if necessary. 932efb7e53dSJordan K. Hubbard */ 933efb7e53dSJordan K. Hubbard #define ADDTYPE(type) \ 934efb7e53dSJordan K. Hubbard ((nextarg >= tablesize) ? \ 935efb7e53dSJordan K. Hubbard __grow_type_table(nextarg, &typetable, &tablesize) : 0, \ 936efb7e53dSJordan K. Hubbard typetable[nextarg++] = type, \ 937efb7e53dSJordan K. Hubbard (nextarg > tablemax) ? tablemax = nextarg : 0) 938efb7e53dSJordan K. Hubbard 939efb7e53dSJordan K. Hubbard #define ADDSARG() \ 940efb7e53dSJordan K. Hubbard ((flags&LONGINT) ? ADDTYPE(T_LONG) : \ 941efb7e53dSJordan K. Hubbard ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT))) 942efb7e53dSJordan K. Hubbard 943efb7e53dSJordan K. Hubbard #define ADDUARG() \ 944efb7e53dSJordan K. Hubbard ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \ 945efb7e53dSJordan K. Hubbard ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT))) 946efb7e53dSJordan K. Hubbard 947efb7e53dSJordan K. Hubbard /* 948efb7e53dSJordan K. Hubbard * Add * arguments to the type array. 949efb7e53dSJordan K. Hubbard */ 950efb7e53dSJordan K. Hubbard #define ADDASTER() \ 951efb7e53dSJordan K. Hubbard n2 = 0; \ 952efb7e53dSJordan K. Hubbard cp = fmt; \ 953efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 954efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 955efb7e53dSJordan K. Hubbard cp++; \ 956efb7e53dSJordan K. Hubbard } \ 957efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 958efb7e53dSJordan K. Hubbard int hold = nextarg; \ 959efb7e53dSJordan K. Hubbard nextarg = n2; \ 960efb7e53dSJordan K. Hubbard ADDTYPE (T_INT); \ 961efb7e53dSJordan K. Hubbard nextarg = hold; \ 962efb7e53dSJordan K. Hubbard fmt = ++cp; \ 963efb7e53dSJordan K. Hubbard } else { \ 964efb7e53dSJordan K. Hubbard ADDTYPE (T_INT); \ 965efb7e53dSJordan K. Hubbard } 966efb7e53dSJordan K. Hubbard fmt = (char *)fmt0; 967efb7e53dSJordan K. Hubbard typetable = stattypetable; 968efb7e53dSJordan K. Hubbard tablesize = STATIC_ARG_TBL_SIZE; 969efb7e53dSJordan K. Hubbard tablemax = 0; 970efb7e53dSJordan K. Hubbard nextarg = 1; 971efb7e53dSJordan K. Hubbard memset (typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); 972efb7e53dSJordan K. Hubbard 973efb7e53dSJordan K. Hubbard /* 974efb7e53dSJordan K. Hubbard * Scan the format for conversions (`%' character). 975efb7e53dSJordan K. Hubbard */ 976efb7e53dSJordan K. Hubbard for (;;) { 977efb7e53dSJordan K. Hubbard for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 978efb7e53dSJordan K. Hubbard /* void */; 979efb7e53dSJordan K. Hubbard if (ch == '\0') 980efb7e53dSJordan K. Hubbard goto done; 981efb7e53dSJordan K. Hubbard fmt++; /* skip over '%' */ 982efb7e53dSJordan K. Hubbard 983efb7e53dSJordan K. Hubbard flags = 0; 984efb7e53dSJordan K. Hubbard width = 0; 985efb7e53dSJordan K. Hubbard 986efb7e53dSJordan K. Hubbard rflag: ch = *fmt++; 987efb7e53dSJordan K. Hubbard reswitch: switch (ch) { 988efb7e53dSJordan K. Hubbard case ' ': 989efb7e53dSJordan K. Hubbard case '#': 990efb7e53dSJordan K. Hubbard goto rflag; 991efb7e53dSJordan K. Hubbard case '*': 992efb7e53dSJordan K. Hubbard ADDASTER (); 993efb7e53dSJordan K. Hubbard goto rflag; 994efb7e53dSJordan K. Hubbard case '-': 995efb7e53dSJordan K. Hubbard case '+': 996efb7e53dSJordan K. Hubbard goto rflag; 997efb7e53dSJordan K. Hubbard case '.': 998efb7e53dSJordan K. Hubbard if ((ch = *fmt++) == '*') { 999efb7e53dSJordan K. Hubbard ADDASTER (); 1000efb7e53dSJordan K. Hubbard goto rflag; 1001efb7e53dSJordan K. Hubbard } 1002efb7e53dSJordan K. Hubbard while (is_digit(ch)) { 1003efb7e53dSJordan K. Hubbard ch = *fmt++; 1004efb7e53dSJordan K. Hubbard } 1005efb7e53dSJordan K. Hubbard goto reswitch; 1006efb7e53dSJordan K. Hubbard case '0': 1007efb7e53dSJordan K. Hubbard goto rflag; 1008efb7e53dSJordan K. Hubbard case '1': case '2': case '3': case '4': 1009efb7e53dSJordan K. Hubbard case '5': case '6': case '7': case '8': case '9': 1010efb7e53dSJordan K. Hubbard n = 0; 1011efb7e53dSJordan K. Hubbard do { 1012efb7e53dSJordan K. Hubbard n = 10 * n + to_digit(ch); 1013efb7e53dSJordan K. Hubbard ch = *fmt++; 1014efb7e53dSJordan K. Hubbard } while (is_digit(ch)); 1015efb7e53dSJordan K. Hubbard if (ch == '$') { 1016efb7e53dSJordan K. Hubbard nextarg = n; 1017efb7e53dSJordan K. Hubbard goto rflag; 1018efb7e53dSJordan K. Hubbard } 1019efb7e53dSJordan K. Hubbard width = n; 1020efb7e53dSJordan K. Hubbard goto reswitch; 1021efb7e53dSJordan K. Hubbard #ifdef FLOATING_POINT 1022efb7e53dSJordan K. Hubbard case 'L': 1023efb7e53dSJordan K. Hubbard flags |= LONGDBL; 1024efb7e53dSJordan K. Hubbard goto rflag; 1025efb7e53dSJordan K. Hubbard #endif 1026efb7e53dSJordan K. Hubbard case 'h': 1027efb7e53dSJordan K. Hubbard flags |= SHORTINT; 1028efb7e53dSJordan K. Hubbard goto rflag; 1029efb7e53dSJordan K. Hubbard case 'l': 1030efb7e53dSJordan K. Hubbard flags |= LONGINT; 1031efb7e53dSJordan K. Hubbard goto rflag; 1032efb7e53dSJordan K. Hubbard case 'q': 1033efb7e53dSJordan K. Hubbard flags |= QUADINT; 1034efb7e53dSJordan K. Hubbard goto rflag; 1035efb7e53dSJordan K. Hubbard case 'c': 1036efb7e53dSJordan K. Hubbard ADDTYPE(T_INT); 1037efb7e53dSJordan K. Hubbard break; 1038efb7e53dSJordan K. Hubbard case 'D': 1039efb7e53dSJordan K. Hubbard flags |= LONGINT; 1040efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1041efb7e53dSJordan K. Hubbard case 'd': 1042efb7e53dSJordan K. Hubbard case 'i': 1043efb7e53dSJordan K. Hubbard if (flags & QUADINT) { 1044efb7e53dSJordan K. Hubbard ADDTYPE(T_QUAD); 1045efb7e53dSJordan K. Hubbard } else { 1046efb7e53dSJordan K. Hubbard ADDSARG(); 1047efb7e53dSJordan K. Hubbard } 1048efb7e53dSJordan K. Hubbard break; 1049efb7e53dSJordan K. Hubbard #ifdef FLOATING_POINT 1050efb7e53dSJordan K. Hubbard case 'e': 1051efb7e53dSJordan K. Hubbard case 'E': 1052efb7e53dSJordan K. Hubbard case 'f': 1053efb7e53dSJordan K. Hubbard case 'g': 1054efb7e53dSJordan K. Hubbard case 'G': 1055efb7e53dSJordan K. Hubbard if (flags & LONGDBL) 1056efb7e53dSJordan K. Hubbard ADDTYPE(T_LONG_DOUBLE); 1057efb7e53dSJordan K. Hubbard else 1058efb7e53dSJordan K. Hubbard ADDTYPE(T_DOUBLE); 1059efb7e53dSJordan K. Hubbard break; 1060efb7e53dSJordan K. Hubbard #endif /* FLOATING_POINT */ 1061efb7e53dSJordan K. Hubbard case 'n': 1062efb7e53dSJordan K. Hubbard if (flags & QUADINT) 1063efb7e53dSJordan K. Hubbard ADDTYPE(TP_QUAD); 1064efb7e53dSJordan K. Hubbard else if (flags & LONGINT) 1065efb7e53dSJordan K. Hubbard ADDTYPE(TP_LONG); 1066efb7e53dSJordan K. Hubbard else if (flags & SHORTINT) 1067efb7e53dSJordan K. Hubbard ADDTYPE(TP_SHORT); 1068efb7e53dSJordan K. Hubbard else 1069efb7e53dSJordan K. Hubbard ADDTYPE(TP_INT); 1070efb7e53dSJordan K. Hubbard continue; /* no output */ 1071efb7e53dSJordan K. Hubbard case 'O': 1072efb7e53dSJordan K. Hubbard flags |= LONGINT; 1073efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1074efb7e53dSJordan K. Hubbard case 'o': 1075efb7e53dSJordan K. Hubbard if (flags & QUADINT) 1076efb7e53dSJordan K. Hubbard ADDTYPE(T_U_QUAD); 1077efb7e53dSJordan K. Hubbard else 1078efb7e53dSJordan K. Hubbard ADDUARG(); 1079efb7e53dSJordan K. Hubbard break; 1080efb7e53dSJordan K. Hubbard case 'p': 1081efb7e53dSJordan K. Hubbard ADDTYPE(TP_VOID); 1082efb7e53dSJordan K. Hubbard break; 1083efb7e53dSJordan K. Hubbard case 's': 1084efb7e53dSJordan K. Hubbard ADDTYPE(TP_CHAR); 1085efb7e53dSJordan K. Hubbard break; 1086efb7e53dSJordan K. Hubbard case 'U': 1087efb7e53dSJordan K. Hubbard flags |= LONGINT; 1088efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1089efb7e53dSJordan K. Hubbard case 'u': 1090efb7e53dSJordan K. Hubbard if (flags & QUADINT) 1091efb7e53dSJordan K. Hubbard ADDTYPE(T_U_QUAD); 1092efb7e53dSJordan K. Hubbard else 1093efb7e53dSJordan K. Hubbard ADDUARG(); 1094efb7e53dSJordan K. Hubbard break; 1095efb7e53dSJordan K. Hubbard case 'X': 1096efb7e53dSJordan K. Hubbard case 'x': 1097efb7e53dSJordan K. Hubbard if (flags & QUADINT) 1098efb7e53dSJordan K. Hubbard ADDTYPE(T_U_QUAD); 1099efb7e53dSJordan K. Hubbard else 1100efb7e53dSJordan K. Hubbard ADDUARG(); 1101efb7e53dSJordan K. Hubbard break; 1102efb7e53dSJordan K. Hubbard default: /* "%?" prints ?, unless ? is NUL */ 1103efb7e53dSJordan K. Hubbard if (ch == '\0') 1104efb7e53dSJordan K. Hubbard goto done; 1105efb7e53dSJordan K. Hubbard break; 1106efb7e53dSJordan K. Hubbard } 1107efb7e53dSJordan K. Hubbard } 1108efb7e53dSJordan K. Hubbard done: 1109efb7e53dSJordan K. Hubbard /* 1110efb7e53dSJordan K. Hubbard * Build the argument table. 1111efb7e53dSJordan K. Hubbard */ 1112efb7e53dSJordan K. Hubbard if (tablemax >= STATIC_ARG_TBL_SIZE) { 1113efb7e53dSJordan K. Hubbard *argtable = (void **) 1114efb7e53dSJordan K. Hubbard malloc (sizeof (void *) * (tablemax + 1)); 1115efb7e53dSJordan K. Hubbard } 1116efb7e53dSJordan K. Hubbard 1117efb7e53dSJordan K. Hubbard (*argtable) [0] = NULL; 1118efb7e53dSJordan K. Hubbard for (n = 1; n <= tablemax; n++) { 1119efb7e53dSJordan K. Hubbard (*argtable) [n] = ap; 1120efb7e53dSJordan K. Hubbard switch (typetable [n]) { 1121efb7e53dSJordan K. Hubbard case T_UNUSED: 1122efb7e53dSJordan K. Hubbard (void) va_arg (ap, int); 1123efb7e53dSJordan K. Hubbard break; 1124efb7e53dSJordan K. Hubbard case T_SHORT: 1125efb7e53dSJordan K. Hubbard (void) va_arg (ap, int); 1126efb7e53dSJordan K. Hubbard break; 1127efb7e53dSJordan K. Hubbard case T_U_SHORT: 1128efb7e53dSJordan K. Hubbard (void) va_arg (ap, int); 1129efb7e53dSJordan K. Hubbard break; 1130efb7e53dSJordan K. Hubbard case TP_SHORT: 1131efb7e53dSJordan K. Hubbard (void) va_arg (ap, short *); 1132efb7e53dSJordan K. Hubbard break; 1133efb7e53dSJordan K. Hubbard case T_INT: 1134efb7e53dSJordan K. Hubbard (void) va_arg (ap, int); 1135efb7e53dSJordan K. Hubbard break; 1136efb7e53dSJordan K. Hubbard case T_U_INT: 1137efb7e53dSJordan K. Hubbard (void) va_arg (ap, unsigned int); 1138efb7e53dSJordan K. Hubbard break; 1139efb7e53dSJordan K. Hubbard case TP_INT: 1140efb7e53dSJordan K. Hubbard (void) va_arg (ap, int *); 1141efb7e53dSJordan K. Hubbard break; 1142efb7e53dSJordan K. Hubbard case T_LONG: 1143efb7e53dSJordan K. Hubbard (void) va_arg (ap, long); 1144efb7e53dSJordan K. Hubbard break; 1145efb7e53dSJordan K. Hubbard case T_U_LONG: 1146efb7e53dSJordan K. Hubbard (void) va_arg (ap, unsigned long); 1147efb7e53dSJordan K. Hubbard break; 1148efb7e53dSJordan K. Hubbard case TP_LONG: 1149efb7e53dSJordan K. Hubbard (void) va_arg (ap, long *); 1150efb7e53dSJordan K. Hubbard break; 1151efb7e53dSJordan K. Hubbard case T_QUAD: 1152efb7e53dSJordan K. Hubbard (void) va_arg (ap, quad_t); 1153efb7e53dSJordan K. Hubbard break; 1154efb7e53dSJordan K. Hubbard case T_U_QUAD: 1155efb7e53dSJordan K. Hubbard (void) va_arg (ap, u_quad_t); 1156efb7e53dSJordan K. Hubbard break; 1157efb7e53dSJordan K. Hubbard case TP_QUAD: 1158efb7e53dSJordan K. Hubbard (void) va_arg (ap, quad_t *); 1159efb7e53dSJordan K. Hubbard break; 1160efb7e53dSJordan K. Hubbard case T_DOUBLE: 1161efb7e53dSJordan K. Hubbard (void) va_arg (ap, double); 1162efb7e53dSJordan K. Hubbard break; 1163efb7e53dSJordan K. Hubbard case T_LONG_DOUBLE: 1164efb7e53dSJordan K. Hubbard (void) va_arg (ap, long double); 1165efb7e53dSJordan K. Hubbard break; 1166efb7e53dSJordan K. Hubbard case TP_CHAR: 1167efb7e53dSJordan K. Hubbard (void) va_arg (ap, char *); 1168efb7e53dSJordan K. Hubbard break; 1169efb7e53dSJordan K. Hubbard case TP_VOID: 1170efb7e53dSJordan K. Hubbard (void) va_arg (ap, void *); 1171efb7e53dSJordan K. Hubbard break; 1172efb7e53dSJordan K. Hubbard } 1173efb7e53dSJordan K. Hubbard } 1174efb7e53dSJordan K. Hubbard 1175efb7e53dSJordan K. Hubbard if ((typetable != NULL) && (typetable != stattypetable)) 1176efb7e53dSJordan K. Hubbard free (typetable); 1177efb7e53dSJordan K. Hubbard } 1178efb7e53dSJordan K. Hubbard 1179efb7e53dSJordan K. Hubbard /* 1180efb7e53dSJordan K. Hubbard * Increase the size of the type table. 1181efb7e53dSJordan K. Hubbard */ 1182efb7e53dSJordan K. Hubbard static void 1183efb7e53dSJordan K. Hubbard __grow_type_table (nextarg, typetable, tablesize) 1184efb7e53dSJordan K. Hubbard int nextarg; 1185efb7e53dSJordan K. Hubbard unsigned char **typetable; 1186efb7e53dSJordan K. Hubbard int *tablesize; 1187efb7e53dSJordan K. Hubbard { 1188efb7e53dSJordan K. Hubbard unsigned char *oldtable = *typetable; 1189efb7e53dSJordan K. Hubbard int newsize = *tablesize * 2; 1190efb7e53dSJordan K. Hubbard 1191efb7e53dSJordan K. Hubbard if (*tablesize == STATIC_ARG_TBL_SIZE) { 1192efb7e53dSJordan K. Hubbard *typetable = (unsigned char *) 1193efb7e53dSJordan K. Hubbard malloc (sizeof (unsigned char) * newsize); 1194efb7e53dSJordan K. Hubbard bcopy (oldtable, *typetable, *tablesize); 1195efb7e53dSJordan K. Hubbard } else { 1196efb7e53dSJordan K. Hubbard *typetable = (unsigned char *) 1197efb7e53dSJordan K. Hubbard realloc (typetable, sizeof (unsigned char) * newsize); 1198efb7e53dSJordan K. Hubbard 1199efb7e53dSJordan K. Hubbard } 1200efb7e53dSJordan K. Hubbard memset (&typetable [*tablesize], T_UNUSED, (newsize - *tablesize)); 1201efb7e53dSJordan K. Hubbard 1202efb7e53dSJordan K. Hubbard *tablesize = newsize; 1203efb7e53dSJordan K. Hubbard } 1204efb7e53dSJordan K. Hubbard 1205efb7e53dSJordan K. Hubbard 120658f0484fSRodney W. Grimes #ifdef FLOATING_POINT 120758f0484fSRodney W. Grimes 120858f0484fSRodney W. Grimes extern char *__dtoa __P((double, int, int, int *, int *, char **)); 120958f0484fSRodney W. Grimes 121058f0484fSRodney W. Grimes static char * 121158f0484fSRodney W. Grimes cvt(value, ndigits, flags, sign, decpt, ch, length) 121258f0484fSRodney W. Grimes double value; 121358f0484fSRodney W. Grimes int ndigits, flags, *decpt, ch, *length; 121458f0484fSRodney W. Grimes char *sign; 121558f0484fSRodney W. Grimes { 121658f0484fSRodney W. Grimes int mode, dsgn; 121758f0484fSRodney W. Grimes char *digits, *bp, *rve; 121858f0484fSRodney W. Grimes 121958f0484fSRodney W. Grimes if (ch == 'f') 1220d26be6f0SBruce Evans mode = 3; /* ndigits after the decimal point */ 122158f0484fSRodney W. Grimes else { 1222d26be6f0SBruce Evans /* 1223d26be6f0SBruce Evans * To obtain ndigits after the decimal point for the 'e' 1224d26be6f0SBruce Evans * and 'E' formats, round to ndigits + 1 significant 1225d26be6f0SBruce Evans * figures. 1226d26be6f0SBruce Evans */ 1227d26be6f0SBruce Evans if (ch == 'e' || ch == 'E') 1228d26be6f0SBruce Evans ndigits++; 1229d26be6f0SBruce Evans mode = 2; /* ndigits significant digits */ 123058f0484fSRodney W. Grimes } 123158f0484fSRodney W. Grimes if (value < 0) { 123258f0484fSRodney W. Grimes value = -value; 123358f0484fSRodney W. Grimes *sign = '-'; 123458f0484fSRodney W. Grimes } else 123558f0484fSRodney W. Grimes *sign = '\000'; 123658f0484fSRodney W. Grimes digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve); 1237d26be6f0SBruce Evans if ((ch != 'g' && ch != 'G') || flags & ALT) { 1238d26be6f0SBruce Evans /* print trailing zeros */ 123958f0484fSRodney W. Grimes bp = digits + ndigits; 124058f0484fSRodney W. Grimes if (ch == 'f') { 124158f0484fSRodney W. Grimes if (*digits == '0' && value) 124258f0484fSRodney W. Grimes *decpt = -ndigits + 1; 124358f0484fSRodney W. Grimes bp += *decpt; 124458f0484fSRodney W. Grimes } 124558f0484fSRodney W. Grimes if (value == 0) /* kludge for __dtoa irregularity */ 124658f0484fSRodney W. Grimes rve = bp; 124758f0484fSRodney W. Grimes while (rve < bp) 124858f0484fSRodney W. Grimes *rve++ = '0'; 124958f0484fSRodney W. Grimes } 125058f0484fSRodney W. Grimes *length = rve - digits; 125158f0484fSRodney W. Grimes return (digits); 125258f0484fSRodney W. Grimes } 125358f0484fSRodney W. Grimes 125458f0484fSRodney W. Grimes static int 125558f0484fSRodney W. Grimes exponent(p0, exp, fmtch) 125658f0484fSRodney W. Grimes char *p0; 125758f0484fSRodney W. Grimes int exp, fmtch; 125858f0484fSRodney W. Grimes { 125958f0484fSRodney W. Grimes register char *p, *t; 126058f0484fSRodney W. Grimes char expbuf[MAXEXP]; 126158f0484fSRodney W. Grimes 126258f0484fSRodney W. Grimes p = p0; 126358f0484fSRodney W. Grimes *p++ = fmtch; 126458f0484fSRodney W. Grimes if (exp < 0) { 126558f0484fSRodney W. Grimes exp = -exp; 126658f0484fSRodney W. Grimes *p++ = '-'; 126758f0484fSRodney W. Grimes } 126858f0484fSRodney W. Grimes else 126958f0484fSRodney W. Grimes *p++ = '+'; 127058f0484fSRodney W. Grimes t = expbuf + MAXEXP; 127158f0484fSRodney W. Grimes if (exp > 9) { 127258f0484fSRodney W. Grimes do { 127358f0484fSRodney W. Grimes *--t = to_char(exp % 10); 127458f0484fSRodney W. Grimes } while ((exp /= 10) > 9); 127558f0484fSRodney W. Grimes *--t = to_char(exp); 127658f0484fSRodney W. Grimes for (; t < expbuf + MAXEXP; *p++ = *t++); 127758f0484fSRodney W. Grimes } 127858f0484fSRodney W. Grimes else { 127958f0484fSRodney W. Grimes *p++ = '0'; 128058f0484fSRodney W. Grimes *p++ = to_char(exp); 128158f0484fSRodney W. Grimes } 128258f0484fSRodney W. Grimes return (p - p0); 128358f0484fSRodney W. Grimes } 128458f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 1285