1 /*- 2 * Copyright (c) 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Chris Torek. 7 * 8 * Copyright (c) 2011 The FreeBSD Foundation 9 * All rights reserved. 10 * Portions of this software were developed by David Chisnall 11 * under sponsorship from the FreeBSD Foundation. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * $FreeBSD: head/lib/libc/stdio/printfcommon.h 227753 2011-11-20 14:45:42Z theraven $ 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 > INTMAX_MAX) { 233 *--cp = to_char(val % 10); 234 sval = val / 10; 235 } else 236 sval = val; 237 do { 238 *--cp = to_char(sval % 10); 239 sval /= 10; 240 } while (sval != 0); 241 break; 242 243 case 8: 244 do { 245 *--cp = to_char(val & 7); 246 val >>= 3; 247 } while (val); 248 if (octzero && *cp != '0') 249 *--cp = '0'; 250 break; 251 252 case 16: 253 do { 254 *--cp = xdigs[val & 15]; 255 val >>= 4; 256 } while (val); 257 break; 258 259 default: 260 abort(); 261 } 262 return (cp); 263 } 264 265 #ifndef NO_FLOATING_POINT 266 267 static int 268 exponent(CHAR *p0, int exp, CHAR fmtch) 269 { 270 CHAR *p, *t; 271 CHAR expbuf[MAXEXPDIG]; 272 273 p = p0; 274 *p++ = fmtch; 275 if (exp < 0) { 276 exp = -exp; 277 *p++ = '-'; 278 } 279 else 280 *p++ = '+'; 281 t = expbuf + MAXEXPDIG; 282 if (exp > 9) { 283 do { 284 *--t = to_char(exp % 10); 285 } while ((exp /= 10) > 9); 286 *--t = to_char(exp); 287 for (; t < expbuf + MAXEXPDIG; *p++ = *t++); 288 } 289 else { 290 /* 291 * Exponents for decimal floating point conversions 292 * (%[eEgG]) must be at least two characters long, 293 * whereas exponents for hexadecimal conversions can 294 * be only one character long. 295 */ 296 if (fmtch == 'e' || fmtch == 'E') 297 *p++ = '0'; 298 *p++ = to_char(exp); 299 } 300 return (p - p0); 301 } 302 303 #endif /* !NO_FLOATING_POINT */ 304