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