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 570a492640SDavid Schultz static CHAR *__ujtoa(uintmax_t, CHAR *, int, int, const char *, int, char, 580a492640SDavid Schultz const char *); 590a492640SDavid Schultz static CHAR *__ultoa(u_long, CHAR *, int, int, const char *, int, char, 600a492640SDavid Schultz const char *); 610a492640SDavid Schultz 62814d1bc9SDavid Schultz #define NIOV 8 63814d1bc9SDavid Schultz struct io_state { 64814d1bc9SDavid Schultz FILE *fp; 65814d1bc9SDavid Schultz struct __suio uio; /* output information: summary */ 66814d1bc9SDavid Schultz struct __siov iov[NIOV];/* ... and individual io vectors */ 67814d1bc9SDavid Schultz struct __siov *iovp; /* pointer to next free slot in iov */ 68814d1bc9SDavid Schultz }; 69814d1bc9SDavid Schultz 70814d1bc9SDavid Schultz static inline void 71814d1bc9SDavid Schultz io_init(struct io_state *iop, FILE *fp) 72814d1bc9SDavid Schultz { 73814d1bc9SDavid Schultz 74814d1bc9SDavid Schultz iop->uio.uio_iov = iop->iovp = iop->iov; 75814d1bc9SDavid Schultz iop->uio.uio_resid = 0; 76814d1bc9SDavid Schultz iop->uio.uio_iovcnt = 0; 77814d1bc9SDavid Schultz iop->fp = fp; 78814d1bc9SDavid Schultz } 79814d1bc9SDavid Schultz 80814d1bc9SDavid Schultz /* 81814d1bc9SDavid Schultz * WARNING: The buffer passed to io_print() is not copied immediately; it must 82814d1bc9SDavid Schultz * remain valid until io_flush() is called. 83814d1bc9SDavid Schultz */ 84814d1bc9SDavid Schultz static inline int 85814d1bc9SDavid Schultz io_print(struct io_state *iop, const CHAR * __restrict ptr, int len) 86814d1bc9SDavid Schultz { 87814d1bc9SDavid Schultz 88814d1bc9SDavid Schultz iop->iovp->iov_base = (char *)ptr; 89814d1bc9SDavid Schultz iop->iovp->iov_len = len; 90814d1bc9SDavid Schultz iop->uio.uio_resid += len; 91814d1bc9SDavid Schultz iop->iovp++; 92814d1bc9SDavid Schultz if (++iop->uio.uio_iovcnt >= NIOV) { 93814d1bc9SDavid Schultz iop->iovp = iop->iov; 94814d1bc9SDavid Schultz return (__sprint(iop->fp, &iop->uio)); 95814d1bc9SDavid Schultz } 96814d1bc9SDavid Schultz return (0); 97814d1bc9SDavid Schultz } 98814d1bc9SDavid Schultz 99814d1bc9SDavid Schultz /* 100814d1bc9SDavid Schultz * Choose PADSIZE to trade efficiency vs. size. If larger printf 101814d1bc9SDavid Schultz * fields occur frequently, increase PADSIZE and make the initialisers 102814d1bc9SDavid Schultz * below longer. 103814d1bc9SDavid Schultz */ 104814d1bc9SDavid Schultz #define PADSIZE 16 /* pad chunk size */ 105814d1bc9SDavid Schultz static const CHAR blanks[PADSIZE] = 106814d1bc9SDavid Schultz {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 107814d1bc9SDavid Schultz static const CHAR zeroes[PADSIZE] = 108814d1bc9SDavid Schultz {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 109814d1bc9SDavid Schultz 110814d1bc9SDavid Schultz /* 111814d1bc9SDavid Schultz * Pad with blanks or zeroes. 'with' should point to either the blanks array 112814d1bc9SDavid Schultz * or the zeroes array. 113814d1bc9SDavid Schultz */ 114814d1bc9SDavid Schultz static inline int 115814d1bc9SDavid Schultz io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with) 116814d1bc9SDavid Schultz { 117814d1bc9SDavid Schultz 118814d1bc9SDavid Schultz while (howmany > PADSIZE) { 119814d1bc9SDavid Schultz if (io_print(iop, with, PADSIZE)) 120814d1bc9SDavid Schultz return (-1); 121814d1bc9SDavid Schultz howmany -= PADSIZE; 122814d1bc9SDavid Schultz } 123814d1bc9SDavid Schultz if (howmany > 0 && io_print(iop, with, howmany)) 124814d1bc9SDavid Schultz return (-1); 125814d1bc9SDavid Schultz return (0); 126814d1bc9SDavid Schultz } 127814d1bc9SDavid Schultz 128814d1bc9SDavid Schultz /* 129814d1bc9SDavid Schultz * Print exactly len characters of the string spanning p to ep, truncating 130814d1bc9SDavid Schultz * or padding with 'with' as necessary. 131814d1bc9SDavid Schultz */ 132814d1bc9SDavid Schultz static inline int 133814d1bc9SDavid Schultz io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep, 134814d1bc9SDavid Schultz int len, const CHAR * __restrict with) 135814d1bc9SDavid Schultz { 136814d1bc9SDavid Schultz int p_len; 137814d1bc9SDavid Schultz 138814d1bc9SDavid Schultz p_len = ep - p; 139814d1bc9SDavid Schultz if (p_len > len) 140814d1bc9SDavid Schultz p_len = len; 141814d1bc9SDavid Schultz if (p_len > 0 && io_print(iop, p, p_len)) 142814d1bc9SDavid Schultz return (-1); 143814d1bc9SDavid Schultz return (io_pad(iop, len - (p_len > 0 ? p_len : 0), with)); 144814d1bc9SDavid Schultz } 145814d1bc9SDavid Schultz 146814d1bc9SDavid Schultz static inline int 147814d1bc9SDavid Schultz io_flush(struct io_state *iop) 148814d1bc9SDavid Schultz { 149814d1bc9SDavid Schultz 150814d1bc9SDavid Schultz iop->iovp = iop->iov; 151814d1bc9SDavid Schultz return (__sprint(iop->fp, &iop->uio)); 152814d1bc9SDavid Schultz } 1530a492640SDavid Schultz 1540a492640SDavid Schultz /* 1550a492640SDavid Schultz * Convert an unsigned long to ASCII for printf purposes, returning 1560a492640SDavid Schultz * a pointer to the first character of the string representation. 1570a492640SDavid Schultz * Octal numbers can be forced to have a leading zero; hex numbers 1580a492640SDavid Schultz * use the given digits. 1590a492640SDavid Schultz */ 1600a492640SDavid Schultz static CHAR * 1610a492640SDavid Schultz __ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs, 1620a492640SDavid Schultz int needgrp, char thousep, const char *grp) 1630a492640SDavid Schultz { 1640a492640SDavid Schultz CHAR *cp = endp; 1650a492640SDavid Schultz long sval; 1660a492640SDavid Schultz int ndig; 1670a492640SDavid Schultz 1680a492640SDavid Schultz /* 1690a492640SDavid Schultz * Handle the three cases separately, in the hope of getting 1700a492640SDavid Schultz * better/faster code. 1710a492640SDavid Schultz */ 1720a492640SDavid Schultz switch (base) { 1730a492640SDavid Schultz case 10: 1740a492640SDavid Schultz if (val < 10) { /* many numbers are 1 digit */ 1750a492640SDavid Schultz *--cp = to_char(val); 1760a492640SDavid Schultz return (cp); 1770a492640SDavid Schultz } 1780a492640SDavid Schultz ndig = 0; 1790a492640SDavid Schultz /* 1800a492640SDavid Schultz * On many machines, unsigned arithmetic is harder than 1810a492640SDavid Schultz * signed arithmetic, so we do at most one unsigned mod and 1820a492640SDavid Schultz * divide; this is sufficient to reduce the range of 1830a492640SDavid Schultz * the incoming value to where signed arithmetic works. 1840a492640SDavid Schultz */ 1850a492640SDavid Schultz if (val > LONG_MAX) { 1860a492640SDavid Schultz *--cp = to_char(val % 10); 1870a492640SDavid Schultz ndig++; 1880a492640SDavid Schultz sval = val / 10; 1890a492640SDavid Schultz } else 1900a492640SDavid Schultz sval = val; 1910a492640SDavid Schultz do { 1920a492640SDavid Schultz *--cp = to_char(sval % 10); 1930a492640SDavid Schultz ndig++; 1940a492640SDavid Schultz /* 1950a492640SDavid Schultz * If (*grp == CHAR_MAX) then no more grouping 1960a492640SDavid Schultz * should be performed. 1970a492640SDavid Schultz */ 1980a492640SDavid Schultz if (needgrp && ndig == *grp && *grp != CHAR_MAX 1990a492640SDavid Schultz && sval > 9) { 2000a492640SDavid Schultz *--cp = thousep; 2010a492640SDavid Schultz ndig = 0; 2020a492640SDavid Schultz /* 2030a492640SDavid Schultz * If (*(grp+1) == '\0') then we have to 2040a492640SDavid Schultz * use *grp character (last grouping rule) 2050a492640SDavid Schultz * for all next cases 2060a492640SDavid Schultz */ 2070a492640SDavid Schultz if (*(grp+1) != '\0') 2080a492640SDavid Schultz grp++; 2090a492640SDavid Schultz } 2100a492640SDavid Schultz sval /= 10; 2110a492640SDavid Schultz } while (sval != 0); 2120a492640SDavid Schultz break; 2130a492640SDavid Schultz 2140a492640SDavid Schultz case 8: 2150a492640SDavid Schultz do { 2160a492640SDavid Schultz *--cp = to_char(val & 7); 2170a492640SDavid Schultz val >>= 3; 2180a492640SDavid Schultz } while (val); 2190a492640SDavid Schultz if (octzero && *cp != '0') 2200a492640SDavid Schultz *--cp = '0'; 2210a492640SDavid Schultz break; 2220a492640SDavid Schultz 2230a492640SDavid Schultz case 16: 2240a492640SDavid Schultz do { 2250a492640SDavid Schultz *--cp = xdigs[val & 15]; 2260a492640SDavid Schultz val >>= 4; 2270a492640SDavid Schultz } while (val); 2280a492640SDavid Schultz break; 2290a492640SDavid Schultz 2300a492640SDavid Schultz default: /* oops */ 2310a492640SDavid Schultz abort(); 2320a492640SDavid Schultz } 2330a492640SDavid Schultz return (cp); 2340a492640SDavid Schultz } 2350a492640SDavid Schultz 2360a492640SDavid Schultz /* Identical to __ultoa, but for intmax_t. */ 2370a492640SDavid Schultz static CHAR * 2380a492640SDavid Schultz __ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs, 2390a492640SDavid Schultz int needgrp, char thousep, const char *grp) 2400a492640SDavid Schultz { 2410a492640SDavid Schultz CHAR *cp = endp; 2420a492640SDavid Schultz intmax_t sval; 2430a492640SDavid Schultz int ndig; 2440a492640SDavid Schultz 2450a492640SDavid Schultz /* quick test for small values; __ultoa is typically much faster */ 2460a492640SDavid Schultz /* (perhaps instead we should run until small, then call __ultoa?) */ 2470a492640SDavid Schultz if (val <= ULONG_MAX) 2480a492640SDavid Schultz return (__ultoa((u_long)val, endp, base, octzero, xdigs, 2490a492640SDavid Schultz needgrp, thousep, grp)); 2500a492640SDavid Schultz switch (base) { 2510a492640SDavid Schultz case 10: 2520a492640SDavid Schultz if (val < 10) { 2530a492640SDavid Schultz *--cp = to_char(val % 10); 2540a492640SDavid Schultz return (cp); 2550a492640SDavid Schultz } 2560a492640SDavid Schultz ndig = 0; 2570a492640SDavid Schultz if (val > INTMAX_MAX) { 2580a492640SDavid Schultz *--cp = to_char(val % 10); 2590a492640SDavid Schultz ndig++; 2600a492640SDavid Schultz sval = val / 10; 2610a492640SDavid Schultz } else 2620a492640SDavid Schultz sval = val; 2630a492640SDavid Schultz do { 2640a492640SDavid Schultz *--cp = to_char(sval % 10); 2650a492640SDavid Schultz ndig++; 2660a492640SDavid Schultz /* 2670a492640SDavid Schultz * If (*grp == CHAR_MAX) then no more grouping 2680a492640SDavid Schultz * should be performed. 2690a492640SDavid Schultz */ 2700a492640SDavid Schultz if (needgrp && *grp != CHAR_MAX && ndig == *grp 2710a492640SDavid Schultz && sval > 9) { 2720a492640SDavid Schultz *--cp = thousep; 2730a492640SDavid Schultz ndig = 0; 2740a492640SDavid Schultz /* 2750a492640SDavid Schultz * If (*(grp+1) == '\0') then we have to 2760a492640SDavid Schultz * use *grp character (last grouping rule) 2770a492640SDavid Schultz * for all next cases 2780a492640SDavid Schultz */ 2790a492640SDavid Schultz if (*(grp+1) != '\0') 2800a492640SDavid Schultz grp++; 2810a492640SDavid Schultz } 2820a492640SDavid Schultz sval /= 10; 2830a492640SDavid Schultz } while (sval != 0); 2840a492640SDavid Schultz break; 2850a492640SDavid Schultz 2860a492640SDavid Schultz case 8: 2870a492640SDavid Schultz do { 2880a492640SDavid Schultz *--cp = to_char(val & 7); 2890a492640SDavid Schultz val >>= 3; 2900a492640SDavid Schultz } while (val); 2910a492640SDavid Schultz if (octzero && *cp != '0') 2920a492640SDavid Schultz *--cp = '0'; 2930a492640SDavid Schultz break; 2940a492640SDavid Schultz 2950a492640SDavid Schultz case 16: 2960a492640SDavid Schultz do { 2970a492640SDavid Schultz *--cp = xdigs[val & 15]; 2980a492640SDavid Schultz val >>= 4; 2990a492640SDavid Schultz } while (val); 3000a492640SDavid Schultz break; 3010a492640SDavid Schultz 3020a492640SDavid Schultz default: 3030a492640SDavid Schultz abort(); 3040a492640SDavid Schultz } 3050a492640SDavid Schultz return (cp); 3060a492640SDavid Schultz } 3070a492640SDavid Schultz 3080a492640SDavid Schultz #ifndef NO_FLOATING_POINT 3090a492640SDavid Schultz 3100a492640SDavid Schultz static int 3110a492640SDavid Schultz exponent(CHAR *p0, int exp, CHAR fmtch) 3120a492640SDavid Schultz { 3130a492640SDavid Schultz CHAR *p, *t; 3140a492640SDavid Schultz CHAR expbuf[MAXEXPDIG]; 3150a492640SDavid Schultz 3160a492640SDavid Schultz p = p0; 3170a492640SDavid Schultz *p++ = fmtch; 3180a492640SDavid Schultz if (exp < 0) { 3190a492640SDavid Schultz exp = -exp; 3200a492640SDavid Schultz *p++ = '-'; 3210a492640SDavid Schultz } 3220a492640SDavid Schultz else 3230a492640SDavid Schultz *p++ = '+'; 3240a492640SDavid Schultz t = expbuf + MAXEXPDIG; 3250a492640SDavid Schultz if (exp > 9) { 3260a492640SDavid Schultz do { 3270a492640SDavid Schultz *--t = to_char(exp % 10); 3280a492640SDavid Schultz } while ((exp /= 10) > 9); 3290a492640SDavid Schultz *--t = to_char(exp); 3300a492640SDavid Schultz for (; t < expbuf + MAXEXPDIG; *p++ = *t++); 3310a492640SDavid Schultz } 3320a492640SDavid Schultz else { 3330a492640SDavid Schultz /* 3340a492640SDavid Schultz * Exponents for decimal floating point conversions 3350a492640SDavid Schultz * (%[eEgG]) must be at least two characters long, 3360a492640SDavid Schultz * whereas exponents for hexadecimal conversions can 3370a492640SDavid Schultz * be only one character long. 3380a492640SDavid Schultz */ 3390a492640SDavid Schultz if (fmtch == 'e' || fmtch == 'E') 3400a492640SDavid Schultz *p++ = '0'; 3410a492640SDavid Schultz *p++ = to_char(exp); 3420a492640SDavid Schultz } 3430a492640SDavid Schultz return (p - p0); 3440a492640SDavid Schultz } 3450a492640SDavid Schultz 3460a492640SDavid Schultz #endif /* !NO_FLOATING_POINT */ 347