1814d1bc9SDavid Schultz /*- 2*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3*8a16b7a1SPedro F. Giffuni * 4814d1bc9SDavid Schultz * Copyright (c) 1990, 1993 5814d1bc9SDavid Schultz * The Regents of the University of California. All rights reserved. 6814d1bc9SDavid Schultz * 7814d1bc9SDavid Schultz * This code is derived from software contributed to Berkeley by 8814d1bc9SDavid Schultz * Chris Torek. 9814d1bc9SDavid Schultz * 103c87aa1dSDavid Chisnall * Copyright (c) 2011 The FreeBSD Foundation 113c87aa1dSDavid Chisnall * All rights reserved. 123c87aa1dSDavid Chisnall * Portions of this software were developed by David Chisnall 133c87aa1dSDavid Chisnall * under sponsorship from the FreeBSD Foundation. 143c87aa1dSDavid Chisnall * 15814d1bc9SDavid Schultz * Redistribution and use in source and binary forms, with or without 16814d1bc9SDavid Schultz * modification, are permitted provided that the following conditions 17814d1bc9SDavid Schultz * are met: 18814d1bc9SDavid Schultz * 1. Redistributions of source code must retain the above copyright 19814d1bc9SDavid Schultz * notice, this list of conditions and the following disclaimer. 20814d1bc9SDavid Schultz * 2. Redistributions in binary form must reproduce the above copyright 21814d1bc9SDavid Schultz * notice, this list of conditions and the following disclaimer in the 22814d1bc9SDavid Schultz * documentation and/or other materials provided with the distribution. 23fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 24814d1bc9SDavid Schultz * may be used to endorse or promote products derived from this software 25814d1bc9SDavid Schultz * without specific prior written permission. 26814d1bc9SDavid Schultz * 27814d1bc9SDavid Schultz * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28814d1bc9SDavid Schultz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29814d1bc9SDavid Schultz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30814d1bc9SDavid Schultz * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31814d1bc9SDavid Schultz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32814d1bc9SDavid Schultz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33814d1bc9SDavid Schultz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34814d1bc9SDavid Schultz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35814d1bc9SDavid Schultz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36814d1bc9SDavid Schultz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37814d1bc9SDavid Schultz * SUCH DAMAGE. 38814d1bc9SDavid Schultz * 39814d1bc9SDavid Schultz * $FreeBSD$ 40814d1bc9SDavid Schultz */ 41814d1bc9SDavid Schultz 42814d1bc9SDavid Schultz /* 43814d1bc9SDavid Schultz * This file defines common routines used by both printf and wprintf. 44814d1bc9SDavid Schultz * You must define CHAR to either char or wchar_t prior to including this. 45814d1bc9SDavid Schultz */ 46814d1bc9SDavid Schultz 470a492640SDavid Schultz 480a492640SDavid Schultz #ifndef NO_FLOATING_POINT 490a492640SDavid Schultz 500a492640SDavid Schultz #define dtoa __dtoa 510a492640SDavid Schultz #define freedtoa __freedtoa 520a492640SDavid Schultz 530a492640SDavid Schultz #include <float.h> 540a492640SDavid Schultz #include <math.h> 550a492640SDavid Schultz #include "floatio.h" 560a492640SDavid Schultz #include "gdtoa.h" 570a492640SDavid Schultz 580a492640SDavid Schultz #define DEFPREC 6 590a492640SDavid Schultz 600a492640SDavid Schultz static int exponent(CHAR *, int, CHAR); 610a492640SDavid Schultz 620a492640SDavid Schultz #endif /* !NO_FLOATING_POINT */ 630a492640SDavid Schultz 6421ca178eSDavid Schultz static CHAR *__ujtoa(uintmax_t, CHAR *, int, int, const char *); 6521ca178eSDavid Schultz static CHAR *__ultoa(u_long, CHAR *, int, int, const char *); 660a492640SDavid Schultz 67814d1bc9SDavid Schultz #define NIOV 8 68814d1bc9SDavid Schultz struct io_state { 69814d1bc9SDavid Schultz FILE *fp; 70814d1bc9SDavid Schultz struct __suio uio; /* output information: summary */ 71814d1bc9SDavid Schultz struct __siov iov[NIOV];/* ... and individual io vectors */ 72814d1bc9SDavid Schultz }; 73814d1bc9SDavid Schultz 74814d1bc9SDavid Schultz static inline void 75814d1bc9SDavid Schultz io_init(struct io_state *iop, FILE *fp) 76814d1bc9SDavid Schultz { 77814d1bc9SDavid Schultz 786ec35123SDavid Schultz iop->uio.uio_iov = iop->iov; 79814d1bc9SDavid Schultz iop->uio.uio_resid = 0; 80814d1bc9SDavid Schultz iop->uio.uio_iovcnt = 0; 81814d1bc9SDavid Schultz iop->fp = fp; 82814d1bc9SDavid Schultz } 83814d1bc9SDavid Schultz 84814d1bc9SDavid Schultz /* 85814d1bc9SDavid Schultz * WARNING: The buffer passed to io_print() is not copied immediately; it must 86814d1bc9SDavid Schultz * remain valid until io_flush() is called. 87814d1bc9SDavid Schultz */ 88814d1bc9SDavid Schultz static inline int 893c87aa1dSDavid Chisnall io_print(struct io_state *iop, const CHAR * __restrict ptr, int len, locale_t locale) 90814d1bc9SDavid Schultz { 91814d1bc9SDavid Schultz 926ec35123SDavid Schultz iop->iov[iop->uio.uio_iovcnt].iov_base = (char *)ptr; 936ec35123SDavid Schultz iop->iov[iop->uio.uio_iovcnt].iov_len = len; 94814d1bc9SDavid Schultz iop->uio.uio_resid += len; 956ec35123SDavid Schultz if (++iop->uio.uio_iovcnt >= NIOV) 963c87aa1dSDavid Chisnall return (__sprint(iop->fp, &iop->uio, locale)); 976ec35123SDavid Schultz else 98814d1bc9SDavid Schultz return (0); 99814d1bc9SDavid Schultz } 100814d1bc9SDavid Schultz 101814d1bc9SDavid Schultz /* 102814d1bc9SDavid Schultz * Choose PADSIZE to trade efficiency vs. size. If larger printf 103814d1bc9SDavid Schultz * fields occur frequently, increase PADSIZE and make the initialisers 104814d1bc9SDavid Schultz * below longer. 105814d1bc9SDavid Schultz */ 106814d1bc9SDavid Schultz #define PADSIZE 16 /* pad chunk size */ 107814d1bc9SDavid Schultz static const CHAR blanks[PADSIZE] = 108814d1bc9SDavid Schultz {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 109814d1bc9SDavid Schultz static const CHAR zeroes[PADSIZE] = 110814d1bc9SDavid Schultz {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 111814d1bc9SDavid Schultz 112814d1bc9SDavid Schultz /* 113814d1bc9SDavid Schultz * Pad with blanks or zeroes. 'with' should point to either the blanks array 114814d1bc9SDavid Schultz * or the zeroes array. 115814d1bc9SDavid Schultz */ 116814d1bc9SDavid Schultz static inline int 1173c87aa1dSDavid Chisnall io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with, 1183c87aa1dSDavid Chisnall locale_t locale) 119814d1bc9SDavid Schultz { 1206ec35123SDavid Schultz int n; 121814d1bc9SDavid Schultz 1226ec35123SDavid Schultz while (howmany > 0) { 1236ec35123SDavid Schultz n = (howmany >= PADSIZE) ? PADSIZE : howmany; 1243c87aa1dSDavid Chisnall if (io_print(iop, with, n, locale)) 125814d1bc9SDavid Schultz return (-1); 1266ec35123SDavid Schultz howmany -= n; 127814d1bc9SDavid Schultz } 128814d1bc9SDavid Schultz return (0); 129814d1bc9SDavid Schultz } 130814d1bc9SDavid Schultz 131814d1bc9SDavid Schultz /* 132814d1bc9SDavid Schultz * Print exactly len characters of the string spanning p to ep, truncating 133814d1bc9SDavid Schultz * or padding with 'with' as necessary. 134814d1bc9SDavid Schultz */ 135814d1bc9SDavid Schultz static inline int 136814d1bc9SDavid Schultz io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep, 1373c87aa1dSDavid Chisnall int len, const CHAR * __restrict with, locale_t locale) 138814d1bc9SDavid Schultz { 139814d1bc9SDavid Schultz int p_len; 140814d1bc9SDavid Schultz 141814d1bc9SDavid Schultz p_len = ep - p; 142814d1bc9SDavid Schultz if (p_len > len) 143814d1bc9SDavid Schultz p_len = len; 1446ec35123SDavid Schultz if (p_len > 0) { 1453c87aa1dSDavid Chisnall if (io_print(iop, p, p_len, locale)) 146814d1bc9SDavid Schultz return (-1); 1476ec35123SDavid Schultz } else { 1486ec35123SDavid Schultz p_len = 0; 1496ec35123SDavid Schultz } 1503c87aa1dSDavid Chisnall return (io_pad(iop, len - p_len, with, locale)); 151814d1bc9SDavid Schultz } 152814d1bc9SDavid Schultz 153814d1bc9SDavid Schultz static inline int 1543c87aa1dSDavid Chisnall io_flush(struct io_state *iop, locale_t locale) 155814d1bc9SDavid Schultz { 156814d1bc9SDavid Schultz 1573c87aa1dSDavid Chisnall return (__sprint(iop->fp, &iop->uio, locale)); 158814d1bc9SDavid Schultz } 1590a492640SDavid Schultz 1600a492640SDavid Schultz /* 1610a492640SDavid Schultz * Convert an unsigned long to ASCII for printf purposes, returning 1620a492640SDavid Schultz * a pointer to the first character of the string representation. 1630a492640SDavid Schultz * Octal numbers can be forced to have a leading zero; hex numbers 1640a492640SDavid Schultz * use the given digits. 1650a492640SDavid Schultz */ 1660a492640SDavid Schultz static CHAR * 16721ca178eSDavid Schultz __ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs) 1680a492640SDavid Schultz { 1690a492640SDavid Schultz CHAR *cp = endp; 1700a492640SDavid Schultz long sval; 1710a492640SDavid Schultz 1720a492640SDavid Schultz /* 1730a492640SDavid Schultz * Handle the three cases separately, in the hope of getting 1740a492640SDavid Schultz * better/faster code. 1750a492640SDavid Schultz */ 1760a492640SDavid Schultz switch (base) { 1770a492640SDavid Schultz case 10: 1780a492640SDavid Schultz if (val < 10) { /* many numbers are 1 digit */ 1790a492640SDavid Schultz *--cp = to_char(val); 1800a492640SDavid Schultz return (cp); 1810a492640SDavid Schultz } 1820a492640SDavid Schultz /* 1830a492640SDavid Schultz * On many machines, unsigned arithmetic is harder than 1840a492640SDavid Schultz * signed arithmetic, so we do at most one unsigned mod and 1850a492640SDavid Schultz * divide; this is sufficient to reduce the range of 1860a492640SDavid Schultz * the incoming value to where signed arithmetic works. 1870a492640SDavid Schultz */ 1880a492640SDavid Schultz if (val > LONG_MAX) { 1890a492640SDavid Schultz *--cp = to_char(val % 10); 1900a492640SDavid Schultz sval = val / 10; 1910a492640SDavid Schultz } else 1920a492640SDavid Schultz sval = val; 1930a492640SDavid Schultz do { 1940a492640SDavid Schultz *--cp = to_char(sval % 10); 1950a492640SDavid Schultz sval /= 10; 1960a492640SDavid Schultz } while (sval != 0); 1970a492640SDavid Schultz break; 1980a492640SDavid Schultz 1990a492640SDavid Schultz case 8: 2000a492640SDavid Schultz do { 2010a492640SDavid Schultz *--cp = to_char(val & 7); 2020a492640SDavid Schultz val >>= 3; 2030a492640SDavid Schultz } while (val); 2040a492640SDavid Schultz if (octzero && *cp != '0') 2050a492640SDavid Schultz *--cp = '0'; 2060a492640SDavid Schultz break; 2070a492640SDavid Schultz 2080a492640SDavid Schultz case 16: 2090a492640SDavid Schultz do { 2100a492640SDavid Schultz *--cp = xdigs[val & 15]; 2110a492640SDavid Schultz val >>= 4; 2120a492640SDavid Schultz } while (val); 2130a492640SDavid Schultz break; 2140a492640SDavid Schultz 2150a492640SDavid Schultz default: /* oops */ 2160a492640SDavid Schultz abort(); 2170a492640SDavid Schultz } 2180a492640SDavid Schultz return (cp); 2190a492640SDavid Schultz } 2200a492640SDavid Schultz 2210a492640SDavid Schultz /* Identical to __ultoa, but for intmax_t. */ 2220a492640SDavid Schultz static CHAR * 22321ca178eSDavid Schultz __ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs) 2240a492640SDavid Schultz { 2250a492640SDavid Schultz CHAR *cp = endp; 2260a492640SDavid Schultz intmax_t sval; 2270a492640SDavid Schultz 2280a492640SDavid Schultz /* quick test for small values; __ultoa is typically much faster */ 2290a492640SDavid Schultz /* (perhaps instead we should run until small, then call __ultoa?) */ 2300a492640SDavid Schultz if (val <= ULONG_MAX) 23121ca178eSDavid Schultz return (__ultoa((u_long)val, endp, base, octzero, xdigs)); 2320a492640SDavid Schultz switch (base) { 2330a492640SDavid Schultz case 10: 2340a492640SDavid Schultz if (val < 10) { 2350a492640SDavid Schultz *--cp = to_char(val % 10); 2360a492640SDavid Schultz return (cp); 2370a492640SDavid Schultz } 2380a492640SDavid Schultz if (val > INTMAX_MAX) { 2390a492640SDavid Schultz *--cp = to_char(val % 10); 2400a492640SDavid Schultz sval = val / 10; 2410a492640SDavid Schultz } else 2420a492640SDavid Schultz sval = val; 2430a492640SDavid Schultz do { 2440a492640SDavid Schultz *--cp = to_char(sval % 10); 2450a492640SDavid Schultz sval /= 10; 2460a492640SDavid Schultz } while (sval != 0); 2470a492640SDavid Schultz break; 2480a492640SDavid Schultz 2490a492640SDavid Schultz case 8: 2500a492640SDavid Schultz do { 2510a492640SDavid Schultz *--cp = to_char(val & 7); 2520a492640SDavid Schultz val >>= 3; 2530a492640SDavid Schultz } while (val); 2540a492640SDavid Schultz if (octzero && *cp != '0') 2550a492640SDavid Schultz *--cp = '0'; 2560a492640SDavid Schultz break; 2570a492640SDavid Schultz 2580a492640SDavid Schultz case 16: 2590a492640SDavid Schultz do { 2600a492640SDavid Schultz *--cp = xdigs[val & 15]; 2610a492640SDavid Schultz val >>= 4; 2620a492640SDavid Schultz } while (val); 2630a492640SDavid Schultz break; 2640a492640SDavid Schultz 2650a492640SDavid Schultz default: 2660a492640SDavid Schultz abort(); 2670a492640SDavid Schultz } 2680a492640SDavid Schultz return (cp); 2690a492640SDavid Schultz } 2700a492640SDavid Schultz 2710a492640SDavid Schultz #ifndef NO_FLOATING_POINT 2720a492640SDavid Schultz 2730a492640SDavid Schultz static int 2740a492640SDavid Schultz exponent(CHAR *p0, int exp, CHAR fmtch) 2750a492640SDavid Schultz { 2760a492640SDavid Schultz CHAR *p, *t; 2770a492640SDavid Schultz CHAR expbuf[MAXEXPDIG]; 2780a492640SDavid Schultz 2790a492640SDavid Schultz p = p0; 2800a492640SDavid Schultz *p++ = fmtch; 2810a492640SDavid Schultz if (exp < 0) { 2820a492640SDavid Schultz exp = -exp; 2830a492640SDavid Schultz *p++ = '-'; 2840a492640SDavid Schultz } 2850a492640SDavid Schultz else 2860a492640SDavid Schultz *p++ = '+'; 2870a492640SDavid Schultz t = expbuf + MAXEXPDIG; 2880a492640SDavid Schultz if (exp > 9) { 2890a492640SDavid Schultz do { 2900a492640SDavid Schultz *--t = to_char(exp % 10); 2910a492640SDavid Schultz } while ((exp /= 10) > 9); 2920a492640SDavid Schultz *--t = to_char(exp); 2930a492640SDavid Schultz for (; t < expbuf + MAXEXPDIG; *p++ = *t++); 2940a492640SDavid Schultz } 2950a492640SDavid Schultz else { 2960a492640SDavid Schultz /* 2970a492640SDavid Schultz * Exponents for decimal floating point conversions 2980a492640SDavid Schultz * (%[eEgG]) must be at least two characters long, 2990a492640SDavid Schultz * whereas exponents for hexadecimal conversions can 3000a492640SDavid Schultz * be only one character long. 3010a492640SDavid Schultz */ 3020a492640SDavid Schultz if (fmtch == 'e' || fmtch == 'E') 3030a492640SDavid Schultz *p++ = '0'; 3040a492640SDavid Schultz *p++ = to_char(exp); 3050a492640SDavid Schultz } 3060a492640SDavid Schultz return (p - p0); 3070a492640SDavid Schultz } 3080a492640SDavid Schultz 3090a492640SDavid Schultz #endif /* !NO_FLOATING_POINT */ 310