1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Chris Torek. 9 * 10 * Copyright (c) 2011 The FreeBSD Foundation 11 * 12 * Portions of this software were developed by David Chisnall 13 * under sponsorship from the FreeBSD Foundation. 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 3. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 */ 39 40 /* 41 * This file defines common routines used by both printf and wprintf. 42 * You must define CHAR to either char or wchar_t prior to including this. 43 */ 44 45 46 #ifndef NO_FLOATING_POINT 47 48 #define dtoa __dtoa 49 #define freedtoa __freedtoa 50 51 #include <float.h> 52 #include <math.h> 53 #include "floatio.h" 54 #include "gdtoa.h" 55 56 #define DEFPREC 6 57 58 static int exponent(CHAR *, int, CHAR); 59 60 #endif /* !NO_FLOATING_POINT */ 61 62 static CHAR *__ujtoa(uintmax_t, CHAR *, int, int, const char *); 63 static CHAR *__ultoa(u_long, CHAR *, int, int, const char *); 64 65 #define NIOV 8 66 struct io_state { 67 FILE *fp; 68 struct __suio uio; /* output information: summary */ 69 struct __siov iov[NIOV];/* ... and individual io vectors */ 70 }; 71 72 static inline void 73 io_init(struct io_state *iop, FILE *fp) 74 { 75 76 iop->uio.uio_iov = iop->iov; 77 iop->uio.uio_resid = 0; 78 iop->uio.uio_iovcnt = 0; 79 iop->fp = fp; 80 } 81 82 /* 83 * WARNING: The buffer passed to io_print() is not copied immediately; it must 84 * remain valid until io_flush() is called. 85 */ 86 static inline int 87 io_print(struct io_state *iop, const CHAR * __restrict ptr, int len, locale_t locale) 88 { 89 90 iop->iov[iop->uio.uio_iovcnt].iov_base = (char *)ptr; 91 iop->iov[iop->uio.uio_iovcnt].iov_len = len; 92 iop->uio.uio_resid += len; 93 if (++iop->uio.uio_iovcnt >= NIOV) 94 return (__sprint(iop->fp, &iop->uio, locale)); 95 else 96 return (0); 97 } 98 99 /* 100 * Choose PADSIZE to trade efficiency vs. size. If larger printf 101 * fields occur frequently, increase PADSIZE and make the initialisers 102 * below longer. 103 */ 104 #define PADSIZE 16 /* pad chunk size */ 105 static const CHAR blanks[PADSIZE] = 106 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 107 static const CHAR zeroes[PADSIZE] = 108 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 109 110 /* 111 * Pad with blanks or zeroes. 'with' should point to either the blanks array 112 * or the zeroes array. 113 */ 114 static inline int 115 io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with, 116 locale_t locale) 117 { 118 int n; 119 120 while (howmany > 0) { 121 n = (howmany >= PADSIZE) ? PADSIZE : howmany; 122 if (io_print(iop, with, n, locale)) 123 return (-1); 124 howmany -= n; 125 } 126 return (0); 127 } 128 129 /* 130 * Print exactly len characters of the string spanning p to ep, truncating 131 * or padding with 'with' as necessary. 132 */ 133 static inline int 134 io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep, 135 int len, const CHAR * __restrict with, locale_t locale) 136 { 137 int p_len; 138 139 p_len = ep - p; 140 if (p_len > len) 141 p_len = len; 142 if (p_len > 0) { 143 if (io_print(iop, p, p_len, locale)) 144 return (-1); 145 } else { 146 p_len = 0; 147 } 148 return (io_pad(iop, len - p_len, with, locale)); 149 } 150 151 static inline int 152 io_flush(struct io_state *iop, locale_t locale) 153 { 154 155 return (__sprint(iop->fp, &iop->uio, locale)); 156 } 157 158 /* 159 * Convert an unsigned long to ASCII for printf purposes, returning 160 * a pointer to the first character of the string representation. 161 * Octal numbers can be forced to have a leading zero; hex numbers 162 * use the given digits. 163 */ 164 static CHAR * 165 __ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs) 166 { 167 CHAR *cp = endp; 168 long sval; 169 170 /* 171 * Handle the three cases separately, in the hope of getting 172 * better/faster code. 173 */ 174 switch (base) { 175 case 10: 176 if (val < 10) { /* many numbers are 1 digit */ 177 *--cp = to_char(val); 178 return (cp); 179 } 180 /* 181 * On many machines, unsigned arithmetic is harder than 182 * signed arithmetic, so we do at most one unsigned mod and 183 * divide; this is sufficient to reduce the range of 184 * the incoming value to where signed arithmetic works. 185 */ 186 if (val > LONG_MAX) { 187 *--cp = to_char(val % 10); 188 sval = val / 10; 189 } else 190 sval = val; 191 do { 192 *--cp = to_char(sval % 10); 193 sval /= 10; 194 } while (sval != 0); 195 break; 196 197 case 8: 198 do { 199 *--cp = to_char(val & 7); 200 val >>= 3; 201 } while (val); 202 if (octzero && *cp != '0') 203 *--cp = '0'; 204 break; 205 206 case 16: 207 do { 208 *--cp = xdigs[val & 15]; 209 val >>= 4; 210 } while (val); 211 break; 212 213 default: /* oops */ 214 abort(); 215 } 216 return (cp); 217 } 218 219 /* Identical to __ultoa, but for intmax_t. */ 220 static CHAR * 221 __ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs) 222 { 223 CHAR *cp = endp; 224 intmax_t sval; 225 226 /* quick test for small values; __ultoa is typically much faster */ 227 /* (perhaps instead we should run until small, then call __ultoa?) */ 228 if (val <= ULONG_MAX) 229 return (__ultoa((u_long)val, endp, base, octzero, xdigs)); 230 switch (base) { 231 case 10: 232 if (val < 10) { 233 *--cp = to_char(val % 10); 234 return (cp); 235 } 236 if (val > INTMAX_MAX) { 237 *--cp = to_char(val % 10); 238 sval = val / 10; 239 } else 240 sval = val; 241 do { 242 *--cp = to_char(sval % 10); 243 sval /= 10; 244 } while (sval != 0); 245 break; 246 247 case 8: 248 do { 249 *--cp = to_char(val & 7); 250 val >>= 3; 251 } while (val); 252 if (octzero && *cp != '0') 253 *--cp = '0'; 254 break; 255 256 case 16: 257 do { 258 *--cp = xdigs[val & 15]; 259 val >>= 4; 260 } while (val); 261 break; 262 263 default: 264 abort(); 265 } 266 return (cp); 267 } 268 269 #ifndef NO_FLOATING_POINT 270 271 static int 272 exponent(CHAR *p0, int exp, CHAR fmtch) 273 { 274 CHAR *p, *t; 275 CHAR expbuf[MAXEXPDIG]; 276 277 p = p0; 278 *p++ = fmtch; 279 if (exp < 0) { 280 exp = -exp; 281 *p++ = '-'; 282 } 283 else 284 *p++ = '+'; 285 t = expbuf + MAXEXPDIG; 286 if (exp > 9) { 287 do { 288 *--t = to_char(exp % 10); 289 } while ((exp /= 10) > 9); 290 *--t = to_char(exp); 291 for (; t < expbuf + MAXEXPDIG; *p++ = *t++); 292 } 293 else { 294 /* 295 * Exponents for decimal floating point conversions 296 * (%[eEgG]) must be at least two characters long, 297 * whereas exponents for hexadecimal conversions can 298 * be only one character long. 299 */ 300 if (fmtch == 'e' || fmtch == 'E') 301 *p++ = '0'; 302 *p++ = to_char(exp); 303 } 304 return (p - p0); 305 } 306 307 #endif /* !NO_FLOATING_POINT */ 308