1 /*- 2 * Copyright (c) 2005 Poul-Henning Kamp 3 * Copyright (c) 1990, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Chris Torek. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $FreeBSD$ 34 */ 35 36 #include <namespace.h> 37 #include <stdio.h> 38 #include <wchar.h> 39 #include <assert.h> 40 #include <locale.h> 41 #include <limits.h> 42 43 #define dtoa __dtoa 44 #define freedtoa __freedtoa 45 46 #include <float.h> 47 #include <math.h> 48 #include "gdtoa.h" 49 #include "floatio.h" 50 #include "printf.h" 51 #include <un-namespace.h> 52 53 /* 54 * The size of the buffer we use as scratch space for integer 55 * conversions, among other things. Technically, we would need the 56 * most space for base 10 conversions with thousands' grouping 57 * characters between each pair of digits. 100 bytes is a 58 * conservative overestimate even for a 128-bit uintmax_t. 59 */ 60 #define BUF 100 61 62 #define DEFPREC 6 /* Default FP precision */ 63 64 65 /* various globals ---------------------------------------------------*/ 66 67 68 /* padding function---------------------------------------------------*/ 69 70 #define PRINTANDPAD(p, ep, len, with) do { \ 71 n2 = (ep) - (p); \ 72 if (n2 > (len)) \ 73 n2 = (len); \ 74 if (n2 > 0) \ 75 ret += __printf_puts(io, (p), n2); \ 76 ret += __printf_pad(io, (len) - (n2 > 0 ? n2 : 0), (with)); \ 77 } while(0) 78 79 /* misc --------------------------------------------------------------*/ 80 81 #define to_char(n) ((n) + '0') 82 83 static int 84 exponent(char *p0, int expo, int fmtch) 85 { 86 char *p, *t; 87 char expbuf[MAXEXPDIG]; 88 89 p = p0; 90 *p++ = fmtch; 91 if (expo < 0) { 92 expo = -expo; 93 *p++ = '-'; 94 } 95 else 96 *p++ = '+'; 97 t = expbuf + MAXEXPDIG; 98 if (expo > 9) { 99 do { 100 *--t = to_char(expo % 10); 101 } while ((expo /= 10) > 9); 102 *--t = to_char(expo); 103 for (; t < expbuf + MAXEXPDIG; *p++ = *t++) 104 ; 105 } 106 else { 107 /* 108 * Exponents for decimal floating point conversions 109 * (%[eEgG]) must be at least two characters long, 110 * whereas exponents for hexadecimal conversions can 111 * be only one character long. 112 */ 113 if (fmtch == 'e' || fmtch == 'E') 114 *p++ = '0'; 115 *p++ = to_char(expo); 116 } 117 return (p - p0); 118 } 119 120 /* 'f' ---------------------------------------------------------------*/ 121 122 int 123 __printf_arginfo_float(const struct printf_info *pi, size_t n, int *argt) 124 { 125 assert (n > 0); 126 argt[0] = PA_DOUBLE; 127 if (pi->is_long_double) 128 argt[0] |= PA_FLAG_LONG_DOUBLE; 129 return (1); 130 } 131 132 /* 133 * We can decompose the printed representation of floating 134 * point numbers into several parts, some of which may be empty: 135 * 136 * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ 137 * A B ---C--- D E F 138 * 139 * A: 'sign' holds this value if present; '\0' otherwise 140 * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal 141 * C: cp points to the string MMMNNN. Leading and trailing 142 * zeros are not in the string and must be added. 143 * D: expchar holds this character; '\0' if no exponent, e.g. %f 144 * F: at least two digits for decimal, at least one digit for hex 145 */ 146 147 int 148 __printf_render_float(struct __printf_io *io, const struct printf_info *pi, const void *const *arg) 149 { 150 int prec; /* precision from format; <0 for N/A */ 151 char *dtoaresult; /* buffer allocated by dtoa */ 152 char expchar; /* exponent character: [eEpP\0] */ 153 char *cp; 154 int expt; /* integer value of exponent */ 155 int signflag; /* true if float is negative */ 156 char *dtoaend; /* pointer to end of converted digits */ 157 char sign; /* sign prefix (' ', '+', '-', or \0) */ 158 int size; /* size of converted field or string */ 159 int ndig; /* actual number of digits returned by dtoa */ 160 int expsize; /* character count for expstr */ 161 char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ 162 int nseps; /* number of group separators with ' */ 163 int nrepeats; /* number of repeats of the last group */ 164 const char *grouping; /* locale specific numeric grouping rules */ 165 int lead; /* sig figs before decimal or group sep */ 166 long double ld; 167 double d; 168 int realsz; /* field size expanded by dprec, sign, etc */ 169 int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 170 char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ 171 int prsize; /* max size of printed field */ 172 int ret; /* return value accumulator */ 173 char *decimal_point; /* locale specific decimal point */ 174 int n2; /* XXX: for PRINTANDPAD */ 175 char thousands_sep; /* locale specific thousands separator */ 176 char buf[BUF]; /* buffer with space for digits of uintmax_t */ 177 const char *xdigs; 178 int flag; 179 180 prec = pi->prec; 181 ox[1] = '\0'; 182 sign = pi->showsign; 183 flag = 0; 184 ret = 0; 185 186 thousands_sep = *(localeconv()->thousands_sep); 187 grouping = NULL; 188 if (pi->alt) 189 grouping = localeconv()->grouping; 190 decimal_point = localeconv()->decimal_point; 191 dprec = -1; 192 193 switch(pi->spec) { 194 case 'a': 195 case 'A': 196 if (pi->spec == 'a') { 197 ox[1] = 'x'; 198 xdigs = __lowercase_hex; 199 expchar = 'p'; 200 } else { 201 ox[1] = 'X'; 202 xdigs = __uppercase_hex; 203 expchar = 'P'; 204 } 205 if (prec >= 0) 206 prec++; 207 if (pi->is_long_double) { 208 ld = *((long double *)arg[0]); 209 dtoaresult = cp = 210 __hldtoa(ld, xdigs, prec, 211 &expt, &signflag, &dtoaend); 212 } else { 213 d = *((double *)arg[0]); 214 dtoaresult = cp = 215 __hdtoa(d, xdigs, prec, 216 &expt, &signflag, &dtoaend); 217 } 218 if (prec < 0) 219 prec = dtoaend - cp; 220 if (expt == INT_MAX) 221 ox[1] = '\0'; 222 goto fp_common; 223 case 'e': 224 case 'E': 225 expchar = pi->spec; 226 if (prec < 0) /* account for digit before decpt */ 227 prec = DEFPREC + 1; 228 else 229 prec++; 230 break; 231 case 'f': 232 case 'F': 233 expchar = '\0'; 234 break; 235 case 'g': 236 case 'G': 237 expchar = pi->spec - ('g' - 'e'); 238 if (prec == 0) 239 prec = 1; 240 break; 241 default: 242 assert(pi->spec == 'f'); 243 } 244 245 if (prec < 0) 246 prec = DEFPREC; 247 if (pi->is_long_double) { 248 ld = *((long double *)arg[0]); 249 dtoaresult = cp = 250 __ldtoa(&ld, expchar ? 2 : 3, prec, 251 &expt, &signflag, &dtoaend); 252 } else { 253 d = *((double *)arg[0]); 254 dtoaresult = cp = 255 dtoa(d, expchar ? 2 : 3, prec, 256 &expt, &signflag, &dtoaend); 257 if (expt == 9999) 258 expt = INT_MAX; 259 } 260 fp_common: 261 if (signflag) 262 sign = '-'; 263 if (expt == INT_MAX) { /* inf or nan */ 264 if (*cp == 'N') { 265 cp = (pi->spec >= 'a') ? "nan" : "NAN"; 266 sign = '\0'; 267 } else 268 cp = (pi->spec >= 'a') ? "inf" : "INF"; 269 size = 3; 270 flag = 1; 271 goto here; 272 } 273 ndig = dtoaend - cp; 274 if (pi->spec == 'g' || pi->spec == 'G') { 275 if (expt > -4 && expt <= prec) { 276 /* Make %[gG] smell like %[fF] */ 277 expchar = '\0'; 278 if (pi->alt) 279 prec -= expt; 280 else 281 prec = ndig - expt; 282 if (prec < 0) 283 prec = 0; 284 } else { 285 /* 286 * Make %[gG] smell like %[eE], but 287 * trim trailing zeroes if no # flag. 288 */ 289 if (!pi->alt) 290 prec = ndig; 291 } 292 } 293 if (expchar) { 294 expsize = exponent(expstr, expt - 1, expchar); 295 size = expsize + prec; 296 if (prec > 1 || pi->alt) 297 ++size; 298 } else { 299 /* space for digits before decimal point */ 300 if (expt > 0) 301 size = expt; 302 else /* "0" */ 303 size = 1; 304 /* space for decimal pt and following digits */ 305 if (prec || pi->alt) 306 size += prec + 1; 307 if (grouping && expt > 0) { 308 /* space for thousands' grouping */ 309 nseps = nrepeats = 0; 310 lead = expt; 311 while (*grouping != CHAR_MAX) { 312 if (lead <= *grouping) 313 break; 314 lead -= *grouping; 315 if (*(grouping+1)) { 316 nseps++; 317 grouping++; 318 } else 319 nrepeats++; 320 } 321 size += nseps + nrepeats; 322 } else 323 lead = expt; 324 } 325 326 here: 327 /* 328 * All reasonable formats wind up here. At this point, `cp' 329 * points to a string which (if not flags&LADJUST) should be 330 * padded out to `width' places. If flags&ZEROPAD, it should 331 * first be prefixed by any sign or other prefix; otherwise, 332 * it should be blank padded before the prefix is emitted. 333 * After any left-hand padding and prefixing, emit zeroes 334 * required by a decimal [diouxX] precision, then print the 335 * string proper, then emit zeroes required by any leftover 336 * floating precision; finally, if LADJUST, pad with blanks. 337 * 338 * Compute actual size, so we know how much to pad. 339 * size excludes decimal prec; realsz includes it. 340 */ 341 realsz = dprec > size ? dprec : size; 342 if (sign) 343 realsz++; 344 if (ox[1]) 345 realsz += 2; 346 347 prsize = pi->width > realsz ? pi->width : realsz; 348 349 /* right-adjusting blank padding */ 350 if (pi->pad != '0' && pi->left == 0) 351 ret += __printf_pad(io, pi->width - realsz, 0); 352 353 /* prefix */ 354 if (sign) 355 ret += __printf_puts(io, &sign, 1); 356 357 if (ox[1]) { /* ox[1] is either x, X, or \0 */ 358 ox[0] = '0'; 359 ret += __printf_puts(io, ox, 2); 360 } 361 362 /* right-adjusting zero padding */ 363 if (pi->pad == '0' && pi->left == 0) 364 ret += __printf_pad(io, pi->width - realsz, 1); 365 366 /* leading zeroes from decimal precision */ 367 ret += __printf_pad(io, dprec - size, 1); 368 369 if (flag) 370 ret += __printf_puts(io, cp, size); 371 else { 372 /* glue together f_p fragments */ 373 if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 374 if (expt <= 0) { 375 ret += __printf_puts(io, "0", 1); 376 if (prec || pi->alt) 377 ret += __printf_puts(io, decimal_point, 1); 378 ret += __printf_pad(io, -expt, 1); 379 /* already handled initial 0's */ 380 prec += expt; 381 } else { 382 PRINTANDPAD(cp, dtoaend, lead, 1); 383 cp += lead; 384 if (grouping) { 385 while (nseps>0 || nrepeats>0) { 386 if (nrepeats > 0) 387 nrepeats--; 388 else { 389 grouping--; 390 nseps--; 391 } 392 ret += __printf_puts(io, &thousands_sep, 1); 393 PRINTANDPAD(cp,dtoaend, 394 *grouping, 1); 395 cp += *grouping; 396 } 397 if (cp > dtoaend) 398 cp = dtoaend; 399 } 400 if (prec || pi->alt) 401 ret += __printf_puts(io, decimal_point,1); 402 } 403 PRINTANDPAD(cp, dtoaend, prec, 1); 404 } else { /* %[eE] or sufficiently long %[gG] */ 405 if (prec > 1 || pi->alt) { 406 buf[0] = *cp++; 407 buf[1] = *decimal_point; 408 ret += __printf_puts(io, buf, 2); 409 ret += __printf_puts(io, cp, ndig-1); 410 ret += __printf_pad(io, prec - ndig, 1); 411 } else /* XeYYY */ 412 ret += __printf_puts(io, cp, 1); 413 ret += __printf_puts(io, expstr, expsize); 414 } 415 } 416 /* left-adjusting padding (always blank) */ 417 if (pi->left) 418 ret += __printf_pad(io, pi->width - realsz, 0); 419 420 __printf_flush(io); 421 if (dtoaresult != NULL) 422 freedtoa(dtoaresult); 423 424 return (ret); 425 } 426