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[] = 421130b656SJordan K. Hubbard "$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 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 */ 28758f0484fSRodney W. Grimes #define LONGDBL 0x008 /* long double; unimplemented */ 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 */ 32358f0484fSRodney W. Grimes char *xdigs; /* digits for [xX] conversion */ 32458f0484fSRodney W. Grimes #define NIOV 8 32558f0484fSRodney W. Grimes struct __suio uio; /* output information: summary */ 32658f0484fSRodney W. Grimes struct __siov iov[NIOV];/* ... and individual io vectors */ 32758f0484fSRodney W. Grimes char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 32858f0484fSRodney W. Grimes char ox[2]; /* space for 0x hex-prefix */ 329efb7e53dSJordan K. Hubbard void **argtable; /* args, built due to positional arg */ 330efb7e53dSJordan K. Hubbard void *statargtable [STATIC_ARG_TBL_SIZE]; 331efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 332efb7e53dSJordan K. Hubbard va_list orgap; /* original argument pointer */ 33358f0484fSRodney W. Grimes 33458f0484fSRodney W. Grimes /* 33558f0484fSRodney W. Grimes * Choose PADSIZE to trade efficiency vs. size. If larger printf 33658f0484fSRodney W. Grimes * fields occur frequently, increase PADSIZE and make the initialisers 33758f0484fSRodney W. Grimes * below longer. 33858f0484fSRodney W. Grimes */ 33958f0484fSRodney W. Grimes #define PADSIZE 16 /* pad chunk size */ 34058f0484fSRodney W. Grimes static char blanks[PADSIZE] = 34158f0484fSRodney W. Grimes {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 34258f0484fSRodney W. Grimes static char zeroes[PADSIZE] = 34358f0484fSRodney W. Grimes {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 34458f0484fSRodney W. Grimes 34558f0484fSRodney W. Grimes /* 34658f0484fSRodney W. Grimes * BEWARE, these `goto error' on error, and PAD uses `n'. 34758f0484fSRodney W. Grimes */ 34858f0484fSRodney W. Grimes #define PRINT(ptr, len) { \ 34958f0484fSRodney W. Grimes iovp->iov_base = (ptr); \ 35058f0484fSRodney W. Grimes iovp->iov_len = (len); \ 35158f0484fSRodney W. Grimes uio.uio_resid += (len); \ 35258f0484fSRodney W. Grimes iovp++; \ 35358f0484fSRodney W. Grimes if (++uio.uio_iovcnt >= NIOV) { \ 35458f0484fSRodney W. Grimes if (__sprint(fp, &uio)) \ 35558f0484fSRodney W. Grimes goto error; \ 35658f0484fSRodney W. Grimes iovp = iov; \ 35758f0484fSRodney W. Grimes } \ 35858f0484fSRodney W. Grimes } 35958f0484fSRodney W. Grimes #define PAD(howmany, with) { \ 36058f0484fSRodney W. Grimes if ((n = (howmany)) > 0) { \ 36158f0484fSRodney W. Grimes while (n > PADSIZE) { \ 36258f0484fSRodney W. Grimes PRINT(with, PADSIZE); \ 36358f0484fSRodney W. Grimes n -= PADSIZE; \ 36458f0484fSRodney W. Grimes } \ 36558f0484fSRodney W. Grimes PRINT(with, n); \ 36658f0484fSRodney W. Grimes } \ 36758f0484fSRodney W. Grimes } 36858f0484fSRodney W. Grimes #define FLUSH() { \ 36958f0484fSRodney W. Grimes if (uio.uio_resid && __sprint(fp, &uio)) \ 37058f0484fSRodney W. Grimes goto error; \ 37158f0484fSRodney W. Grimes uio.uio_iovcnt = 0; \ 37258f0484fSRodney W. Grimes iovp = iov; \ 37358f0484fSRodney W. Grimes } 37458f0484fSRodney W. Grimes 37558f0484fSRodney W. Grimes /* 376efb7e53dSJordan K. Hubbard * Get the argument indexed by nextarg. If the argument table is 377efb7e53dSJordan K. Hubbard * built, use it to get the argument. If its not, get the next 378efb7e53dSJordan K. Hubbard * argument (and arguments must be gotten sequentially). 379efb7e53dSJordan K. Hubbard */ 380efb7e53dSJordan K. Hubbard #define GETARG(type) \ 381efb7e53dSJordan K. Hubbard ((argtable != NULL) ? *((type*)(argtable[nextarg++])) : \ 382efb7e53dSJordan K. Hubbard (nextarg++, va_arg(ap, type))) 383efb7e53dSJordan K. Hubbard 384efb7e53dSJordan K. Hubbard /* 38558f0484fSRodney W. Grimes * To extend shorts properly, we need both signed and unsigned 38658f0484fSRodney W. Grimes * argument extraction methods. 38758f0484fSRodney W. Grimes */ 38858f0484fSRodney W. Grimes #define SARG() \ 389efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(long) : \ 390efb7e53dSJordan K. Hubbard flags&SHORTINT ? (long)(short)GETARG(int) : \ 391efb7e53dSJordan K. Hubbard (long)GETARG(int)) 39258f0484fSRodney W. Grimes #define UARG() \ 393efb7e53dSJordan K. Hubbard (flags&LONGINT ? GETARG(u_long) : \ 394efb7e53dSJordan K. Hubbard flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ 395efb7e53dSJordan K. Hubbard (u_long)GETARG(u_int)) 396efb7e53dSJordan K. Hubbard 397efb7e53dSJordan K. Hubbard /* 398efb7e53dSJordan K. Hubbard * Get * arguments, including the form *nn$. Preserve the nextarg 399efb7e53dSJordan K. Hubbard * that the argument can be gotten once the type is determined. 400efb7e53dSJordan K. Hubbard */ 401efb7e53dSJordan K. Hubbard #define GETASTER(val) \ 402efb7e53dSJordan K. Hubbard n2 = 0; \ 403efb7e53dSJordan K. Hubbard cp = fmt; \ 404efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 405efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 406efb7e53dSJordan K. Hubbard cp++; \ 407efb7e53dSJordan K. Hubbard } \ 408efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 409efb7e53dSJordan K. Hubbard int hold = nextarg; \ 410efb7e53dSJordan K. Hubbard if (argtable == NULL) { \ 411efb7e53dSJordan K. Hubbard argtable = statargtable; \ 412efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, &argtable); \ 413efb7e53dSJordan K. Hubbard } \ 414efb7e53dSJordan K. Hubbard nextarg = n2; \ 415efb7e53dSJordan K. Hubbard val = GETARG (int); \ 416efb7e53dSJordan K. Hubbard nextarg = hold; \ 417efb7e53dSJordan K. Hubbard fmt = ++cp; \ 418efb7e53dSJordan K. Hubbard } else { \ 419efb7e53dSJordan K. Hubbard val = GETARG (int); \ 420efb7e53dSJordan K. Hubbard } 421efb7e53dSJordan K. Hubbard 42258f0484fSRodney W. Grimes 423f70177e7SJulian Elischer #ifdef _THREAD_SAFE 424f70177e7SJulian Elischer _thread_flockfile(fp,__FILE__,__LINE__); 425f70177e7SJulian Elischer #endif 42658f0484fSRodney W. Grimes /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 427f70177e7SJulian Elischer if (cantwrite(fp)) { 428f70177e7SJulian Elischer #ifdef _THREAD_SAFE 429f70177e7SJulian Elischer _thread_funlockfile(fp); 430f70177e7SJulian Elischer #endif 43158f0484fSRodney W. Grimes return (EOF); 432f70177e7SJulian Elischer } 43358f0484fSRodney W. Grimes 43458f0484fSRodney W. Grimes /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 43558f0484fSRodney W. Grimes if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 436f70177e7SJulian Elischer fp->_file >= 0) { 437f70177e7SJulian Elischer #ifdef _THREAD_SAFE 438f70177e7SJulian Elischer _thread_funlockfile(fp); 439f70177e7SJulian Elischer #endif 44058f0484fSRodney W. Grimes return (__sbprintf(fp, fmt0, ap)); 441f70177e7SJulian Elischer } 44258f0484fSRodney W. Grimes 44358f0484fSRodney W. Grimes fmt = (char *)fmt0; 444efb7e53dSJordan K. Hubbard argtable = NULL; 445efb7e53dSJordan K. Hubbard nextarg = 1; 446efb7e53dSJordan K. Hubbard orgap = ap; 44758f0484fSRodney W. Grimes uio.uio_iov = iovp = iov; 44858f0484fSRodney W. Grimes uio.uio_resid = 0; 44958f0484fSRodney W. Grimes uio.uio_iovcnt = 0; 45058f0484fSRodney W. Grimes ret = 0; 45158f0484fSRodney W. Grimes 45258f0484fSRodney W. Grimes /* 45358f0484fSRodney W. Grimes * Scan the format for conversions (`%' character). 45458f0484fSRodney W. Grimes */ 45558f0484fSRodney W. Grimes for (;;) { 45658f0484fSRodney W. Grimes for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 45758f0484fSRodney W. Grimes /* void */; 45858f0484fSRodney W. Grimes if ((n = fmt - cp) != 0) { 45958f0484fSRodney W. Grimes PRINT(cp, n); 46058f0484fSRodney W. Grimes ret += n; 46158f0484fSRodney W. Grimes } 46258f0484fSRodney W. Grimes if (ch == '\0') 46358f0484fSRodney W. Grimes goto done; 46458f0484fSRodney W. Grimes fmt++; /* skip over '%' */ 46558f0484fSRodney W. Grimes 46658f0484fSRodney W. Grimes flags = 0; 46758f0484fSRodney W. Grimes dprec = 0; 46858f0484fSRodney W. Grimes width = 0; 46958f0484fSRodney W. Grimes prec = -1; 47058f0484fSRodney W. Grimes sign = '\0'; 47158f0484fSRodney W. Grimes 47258f0484fSRodney W. Grimes rflag: ch = *fmt++; 47358f0484fSRodney W. Grimes reswitch: switch (ch) { 47458f0484fSRodney W. Grimes case ' ': 47558f0484fSRodney W. Grimes /* 47658f0484fSRodney W. Grimes * ``If the space and + flags both appear, the space 47758f0484fSRodney W. Grimes * flag will be ignored.'' 47858f0484fSRodney W. Grimes * -- ANSI X3J11 47958f0484fSRodney W. Grimes */ 48058f0484fSRodney W. Grimes if (!sign) 48158f0484fSRodney W. Grimes sign = ' '; 48258f0484fSRodney W. Grimes goto rflag; 48358f0484fSRodney W. Grimes case '#': 48458f0484fSRodney W. Grimes flags |= ALT; 48558f0484fSRodney W. Grimes goto rflag; 48658f0484fSRodney W. Grimes case '*': 48758f0484fSRodney W. Grimes /* 48858f0484fSRodney W. Grimes * ``A negative field width argument is taken as a 48958f0484fSRodney W. Grimes * - flag followed by a positive field width.'' 49058f0484fSRodney W. Grimes * -- ANSI X3J11 49158f0484fSRodney W. Grimes * They don't exclude field widths read from args. 49258f0484fSRodney W. Grimes */ 493efb7e53dSJordan K. Hubbard GETASTER (width); 494efb7e53dSJordan K. Hubbard if (width >= 0) 49558f0484fSRodney W. Grimes goto rflag; 49658f0484fSRodney W. Grimes width = -width; 49758f0484fSRodney W. Grimes /* FALLTHROUGH */ 49858f0484fSRodney W. Grimes case '-': 49958f0484fSRodney W. Grimes flags |= LADJUST; 50058f0484fSRodney W. Grimes goto rflag; 50158f0484fSRodney W. Grimes case '+': 50258f0484fSRodney W. Grimes sign = '+'; 50358f0484fSRodney W. Grimes goto rflag; 50458f0484fSRodney W. Grimes case '.': 50558f0484fSRodney W. Grimes if ((ch = *fmt++) == '*') { 506efb7e53dSJordan K. Hubbard GETASTER (n); 50758f0484fSRodney W. Grimes prec = n < 0 ? -1 : n; 50858f0484fSRodney W. Grimes goto rflag; 50958f0484fSRodney W. Grimes } 51058f0484fSRodney W. Grimes n = 0; 51158f0484fSRodney W. Grimes while (is_digit(ch)) { 51258f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 51358f0484fSRodney W. Grimes ch = *fmt++; 51458f0484fSRodney W. Grimes } 51558f0484fSRodney W. Grimes prec = n < 0 ? -1 : n; 51658f0484fSRodney W. Grimes goto reswitch; 51758f0484fSRodney W. Grimes case '0': 51858f0484fSRodney W. Grimes /* 51958f0484fSRodney W. Grimes * ``Note that 0 is taken as a flag, not as the 52058f0484fSRodney W. Grimes * beginning of a field width.'' 52158f0484fSRodney W. Grimes * -- ANSI X3J11 52258f0484fSRodney W. Grimes */ 52358f0484fSRodney W. Grimes flags |= ZEROPAD; 52458f0484fSRodney W. Grimes goto rflag; 52558f0484fSRodney W. Grimes case '1': case '2': case '3': case '4': 52658f0484fSRodney W. Grimes case '5': case '6': case '7': case '8': case '9': 52758f0484fSRodney W. Grimes n = 0; 52858f0484fSRodney W. Grimes do { 52958f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 53058f0484fSRodney W. Grimes ch = *fmt++; 53158f0484fSRodney W. Grimes } while (is_digit(ch)); 532efb7e53dSJordan K. Hubbard if (ch == '$') { 533efb7e53dSJordan K. Hubbard nextarg = n; 534efb7e53dSJordan K. Hubbard if (argtable == NULL) { 535efb7e53dSJordan K. Hubbard argtable = statargtable; 536efb7e53dSJordan K. Hubbard __find_arguments (fmt0, orgap, 537efb7e53dSJordan K. Hubbard &argtable); 538efb7e53dSJordan K. Hubbard } 539efb7e53dSJordan K. Hubbard goto rflag; 540efb7e53dSJordan K. Hubbard } 54158f0484fSRodney W. Grimes width = n; 54258f0484fSRodney W. Grimes goto reswitch; 54358f0484fSRodney W. Grimes #ifdef FLOATING_POINT 54458f0484fSRodney W. Grimes case 'L': 54558f0484fSRodney W. Grimes flags |= LONGDBL; 54658f0484fSRodney W. Grimes goto rflag; 54758f0484fSRodney W. Grimes #endif 54858f0484fSRodney W. Grimes case 'h': 54958f0484fSRodney W. Grimes flags |= SHORTINT; 55058f0484fSRodney W. Grimes goto rflag; 55158f0484fSRodney W. Grimes case 'l': 55258f0484fSRodney W. Grimes flags |= LONGINT; 55358f0484fSRodney W. Grimes goto rflag; 55458f0484fSRodney W. Grimes case 'q': 55558f0484fSRodney W. Grimes flags |= QUADINT; 55658f0484fSRodney W. Grimes goto rflag; 55758f0484fSRodney W. Grimes case 'c': 558efb7e53dSJordan K. Hubbard *(cp = buf) = GETARG(int); 55958f0484fSRodney W. Grimes size = 1; 56058f0484fSRodney W. Grimes sign = '\0'; 56158f0484fSRodney W. Grimes break; 56258f0484fSRodney W. Grimes case 'D': 56358f0484fSRodney W. Grimes flags |= LONGINT; 56458f0484fSRodney W. Grimes /*FALLTHROUGH*/ 56558f0484fSRodney W. Grimes case 'd': 56658f0484fSRodney W. Grimes case 'i': 56758f0484fSRodney W. Grimes if (flags & QUADINT) { 568efb7e53dSJordan K. Hubbard uqval = GETARG(quad_t); 56958f0484fSRodney W. Grimes if ((quad_t)uqval < 0) { 57058f0484fSRodney W. Grimes uqval = -uqval; 57158f0484fSRodney W. Grimes sign = '-'; 57258f0484fSRodney W. Grimes } 57358f0484fSRodney W. Grimes } else { 57458f0484fSRodney W. Grimes ulval = SARG(); 57558f0484fSRodney W. Grimes if ((long)ulval < 0) { 57658f0484fSRodney W. Grimes ulval = -ulval; 57758f0484fSRodney W. Grimes sign = '-'; 57858f0484fSRodney W. Grimes } 57958f0484fSRodney W. Grimes } 58058f0484fSRodney W. Grimes base = 10; 58158f0484fSRodney W. Grimes goto number; 58258f0484fSRodney W. Grimes #ifdef FLOATING_POINT 583d26be6f0SBruce Evans case 'e': 58458f0484fSRodney W. Grimes case 'E': 585d26be6f0SBruce Evans case 'f': 586d26be6f0SBruce Evans goto fp_begin; 58758f0484fSRodney W. Grimes case 'g': 58858f0484fSRodney W. Grimes case 'G': 589d26be6f0SBruce Evans if (prec == 0) 590d26be6f0SBruce Evans prec = 1; 591d26be6f0SBruce Evans fp_begin: if (prec == -1) 59258f0484fSRodney W. Grimes prec = DEFPREC; 593d26be6f0SBruce Evans if (flags & LONGDBL) 594efb7e53dSJordan K. Hubbard _double = (double)GETARG(long double); 595d26be6f0SBruce Evans else 596efb7e53dSJordan K. Hubbard _double = GETARG(double); 59758f0484fSRodney W. Grimes /* do this before tricky precision changes */ 59858f0484fSRodney W. Grimes if (isinf(_double)) { 59958f0484fSRodney W. Grimes if (_double < 0) 60058f0484fSRodney W. Grimes sign = '-'; 60158f0484fSRodney W. Grimes cp = "Inf"; 60258f0484fSRodney W. Grimes size = 3; 60358f0484fSRodney W. Grimes break; 60458f0484fSRodney W. Grimes } 60558f0484fSRodney W. Grimes if (isnan(_double)) { 60658f0484fSRodney W. Grimes cp = "NaN"; 60758f0484fSRodney W. Grimes size = 3; 60858f0484fSRodney W. Grimes break; 60958f0484fSRodney W. Grimes } 61058f0484fSRodney W. Grimes flags |= FPT; 61158f0484fSRodney W. Grimes cp = cvt(_double, prec, flags, &softsign, 61258f0484fSRodney W. Grimes &expt, ch, &ndig); 61358f0484fSRodney W. Grimes if (ch == 'g' || ch == 'G') { 61458f0484fSRodney W. Grimes if (expt <= -4 || expt > prec) 61558f0484fSRodney W. Grimes ch = (ch == 'g') ? 'e' : 'E'; 61658f0484fSRodney W. Grimes else 61758f0484fSRodney W. Grimes ch = 'g'; 61858f0484fSRodney W. Grimes } 61958f0484fSRodney W. Grimes if (ch <= 'e') { /* 'e' or 'E' fmt */ 62058f0484fSRodney W. Grimes --expt; 62158f0484fSRodney W. Grimes expsize = exponent(expstr, expt, ch); 62258f0484fSRodney W. Grimes size = expsize + ndig; 62358f0484fSRodney W. Grimes if (ndig > 1 || flags & ALT) 62458f0484fSRodney W. Grimes ++size; 62558f0484fSRodney W. Grimes } else if (ch == 'f') { /* f fmt */ 62658f0484fSRodney W. Grimes if (expt > 0) { 62758f0484fSRodney W. Grimes size = expt; 62858f0484fSRodney W. Grimes if (prec || flags & ALT) 62958f0484fSRodney W. Grimes size += prec + 1; 63058f0484fSRodney W. Grimes } else /* "0.X" */ 63158f0484fSRodney W. Grimes size = prec + 2; 63258f0484fSRodney W. Grimes } else if (expt >= ndig) { /* fixed g fmt */ 63358f0484fSRodney W. Grimes size = expt; 63458f0484fSRodney W. Grimes if (flags & ALT) 63558f0484fSRodney W. Grimes ++size; 63658f0484fSRodney W. Grimes } else 63758f0484fSRodney W. Grimes size = ndig + (expt > 0 ? 63858f0484fSRodney W. Grimes 1 : 2 - expt); 63958f0484fSRodney W. Grimes 64058f0484fSRodney W. Grimes if (softsign) 64158f0484fSRodney W. Grimes sign = '-'; 64258f0484fSRodney W. Grimes break; 64358f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 64458f0484fSRodney W. Grimes case 'n': 64558f0484fSRodney W. Grimes if (flags & QUADINT) 646efb7e53dSJordan K. Hubbard *GETARG(quad_t *) = ret; 64758f0484fSRodney W. Grimes else if (flags & LONGINT) 648efb7e53dSJordan K. Hubbard *GETARG(long *) = ret; 64958f0484fSRodney W. Grimes else if (flags & SHORTINT) 650efb7e53dSJordan K. Hubbard *GETARG(short *) = ret; 65158f0484fSRodney W. Grimes else 652efb7e53dSJordan K. Hubbard *GETARG(int *) = ret; 65358f0484fSRodney W. Grimes continue; /* no output */ 65458f0484fSRodney W. Grimes case 'O': 65558f0484fSRodney W. Grimes flags |= LONGINT; 65658f0484fSRodney W. Grimes /*FALLTHROUGH*/ 65758f0484fSRodney W. Grimes case 'o': 65858f0484fSRodney W. Grimes if (flags & QUADINT) 659efb7e53dSJordan K. Hubbard uqval = GETARG(u_quad_t); 66058f0484fSRodney W. Grimes else 66158f0484fSRodney W. Grimes ulval = UARG(); 66258f0484fSRodney W. Grimes base = 8; 66358f0484fSRodney W. Grimes goto nosign; 66458f0484fSRodney W. Grimes case 'p': 66558f0484fSRodney W. Grimes /* 66658f0484fSRodney W. Grimes * ``The argument shall be a pointer to void. The 66758f0484fSRodney W. Grimes * value of the pointer is converted to a sequence 66858f0484fSRodney W. Grimes * of printable characters, in an implementation- 66958f0484fSRodney W. Grimes * defined manner.'' 67058f0484fSRodney W. Grimes * -- ANSI X3J11 67158f0484fSRodney W. Grimes */ 672efb7e53dSJordan K. Hubbard ulval = (u_long)GETARG(void *); 67358f0484fSRodney W. Grimes base = 16; 67458f0484fSRodney W. Grimes xdigs = "0123456789abcdef"; 67558f0484fSRodney W. Grimes flags = (flags & ~QUADINT) | HEXPREFIX; 67658f0484fSRodney W. Grimes ch = 'x'; 67758f0484fSRodney W. Grimes goto nosign; 67858f0484fSRodney W. Grimes case 's': 679efb7e53dSJordan K. Hubbard if ((cp = GETARG(char *)) == NULL) 68058f0484fSRodney W. Grimes cp = "(null)"; 68158f0484fSRodney W. Grimes if (prec >= 0) { 68258f0484fSRodney W. Grimes /* 68358f0484fSRodney W. Grimes * can't use strlen; can only look for the 68458f0484fSRodney W. Grimes * NUL in the first `prec' characters, and 68558f0484fSRodney W. Grimes * strlen() will go further. 68658f0484fSRodney W. Grimes */ 687ce51cf03SJames Raynard char *p = memchr(cp, 0, (size_t)prec); 68858f0484fSRodney W. Grimes 68958f0484fSRodney W. Grimes if (p != NULL) { 69058f0484fSRodney W. Grimes size = p - cp; 69158f0484fSRodney W. Grimes if (size > prec) 69258f0484fSRodney W. Grimes size = prec; 69358f0484fSRodney W. Grimes } else 69458f0484fSRodney W. Grimes size = prec; 69558f0484fSRodney W. Grimes } else 69658f0484fSRodney W. Grimes size = strlen(cp); 69758f0484fSRodney W. Grimes sign = '\0'; 69858f0484fSRodney W. Grimes break; 69958f0484fSRodney W. Grimes case 'U': 70058f0484fSRodney W. Grimes flags |= LONGINT; 70158f0484fSRodney W. Grimes /*FALLTHROUGH*/ 70258f0484fSRodney W. Grimes case 'u': 70358f0484fSRodney W. Grimes if (flags & QUADINT) 704efb7e53dSJordan K. Hubbard uqval = GETARG(u_quad_t); 70558f0484fSRodney W. Grimes else 70658f0484fSRodney W. Grimes ulval = UARG(); 70758f0484fSRodney W. Grimes base = 10; 70858f0484fSRodney W. Grimes goto nosign; 70958f0484fSRodney W. Grimes case 'X': 71058f0484fSRodney W. Grimes xdigs = "0123456789ABCDEF"; 71158f0484fSRodney W. Grimes goto hex; 71258f0484fSRodney W. Grimes case 'x': 71358f0484fSRodney W. Grimes xdigs = "0123456789abcdef"; 71458f0484fSRodney W. Grimes hex: if (flags & QUADINT) 715efb7e53dSJordan K. Hubbard uqval = GETARG(u_quad_t); 71658f0484fSRodney W. Grimes else 71758f0484fSRodney W. Grimes ulval = UARG(); 71858f0484fSRodney W. Grimes base = 16; 71958f0484fSRodney W. Grimes /* leading 0x/X only if non-zero */ 72058f0484fSRodney W. Grimes if (flags & ALT && 72158f0484fSRodney W. Grimes (flags & QUADINT ? uqval != 0 : ulval != 0)) 72258f0484fSRodney W. Grimes flags |= HEXPREFIX; 72358f0484fSRodney W. Grimes 72458f0484fSRodney W. Grimes /* unsigned conversions */ 72558f0484fSRodney W. Grimes nosign: sign = '\0'; 72658f0484fSRodney W. Grimes /* 72758f0484fSRodney W. Grimes * ``... diouXx conversions ... if a precision is 72858f0484fSRodney W. Grimes * specified, the 0 flag will be ignored.'' 72958f0484fSRodney W. Grimes * -- ANSI X3J11 73058f0484fSRodney W. Grimes */ 73158f0484fSRodney W. Grimes number: if ((dprec = prec) >= 0) 73258f0484fSRodney W. Grimes flags &= ~ZEROPAD; 73358f0484fSRodney W. Grimes 73458f0484fSRodney W. Grimes /* 73558f0484fSRodney W. Grimes * ``The result of converting a zero value with an 73658f0484fSRodney W. Grimes * explicit precision of zero is no characters.'' 73758f0484fSRodney W. Grimes * -- ANSI X3J11 73858f0484fSRodney W. Grimes */ 73958f0484fSRodney W. Grimes cp = buf + BUF; 74058f0484fSRodney W. Grimes if (flags & QUADINT) { 74158f0484fSRodney W. Grimes if (uqval != 0 || prec != 0) 74258f0484fSRodney W. Grimes cp = __uqtoa(uqval, cp, base, 74358f0484fSRodney W. Grimes flags & ALT, xdigs); 74458f0484fSRodney W. Grimes } else { 74558f0484fSRodney W. Grimes if (ulval != 0 || prec != 0) 74658f0484fSRodney W. Grimes cp = __ultoa(ulval, cp, base, 74758f0484fSRodney W. Grimes flags & ALT, xdigs); 74858f0484fSRodney W. Grimes } 74958f0484fSRodney W. Grimes size = buf + BUF - cp; 75058f0484fSRodney W. Grimes break; 75158f0484fSRodney W. Grimes default: /* "%?" prints ?, unless ? is NUL */ 75258f0484fSRodney W. Grimes if (ch == '\0') 75358f0484fSRodney W. Grimes goto done; 75458f0484fSRodney W. Grimes /* pretend it was %c with argument ch */ 75558f0484fSRodney W. Grimes cp = buf; 75658f0484fSRodney W. Grimes *cp = ch; 75758f0484fSRodney W. Grimes size = 1; 75858f0484fSRodney W. Grimes sign = '\0'; 75958f0484fSRodney W. Grimes break; 76058f0484fSRodney W. Grimes } 76158f0484fSRodney W. Grimes 76258f0484fSRodney W. Grimes /* 76358f0484fSRodney W. Grimes * All reasonable formats wind up here. At this point, `cp' 76458f0484fSRodney W. Grimes * points to a string which (if not flags&LADJUST) should be 76558f0484fSRodney W. Grimes * padded out to `width' places. If flags&ZEROPAD, it should 76658f0484fSRodney W. Grimes * first be prefixed by any sign or other prefix; otherwise, 76758f0484fSRodney W. Grimes * it should be blank padded before the prefix is emitted. 76858f0484fSRodney W. Grimes * After any left-hand padding and prefixing, emit zeroes 76958f0484fSRodney W. Grimes * required by a decimal [diouxX] precision, then print the 77058f0484fSRodney W. Grimes * string proper, then emit zeroes required by any leftover 77158f0484fSRodney W. Grimes * floating precision; finally, if LADJUST, pad with blanks. 77258f0484fSRodney W. Grimes * 77358f0484fSRodney W. Grimes * Compute actual size, so we know how much to pad. 774261a532aSBill Fenner * size excludes decimal prec; realsz includes it. 77558f0484fSRodney W. Grimes */ 776261a532aSBill Fenner realsz = dprec > size ? dprec : size; 77758f0484fSRodney W. Grimes if (sign) 778261a532aSBill Fenner realsz++; 77958f0484fSRodney W. Grimes else if (flags & HEXPREFIX) 780261a532aSBill Fenner realsz += 2; 78158f0484fSRodney W. Grimes 78258f0484fSRodney W. Grimes /* right-adjusting blank padding */ 78358f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == 0) 78458f0484fSRodney W. Grimes PAD(width - realsz, blanks); 78558f0484fSRodney W. Grimes 78658f0484fSRodney W. Grimes /* prefix */ 78758f0484fSRodney W. Grimes if (sign) { 78858f0484fSRodney W. Grimes PRINT(&sign, 1); 78958f0484fSRodney W. Grimes } else if (flags & HEXPREFIX) { 79058f0484fSRodney W. Grimes ox[0] = '0'; 79158f0484fSRodney W. Grimes ox[1] = ch; 79258f0484fSRodney W. Grimes PRINT(ox, 2); 79358f0484fSRodney W. Grimes } 79458f0484fSRodney W. Grimes 79558f0484fSRodney W. Grimes /* right-adjusting zero padding */ 79658f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 79758f0484fSRodney W. Grimes PAD(width - realsz, zeroes); 79858f0484fSRodney W. Grimes 79958f0484fSRodney W. Grimes /* leading zeroes from decimal precision */ 800261a532aSBill Fenner PAD(dprec - size, zeroes); 80158f0484fSRodney W. Grimes 80258f0484fSRodney W. Grimes /* the string or number proper */ 80358f0484fSRodney W. Grimes #ifdef FLOATING_POINT 80458f0484fSRodney W. Grimes if ((flags & FPT) == 0) { 80558f0484fSRodney W. Grimes PRINT(cp, size); 80658f0484fSRodney W. Grimes } else { /* glue together f_p fragments */ 80758f0484fSRodney W. Grimes if (ch >= 'f') { /* 'f' or 'g' */ 80858f0484fSRodney W. Grimes if (_double == 0) { 80958f0484fSRodney W. Grimes /* kludge for __dtoa irregularity */ 810ffe57f1aSBruce Evans if (expt >= ndig && 811ffe57f1aSBruce Evans (flags & ALT) == 0) { 81258f0484fSRodney W. Grimes PRINT("0", 1); 81358f0484fSRodney W. Grimes } else { 81458f0484fSRodney W. Grimes PRINT("0.", 2); 81558f0484fSRodney W. Grimes PAD(ndig - 1, zeroes); 81658f0484fSRodney W. Grimes } 81758f0484fSRodney W. Grimes } else if (expt <= 0) { 81858f0484fSRodney W. Grimes PRINT("0.", 2); 81958f0484fSRodney W. Grimes PAD(-expt, zeroes); 82058f0484fSRodney W. Grimes PRINT(cp, ndig); 82158f0484fSRodney W. Grimes } else if (expt >= ndig) { 82258f0484fSRodney W. Grimes PRINT(cp, ndig); 82358f0484fSRodney W. Grimes PAD(expt - ndig, zeroes); 82458f0484fSRodney W. Grimes if (flags & ALT) 82558f0484fSRodney W. Grimes PRINT(".", 1); 82658f0484fSRodney W. Grimes } else { 82758f0484fSRodney W. Grimes PRINT(cp, expt); 82858f0484fSRodney W. Grimes cp += expt; 82958f0484fSRodney W. Grimes PRINT(".", 1); 83058f0484fSRodney W. Grimes PRINT(cp, ndig-expt); 83158f0484fSRodney W. Grimes } 83258f0484fSRodney W. Grimes } else { /* 'e' or 'E' */ 83358f0484fSRodney W. Grimes if (ndig > 1 || flags & ALT) { 83458f0484fSRodney W. Grimes ox[0] = *cp++; 83558f0484fSRodney W. Grimes ox[1] = '.'; 83658f0484fSRodney W. Grimes PRINT(ox, 2); 837918bed75SBruce Evans if (_double) { 83858f0484fSRodney W. Grimes PRINT(cp, ndig-1); 83958f0484fSRodney W. Grimes } else /* 0.[0..] */ 84058f0484fSRodney W. Grimes /* __dtoa irregularity */ 84158f0484fSRodney W. Grimes PAD(ndig - 1, zeroes); 84258f0484fSRodney W. Grimes } else /* XeYYY */ 84358f0484fSRodney W. Grimes PRINT(cp, 1); 84458f0484fSRodney W. Grimes PRINT(expstr, expsize); 84558f0484fSRodney W. Grimes } 84658f0484fSRodney W. Grimes } 84758f0484fSRodney W. Grimes #else 84858f0484fSRodney W. Grimes PRINT(cp, size); 84958f0484fSRodney W. Grimes #endif 85058f0484fSRodney W. Grimes /* left-adjusting padding (always blank) */ 85158f0484fSRodney W. Grimes if (flags & LADJUST) 85258f0484fSRodney W. Grimes PAD(width - realsz, blanks); 85358f0484fSRodney W. Grimes 85458f0484fSRodney W. Grimes /* finally, adjust ret */ 85558f0484fSRodney W. Grimes ret += width > realsz ? width : realsz; 85658f0484fSRodney W. Grimes 85758f0484fSRodney W. Grimes FLUSH(); /* copy out the I/O vectors */ 85858f0484fSRodney W. Grimes } 85958f0484fSRodney W. Grimes done: 86058f0484fSRodney W. Grimes FLUSH(); 86158f0484fSRodney W. Grimes error: 862f70177e7SJulian Elischer if (__sferror(fp)) 863f70177e7SJulian Elischer ret = EOF; 864f70177e7SJulian Elischer #ifdef _THREAD_SAFE 865f70177e7SJulian Elischer _thread_funlockfile(fp); 866f70177e7SJulian Elischer #endif 867efb7e53dSJordan K. Hubbard if ((argtable != NULL) && (argtable != statargtable)) 868efb7e53dSJordan K. Hubbard free (argtable); 869f70177e7SJulian Elischer return (ret); 87058f0484fSRodney W. Grimes /* NOTREACHED */ 87158f0484fSRodney W. Grimes } 87258f0484fSRodney W. Grimes 873efb7e53dSJordan K. Hubbard /* 874efb7e53dSJordan K. Hubbard * Type ids for argument type table. 875efb7e53dSJordan K. Hubbard */ 876efb7e53dSJordan K. Hubbard #define T_UNUSED 0 877efb7e53dSJordan K. Hubbard #define T_SHORT 1 878efb7e53dSJordan K. Hubbard #define T_U_SHORT 2 879efb7e53dSJordan K. Hubbard #define TP_SHORT 3 880efb7e53dSJordan K. Hubbard #define T_INT 4 881efb7e53dSJordan K. Hubbard #define T_U_INT 5 882efb7e53dSJordan K. Hubbard #define TP_INT 6 883efb7e53dSJordan K. Hubbard #define T_LONG 7 884efb7e53dSJordan K. Hubbard #define T_U_LONG 8 885efb7e53dSJordan K. Hubbard #define TP_LONG 9 886efb7e53dSJordan K. Hubbard #define T_QUAD 10 887efb7e53dSJordan K. Hubbard #define T_U_QUAD 11 888efb7e53dSJordan K. Hubbard #define TP_QUAD 12 889efb7e53dSJordan K. Hubbard #define T_DOUBLE 13 890efb7e53dSJordan K. Hubbard #define T_LONG_DOUBLE 14 891efb7e53dSJordan K. Hubbard #define TP_CHAR 15 892efb7e53dSJordan K. Hubbard #define TP_VOID 16 893efb7e53dSJordan K. Hubbard 894efb7e53dSJordan K. Hubbard /* 895efb7e53dSJordan K. Hubbard * Find all arguments when a positional parameter is encountered. Returns a 896efb7e53dSJordan K. Hubbard * table, indexed by argument number, of pointers to each arguments. The 897efb7e53dSJordan K. Hubbard * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 898efb7e53dSJordan K. Hubbard * It will be replaces with a malloc-ed on if it overflows. 899efb7e53dSJordan K. Hubbard */ 900efb7e53dSJordan K. Hubbard static void 901efb7e53dSJordan K. Hubbard __find_arguments (fmt0, ap, argtable) 902efb7e53dSJordan K. Hubbard const char *fmt0; 903efb7e53dSJordan K. Hubbard va_list ap; 904efb7e53dSJordan K. Hubbard void ***argtable; 905efb7e53dSJordan K. Hubbard { 906efb7e53dSJordan K. Hubbard register char *fmt; /* format string */ 907efb7e53dSJordan K. Hubbard register int ch; /* character from fmt */ 908efb7e53dSJordan K. Hubbard register int n, n2; /* handy integer (short term usage) */ 909efb7e53dSJordan K. Hubbard register char *cp; /* handy char pointer (short term usage) */ 910efb7e53dSJordan K. Hubbard register int flags; /* flags as above */ 911efb7e53dSJordan K. Hubbard int width; /* width from format (%8d), or 0 */ 912efb7e53dSJordan K. Hubbard unsigned char *typetable; /* table of types */ 913efb7e53dSJordan K. Hubbard unsigned char stattypetable [STATIC_ARG_TBL_SIZE]; 914efb7e53dSJordan K. Hubbard int tablesize; /* current size of type table */ 915efb7e53dSJordan K. Hubbard int tablemax; /* largest used index in table */ 916efb7e53dSJordan K. Hubbard int nextarg; /* 1-based argument index */ 917efb7e53dSJordan K. Hubbard 918efb7e53dSJordan K. Hubbard /* 919efb7e53dSJordan K. Hubbard * Add an argument type to the table, expanding if necessary. 920efb7e53dSJordan K. Hubbard */ 921efb7e53dSJordan K. Hubbard #define ADDTYPE(type) \ 922efb7e53dSJordan K. Hubbard ((nextarg >= tablesize) ? \ 923efb7e53dSJordan K. Hubbard __grow_type_table(nextarg, &typetable, &tablesize) : 0, \ 924efb7e53dSJordan K. Hubbard typetable[nextarg++] = type, \ 925efb7e53dSJordan K. Hubbard (nextarg > tablemax) ? tablemax = nextarg : 0) 926efb7e53dSJordan K. Hubbard 927efb7e53dSJordan K. Hubbard #define ADDSARG() \ 928efb7e53dSJordan K. Hubbard ((flags&LONGINT) ? ADDTYPE(T_LONG) : \ 929efb7e53dSJordan K. Hubbard ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT))) 930efb7e53dSJordan K. Hubbard 931efb7e53dSJordan K. Hubbard #define ADDUARG() \ 932efb7e53dSJordan K. Hubbard ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \ 933efb7e53dSJordan K. Hubbard ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT))) 934efb7e53dSJordan K. Hubbard 935efb7e53dSJordan K. Hubbard /* 936efb7e53dSJordan K. Hubbard * Add * arguments to the type array. 937efb7e53dSJordan K. Hubbard */ 938efb7e53dSJordan K. Hubbard #define ADDASTER() \ 939efb7e53dSJordan K. Hubbard n2 = 0; \ 940efb7e53dSJordan K. Hubbard cp = fmt; \ 941efb7e53dSJordan K. Hubbard while (is_digit(*cp)) { \ 942efb7e53dSJordan K. Hubbard n2 = 10 * n2 + to_digit(*cp); \ 943efb7e53dSJordan K. Hubbard cp++; \ 944efb7e53dSJordan K. Hubbard } \ 945efb7e53dSJordan K. Hubbard if (*cp == '$') { \ 946efb7e53dSJordan K. Hubbard int hold = nextarg; \ 947efb7e53dSJordan K. Hubbard nextarg = n2; \ 948efb7e53dSJordan K. Hubbard ADDTYPE (T_INT); \ 949efb7e53dSJordan K. Hubbard nextarg = hold; \ 950efb7e53dSJordan K. Hubbard fmt = ++cp; \ 951efb7e53dSJordan K. Hubbard } else { \ 952efb7e53dSJordan K. Hubbard ADDTYPE (T_INT); \ 953efb7e53dSJordan K. Hubbard } 954efb7e53dSJordan K. Hubbard fmt = (char *)fmt0; 955efb7e53dSJordan K. Hubbard typetable = stattypetable; 956efb7e53dSJordan K. Hubbard tablesize = STATIC_ARG_TBL_SIZE; 957efb7e53dSJordan K. Hubbard tablemax = 0; 958efb7e53dSJordan K. Hubbard nextarg = 1; 959efb7e53dSJordan K. Hubbard memset (typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); 960efb7e53dSJordan K. Hubbard 961efb7e53dSJordan K. Hubbard /* 962efb7e53dSJordan K. Hubbard * Scan the format for conversions (`%' character). 963efb7e53dSJordan K. Hubbard */ 964efb7e53dSJordan K. Hubbard for (;;) { 965efb7e53dSJordan K. Hubbard for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 966efb7e53dSJordan K. Hubbard /* void */; 967efb7e53dSJordan K. Hubbard if (ch == '\0') 968efb7e53dSJordan K. Hubbard goto done; 969efb7e53dSJordan K. Hubbard fmt++; /* skip over '%' */ 970efb7e53dSJordan K. Hubbard 971efb7e53dSJordan K. Hubbard flags = 0; 972efb7e53dSJordan K. Hubbard width = 0; 973efb7e53dSJordan K. Hubbard 974efb7e53dSJordan K. Hubbard rflag: ch = *fmt++; 975efb7e53dSJordan K. Hubbard reswitch: switch (ch) { 976efb7e53dSJordan K. Hubbard case ' ': 977efb7e53dSJordan K. Hubbard case '#': 978efb7e53dSJordan K. Hubbard goto rflag; 979efb7e53dSJordan K. Hubbard case '*': 980efb7e53dSJordan K. Hubbard ADDASTER (); 981efb7e53dSJordan K. Hubbard goto rflag; 982efb7e53dSJordan K. Hubbard case '-': 983efb7e53dSJordan K. Hubbard case '+': 984efb7e53dSJordan K. Hubbard goto rflag; 985efb7e53dSJordan K. Hubbard case '.': 986efb7e53dSJordan K. Hubbard if ((ch = *fmt++) == '*') { 987efb7e53dSJordan K. Hubbard ADDASTER (); 988efb7e53dSJordan K. Hubbard goto rflag; 989efb7e53dSJordan K. Hubbard } 990efb7e53dSJordan K. Hubbard while (is_digit(ch)) { 991efb7e53dSJordan K. Hubbard ch = *fmt++; 992efb7e53dSJordan K. Hubbard } 993efb7e53dSJordan K. Hubbard goto reswitch; 994efb7e53dSJordan K. Hubbard case '0': 995efb7e53dSJordan K. Hubbard goto rflag; 996efb7e53dSJordan K. Hubbard case '1': case '2': case '3': case '4': 997efb7e53dSJordan K. Hubbard case '5': case '6': case '7': case '8': case '9': 998efb7e53dSJordan K. Hubbard n = 0; 999efb7e53dSJordan K. Hubbard do { 1000efb7e53dSJordan K. Hubbard n = 10 * n + to_digit(ch); 1001efb7e53dSJordan K. Hubbard ch = *fmt++; 1002efb7e53dSJordan K. Hubbard } while (is_digit(ch)); 1003efb7e53dSJordan K. Hubbard if (ch == '$') { 1004efb7e53dSJordan K. Hubbard nextarg = n; 1005efb7e53dSJordan K. Hubbard goto rflag; 1006efb7e53dSJordan K. Hubbard } 1007efb7e53dSJordan K. Hubbard width = n; 1008efb7e53dSJordan K. Hubbard goto reswitch; 1009efb7e53dSJordan K. Hubbard #ifdef FLOATING_POINT 1010efb7e53dSJordan K. Hubbard case 'L': 1011efb7e53dSJordan K. Hubbard flags |= LONGDBL; 1012efb7e53dSJordan K. Hubbard goto rflag; 1013efb7e53dSJordan K. Hubbard #endif 1014efb7e53dSJordan K. Hubbard case 'h': 1015efb7e53dSJordan K. Hubbard flags |= SHORTINT; 1016efb7e53dSJordan K. Hubbard goto rflag; 1017efb7e53dSJordan K. Hubbard case 'l': 1018efb7e53dSJordan K. Hubbard flags |= LONGINT; 1019efb7e53dSJordan K. Hubbard goto rflag; 1020efb7e53dSJordan K. Hubbard case 'q': 1021efb7e53dSJordan K. Hubbard flags |= QUADINT; 1022efb7e53dSJordan K. Hubbard goto rflag; 1023efb7e53dSJordan K. Hubbard case 'c': 1024efb7e53dSJordan K. Hubbard ADDTYPE(T_INT); 1025efb7e53dSJordan K. Hubbard break; 1026efb7e53dSJordan K. Hubbard case 'D': 1027efb7e53dSJordan K. Hubbard flags |= LONGINT; 1028efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1029efb7e53dSJordan K. Hubbard case 'd': 1030efb7e53dSJordan K. Hubbard case 'i': 1031efb7e53dSJordan K. Hubbard if (flags & QUADINT) { 1032efb7e53dSJordan K. Hubbard ADDTYPE(T_QUAD); 1033efb7e53dSJordan K. Hubbard } else { 1034efb7e53dSJordan K. Hubbard ADDSARG(); 1035efb7e53dSJordan K. Hubbard } 1036efb7e53dSJordan K. Hubbard break; 1037efb7e53dSJordan K. Hubbard #ifdef FLOATING_POINT 1038efb7e53dSJordan K. Hubbard case 'e': 1039efb7e53dSJordan K. Hubbard case 'E': 1040efb7e53dSJordan K. Hubbard case 'f': 1041efb7e53dSJordan K. Hubbard case 'g': 1042efb7e53dSJordan K. Hubbard case 'G': 1043efb7e53dSJordan K. Hubbard if (flags & LONGDBL) 1044efb7e53dSJordan K. Hubbard ADDTYPE(T_LONG_DOUBLE); 1045efb7e53dSJordan K. Hubbard else 1046efb7e53dSJordan K. Hubbard ADDTYPE(T_DOUBLE); 1047efb7e53dSJordan K. Hubbard break; 1048efb7e53dSJordan K. Hubbard #endif /* FLOATING_POINT */ 1049efb7e53dSJordan K. Hubbard case 'n': 1050efb7e53dSJordan K. Hubbard if (flags & QUADINT) 1051efb7e53dSJordan K. Hubbard ADDTYPE(TP_QUAD); 1052efb7e53dSJordan K. Hubbard else if (flags & LONGINT) 1053efb7e53dSJordan K. Hubbard ADDTYPE(TP_LONG); 1054efb7e53dSJordan K. Hubbard else if (flags & SHORTINT) 1055efb7e53dSJordan K. Hubbard ADDTYPE(TP_SHORT); 1056efb7e53dSJordan K. Hubbard else 1057efb7e53dSJordan K. Hubbard ADDTYPE(TP_INT); 1058efb7e53dSJordan K. Hubbard continue; /* no output */ 1059efb7e53dSJordan K. Hubbard case 'O': 1060efb7e53dSJordan K. Hubbard flags |= LONGINT; 1061efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1062efb7e53dSJordan K. Hubbard case 'o': 1063efb7e53dSJordan K. Hubbard if (flags & QUADINT) 1064efb7e53dSJordan K. Hubbard ADDTYPE(T_U_QUAD); 1065efb7e53dSJordan K. Hubbard else 1066efb7e53dSJordan K. Hubbard ADDUARG(); 1067efb7e53dSJordan K. Hubbard break; 1068efb7e53dSJordan K. Hubbard case 'p': 1069efb7e53dSJordan K. Hubbard ADDTYPE(TP_VOID); 1070efb7e53dSJordan K. Hubbard break; 1071efb7e53dSJordan K. Hubbard case 's': 1072efb7e53dSJordan K. Hubbard ADDTYPE(TP_CHAR); 1073efb7e53dSJordan K. Hubbard break; 1074efb7e53dSJordan K. Hubbard case 'U': 1075efb7e53dSJordan K. Hubbard flags |= LONGINT; 1076efb7e53dSJordan K. Hubbard /*FALLTHROUGH*/ 1077efb7e53dSJordan K. Hubbard case 'u': 1078efb7e53dSJordan K. Hubbard if (flags & QUADINT) 1079efb7e53dSJordan K. Hubbard ADDTYPE(T_U_QUAD); 1080efb7e53dSJordan K. Hubbard else 1081efb7e53dSJordan K. Hubbard ADDUARG(); 1082efb7e53dSJordan K. Hubbard break; 1083efb7e53dSJordan K. Hubbard case 'X': 1084efb7e53dSJordan K. Hubbard case 'x': 1085efb7e53dSJordan K. Hubbard if (flags & QUADINT) 1086efb7e53dSJordan K. Hubbard ADDTYPE(T_U_QUAD); 1087efb7e53dSJordan K. Hubbard else 1088efb7e53dSJordan K. Hubbard ADDUARG(); 1089efb7e53dSJordan K. Hubbard break; 1090efb7e53dSJordan K. Hubbard default: /* "%?" prints ?, unless ? is NUL */ 1091efb7e53dSJordan K. Hubbard if (ch == '\0') 1092efb7e53dSJordan K. Hubbard goto done; 1093efb7e53dSJordan K. Hubbard break; 1094efb7e53dSJordan K. Hubbard } 1095efb7e53dSJordan K. Hubbard } 1096efb7e53dSJordan K. Hubbard done: 1097efb7e53dSJordan K. Hubbard /* 1098efb7e53dSJordan K. Hubbard * Build the argument table. 1099efb7e53dSJordan K. Hubbard */ 1100efb7e53dSJordan K. Hubbard if (tablemax >= STATIC_ARG_TBL_SIZE) { 1101efb7e53dSJordan K. Hubbard *argtable = (void **) 1102efb7e53dSJordan K. Hubbard malloc (sizeof (void *) * (tablemax + 1)); 1103efb7e53dSJordan K. Hubbard } 1104efb7e53dSJordan K. Hubbard 1105efb7e53dSJordan K. Hubbard (*argtable) [0] = NULL; 1106efb7e53dSJordan K. Hubbard for (n = 1; n <= tablemax; n++) { 1107efb7e53dSJordan K. Hubbard (*argtable) [n] = ap; 1108efb7e53dSJordan K. Hubbard switch (typetable [n]) { 1109efb7e53dSJordan K. Hubbard case T_UNUSED: 1110efb7e53dSJordan K. Hubbard (void) va_arg (ap, int); 1111efb7e53dSJordan K. Hubbard break; 1112efb7e53dSJordan K. Hubbard case T_SHORT: 1113efb7e53dSJordan K. Hubbard (void) va_arg (ap, int); 1114efb7e53dSJordan K. Hubbard break; 1115efb7e53dSJordan K. Hubbard case T_U_SHORT: 1116efb7e53dSJordan K. Hubbard (void) va_arg (ap, int); 1117efb7e53dSJordan K. Hubbard break; 1118efb7e53dSJordan K. Hubbard case TP_SHORT: 1119efb7e53dSJordan K. Hubbard (void) va_arg (ap, short *); 1120efb7e53dSJordan K. Hubbard break; 1121efb7e53dSJordan K. Hubbard case T_INT: 1122efb7e53dSJordan K. Hubbard (void) va_arg (ap, int); 1123efb7e53dSJordan K. Hubbard break; 1124efb7e53dSJordan K. Hubbard case T_U_INT: 1125efb7e53dSJordan K. Hubbard (void) va_arg (ap, unsigned int); 1126efb7e53dSJordan K. Hubbard break; 1127efb7e53dSJordan K. Hubbard case TP_INT: 1128efb7e53dSJordan K. Hubbard (void) va_arg (ap, int *); 1129efb7e53dSJordan K. Hubbard break; 1130efb7e53dSJordan K. Hubbard case T_LONG: 1131efb7e53dSJordan K. Hubbard (void) va_arg (ap, long); 1132efb7e53dSJordan K. Hubbard break; 1133efb7e53dSJordan K. Hubbard case T_U_LONG: 1134efb7e53dSJordan K. Hubbard (void) va_arg (ap, unsigned long); 1135efb7e53dSJordan K. Hubbard break; 1136efb7e53dSJordan K. Hubbard case TP_LONG: 1137efb7e53dSJordan K. Hubbard (void) va_arg (ap, long *); 1138efb7e53dSJordan K. Hubbard break; 1139efb7e53dSJordan K. Hubbard case T_QUAD: 1140efb7e53dSJordan K. Hubbard (void) va_arg (ap, quad_t); 1141efb7e53dSJordan K. Hubbard break; 1142efb7e53dSJordan K. Hubbard case T_U_QUAD: 1143efb7e53dSJordan K. Hubbard (void) va_arg (ap, u_quad_t); 1144efb7e53dSJordan K. Hubbard break; 1145efb7e53dSJordan K. Hubbard case TP_QUAD: 1146efb7e53dSJordan K. Hubbard (void) va_arg (ap, quad_t *); 1147efb7e53dSJordan K. Hubbard break; 1148efb7e53dSJordan K. Hubbard case T_DOUBLE: 1149efb7e53dSJordan K. Hubbard (void) va_arg (ap, double); 1150efb7e53dSJordan K. Hubbard break; 1151efb7e53dSJordan K. Hubbard case T_LONG_DOUBLE: 1152efb7e53dSJordan K. Hubbard (void) va_arg (ap, long double); 1153efb7e53dSJordan K. Hubbard break; 1154efb7e53dSJordan K. Hubbard case TP_CHAR: 1155efb7e53dSJordan K. Hubbard (void) va_arg (ap, char *); 1156efb7e53dSJordan K. Hubbard break; 1157efb7e53dSJordan K. Hubbard case TP_VOID: 1158efb7e53dSJordan K. Hubbard (void) va_arg (ap, void *); 1159efb7e53dSJordan K. Hubbard break; 1160efb7e53dSJordan K. Hubbard } 1161efb7e53dSJordan K. Hubbard } 1162efb7e53dSJordan K. Hubbard 1163efb7e53dSJordan K. Hubbard if ((typetable != NULL) && (typetable != stattypetable)) 1164efb7e53dSJordan K. Hubbard free (typetable); 1165efb7e53dSJordan K. Hubbard } 1166efb7e53dSJordan K. Hubbard 1167efb7e53dSJordan K. Hubbard /* 1168efb7e53dSJordan K. Hubbard * Increase the size of the type table. 1169efb7e53dSJordan K. Hubbard */ 1170efb7e53dSJordan K. Hubbard static void 1171efb7e53dSJordan K. Hubbard __grow_type_table (nextarg, typetable, tablesize) 1172efb7e53dSJordan K. Hubbard int nextarg; 1173efb7e53dSJordan K. Hubbard unsigned char **typetable; 1174efb7e53dSJordan K. Hubbard int *tablesize; 1175efb7e53dSJordan K. Hubbard { 1176efb7e53dSJordan K. Hubbard unsigned char *oldtable = *typetable; 1177efb7e53dSJordan K. Hubbard int newsize = *tablesize * 2; 1178efb7e53dSJordan K. Hubbard 1179efb7e53dSJordan K. Hubbard if (*tablesize == STATIC_ARG_TBL_SIZE) { 1180efb7e53dSJordan K. Hubbard *typetable = (unsigned char *) 1181efb7e53dSJordan K. Hubbard malloc (sizeof (unsigned char) * newsize); 1182efb7e53dSJordan K. Hubbard bcopy (oldtable, *typetable, *tablesize); 1183efb7e53dSJordan K. Hubbard } else { 1184efb7e53dSJordan K. Hubbard *typetable = (unsigned char *) 1185efb7e53dSJordan K. Hubbard realloc (typetable, sizeof (unsigned char) * newsize); 1186efb7e53dSJordan K. Hubbard 1187efb7e53dSJordan K. Hubbard } 1188efb7e53dSJordan K. Hubbard memset (&typetable [*tablesize], T_UNUSED, (newsize - *tablesize)); 1189efb7e53dSJordan K. Hubbard 1190efb7e53dSJordan K. Hubbard *tablesize = newsize; 1191efb7e53dSJordan K. Hubbard } 1192efb7e53dSJordan K. Hubbard 1193efb7e53dSJordan K. Hubbard 119458f0484fSRodney W. Grimes #ifdef FLOATING_POINT 119558f0484fSRodney W. Grimes 119658f0484fSRodney W. Grimes extern char *__dtoa __P((double, int, int, int *, int *, char **)); 119758f0484fSRodney W. Grimes 119858f0484fSRodney W. Grimes static char * 119958f0484fSRodney W. Grimes cvt(value, ndigits, flags, sign, decpt, ch, length) 120058f0484fSRodney W. Grimes double value; 120158f0484fSRodney W. Grimes int ndigits, flags, *decpt, ch, *length; 120258f0484fSRodney W. Grimes char *sign; 120358f0484fSRodney W. Grimes { 120458f0484fSRodney W. Grimes int mode, dsgn; 120558f0484fSRodney W. Grimes char *digits, *bp, *rve; 120658f0484fSRodney W. Grimes 120758f0484fSRodney W. Grimes if (ch == 'f') 1208d26be6f0SBruce Evans mode = 3; /* ndigits after the decimal point */ 120958f0484fSRodney W. Grimes else { 1210d26be6f0SBruce Evans /* 1211d26be6f0SBruce Evans * To obtain ndigits after the decimal point for the 'e' 1212d26be6f0SBruce Evans * and 'E' formats, round to ndigits + 1 significant 1213d26be6f0SBruce Evans * figures. 1214d26be6f0SBruce Evans */ 1215d26be6f0SBruce Evans if (ch == 'e' || ch == 'E') 1216d26be6f0SBruce Evans ndigits++; 1217d26be6f0SBruce Evans mode = 2; /* ndigits significant digits */ 121858f0484fSRodney W. Grimes } 121958f0484fSRodney W. Grimes if (value < 0) { 122058f0484fSRodney W. Grimes value = -value; 122158f0484fSRodney W. Grimes *sign = '-'; 122258f0484fSRodney W. Grimes } else 122358f0484fSRodney W. Grimes *sign = '\000'; 122458f0484fSRodney W. Grimes digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve); 1225d26be6f0SBruce Evans if ((ch != 'g' && ch != 'G') || flags & ALT) { 1226d26be6f0SBruce Evans /* print trailing zeros */ 122758f0484fSRodney W. Grimes bp = digits + ndigits; 122858f0484fSRodney W. Grimes if (ch == 'f') { 122958f0484fSRodney W. Grimes if (*digits == '0' && value) 123058f0484fSRodney W. Grimes *decpt = -ndigits + 1; 123158f0484fSRodney W. Grimes bp += *decpt; 123258f0484fSRodney W. Grimes } 123358f0484fSRodney W. Grimes if (value == 0) /* kludge for __dtoa irregularity */ 123458f0484fSRodney W. Grimes rve = bp; 123558f0484fSRodney W. Grimes while (rve < bp) 123658f0484fSRodney W. Grimes *rve++ = '0'; 123758f0484fSRodney W. Grimes } 123858f0484fSRodney W. Grimes *length = rve - digits; 123958f0484fSRodney W. Grimes return (digits); 124058f0484fSRodney W. Grimes } 124158f0484fSRodney W. Grimes 124258f0484fSRodney W. Grimes static int 124358f0484fSRodney W. Grimes exponent(p0, exp, fmtch) 124458f0484fSRodney W. Grimes char *p0; 124558f0484fSRodney W. Grimes int exp, fmtch; 124658f0484fSRodney W. Grimes { 124758f0484fSRodney W. Grimes register char *p, *t; 124858f0484fSRodney W. Grimes char expbuf[MAXEXP]; 124958f0484fSRodney W. Grimes 125058f0484fSRodney W. Grimes p = p0; 125158f0484fSRodney W. Grimes *p++ = fmtch; 125258f0484fSRodney W. Grimes if (exp < 0) { 125358f0484fSRodney W. Grimes exp = -exp; 125458f0484fSRodney W. Grimes *p++ = '-'; 125558f0484fSRodney W. Grimes } 125658f0484fSRodney W. Grimes else 125758f0484fSRodney W. Grimes *p++ = '+'; 125858f0484fSRodney W. Grimes t = expbuf + MAXEXP; 125958f0484fSRodney W. Grimes if (exp > 9) { 126058f0484fSRodney W. Grimes do { 126158f0484fSRodney W. Grimes *--t = to_char(exp % 10); 126258f0484fSRodney W. Grimes } while ((exp /= 10) > 9); 126358f0484fSRodney W. Grimes *--t = to_char(exp); 126458f0484fSRodney W. Grimes for (; t < expbuf + MAXEXP; *p++ = *t++); 126558f0484fSRodney W. Grimes } 126658f0484fSRodney W. Grimes else { 126758f0484fSRodney W. Grimes *p++ = '0'; 126858f0484fSRodney W. Grimes *p++ = to_char(exp); 126958f0484fSRodney W. Grimes } 127058f0484fSRodney W. Grimes return (p - p0); 127158f0484fSRodney W. Grimes } 127258f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 1273