xprintf_float.c
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: src/lib/libc/stdio/xprintf_float.c,v 1.1 2005/12/16 18:56:38 phk Exp $ 34 */ 35 36 #include <namespace.h> 37 #include "xlocale_private.h" 38 #include <stdio.h> 39 #include <string.h> 40 #include <wchar.h> 41 #include <assert.h> 42 #include <locale.h> 43 #include <limits.h> 44 45 #define dtoa __dtoa 46 #define freedtoa __freedtoa 47 48 #include <float.h> 49 #include <math.h> 50 #include "gdtoa.h" 51 #include "floatio.h" 52 #include "printf.h" 53 #include "xprintf_private.h" 54 #include <un-namespace.h> 55 56 /* 57 * The size of the buffer we use as scratch space for integer 58 * conversions, among other things. Technically, we would need the 59 * most space for base 10 conversions with thousands' grouping 60 * characters between each pair of digits. 100 bytes is a 61 * conservative overestimate even for a 128-bit uintmax_t. 62 */ 63 #define BUF 100 64 65 #define DEFPREC 6 /* Default FP precision */ 66 67 68 /* various globals ---------------------------------------------------*/ 69 70 71 /* padding function---------------------------------------------------*/ 72 73 #define PRINTANDPAD(p, ep, len, with) do { \ 74 n2 = (ep) - (p); \ 75 if (n2 > (len)) \ 76 n2 = (len); \ 77 if (n2 > 0) \ 78 ret += __printf_puts(io, (p), n2); \ 79 ret += __printf_pad(io, (len) - (n2 > 0 ? n2 : 0), (with)); \ 80 } while(0) 81 82 /* misc --------------------------------------------------------------*/ 83 84 extern const char *__fix_nogrouping(const char *str); 85 86 #define to_char(n) ((n) + '0') 87 88 static int 89 exponent(char *p0, int expo, int fmtch) 90 { 91 char *p, *t; 92 char expbuf[MAXEXPDIG]; 93 94 p = p0; 95 *p++ = fmtch; 96 if (expo < 0) { 97 expo = -expo; 98 *p++ = '-'; 99 } 100 else 101 *p++ = '+'; 102 t = expbuf + MAXEXPDIG; 103 if (expo > 9) { 104 do { 105 *--t = to_char(expo % 10); 106 } while ((expo /= 10) > 9); 107 *--t = to_char(expo); 108 for (; t < expbuf + MAXEXPDIG; *p++ = *t++) 109 ; 110 } 111 else { 112 /* 113 * Exponents for decimal floating point conversions 114 * (%[eEgG]) must be at least two characters long, 115 * whereas exponents for hexadecimal conversions can 116 * be only one character long. 117 */ 118 if (fmtch == 'e' || fmtch == 'E') 119 *p++ = '0'; 120 *p++ = to_char(expo); 121 } 122 return (p - p0); 123 } 124 125 /* 'f' ---------------------------------------------------------------*/ 126 127 __private_extern__ int 128 __printf_arginfo_float(const struct printf_info *pi, size_t n, int *argt) 129 { 130 assert (n > 0); 131 #ifdef VECTORS 132 if (pi->is_vec) 133 argt[0] = PA_VECTOR; 134 else { 135 #endif /* VECTORS */ 136 argt[0] = PA_DOUBLE; 137 if (pi->is_long_double) 138 argt[0] |= PA_FLAG_LONG_DOUBLE; 139 #ifdef VECTORS 140 } 141 #endif /* VECTORS */ 142 return (1); 143 } 144 145 /* 146 * We can decompose the printed representation of floating 147 * point numbers into several parts, some of which may be empty: 148 * 149 * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ 150 * A B ---C--- D E F 151 * 152 * A: 'sign' holds this value if present; '\0' otherwise 153 * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal 154 * C: cp points to the string MMMNNN. Leading and trailing 155 * zeros are not in the string and must be added. 156 * D: expchar holds this character; '\0' if no exponent, e.g. %f 157 * F: at least two digits for decimal, at least one digit for hex 158 */ 159 160 __private_extern__ int 161 __printf_render_float(struct __printf_io *io, const struct printf_info *pi, const void *const *arg) 162 { 163 int prec; /* precision from format; <0 for N/A */ 164 char *dtoaresult; /* buffer allocated by dtoa */ 165 char expchar; /* exponent character: [eEpP\0] */ 166 char *cp; 167 int expt; /* integer value of exponent */ 168 int signflag; /* true if float is negative */ 169 char *dtoaend; /* pointer to end of converted digits */ 170 char sign; /* sign prefix (' ', '+', '-', or \0) */ 171 int size; /* size of converted field or string */ 172 int ndig; /* actual number of digits returned by dtoa */ 173 int expsize; /* character count for expstr */ 174 char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ 175 int nseps; /* number of group separators with ' */ 176 int nrepeats; /* number of repeats of the last group */ 177 const char *grouping; /* locale specific numeric grouping rules */ 178 int lead; /* sig figs before decimal or group sep */ 179 long double ld; 180 double d; 181 int realsz; /* field size expanded by dprec, sign, etc */ 182 int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 183 char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ 184 int prsize; /* max size of printed field */ 185 int ret; /* return value accumulator */ 186 const char *decimal_point; /* locale specific decimal point */ 187 int decimal_point_len; /* length of locale specific decimal point */ 188 int n2; /* XXX: for PRINTANDPAD */ 189 const char *thousands_sep; /* locale specific thousands separator */ 190 int thousands_sep_len; /* length of locale specific thousands separator */ 191 char buf[BUF]; /* buffer with space for digits of uintmax_t */ 192 const char *xdigs; 193 int flag; 194 195 #ifdef VECTORS 196 if (pi->is_vec) return __xprintf_vector(io, pi, arg); 197 #endif /* VECTORS */ 198 199 prec = pi->prec; 200 ox[1] = '\0'; 201 sign = pi->signchar; 202 flag = 0; 203 ret = 0; 204 205 thousands_sep = localeconv_l(pi->loc)->thousands_sep; 206 thousands_sep_len = strlen(thousands_sep); 207 grouping = NULL; 208 if (pi->group) 209 grouping = __fix_nogrouping(localeconv_l(pi->loc)->grouping); 210 decimal_point = localeconv_l(pi->loc)->decimal_point; 211 decimal_point_len = strlen(decimal_point); 212 dprec = -1; 213 214 switch(pi->spec) { 215 case 'a': 216 case 'A': 217 if (pi->spec == 'a') { 218 ox[1] = 'x'; 219 xdigs = __lowercase_hex; 220 expchar = 'p'; 221 } else { 222 ox[1] = 'X'; 223 xdigs = __uppercase_hex; 224 expchar = 'P'; 225 } 226 if (prec >= 0) 227 prec++; 228 if (pi->is_long_double) { 229 ld = *((long double *)arg[0]); 230 dtoaresult = cp = 231 __hldtoa(ld, xdigs, prec, 232 &expt, &signflag, &dtoaend); 233 } else { 234 d = *((double *)arg[0]); 235 dtoaresult = cp = 236 __hdtoa(d, xdigs, prec, 237 &expt, &signflag, &dtoaend); 238 } 239 if (prec < 0) 240 prec = dtoaend - cp; 241 if (expt == INT_MAX) 242 ox[1] = '\0'; 243 goto fp_common; 244 case 'e': 245 case 'E': 246 expchar = pi->spec; 247 if (prec < 0) /* account for digit before decpt */ 248 prec = DEFPREC + 1; 249 else 250 prec++; 251 break; 252 case 'f': 253 case 'F': 254 expchar = '\0'; 255 break; 256 case 'g': 257 case 'G': 258 expchar = pi->spec - ('g' - 'e'); 259 if (prec == 0) 260 prec = 1; 261 break; 262 default: 263 assert(pi->spec == 'f'); 264 } 265 266 if (prec < 0) 267 prec = DEFPREC; 268 if (pi->is_long_double) { 269 ld = *((long double *)arg[0]); 270 dtoaresult = cp = 271 __ldtoa(&ld, expchar ? 2 : 3, prec, 272 &expt, &signflag, &dtoaend); 273 } else { 274 d = *((double *)arg[0]); 275 dtoaresult = cp = 276 dtoa(d, expchar ? 2 : 3, prec, 277 &expt, &signflag, &dtoaend); 278 if (expt == 9999) 279 expt = INT_MAX; 280 } 281 fp_common: 282 if (signflag) 283 sign = '-'; 284 if (expt == INT_MAX) { /* inf or nan */ 285 if (*cp == 'N') { 286 cp = (pi->spec >= 'a') ? "nan" : "NAN"; 287 sign = '\0'; 288 } else 289 cp = (pi->spec >= 'a') ? "inf" : "INF"; 290 size = 3; 291 flag = 1; 292 goto here; 293 } 294 ndig = dtoaend - cp; 295 if (pi->spec == 'g' || pi->spec == 'G') { 296 if (expt > -4 && expt <= prec) { 297 /* Make %[gG] smell like %[fF] */ 298 expchar = '\0'; 299 if (pi->alt) 300 prec -= expt; 301 else 302 prec = ndig - expt; 303 if (prec < 0) 304 prec = 0; 305 } else { 306 /* 307 * Make %[gG] smell like %[eE], but 308 * trim trailing zeroes if no # flag. 309 */ 310 if (!pi->alt) 311 prec = ndig; 312 } 313 } 314 if (expchar) { 315 expsize = exponent(expstr, expt - 1, expchar); 316 size = expsize + prec; 317 if (prec > 1 || pi->alt) 318 ++size; 319 } else { 320 /* space for digits before decimal point */ 321 if (expt > 0) 322 size = expt; 323 else /* "0" */ 324 size = 1; 325 /* space for decimal pt and following digits */ 326 if (prec || pi->alt) 327 size += prec + 1; 328 if (grouping && expt > 0) { 329 /* space for thousands' grouping */ 330 nseps = nrepeats = 0; 331 lead = expt; 332 while (*grouping != CHAR_MAX) { 333 if (lead <= *grouping) 334 break; 335 lead -= *grouping; 336 if (*(grouping+1)) { 337 nseps++; 338 grouping++; 339 } else 340 nrepeats++; 341 } 342 size += nseps + nrepeats; 343 } else 344 lead = expt; 345 } 346 347 here: 348 /* 349 * All reasonable formats wind up here. At this point, `cp' 350 * points to a string which (if not flags&LADJUST) should be 351 * padded out to `width' places. If flags&ZEROPAD, it should 352 * first be prefixed by any sign or other prefix; otherwise, 353 * it should be blank padded before the prefix is emitted. 354 * After any left-hand padding and prefixing, emit zeroes 355 * required by a decimal [diouxX] precision, then print the 356 * string proper, then emit zeroes required by any leftover 357 * floating precision; finally, if LADJUST, pad with blanks. 358 * 359 * Compute actual size, so we know how much to pad. 360 * size excludes decimal prec; realsz includes it. 361 */ 362 realsz = dprec > size ? dprec : size; 363 if (sign) 364 realsz++; 365 if (ox[1]) 366 realsz += 2; 367 368 prsize = pi->width > realsz ? pi->width : realsz; 369 370 /* right-adjusting blank padding */ 371 if (pi->pad != '0' && pi->left == 0) 372 ret += __printf_pad(io, pi->width - realsz, 0); 373 374 /* prefix */ 375 if (sign) 376 ret += __printf_puts(io, &sign, 1); 377 378 if (ox[1]) { /* ox[1] is either x, X, or \0 */ 379 ox[0] = '0'; 380 ret += __printf_puts(io, ox, 2); 381 } 382 383 /* right-adjusting zero padding */ 384 if (pi->pad == '0' && pi->left == 0) 385 ret += __printf_pad(io, pi->width - realsz, 1); 386 387 /* leading zeroes from decimal precision */ 388 ret += __printf_pad(io, dprec - size, 1); 389 390 if (flag) 391 ret += __printf_puts(io, cp, size); 392 else { 393 /* glue together f_p fragments */ 394 if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 395 if (expt <= 0) { 396 ret += __printf_puts(io, "0", 1); 397 if (prec || pi->alt) 398 ret += __printf_puts(io, decimal_point, decimal_point_len); 399 ret += __printf_pad(io, -expt, 1); 400 /* already handled initial 0's */ 401 prec += expt; 402 } else { 403 PRINTANDPAD(cp, dtoaend, lead, 1); 404 cp += lead; 405 if (grouping) { 406 while (nseps>0 || nrepeats>0) { 407 if (nrepeats > 0) 408 nrepeats--; 409 else { 410 grouping--; 411 nseps--; 412 } 413 ret += __printf_puts(io, thousands_sep, thousands_sep_len); 414 PRINTANDPAD(cp,dtoaend, 415 *grouping, 1); 416 cp += *grouping; 417 } 418 if (cp > dtoaend) 419 cp = dtoaend; 420 } 421 if (prec || pi->alt) 422 ret += __printf_puts(io, decimal_point, decimal_point_len); 423 } 424 PRINTANDPAD(cp, dtoaend, prec, 1); 425 } else { /* %[eE] or sufficiently long %[gG] */ 426 if (prec > 1 || pi->alt) { 427 buf[0] = *cp++; 428 memcpy(buf + 1, decimal_point, decimal_point_len); 429 ret += __printf_puts(io, buf, decimal_point_len + 1); 430 ret += __printf_puts(io, cp, ndig-1); 431 ret += __printf_pad(io, prec - ndig, 1); 432 } else /* XeYYY */ 433 ret += __printf_puts(io, cp, 1); 434 ret += __printf_puts(io, expstr, expsize); 435 } 436 } 437 /* left-adjusting padding (always blank) */ 438 if (pi->left) 439 ret += __printf_pad(io, pi->width - realsz, 0); 440 441 __printf_flush(io); 442 if (dtoaresult != NULL) 443 freedtoa(dtoaresult); 444 445 return (ret); 446 }