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[] = 42ce51cf03SJames Raynard "$Id$"; 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 *)); 78ce51cf03SJames Raynard 7958f0484fSRodney W. Grimes /* 8058f0484fSRodney W. Grimes * Flush out all the vectors defined by the given uio, 8158f0484fSRodney W. Grimes * then reset it so that it can be reused. 8258f0484fSRodney W. Grimes */ 8358f0484fSRodney W. Grimes static int 8458f0484fSRodney W. Grimes __sprint(fp, uio) 8558f0484fSRodney W. Grimes FILE *fp; 8658f0484fSRodney W. Grimes register struct __suio *uio; 8758f0484fSRodney W. Grimes { 8858f0484fSRodney W. Grimes register int err; 8958f0484fSRodney W. Grimes 9058f0484fSRodney W. Grimes if (uio->uio_resid == 0) { 9158f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 9258f0484fSRodney W. Grimes return (0); 9358f0484fSRodney W. Grimes } 9458f0484fSRodney W. Grimes err = __sfvwrite(fp, uio); 9558f0484fSRodney W. Grimes uio->uio_resid = 0; 9658f0484fSRodney W. Grimes uio->uio_iovcnt = 0; 9758f0484fSRodney W. Grimes return (err); 9858f0484fSRodney W. Grimes } 9958f0484fSRodney W. Grimes 10058f0484fSRodney W. Grimes /* 10158f0484fSRodney W. Grimes * Helper function for `fprintf to unbuffered unix file': creates a 10258f0484fSRodney W. Grimes * temporary buffer. We only work on write-only files; this avoids 10358f0484fSRodney W. Grimes * worries about ungetc buffers and so forth. 10458f0484fSRodney W. Grimes */ 10558f0484fSRodney W. Grimes static int 10658f0484fSRodney W. Grimes __sbprintf(fp, fmt, ap) 10758f0484fSRodney W. Grimes register FILE *fp; 10858f0484fSRodney W. Grimes const char *fmt; 10958f0484fSRodney W. Grimes va_list ap; 11058f0484fSRodney W. Grimes { 11158f0484fSRodney W. Grimes int ret; 11258f0484fSRodney W. Grimes FILE fake; 11358f0484fSRodney W. Grimes unsigned char buf[BUFSIZ]; 11458f0484fSRodney W. Grimes 11558f0484fSRodney W. Grimes /* copy the important variables */ 11658f0484fSRodney W. Grimes fake._flags = fp->_flags & ~__SNBF; 11758f0484fSRodney W. Grimes fake._file = fp->_file; 11858f0484fSRodney W. Grimes fake._cookie = fp->_cookie; 11958f0484fSRodney W. Grimes fake._write = fp->_write; 12058f0484fSRodney W. Grimes 12158f0484fSRodney W. Grimes /* set up the buffer */ 12258f0484fSRodney W. Grimes fake._bf._base = fake._p = buf; 12358f0484fSRodney W. Grimes fake._bf._size = fake._w = sizeof(buf); 12458f0484fSRodney W. Grimes fake._lbfsize = 0; /* not actually used, but Just In Case */ 12558f0484fSRodney W. Grimes 12658f0484fSRodney W. Grimes /* do the work, then copy any error status */ 12758f0484fSRodney W. Grimes ret = vfprintf(&fake, fmt, ap); 12858f0484fSRodney W. Grimes if (ret >= 0 && fflush(&fake)) 12958f0484fSRodney W. Grimes ret = EOF; 13058f0484fSRodney W. Grimes if (fake._flags & __SERR) 13158f0484fSRodney W. Grimes fp->_flags |= __SERR; 13258f0484fSRodney W. Grimes return (ret); 13358f0484fSRodney W. Grimes } 13458f0484fSRodney W. Grimes 13558f0484fSRodney W. Grimes /* 13658f0484fSRodney W. Grimes * Macros for converting digits to letters and vice versa 13758f0484fSRodney W. Grimes */ 13858f0484fSRodney W. Grimes #define to_digit(c) ((c) - '0') 13958f0484fSRodney W. Grimes #define is_digit(c) ((unsigned)to_digit(c) <= 9) 14058f0484fSRodney W. Grimes #define to_char(n) ((n) + '0') 14158f0484fSRodney W. Grimes 14258f0484fSRodney W. Grimes /* 14358f0484fSRodney W. Grimes * Convert an unsigned long to ASCII for printf purposes, returning 14458f0484fSRodney W. Grimes * a pointer to the first character of the string representation. 14558f0484fSRodney W. Grimes * Octal numbers can be forced to have a leading zero; hex numbers 14658f0484fSRodney W. Grimes * use the given digits. 14758f0484fSRodney W. Grimes */ 14858f0484fSRodney W. Grimes static char * 14958f0484fSRodney W. Grimes __ultoa(val, endp, base, octzero, xdigs) 15058f0484fSRodney W. Grimes register u_long val; 15158f0484fSRodney W. Grimes char *endp; 15258f0484fSRodney W. Grimes int base, octzero; 15358f0484fSRodney W. Grimes char *xdigs; 15458f0484fSRodney W. Grimes { 15558f0484fSRodney W. Grimes register char *cp = endp; 15658f0484fSRodney W. Grimes register long sval; 15758f0484fSRodney W. Grimes 15858f0484fSRodney W. Grimes /* 15958f0484fSRodney W. Grimes * Handle the three cases separately, in the hope of getting 16058f0484fSRodney W. Grimes * better/faster code. 16158f0484fSRodney W. Grimes */ 16258f0484fSRodney W. Grimes switch (base) { 16358f0484fSRodney W. Grimes case 10: 16458f0484fSRodney W. Grimes if (val < 10) { /* many numbers are 1 digit */ 16558f0484fSRodney W. Grimes *--cp = to_char(val); 16658f0484fSRodney W. Grimes return (cp); 16758f0484fSRodney W. Grimes } 16858f0484fSRodney W. Grimes /* 16958f0484fSRodney W. Grimes * On many machines, unsigned arithmetic is harder than 17058f0484fSRodney W. Grimes * signed arithmetic, so we do at most one unsigned mod and 17158f0484fSRodney W. Grimes * divide; this is sufficient to reduce the range of 17258f0484fSRodney W. Grimes * the incoming value to where signed arithmetic works. 17358f0484fSRodney W. Grimes */ 17458f0484fSRodney W. Grimes if (val > LONG_MAX) { 17558f0484fSRodney W. Grimes *--cp = to_char(val % 10); 17658f0484fSRodney W. Grimes sval = val / 10; 17758f0484fSRodney W. Grimes } else 17858f0484fSRodney W. Grimes sval = val; 17958f0484fSRodney W. Grimes do { 18058f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 18158f0484fSRodney W. Grimes sval /= 10; 18258f0484fSRodney W. Grimes } while (sval != 0); 18358f0484fSRodney W. Grimes break; 18458f0484fSRodney W. Grimes 18558f0484fSRodney W. Grimes case 8: 18658f0484fSRodney W. Grimes do { 18758f0484fSRodney W. Grimes *--cp = to_char(val & 7); 18858f0484fSRodney W. Grimes val >>= 3; 18958f0484fSRodney W. Grimes } while (val); 19058f0484fSRodney W. Grimes if (octzero && *cp != '0') 19158f0484fSRodney W. Grimes *--cp = '0'; 19258f0484fSRodney W. Grimes break; 19358f0484fSRodney W. Grimes 19458f0484fSRodney W. Grimes case 16: 19558f0484fSRodney W. Grimes do { 19658f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 19758f0484fSRodney W. Grimes val >>= 4; 19858f0484fSRodney W. Grimes } while (val); 19958f0484fSRodney W. Grimes break; 20058f0484fSRodney W. Grimes 20158f0484fSRodney W. Grimes default: /* oops */ 20258f0484fSRodney W. Grimes abort(); 20358f0484fSRodney W. Grimes } 20458f0484fSRodney W. Grimes return (cp); 20558f0484fSRodney W. Grimes } 20658f0484fSRodney W. Grimes 20758f0484fSRodney W. Grimes /* Identical to __ultoa, but for quads. */ 20858f0484fSRodney W. Grimes static char * 20958f0484fSRodney W. Grimes __uqtoa(val, endp, base, octzero, xdigs) 21058f0484fSRodney W. Grimes register u_quad_t val; 21158f0484fSRodney W. Grimes char *endp; 21258f0484fSRodney W. Grimes int base, octzero; 21358f0484fSRodney W. Grimes char *xdigs; 21458f0484fSRodney W. Grimes { 21558f0484fSRodney W. Grimes register char *cp = endp; 21658f0484fSRodney W. Grimes register quad_t sval; 21758f0484fSRodney W. Grimes 21858f0484fSRodney W. Grimes /* quick test for small values; __ultoa is typically much faster */ 21958f0484fSRodney W. Grimes /* (perhaps instead we should run until small, then call __ultoa?) */ 22058f0484fSRodney W. Grimes if (val <= ULONG_MAX) 22158f0484fSRodney W. Grimes return (__ultoa((u_long)val, endp, base, octzero, xdigs)); 22258f0484fSRodney W. Grimes switch (base) { 22358f0484fSRodney W. Grimes case 10: 22458f0484fSRodney W. Grimes if (val < 10) { 22558f0484fSRodney W. Grimes *--cp = to_char(val % 10); 22658f0484fSRodney W. Grimes return (cp); 22758f0484fSRodney W. Grimes } 22858f0484fSRodney W. Grimes if (val > QUAD_MAX) { 22958f0484fSRodney W. Grimes *--cp = to_char(val % 10); 23058f0484fSRodney W. Grimes sval = val / 10; 23158f0484fSRodney W. Grimes } else 23258f0484fSRodney W. Grimes sval = val; 23358f0484fSRodney W. Grimes do { 23458f0484fSRodney W. Grimes *--cp = to_char(sval % 10); 23558f0484fSRodney W. Grimes sval /= 10; 23658f0484fSRodney W. Grimes } while (sval != 0); 23758f0484fSRodney W. Grimes break; 23858f0484fSRodney W. Grimes 23958f0484fSRodney W. Grimes case 8: 24058f0484fSRodney W. Grimes do { 24158f0484fSRodney W. Grimes *--cp = to_char(val & 7); 24258f0484fSRodney W. Grimes val >>= 3; 24358f0484fSRodney W. Grimes } while (val); 24458f0484fSRodney W. Grimes if (octzero && *cp != '0') 24558f0484fSRodney W. Grimes *--cp = '0'; 24658f0484fSRodney W. Grimes break; 24758f0484fSRodney W. Grimes 24858f0484fSRodney W. Grimes case 16: 24958f0484fSRodney W. Grimes do { 25058f0484fSRodney W. Grimes *--cp = xdigs[val & 15]; 25158f0484fSRodney W. Grimes val >>= 4; 25258f0484fSRodney W. Grimes } while (val); 25358f0484fSRodney W. Grimes break; 25458f0484fSRodney W. Grimes 25558f0484fSRodney W. Grimes default: 25658f0484fSRodney W. Grimes abort(); 25758f0484fSRodney W. Grimes } 25858f0484fSRodney W. Grimes return (cp); 25958f0484fSRodney W. Grimes } 26058f0484fSRodney W. Grimes 26158f0484fSRodney W. Grimes #ifdef FLOATING_POINT 26258f0484fSRodney W. Grimes #include <math.h> 26358f0484fSRodney W. Grimes #include "floatio.h" 26458f0484fSRodney W. Grimes 26558f0484fSRodney W. Grimes #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ 26658f0484fSRodney W. Grimes #define DEFPREC 6 26758f0484fSRodney W. Grimes 26858f0484fSRodney W. Grimes static char *cvt __P((double, int, int, char *, int *, int, int *)); 26958f0484fSRodney W. Grimes static int exponent __P((char *, int, int)); 27058f0484fSRodney W. Grimes 27158f0484fSRodney W. Grimes #else /* no FLOATING_POINT */ 27258f0484fSRodney W. Grimes 27358f0484fSRodney W. Grimes #define BUF 68 27458f0484fSRodney W. Grimes 27558f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 27658f0484fSRodney W. Grimes 27758f0484fSRodney W. Grimes 27858f0484fSRodney W. Grimes /* 27958f0484fSRodney W. Grimes * Flags used during conversion. 28058f0484fSRodney W. Grimes */ 28158f0484fSRodney W. Grimes #define ALT 0x001 /* alternate form */ 28258f0484fSRodney W. Grimes #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 28358f0484fSRodney W. Grimes #define LADJUST 0x004 /* left adjustment */ 28458f0484fSRodney W. Grimes #define LONGDBL 0x008 /* long double; unimplemented */ 28558f0484fSRodney W. Grimes #define LONGINT 0x010 /* long integer */ 28658f0484fSRodney W. Grimes #define QUADINT 0x020 /* quad integer */ 28758f0484fSRodney W. Grimes #define SHORTINT 0x040 /* short integer */ 28858f0484fSRodney W. Grimes #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 28958f0484fSRodney W. Grimes #define FPT 0x100 /* Floating point number */ 29058f0484fSRodney W. Grimes int 29158f0484fSRodney W. Grimes vfprintf(fp, fmt0, ap) 29258f0484fSRodney W. Grimes FILE *fp; 29358f0484fSRodney W. Grimes const char *fmt0; 29458f0484fSRodney W. Grimes va_list ap; 29558f0484fSRodney W. Grimes { 29658f0484fSRodney W. Grimes register char *fmt; /* format string */ 29758f0484fSRodney W. Grimes register int ch; /* character from fmt */ 29858f0484fSRodney W. Grimes register int n; /* handy integer (short term usage) */ 29958f0484fSRodney W. Grimes register char *cp; /* handy char pointer (short term usage) */ 30058f0484fSRodney W. Grimes register struct __siov *iovp;/* for PRINT macro */ 30158f0484fSRodney W. Grimes register int flags; /* flags as above */ 30258f0484fSRodney W. Grimes int ret; /* return value accumulator */ 30358f0484fSRodney W. Grimes int width; /* width from format (%8d), or 0 */ 30458f0484fSRodney W. Grimes int prec; /* precision from format (%.3d), or -1 */ 30558f0484fSRodney W. Grimes char sign; /* sign prefix (' ', '+', '-', or \0) */ 30658f0484fSRodney W. Grimes #ifdef FLOATING_POINT 30758f0484fSRodney W. Grimes char softsign; /* temporary negative sign for floats */ 30858f0484fSRodney W. Grimes double _double; /* double precision arguments %[eEfgG] */ 30958f0484fSRodney W. Grimes int expt; /* integer value of exponent */ 31058f0484fSRodney W. Grimes int expsize; /* character count for expstr */ 31158f0484fSRodney W. Grimes int ndig; /* actual number of digits returned by cvt */ 31258f0484fSRodney W. Grimes char expstr[7]; /* buffer for exponent string */ 31358f0484fSRodney W. Grimes #endif 31458f0484fSRodney W. Grimes u_long ulval; /* integer arguments %[diouxX] */ 31558f0484fSRodney W. Grimes u_quad_t uqval; /* %q integers */ 31658f0484fSRodney W. Grimes int base; /* base for [diouxX] conversion */ 31758f0484fSRodney W. Grimes int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 318261a532aSBill Fenner int realsz; /* field size expanded by dprec, sign, etc */ 31958f0484fSRodney W. Grimes int size; /* size of converted field or string */ 32058f0484fSRodney W. Grimes char *xdigs; /* digits for [xX] conversion */ 32158f0484fSRodney W. Grimes #define NIOV 8 32258f0484fSRodney W. Grimes struct __suio uio; /* output information: summary */ 32358f0484fSRodney W. Grimes struct __siov iov[NIOV];/* ... and individual io vectors */ 32458f0484fSRodney W. Grimes char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 32558f0484fSRodney W. Grimes char ox[2]; /* space for 0x hex-prefix */ 32658f0484fSRodney W. Grimes 32758f0484fSRodney W. Grimes /* 32858f0484fSRodney W. Grimes * Choose PADSIZE to trade efficiency vs. size. If larger printf 32958f0484fSRodney W. Grimes * fields occur frequently, increase PADSIZE and make the initialisers 33058f0484fSRodney W. Grimes * below longer. 33158f0484fSRodney W. Grimes */ 33258f0484fSRodney W. Grimes #define PADSIZE 16 /* pad chunk size */ 33358f0484fSRodney W. Grimes static char blanks[PADSIZE] = 33458f0484fSRodney W. Grimes {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 33558f0484fSRodney W. Grimes static char zeroes[PADSIZE] = 33658f0484fSRodney W. Grimes {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 33758f0484fSRodney W. Grimes 33858f0484fSRodney W. Grimes /* 33958f0484fSRodney W. Grimes * BEWARE, these `goto error' on error, and PAD uses `n'. 34058f0484fSRodney W. Grimes */ 34158f0484fSRodney W. Grimes #define PRINT(ptr, len) { \ 34258f0484fSRodney W. Grimes iovp->iov_base = (ptr); \ 34358f0484fSRodney W. Grimes iovp->iov_len = (len); \ 34458f0484fSRodney W. Grimes uio.uio_resid += (len); \ 34558f0484fSRodney W. Grimes iovp++; \ 34658f0484fSRodney W. Grimes if (++uio.uio_iovcnt >= NIOV) { \ 34758f0484fSRodney W. Grimes if (__sprint(fp, &uio)) \ 34858f0484fSRodney W. Grimes goto error; \ 34958f0484fSRodney W. Grimes iovp = iov; \ 35058f0484fSRodney W. Grimes } \ 35158f0484fSRodney W. Grimes } 35258f0484fSRodney W. Grimes #define PAD(howmany, with) { \ 35358f0484fSRodney W. Grimes if ((n = (howmany)) > 0) { \ 35458f0484fSRodney W. Grimes while (n > PADSIZE) { \ 35558f0484fSRodney W. Grimes PRINT(with, PADSIZE); \ 35658f0484fSRodney W. Grimes n -= PADSIZE; \ 35758f0484fSRodney W. Grimes } \ 35858f0484fSRodney W. Grimes PRINT(with, n); \ 35958f0484fSRodney W. Grimes } \ 36058f0484fSRodney W. Grimes } 36158f0484fSRodney W. Grimes #define FLUSH() { \ 36258f0484fSRodney W. Grimes if (uio.uio_resid && __sprint(fp, &uio)) \ 36358f0484fSRodney W. Grimes goto error; \ 36458f0484fSRodney W. Grimes uio.uio_iovcnt = 0; \ 36558f0484fSRodney W. Grimes iovp = iov; \ 36658f0484fSRodney W. Grimes } 36758f0484fSRodney W. Grimes 36858f0484fSRodney W. Grimes /* 36958f0484fSRodney W. Grimes * To extend shorts properly, we need both signed and unsigned 37058f0484fSRodney W. Grimes * argument extraction methods. 37158f0484fSRodney W. Grimes */ 37258f0484fSRodney W. Grimes #define SARG() \ 37358f0484fSRodney W. Grimes (flags&LONGINT ? va_arg(ap, long) : \ 37458f0484fSRodney W. Grimes flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ 37558f0484fSRodney W. Grimes (long)va_arg(ap, int)) 37658f0484fSRodney W. Grimes #define UARG() \ 37758f0484fSRodney W. Grimes (flags&LONGINT ? va_arg(ap, u_long) : \ 37858f0484fSRodney W. Grimes flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \ 37958f0484fSRodney W. Grimes (u_long)va_arg(ap, u_int)) 38058f0484fSRodney W. Grimes 381f70177e7SJulian Elischer #ifdef _THREAD_SAFE 382f70177e7SJulian Elischer _thread_flockfile(fp,__FILE__,__LINE__); 383f70177e7SJulian Elischer #endif 38458f0484fSRodney W. Grimes /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 385f70177e7SJulian Elischer if (cantwrite(fp)) { 386f70177e7SJulian Elischer #ifdef _THREAD_SAFE 387f70177e7SJulian Elischer _thread_funlockfile(fp); 388f70177e7SJulian Elischer #endif 38958f0484fSRodney W. Grimes return (EOF); 390f70177e7SJulian Elischer } 39158f0484fSRodney W. Grimes 39258f0484fSRodney W. Grimes /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 39358f0484fSRodney W. Grimes if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 394f70177e7SJulian Elischer fp->_file >= 0) { 395f70177e7SJulian Elischer #ifdef _THREAD_SAFE 396f70177e7SJulian Elischer _thread_funlockfile(fp); 397f70177e7SJulian Elischer #endif 39858f0484fSRodney W. Grimes return (__sbprintf(fp, fmt0, ap)); 399f70177e7SJulian Elischer } 40058f0484fSRodney W. Grimes 40158f0484fSRodney W. Grimes fmt = (char *)fmt0; 40258f0484fSRodney W. Grimes uio.uio_iov = iovp = iov; 40358f0484fSRodney W. Grimes uio.uio_resid = 0; 40458f0484fSRodney W. Grimes uio.uio_iovcnt = 0; 40558f0484fSRodney W. Grimes ret = 0; 40658f0484fSRodney W. Grimes 40758f0484fSRodney W. Grimes /* 40858f0484fSRodney W. Grimes * Scan the format for conversions (`%' character). 40958f0484fSRodney W. Grimes */ 41058f0484fSRodney W. Grimes for (;;) { 41158f0484fSRodney W. Grimes for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 41258f0484fSRodney W. Grimes /* void */; 41358f0484fSRodney W. Grimes if ((n = fmt - cp) != 0) { 41458f0484fSRodney W. Grimes PRINT(cp, n); 41558f0484fSRodney W. Grimes ret += n; 41658f0484fSRodney W. Grimes } 41758f0484fSRodney W. Grimes if (ch == '\0') 41858f0484fSRodney W. Grimes goto done; 41958f0484fSRodney W. Grimes fmt++; /* skip over '%' */ 42058f0484fSRodney W. Grimes 42158f0484fSRodney W. Grimes flags = 0; 42258f0484fSRodney W. Grimes dprec = 0; 42358f0484fSRodney W. Grimes width = 0; 42458f0484fSRodney W. Grimes prec = -1; 42558f0484fSRodney W. Grimes sign = '\0'; 42658f0484fSRodney W. Grimes 42758f0484fSRodney W. Grimes rflag: ch = *fmt++; 42858f0484fSRodney W. Grimes reswitch: switch (ch) { 42958f0484fSRodney W. Grimes case ' ': 43058f0484fSRodney W. Grimes /* 43158f0484fSRodney W. Grimes * ``If the space and + flags both appear, the space 43258f0484fSRodney W. Grimes * flag will be ignored.'' 43358f0484fSRodney W. Grimes * -- ANSI X3J11 43458f0484fSRodney W. Grimes */ 43558f0484fSRodney W. Grimes if (!sign) 43658f0484fSRodney W. Grimes sign = ' '; 43758f0484fSRodney W. Grimes goto rflag; 43858f0484fSRodney W. Grimes case '#': 43958f0484fSRodney W. Grimes flags |= ALT; 44058f0484fSRodney W. Grimes goto rflag; 44158f0484fSRodney W. Grimes case '*': 44258f0484fSRodney W. Grimes /* 44358f0484fSRodney W. Grimes * ``A negative field width argument is taken as a 44458f0484fSRodney W. Grimes * - flag followed by a positive field width.'' 44558f0484fSRodney W. Grimes * -- ANSI X3J11 44658f0484fSRodney W. Grimes * They don't exclude field widths read from args. 44758f0484fSRodney W. Grimes */ 44858f0484fSRodney W. Grimes if ((width = va_arg(ap, int)) >= 0) 44958f0484fSRodney W. Grimes goto rflag; 45058f0484fSRodney W. Grimes width = -width; 45158f0484fSRodney W. Grimes /* FALLTHROUGH */ 45258f0484fSRodney W. Grimes case '-': 45358f0484fSRodney W. Grimes flags |= LADJUST; 45458f0484fSRodney W. Grimes goto rflag; 45558f0484fSRodney W. Grimes case '+': 45658f0484fSRodney W. Grimes sign = '+'; 45758f0484fSRodney W. Grimes goto rflag; 45858f0484fSRodney W. Grimes case '.': 45958f0484fSRodney W. Grimes if ((ch = *fmt++) == '*') { 46058f0484fSRodney W. Grimes n = va_arg(ap, int); 46158f0484fSRodney W. Grimes prec = n < 0 ? -1 : n; 46258f0484fSRodney W. Grimes goto rflag; 46358f0484fSRodney W. Grimes } 46458f0484fSRodney W. Grimes n = 0; 46558f0484fSRodney W. Grimes while (is_digit(ch)) { 46658f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 46758f0484fSRodney W. Grimes ch = *fmt++; 46858f0484fSRodney W. Grimes } 46958f0484fSRodney W. Grimes prec = n < 0 ? -1 : n; 47058f0484fSRodney W. Grimes goto reswitch; 47158f0484fSRodney W. Grimes case '0': 47258f0484fSRodney W. Grimes /* 47358f0484fSRodney W. Grimes * ``Note that 0 is taken as a flag, not as the 47458f0484fSRodney W. Grimes * beginning of a field width.'' 47558f0484fSRodney W. Grimes * -- ANSI X3J11 47658f0484fSRodney W. Grimes */ 47758f0484fSRodney W. Grimes flags |= ZEROPAD; 47858f0484fSRodney W. Grimes goto rflag; 47958f0484fSRodney W. Grimes case '1': case '2': case '3': case '4': 48058f0484fSRodney W. Grimes case '5': case '6': case '7': case '8': case '9': 48158f0484fSRodney W. Grimes n = 0; 48258f0484fSRodney W. Grimes do { 48358f0484fSRodney W. Grimes n = 10 * n + to_digit(ch); 48458f0484fSRodney W. Grimes ch = *fmt++; 48558f0484fSRodney W. Grimes } while (is_digit(ch)); 48658f0484fSRodney W. Grimes width = n; 48758f0484fSRodney W. Grimes goto reswitch; 48858f0484fSRodney W. Grimes #ifdef FLOATING_POINT 48958f0484fSRodney W. Grimes case 'L': 49058f0484fSRodney W. Grimes flags |= LONGDBL; 49158f0484fSRodney W. Grimes goto rflag; 49258f0484fSRodney W. Grimes #endif 49358f0484fSRodney W. Grimes case 'h': 49458f0484fSRodney W. Grimes flags |= SHORTINT; 49558f0484fSRodney W. Grimes goto rflag; 49658f0484fSRodney W. Grimes case 'l': 49758f0484fSRodney W. Grimes flags |= LONGINT; 49858f0484fSRodney W. Grimes goto rflag; 49958f0484fSRodney W. Grimes case 'q': 50058f0484fSRodney W. Grimes flags |= QUADINT; 50158f0484fSRodney W. Grimes goto rflag; 50258f0484fSRodney W. Grimes case 'c': 50358f0484fSRodney W. Grimes *(cp = buf) = va_arg(ap, int); 50458f0484fSRodney W. Grimes size = 1; 50558f0484fSRodney W. Grimes sign = '\0'; 50658f0484fSRodney W. Grimes break; 50758f0484fSRodney W. Grimes case 'D': 50858f0484fSRodney W. Grimes flags |= LONGINT; 50958f0484fSRodney W. Grimes /*FALLTHROUGH*/ 51058f0484fSRodney W. Grimes case 'd': 51158f0484fSRodney W. Grimes case 'i': 51258f0484fSRodney W. Grimes if (flags & QUADINT) { 51358f0484fSRodney W. Grimes uqval = va_arg(ap, quad_t); 51458f0484fSRodney W. Grimes if ((quad_t)uqval < 0) { 51558f0484fSRodney W. Grimes uqval = -uqval; 51658f0484fSRodney W. Grimes sign = '-'; 51758f0484fSRodney W. Grimes } 51858f0484fSRodney W. Grimes } else { 51958f0484fSRodney W. Grimes ulval = SARG(); 52058f0484fSRodney W. Grimes if ((long)ulval < 0) { 52158f0484fSRodney W. Grimes ulval = -ulval; 52258f0484fSRodney W. Grimes sign = '-'; 52358f0484fSRodney W. Grimes } 52458f0484fSRodney W. Grimes } 52558f0484fSRodney W. Grimes base = 10; 52658f0484fSRodney W. Grimes goto number; 52758f0484fSRodney W. Grimes #ifdef FLOATING_POINT 528d26be6f0SBruce Evans case 'e': 52958f0484fSRodney W. Grimes case 'E': 530d26be6f0SBruce Evans case 'f': 531d26be6f0SBruce Evans goto fp_begin; 53258f0484fSRodney W. Grimes case 'g': 53358f0484fSRodney W. Grimes case 'G': 534d26be6f0SBruce Evans if (prec == 0) 535d26be6f0SBruce Evans prec = 1; 536d26be6f0SBruce Evans fp_begin: if (prec == -1) 53758f0484fSRodney W. Grimes prec = DEFPREC; 538d26be6f0SBruce Evans if (flags & LONGDBL) 539d26be6f0SBruce Evans _double = (double)va_arg(ap, long double); 540d26be6f0SBruce Evans else 541d26be6f0SBruce Evans _double = va_arg(ap, double); 54258f0484fSRodney W. Grimes /* do this before tricky precision changes */ 54358f0484fSRodney W. Grimes if (isinf(_double)) { 54458f0484fSRodney W. Grimes if (_double < 0) 54558f0484fSRodney W. Grimes sign = '-'; 54658f0484fSRodney W. Grimes cp = "Inf"; 54758f0484fSRodney W. Grimes size = 3; 54858f0484fSRodney W. Grimes break; 54958f0484fSRodney W. Grimes } 55058f0484fSRodney W. Grimes if (isnan(_double)) { 55158f0484fSRodney W. Grimes cp = "NaN"; 55258f0484fSRodney W. Grimes size = 3; 55358f0484fSRodney W. Grimes break; 55458f0484fSRodney W. Grimes } 55558f0484fSRodney W. Grimes flags |= FPT; 55658f0484fSRodney W. Grimes cp = cvt(_double, prec, flags, &softsign, 55758f0484fSRodney W. Grimes &expt, ch, &ndig); 55858f0484fSRodney W. Grimes if (ch == 'g' || ch == 'G') { 55958f0484fSRodney W. Grimes if (expt <= -4 || expt > prec) 56058f0484fSRodney W. Grimes ch = (ch == 'g') ? 'e' : 'E'; 56158f0484fSRodney W. Grimes else 56258f0484fSRodney W. Grimes ch = 'g'; 56358f0484fSRodney W. Grimes } 56458f0484fSRodney W. Grimes if (ch <= 'e') { /* 'e' or 'E' fmt */ 56558f0484fSRodney W. Grimes --expt; 56658f0484fSRodney W. Grimes expsize = exponent(expstr, expt, ch); 56758f0484fSRodney W. Grimes size = expsize + ndig; 56858f0484fSRodney W. Grimes if (ndig > 1 || flags & ALT) 56958f0484fSRodney W. Grimes ++size; 57058f0484fSRodney W. Grimes } else if (ch == 'f') { /* f fmt */ 57158f0484fSRodney W. Grimes if (expt > 0) { 57258f0484fSRodney W. Grimes size = expt; 57358f0484fSRodney W. Grimes if (prec || flags & ALT) 57458f0484fSRodney W. Grimes size += prec + 1; 57558f0484fSRodney W. Grimes } else /* "0.X" */ 57658f0484fSRodney W. Grimes size = prec + 2; 57758f0484fSRodney W. Grimes } else if (expt >= ndig) { /* fixed g fmt */ 57858f0484fSRodney W. Grimes size = expt; 57958f0484fSRodney W. Grimes if (flags & ALT) 58058f0484fSRodney W. Grimes ++size; 58158f0484fSRodney W. Grimes } else 58258f0484fSRodney W. Grimes size = ndig + (expt > 0 ? 58358f0484fSRodney W. Grimes 1 : 2 - expt); 58458f0484fSRodney W. Grimes 58558f0484fSRodney W. Grimes if (softsign) 58658f0484fSRodney W. Grimes sign = '-'; 58758f0484fSRodney W. Grimes break; 58858f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 58958f0484fSRodney W. Grimes case 'n': 59058f0484fSRodney W. Grimes if (flags & QUADINT) 59158f0484fSRodney W. Grimes *va_arg(ap, quad_t *) = ret; 59258f0484fSRodney W. Grimes else if (flags & LONGINT) 59358f0484fSRodney W. Grimes *va_arg(ap, long *) = ret; 59458f0484fSRodney W. Grimes else if (flags & SHORTINT) 59558f0484fSRodney W. Grimes *va_arg(ap, short *) = ret; 59658f0484fSRodney W. Grimes else 59758f0484fSRodney W. Grimes *va_arg(ap, int *) = ret; 59858f0484fSRodney W. Grimes continue; /* no output */ 59958f0484fSRodney W. Grimes case 'O': 60058f0484fSRodney W. Grimes flags |= LONGINT; 60158f0484fSRodney W. Grimes /*FALLTHROUGH*/ 60258f0484fSRodney W. Grimes case 'o': 60358f0484fSRodney W. Grimes if (flags & QUADINT) 60458f0484fSRodney W. Grimes uqval = va_arg(ap, u_quad_t); 60558f0484fSRodney W. Grimes else 60658f0484fSRodney W. Grimes ulval = UARG(); 60758f0484fSRodney W. Grimes base = 8; 60858f0484fSRodney W. Grimes goto nosign; 60958f0484fSRodney W. Grimes case 'p': 61058f0484fSRodney W. Grimes /* 61158f0484fSRodney W. Grimes * ``The argument shall be a pointer to void. The 61258f0484fSRodney W. Grimes * value of the pointer is converted to a sequence 61358f0484fSRodney W. Grimes * of printable characters, in an implementation- 61458f0484fSRodney W. Grimes * defined manner.'' 61558f0484fSRodney W. Grimes * -- ANSI X3J11 61658f0484fSRodney W. Grimes */ 61758f0484fSRodney W. Grimes ulval = (u_long)va_arg(ap, void *); 61858f0484fSRodney W. Grimes base = 16; 61958f0484fSRodney W. Grimes xdigs = "0123456789abcdef"; 62058f0484fSRodney W. Grimes flags = (flags & ~QUADINT) | HEXPREFIX; 62158f0484fSRodney W. Grimes ch = 'x'; 62258f0484fSRodney W. Grimes goto nosign; 62358f0484fSRodney W. Grimes case 's': 62458f0484fSRodney W. Grimes if ((cp = va_arg(ap, char *)) == NULL) 62558f0484fSRodney W. Grimes cp = "(null)"; 62658f0484fSRodney W. Grimes if (prec >= 0) { 62758f0484fSRodney W. Grimes /* 62858f0484fSRodney W. Grimes * can't use strlen; can only look for the 62958f0484fSRodney W. Grimes * NUL in the first `prec' characters, and 63058f0484fSRodney W. Grimes * strlen() will go further. 63158f0484fSRodney W. Grimes */ 632ce51cf03SJames Raynard char *p = memchr(cp, 0, (size_t)prec); 63358f0484fSRodney W. Grimes 63458f0484fSRodney W. Grimes if (p != NULL) { 63558f0484fSRodney W. Grimes size = p - cp; 63658f0484fSRodney W. Grimes if (size > prec) 63758f0484fSRodney W. Grimes size = prec; 63858f0484fSRodney W. Grimes } else 63958f0484fSRodney W. Grimes size = prec; 64058f0484fSRodney W. Grimes } else 64158f0484fSRodney W. Grimes size = strlen(cp); 64258f0484fSRodney W. Grimes sign = '\0'; 64358f0484fSRodney W. Grimes break; 64458f0484fSRodney W. Grimes case 'U': 64558f0484fSRodney W. Grimes flags |= LONGINT; 64658f0484fSRodney W. Grimes /*FALLTHROUGH*/ 64758f0484fSRodney W. Grimes case 'u': 64858f0484fSRodney W. Grimes if (flags & QUADINT) 64958f0484fSRodney W. Grimes uqval = va_arg(ap, u_quad_t); 65058f0484fSRodney W. Grimes else 65158f0484fSRodney W. Grimes ulval = UARG(); 65258f0484fSRodney W. Grimes base = 10; 65358f0484fSRodney W. Grimes goto nosign; 65458f0484fSRodney W. Grimes case 'X': 65558f0484fSRodney W. Grimes xdigs = "0123456789ABCDEF"; 65658f0484fSRodney W. Grimes goto hex; 65758f0484fSRodney W. Grimes case 'x': 65858f0484fSRodney W. Grimes xdigs = "0123456789abcdef"; 65958f0484fSRodney W. Grimes hex: if (flags & QUADINT) 66058f0484fSRodney W. Grimes uqval = va_arg(ap, u_quad_t); 66158f0484fSRodney W. Grimes else 66258f0484fSRodney W. Grimes ulval = UARG(); 66358f0484fSRodney W. Grimes base = 16; 66458f0484fSRodney W. Grimes /* leading 0x/X only if non-zero */ 66558f0484fSRodney W. Grimes if (flags & ALT && 66658f0484fSRodney W. Grimes (flags & QUADINT ? uqval != 0 : ulval != 0)) 66758f0484fSRodney W. Grimes flags |= HEXPREFIX; 66858f0484fSRodney W. Grimes 66958f0484fSRodney W. Grimes /* unsigned conversions */ 67058f0484fSRodney W. Grimes nosign: sign = '\0'; 67158f0484fSRodney W. Grimes /* 67258f0484fSRodney W. Grimes * ``... diouXx conversions ... if a precision is 67358f0484fSRodney W. Grimes * specified, the 0 flag will be ignored.'' 67458f0484fSRodney W. Grimes * -- ANSI X3J11 67558f0484fSRodney W. Grimes */ 67658f0484fSRodney W. Grimes number: if ((dprec = prec) >= 0) 67758f0484fSRodney W. Grimes flags &= ~ZEROPAD; 67858f0484fSRodney W. Grimes 67958f0484fSRodney W. Grimes /* 68058f0484fSRodney W. Grimes * ``The result of converting a zero value with an 68158f0484fSRodney W. Grimes * explicit precision of zero is no characters.'' 68258f0484fSRodney W. Grimes * -- ANSI X3J11 68358f0484fSRodney W. Grimes */ 68458f0484fSRodney W. Grimes cp = buf + BUF; 68558f0484fSRodney W. Grimes if (flags & QUADINT) { 68658f0484fSRodney W. Grimes if (uqval != 0 || prec != 0) 68758f0484fSRodney W. Grimes cp = __uqtoa(uqval, cp, base, 68858f0484fSRodney W. Grimes flags & ALT, xdigs); 68958f0484fSRodney W. Grimes } else { 69058f0484fSRodney W. Grimes if (ulval != 0 || prec != 0) 69158f0484fSRodney W. Grimes cp = __ultoa(ulval, cp, base, 69258f0484fSRodney W. Grimes flags & ALT, xdigs); 69358f0484fSRodney W. Grimes } 69458f0484fSRodney W. Grimes size = buf + BUF - cp; 69558f0484fSRodney W. Grimes break; 69658f0484fSRodney W. Grimes default: /* "%?" prints ?, unless ? is NUL */ 69758f0484fSRodney W. Grimes if (ch == '\0') 69858f0484fSRodney W. Grimes goto done; 69958f0484fSRodney W. Grimes /* pretend it was %c with argument ch */ 70058f0484fSRodney W. Grimes cp = buf; 70158f0484fSRodney W. Grimes *cp = ch; 70258f0484fSRodney W. Grimes size = 1; 70358f0484fSRodney W. Grimes sign = '\0'; 70458f0484fSRodney W. Grimes break; 70558f0484fSRodney W. Grimes } 70658f0484fSRodney W. Grimes 70758f0484fSRodney W. Grimes /* 70858f0484fSRodney W. Grimes * All reasonable formats wind up here. At this point, `cp' 70958f0484fSRodney W. Grimes * points to a string which (if not flags&LADJUST) should be 71058f0484fSRodney W. Grimes * padded out to `width' places. If flags&ZEROPAD, it should 71158f0484fSRodney W. Grimes * first be prefixed by any sign or other prefix; otherwise, 71258f0484fSRodney W. Grimes * it should be blank padded before the prefix is emitted. 71358f0484fSRodney W. Grimes * After any left-hand padding and prefixing, emit zeroes 71458f0484fSRodney W. Grimes * required by a decimal [diouxX] precision, then print the 71558f0484fSRodney W. Grimes * string proper, then emit zeroes required by any leftover 71658f0484fSRodney W. Grimes * floating precision; finally, if LADJUST, pad with blanks. 71758f0484fSRodney W. Grimes * 71858f0484fSRodney W. Grimes * Compute actual size, so we know how much to pad. 719261a532aSBill Fenner * size excludes decimal prec; realsz includes it. 72058f0484fSRodney W. Grimes */ 721261a532aSBill Fenner realsz = dprec > size ? dprec : size; 72258f0484fSRodney W. Grimes if (sign) 723261a532aSBill Fenner realsz++; 72458f0484fSRodney W. Grimes else if (flags & HEXPREFIX) 725261a532aSBill Fenner realsz += 2; 72658f0484fSRodney W. Grimes 72758f0484fSRodney W. Grimes /* right-adjusting blank padding */ 72858f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == 0) 72958f0484fSRodney W. Grimes PAD(width - realsz, blanks); 73058f0484fSRodney W. Grimes 73158f0484fSRodney W. Grimes /* prefix */ 73258f0484fSRodney W. Grimes if (sign) { 73358f0484fSRodney W. Grimes PRINT(&sign, 1); 73458f0484fSRodney W. Grimes } else if (flags & HEXPREFIX) { 73558f0484fSRodney W. Grimes ox[0] = '0'; 73658f0484fSRodney W. Grimes ox[1] = ch; 73758f0484fSRodney W. Grimes PRINT(ox, 2); 73858f0484fSRodney W. Grimes } 73958f0484fSRodney W. Grimes 74058f0484fSRodney W. Grimes /* right-adjusting zero padding */ 74158f0484fSRodney W. Grimes if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 74258f0484fSRodney W. Grimes PAD(width - realsz, zeroes); 74358f0484fSRodney W. Grimes 74458f0484fSRodney W. Grimes /* leading zeroes from decimal precision */ 745261a532aSBill Fenner PAD(dprec - size, zeroes); 74658f0484fSRodney W. Grimes 74758f0484fSRodney W. Grimes /* the string or number proper */ 74858f0484fSRodney W. Grimes #ifdef FLOATING_POINT 74958f0484fSRodney W. Grimes if ((flags & FPT) == 0) { 75058f0484fSRodney W. Grimes PRINT(cp, size); 75158f0484fSRodney W. Grimes } else { /* glue together f_p fragments */ 75258f0484fSRodney W. Grimes if (ch >= 'f') { /* 'f' or 'g' */ 75358f0484fSRodney W. Grimes if (_double == 0) { 75458f0484fSRodney W. Grimes /* kludge for __dtoa irregularity */ 755ffe57f1aSBruce Evans if (expt >= ndig && 756ffe57f1aSBruce Evans (flags & ALT) == 0) { 75758f0484fSRodney W. Grimes PRINT("0", 1); 75858f0484fSRodney W. Grimes } else { 75958f0484fSRodney W. Grimes PRINT("0.", 2); 76058f0484fSRodney W. Grimes PAD(ndig - 1, zeroes); 76158f0484fSRodney W. Grimes } 76258f0484fSRodney W. Grimes } else if (expt <= 0) { 76358f0484fSRodney W. Grimes PRINT("0.", 2); 76458f0484fSRodney W. Grimes PAD(-expt, zeroes); 76558f0484fSRodney W. Grimes PRINT(cp, ndig); 76658f0484fSRodney W. Grimes } else if (expt >= ndig) { 76758f0484fSRodney W. Grimes PRINT(cp, ndig); 76858f0484fSRodney W. Grimes PAD(expt - ndig, zeroes); 76958f0484fSRodney W. Grimes if (flags & ALT) 77058f0484fSRodney W. Grimes PRINT(".", 1); 77158f0484fSRodney W. Grimes } else { 77258f0484fSRodney W. Grimes PRINT(cp, expt); 77358f0484fSRodney W. Grimes cp += expt; 77458f0484fSRodney W. Grimes PRINT(".", 1); 77558f0484fSRodney W. Grimes PRINT(cp, ndig-expt); 77658f0484fSRodney W. Grimes } 77758f0484fSRodney W. Grimes } else { /* 'e' or 'E' */ 77858f0484fSRodney W. Grimes if (ndig > 1 || flags & ALT) { 77958f0484fSRodney W. Grimes ox[0] = *cp++; 78058f0484fSRodney W. Grimes ox[1] = '.'; 78158f0484fSRodney W. Grimes PRINT(ox, 2); 782918bed75SBruce Evans if (_double) { 78358f0484fSRodney W. Grimes PRINT(cp, ndig-1); 78458f0484fSRodney W. Grimes } else /* 0.[0..] */ 78558f0484fSRodney W. Grimes /* __dtoa irregularity */ 78658f0484fSRodney W. Grimes PAD(ndig - 1, zeroes); 78758f0484fSRodney W. Grimes } else /* XeYYY */ 78858f0484fSRodney W. Grimes PRINT(cp, 1); 78958f0484fSRodney W. Grimes PRINT(expstr, expsize); 79058f0484fSRodney W. Grimes } 79158f0484fSRodney W. Grimes } 79258f0484fSRodney W. Grimes #else 79358f0484fSRodney W. Grimes PRINT(cp, size); 79458f0484fSRodney W. Grimes #endif 79558f0484fSRodney W. Grimes /* left-adjusting padding (always blank) */ 79658f0484fSRodney W. Grimes if (flags & LADJUST) 79758f0484fSRodney W. Grimes PAD(width - realsz, blanks); 79858f0484fSRodney W. Grimes 79958f0484fSRodney W. Grimes /* finally, adjust ret */ 80058f0484fSRodney W. Grimes ret += width > realsz ? width : realsz; 80158f0484fSRodney W. Grimes 80258f0484fSRodney W. Grimes FLUSH(); /* copy out the I/O vectors */ 80358f0484fSRodney W. Grimes } 80458f0484fSRodney W. Grimes done: 80558f0484fSRodney W. Grimes FLUSH(); 80658f0484fSRodney W. Grimes error: 807f70177e7SJulian Elischer if (__sferror(fp)) 808f70177e7SJulian Elischer ret = EOF; 809f70177e7SJulian Elischer #ifdef _THREAD_SAFE 810f70177e7SJulian Elischer _thread_funlockfile(fp); 811f70177e7SJulian Elischer #endif 812f70177e7SJulian Elischer return (ret); 81358f0484fSRodney W. Grimes /* NOTREACHED */ 81458f0484fSRodney W. Grimes } 81558f0484fSRodney W. Grimes 81658f0484fSRodney W. Grimes #ifdef FLOATING_POINT 81758f0484fSRodney W. Grimes 81858f0484fSRodney W. Grimes extern char *__dtoa __P((double, int, int, int *, int *, char **)); 81958f0484fSRodney W. Grimes 82058f0484fSRodney W. Grimes static char * 82158f0484fSRodney W. Grimes cvt(value, ndigits, flags, sign, decpt, ch, length) 82258f0484fSRodney W. Grimes double value; 82358f0484fSRodney W. Grimes int ndigits, flags, *decpt, ch, *length; 82458f0484fSRodney W. Grimes char *sign; 82558f0484fSRodney W. Grimes { 82658f0484fSRodney W. Grimes int mode, dsgn; 82758f0484fSRodney W. Grimes char *digits, *bp, *rve; 82858f0484fSRodney W. Grimes 82958f0484fSRodney W. Grimes if (ch == 'f') 830d26be6f0SBruce Evans mode = 3; /* ndigits after the decimal point */ 83158f0484fSRodney W. Grimes else { 832d26be6f0SBruce Evans /* 833d26be6f0SBruce Evans * To obtain ndigits after the decimal point for the 'e' 834d26be6f0SBruce Evans * and 'E' formats, round to ndigits + 1 significant 835d26be6f0SBruce Evans * figures. 836d26be6f0SBruce Evans */ 837d26be6f0SBruce Evans if (ch == 'e' || ch == 'E') 838d26be6f0SBruce Evans ndigits++; 839d26be6f0SBruce Evans mode = 2; /* ndigits significant digits */ 84058f0484fSRodney W. Grimes } 84158f0484fSRodney W. Grimes if (value < 0) { 84258f0484fSRodney W. Grimes value = -value; 84358f0484fSRodney W. Grimes *sign = '-'; 84458f0484fSRodney W. Grimes } else 84558f0484fSRodney W. Grimes *sign = '\000'; 84658f0484fSRodney W. Grimes digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve); 847d26be6f0SBruce Evans if ((ch != 'g' && ch != 'G') || flags & ALT) { 848d26be6f0SBruce Evans /* print trailing zeros */ 84958f0484fSRodney W. Grimes bp = digits + ndigits; 85058f0484fSRodney W. Grimes if (ch == 'f') { 85158f0484fSRodney W. Grimes if (*digits == '0' && value) 85258f0484fSRodney W. Grimes *decpt = -ndigits + 1; 85358f0484fSRodney W. Grimes bp += *decpt; 85458f0484fSRodney W. Grimes } 85558f0484fSRodney W. Grimes if (value == 0) /* kludge for __dtoa irregularity */ 85658f0484fSRodney W. Grimes rve = bp; 85758f0484fSRodney W. Grimes while (rve < bp) 85858f0484fSRodney W. Grimes *rve++ = '0'; 85958f0484fSRodney W. Grimes } 86058f0484fSRodney W. Grimes *length = rve - digits; 86158f0484fSRodney W. Grimes return (digits); 86258f0484fSRodney W. Grimes } 86358f0484fSRodney W. Grimes 86458f0484fSRodney W. Grimes static int 86558f0484fSRodney W. Grimes exponent(p0, exp, fmtch) 86658f0484fSRodney W. Grimes char *p0; 86758f0484fSRodney W. Grimes int exp, fmtch; 86858f0484fSRodney W. Grimes { 86958f0484fSRodney W. Grimes register char *p, *t; 87058f0484fSRodney W. Grimes char expbuf[MAXEXP]; 87158f0484fSRodney W. Grimes 87258f0484fSRodney W. Grimes p = p0; 87358f0484fSRodney W. Grimes *p++ = fmtch; 87458f0484fSRodney W. Grimes if (exp < 0) { 87558f0484fSRodney W. Grimes exp = -exp; 87658f0484fSRodney W. Grimes *p++ = '-'; 87758f0484fSRodney W. Grimes } 87858f0484fSRodney W. Grimes else 87958f0484fSRodney W. Grimes *p++ = '+'; 88058f0484fSRodney W. Grimes t = expbuf + MAXEXP; 88158f0484fSRodney W. Grimes if (exp > 9) { 88258f0484fSRodney W. Grimes do { 88358f0484fSRodney W. Grimes *--t = to_char(exp % 10); 88458f0484fSRodney W. Grimes } while ((exp /= 10) > 9); 88558f0484fSRodney W. Grimes *--t = to_char(exp); 88658f0484fSRodney W. Grimes for (; t < expbuf + MAXEXP; *p++ = *t++); 88758f0484fSRodney W. Grimes } 88858f0484fSRodney W. Grimes else { 88958f0484fSRodney W. Grimes *p++ = '0'; 89058f0484fSRodney W. Grimes *p++ = to_char(exp); 89158f0484fSRodney W. Grimes } 89258f0484fSRodney W. Grimes return (p - p0); 89358f0484fSRodney W. Grimes } 89458f0484fSRodney W. Grimes #endif /* FLOATING_POINT */ 895