1814d1bc9SDavid Schultz /*- 2814d1bc9SDavid Schultz * Copyright (c) 1990, 1993 3814d1bc9SDavid Schultz * The Regents of the University of California. All rights reserved. 4814d1bc9SDavid Schultz * 5814d1bc9SDavid Schultz * This code is derived from software contributed to Berkeley by 6814d1bc9SDavid Schultz * Chris Torek. 7814d1bc9SDavid Schultz * 8814d1bc9SDavid Schultz * Redistribution and use in source and binary forms, with or without 9814d1bc9SDavid Schultz * modification, are permitted provided that the following conditions 10814d1bc9SDavid Schultz * are met: 11814d1bc9SDavid Schultz * 1. Redistributions of source code must retain the above copyright 12814d1bc9SDavid Schultz * notice, this list of conditions and the following disclaimer. 13814d1bc9SDavid Schultz * 2. Redistributions in binary form must reproduce the above copyright 14814d1bc9SDavid Schultz * notice, this list of conditions and the following disclaimer in the 15814d1bc9SDavid Schultz * documentation and/or other materials provided with the distribution. 16814d1bc9SDavid Schultz * 4. Neither the name of the University nor the names of its contributors 17814d1bc9SDavid Schultz * may be used to endorse or promote products derived from this software 18814d1bc9SDavid Schultz * without specific prior written permission. 19814d1bc9SDavid Schultz * 20814d1bc9SDavid Schultz * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21814d1bc9SDavid Schultz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22814d1bc9SDavid Schultz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23814d1bc9SDavid Schultz * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24814d1bc9SDavid Schultz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25814d1bc9SDavid Schultz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26814d1bc9SDavid Schultz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27814d1bc9SDavid Schultz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28814d1bc9SDavid Schultz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29814d1bc9SDavid Schultz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30814d1bc9SDavid Schultz * SUCH DAMAGE. 31814d1bc9SDavid Schultz * 32814d1bc9SDavid Schultz * $FreeBSD$ 33814d1bc9SDavid Schultz */ 34814d1bc9SDavid Schultz 35814d1bc9SDavid Schultz /* 36814d1bc9SDavid Schultz * This file defines common routines used by both printf and wprintf. 37814d1bc9SDavid Schultz * You must define CHAR to either char or wchar_t prior to including this. 38814d1bc9SDavid Schultz */ 39814d1bc9SDavid Schultz 400a492640SDavid Schultz 410a492640SDavid Schultz #ifndef NO_FLOATING_POINT 420a492640SDavid Schultz 430a492640SDavid Schultz #define dtoa __dtoa 440a492640SDavid Schultz #define freedtoa __freedtoa 450a492640SDavid Schultz 460a492640SDavid Schultz #include <float.h> 470a492640SDavid Schultz #include <math.h> 480a492640SDavid Schultz #include "floatio.h" 490a492640SDavid Schultz #include "gdtoa.h" 500a492640SDavid Schultz 510a492640SDavid Schultz #define DEFPREC 6 520a492640SDavid Schultz 530a492640SDavid Schultz static int exponent(CHAR *, int, CHAR); 540a492640SDavid Schultz 550a492640SDavid Schultz #endif /* !NO_FLOATING_POINT */ 560a492640SDavid Schultz 5721ca178eSDavid Schultz static CHAR *__ujtoa(uintmax_t, CHAR *, int, int, const char *); 5821ca178eSDavid Schultz static CHAR *__ultoa(u_long, CHAR *, int, int, const char *); 590a492640SDavid Schultz 60814d1bc9SDavid Schultz #define NIOV 8 61814d1bc9SDavid Schultz struct io_state { 62814d1bc9SDavid Schultz FILE *fp; 63814d1bc9SDavid Schultz struct __suio uio; /* output information: summary */ 64814d1bc9SDavid Schultz struct __siov iov[NIOV];/* ... and individual io vectors */ 65814d1bc9SDavid Schultz }; 66814d1bc9SDavid Schultz 67814d1bc9SDavid Schultz static inline void 68814d1bc9SDavid Schultz io_init(struct io_state *iop, FILE *fp) 69814d1bc9SDavid Schultz { 70814d1bc9SDavid Schultz 716ec35123SDavid Schultz iop->uio.uio_iov = iop->iov; 72814d1bc9SDavid Schultz iop->uio.uio_resid = 0; 73814d1bc9SDavid Schultz iop->uio.uio_iovcnt = 0; 74814d1bc9SDavid Schultz iop->fp = fp; 75814d1bc9SDavid Schultz } 76814d1bc9SDavid Schultz 77814d1bc9SDavid Schultz /* 78814d1bc9SDavid Schultz * WARNING: The buffer passed to io_print() is not copied immediately; it must 79814d1bc9SDavid Schultz * remain valid until io_flush() is called. 80814d1bc9SDavid Schultz */ 81814d1bc9SDavid Schultz static inline int 82814d1bc9SDavid Schultz io_print(struct io_state *iop, const CHAR * __restrict ptr, int len) 83814d1bc9SDavid Schultz { 84814d1bc9SDavid Schultz 856ec35123SDavid Schultz iop->iov[iop->uio.uio_iovcnt].iov_base = (char *)ptr; 866ec35123SDavid Schultz iop->iov[iop->uio.uio_iovcnt].iov_len = len; 87814d1bc9SDavid Schultz iop->uio.uio_resid += len; 886ec35123SDavid Schultz if (++iop->uio.uio_iovcnt >= NIOV) 89814d1bc9SDavid Schultz return (__sprint(iop->fp, &iop->uio)); 906ec35123SDavid Schultz else 91814d1bc9SDavid Schultz return (0); 92814d1bc9SDavid Schultz } 93814d1bc9SDavid Schultz 94814d1bc9SDavid Schultz /* 95814d1bc9SDavid Schultz * Choose PADSIZE to trade efficiency vs. size. If larger printf 96814d1bc9SDavid Schultz * fields occur frequently, increase PADSIZE and make the initialisers 97814d1bc9SDavid Schultz * below longer. 98814d1bc9SDavid Schultz */ 99814d1bc9SDavid Schultz #define PADSIZE 16 /* pad chunk size */ 100814d1bc9SDavid Schultz static const CHAR blanks[PADSIZE] = 101814d1bc9SDavid Schultz {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 102814d1bc9SDavid Schultz static const CHAR zeroes[PADSIZE] = 103814d1bc9SDavid Schultz {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 104814d1bc9SDavid Schultz 105814d1bc9SDavid Schultz /* 106814d1bc9SDavid Schultz * Pad with blanks or zeroes. 'with' should point to either the blanks array 107814d1bc9SDavid Schultz * or the zeroes array. 108814d1bc9SDavid Schultz */ 109814d1bc9SDavid Schultz static inline int 110814d1bc9SDavid Schultz io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with) 111814d1bc9SDavid Schultz { 1126ec35123SDavid Schultz int n; 113814d1bc9SDavid Schultz 1146ec35123SDavid Schultz while (howmany > 0) { 1156ec35123SDavid Schultz n = (howmany >= PADSIZE) ? PADSIZE : howmany; 1166ec35123SDavid Schultz if (io_print(iop, with, n)) 117814d1bc9SDavid Schultz return (-1); 1186ec35123SDavid Schultz howmany -= n; 119814d1bc9SDavid Schultz } 120814d1bc9SDavid Schultz return (0); 121814d1bc9SDavid Schultz } 122814d1bc9SDavid Schultz 123814d1bc9SDavid Schultz /* 124814d1bc9SDavid Schultz * Print exactly len characters of the string spanning p to ep, truncating 125814d1bc9SDavid Schultz * or padding with 'with' as necessary. 126814d1bc9SDavid Schultz */ 127814d1bc9SDavid Schultz static inline int 128814d1bc9SDavid Schultz io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep, 129814d1bc9SDavid Schultz int len, const CHAR * __restrict with) 130814d1bc9SDavid Schultz { 131814d1bc9SDavid Schultz int p_len; 132814d1bc9SDavid Schultz 133814d1bc9SDavid Schultz p_len = ep - p; 134814d1bc9SDavid Schultz if (p_len > len) 135814d1bc9SDavid Schultz p_len = len; 1366ec35123SDavid Schultz if (p_len > 0) { 1376ec35123SDavid Schultz if (io_print(iop, p, p_len)) 138814d1bc9SDavid Schultz return (-1); 1396ec35123SDavid Schultz } else { 1406ec35123SDavid Schultz p_len = 0; 1416ec35123SDavid Schultz } 1426ec35123SDavid Schultz return (io_pad(iop, len - p_len, with)); 143814d1bc9SDavid Schultz } 144814d1bc9SDavid Schultz 145814d1bc9SDavid Schultz static inline int 146814d1bc9SDavid Schultz io_flush(struct io_state *iop) 147814d1bc9SDavid Schultz { 148814d1bc9SDavid Schultz 149814d1bc9SDavid Schultz return (__sprint(iop->fp, &iop->uio)); 150814d1bc9SDavid Schultz } 1510a492640SDavid Schultz 1520a492640SDavid Schultz /* 1530a492640SDavid Schultz * Convert an unsigned long to ASCII for printf purposes, returning 1540a492640SDavid Schultz * a pointer to the first character of the string representation. 1550a492640SDavid Schultz * Octal numbers can be forced to have a leading zero; hex numbers 1560a492640SDavid Schultz * use the given digits. 1570a492640SDavid Schultz */ 1580a492640SDavid Schultz static CHAR * 15921ca178eSDavid Schultz __ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs) 1600a492640SDavid Schultz { 1610a492640SDavid Schultz CHAR *cp = endp; 1620a492640SDavid Schultz long sval; 1630a492640SDavid Schultz 1640a492640SDavid Schultz /* 1650a492640SDavid Schultz * Handle the three cases separately, in the hope of getting 1660a492640SDavid Schultz * better/faster code. 1670a492640SDavid Schultz */ 1680a492640SDavid Schultz switch (base) { 1690a492640SDavid Schultz case 10: 1700a492640SDavid Schultz if (val < 10) { /* many numbers are 1 digit */ 1710a492640SDavid Schultz *--cp = to_char(val); 1720a492640SDavid Schultz return (cp); 1730a492640SDavid Schultz } 1740a492640SDavid Schultz /* 1750a492640SDavid Schultz * On many machines, unsigned arithmetic is harder than 1760a492640SDavid Schultz * signed arithmetic, so we do at most one unsigned mod and 1770a492640SDavid Schultz * divide; this is sufficient to reduce the range of 1780a492640SDavid Schultz * the incoming value to where signed arithmetic works. 1790a492640SDavid Schultz */ 1800a492640SDavid Schultz if (val > LONG_MAX) { 1810a492640SDavid Schultz *--cp = to_char(val % 10); 1820a492640SDavid Schultz sval = val / 10; 1830a492640SDavid Schultz } else 1840a492640SDavid Schultz sval = val; 1850a492640SDavid Schultz do { 1860a492640SDavid Schultz *--cp = to_char(sval % 10); 1870a492640SDavid Schultz sval /= 10; 1880a492640SDavid Schultz } while (sval != 0); 1890a492640SDavid Schultz break; 1900a492640SDavid Schultz 1910a492640SDavid Schultz case 8: 1920a492640SDavid Schultz do { 1930a492640SDavid Schultz *--cp = to_char(val & 7); 1940a492640SDavid Schultz val >>= 3; 1950a492640SDavid Schultz } while (val); 1960a492640SDavid Schultz if (octzero && *cp != '0') 1970a492640SDavid Schultz *--cp = '0'; 1980a492640SDavid Schultz break; 1990a492640SDavid Schultz 2000a492640SDavid Schultz case 16: 2010a492640SDavid Schultz do { 2020a492640SDavid Schultz *--cp = xdigs[val & 15]; 2030a492640SDavid Schultz val >>= 4; 2040a492640SDavid Schultz } while (val); 2050a492640SDavid Schultz break; 2060a492640SDavid Schultz 2070a492640SDavid Schultz default: /* oops */ 2080a492640SDavid Schultz abort(); 2090a492640SDavid Schultz } 2100a492640SDavid Schultz return (cp); 2110a492640SDavid Schultz } 2120a492640SDavid Schultz 2130a492640SDavid Schultz /* Identical to __ultoa, but for intmax_t. */ 2140a492640SDavid Schultz static CHAR * 21521ca178eSDavid Schultz __ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs) 2160a492640SDavid Schultz { 2170a492640SDavid Schultz CHAR *cp = endp; 2180a492640SDavid Schultz intmax_t sval; 2190a492640SDavid Schultz 2200a492640SDavid Schultz /* quick test for small values; __ultoa is typically much faster */ 2210a492640SDavid Schultz /* (perhaps instead we should run until small, then call __ultoa?) */ 2220a492640SDavid Schultz if (val <= ULONG_MAX) 22321ca178eSDavid Schultz return (__ultoa((u_long)val, endp, base, octzero, xdigs)); 2240a492640SDavid Schultz switch (base) { 2250a492640SDavid Schultz case 10: 2260a492640SDavid Schultz if (val < 10) { 2270a492640SDavid Schultz *--cp = to_char(val % 10); 2280a492640SDavid Schultz return (cp); 2290a492640SDavid Schultz } 2300a492640SDavid Schultz if (val > INTMAX_MAX) { 2310a492640SDavid Schultz *--cp = to_char(val % 10); 2320a492640SDavid Schultz sval = val / 10; 2330a492640SDavid Schultz } else 2340a492640SDavid Schultz sval = val; 2350a492640SDavid Schultz do { 2360a492640SDavid Schultz *--cp = to_char(sval % 10); 2370a492640SDavid Schultz sval /= 10; 2380a492640SDavid Schultz } while (sval != 0); 2390a492640SDavid Schultz break; 2400a492640SDavid Schultz 2410a492640SDavid Schultz case 8: 2420a492640SDavid Schultz do { 2430a492640SDavid Schultz *--cp = to_char(val & 7); 2440a492640SDavid Schultz val >>= 3; 2450a492640SDavid Schultz } while (val); 2460a492640SDavid Schultz if (octzero && *cp != '0') 2470a492640SDavid Schultz *--cp = '0'; 2480a492640SDavid Schultz break; 2490a492640SDavid Schultz 2500a492640SDavid Schultz case 16: 2510a492640SDavid Schultz do { 2520a492640SDavid Schultz *--cp = xdigs[val & 15]; 2530a492640SDavid Schultz val >>= 4; 2540a492640SDavid Schultz } while (val); 2550a492640SDavid Schultz break; 2560a492640SDavid Schultz 2570a492640SDavid Schultz default: 2580a492640SDavid Schultz abort(); 2590a492640SDavid Schultz } 2600a492640SDavid Schultz return (cp); 2610a492640SDavid Schultz } 2620a492640SDavid Schultz 2630a492640SDavid Schultz #ifndef NO_FLOATING_POINT 2640a492640SDavid Schultz 2650a492640SDavid Schultz static int 2660a492640SDavid Schultz exponent(CHAR *p0, int exp, CHAR fmtch) 2670a492640SDavid Schultz { 2680a492640SDavid Schultz CHAR *p, *t; 2690a492640SDavid Schultz CHAR expbuf[MAXEXPDIG]; 2700a492640SDavid Schultz 2710a492640SDavid Schultz p = p0; 2720a492640SDavid Schultz *p++ = fmtch; 2730a492640SDavid Schultz if (exp < 0) { 2740a492640SDavid Schultz exp = -exp; 2750a492640SDavid Schultz *p++ = '-'; 2760a492640SDavid Schultz } 2770a492640SDavid Schultz else 2780a492640SDavid Schultz *p++ = '+'; 2790a492640SDavid Schultz t = expbuf + MAXEXPDIG; 2800a492640SDavid Schultz if (exp > 9) { 2810a492640SDavid Schultz do { 2820a492640SDavid Schultz *--t = to_char(exp % 10); 2830a492640SDavid Schultz } while ((exp /= 10) > 9); 2840a492640SDavid Schultz *--t = to_char(exp); 2850a492640SDavid Schultz for (; t < expbuf + MAXEXPDIG; *p++ = *t++); 2860a492640SDavid Schultz } 2870a492640SDavid Schultz else { 2880a492640SDavid Schultz /* 2890a492640SDavid Schultz * Exponents for decimal floating point conversions 2900a492640SDavid Schultz * (%[eEgG]) must be at least two characters long, 2910a492640SDavid Schultz * whereas exponents for hexadecimal conversions can 2920a492640SDavid Schultz * be only one character long. 2930a492640SDavid Schultz */ 2940a492640SDavid Schultz if (fmtch == 'e' || fmtch == 'E') 2950a492640SDavid Schultz *p++ = '0'; 2960a492640SDavid Schultz *p++ = to_char(exp); 2970a492640SDavid Schultz } 2980a492640SDavid Schultz return (p - p0); 2990a492640SDavid Schultz } 3000a492640SDavid Schultz 3010a492640SDavid Schultz #endif /* !NO_FLOATING_POINT */ 302