lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | /* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org> |
| 2 | * |
| 3 | * GNU Library General Public License (LGPL) version 2 or later. |
| 4 | * |
| 5 | * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details. |
| 6 | */ |
| 7 | |
| 8 | #include "_stdio.h" |
| 9 | #include <printf.h> |
| 10 | #include <float.h> |
| 11 | #include <locale.h> |
| 12 | #include <bits/uClibc_fpmax.h> |
| 13 | |
| 14 | |
| 15 | typedef size_t (__fp_outfunc_t)(FILE *fp, intptr_t type, intptr_t len, |
| 16 | intptr_t buf); |
| 17 | |
| 18 | |
| 19 | /* Copyright (C) 2000, 2001, 2003 Manuel Novoa III |
| 20 | * |
| 21 | * Function: |
| 22 | * |
| 23 | * ssize_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info, |
| 24 | * __fp_outfunc_t fp_outfunc); |
| 25 | * |
| 26 | * This is derived from the old _dtostr, whic I wrote for uClibc to provide |
| 27 | * floating point support for the printf functions. It handles +/- infinity, |
| 28 | * nan, and signed 0 assuming you have ieee arithmetic. It also now handles |
| 29 | * digit grouping (for the uClibc supported locales) and hexadecimal float |
| 30 | * notation. Finally, via the fp_outfunc parameter, it now supports wide |
| 31 | * output. |
| 32 | * |
| 33 | * Notes: |
| 34 | * |
| 35 | * At most DECIMAL_DIG significant digits are kept. Any trailing digits |
| 36 | * are treated as 0 as they are really just the results of rounding noise |
| 37 | * anyway. If you want to do better, use an arbitary precision arithmetic |
| 38 | * package. ;-) |
| 39 | * |
| 40 | * It should also be fairly portable, as no assumptions are made about the |
| 41 | * bit-layout of doubles. Of course, that does make it less efficient than |
| 42 | * it could be. |
| 43 | * |
| 44 | */ |
| 45 | |
| 46 | /*****************************************************************************/ |
| 47 | /* Don't change anything that follows unless you know what you're doing. */ |
| 48 | /*****************************************************************************/ |
| 49 | /* Fairly portable nan check. Bitwise for i386 generated larger code. |
| 50 | * If you have a better version, comment this out. |
| 51 | */ |
| 52 | #define isnan(x) ((x) != (x)) |
| 53 | |
| 54 | /* Without seminumerical functions to examine the sign bit, this is |
| 55 | * about the best we can do to test for '-0'. |
| 56 | */ |
| 57 | #define zeroisnegative(x) ((1./(x)) < 0) |
| 58 | |
| 59 | /*****************************************************************************/ |
| 60 | /* Don't change anything that follows peroid!!! ;-) */ |
| 61 | /*****************************************************************************/ |
| 62 | #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__ |
| 63 | #if FLT_RADIX != 2 |
| 64 | #error FLT_RADIX != 2 is not currently supported |
| 65 | #endif |
| 66 | #endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */ |
| 67 | |
| 68 | #define NUM_HEX_DIGITS ((FPMAX_MANT_DIG + 3)/ 4) |
| 69 | |
| 70 | /* WARNING: Adjust _fp_out_wide() below if this changes! */ |
| 71 | /* With 32 bit ints, we can get 9 decimal digits per block. */ |
| 72 | #define DIGITS_PER_BLOCK 9 |
| 73 | #define HEX_DIGITS_PER_BLOCK 8 |
| 74 | |
| 75 | /* Maximum number of subcases to output double is... |
| 76 | * 0 - sign |
| 77 | * 1 - padding and initial digit |
| 78 | * 2 - digits left of the radix |
| 79 | * 3 - 0s left of the radix or radix |
| 80 | * 4 - radix or digits right of the radix |
| 81 | * 5 - 0s right of the radix |
| 82 | * 6 - exponent |
| 83 | * 7 - trailing space padding |
| 84 | * although not all cases may occur. |
| 85 | */ |
| 86 | #define MAX_CALLS 8 |
| 87 | |
| 88 | /*****************************************************************************/ |
| 89 | |
| 90 | #define NUM_DIGIT_BLOCKS ((DECIMAL_DIG+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK) |
| 91 | #define NUM_HEX_DIGIT_BLOCKS \ |
| 92 | ((NUM_HEX_DIGITS+HEX_DIGITS_PER_BLOCK-1)/HEX_DIGITS_PER_BLOCK) |
| 93 | |
| 94 | /* WARNING: Adjust _fp_out_wide() below if this changes! */ |
| 95 | |
| 96 | /* extra space for '-', '.', 'e+###', and nul */ |
| 97 | #define BUF_SIZE ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK ) |
| 98 | |
| 99 | /*****************************************************************************/ |
| 100 | |
| 101 | static const char fmt[] = "inf\0INF\0nan\0NAN\0.\0,"; |
| 102 | |
| 103 | #define INF_OFFSET 0 /* must be 1st */ |
| 104 | #define NAN_OFFSET 8 /* must be 2nd.. see hex sign handling */ |
| 105 | #define DECPT_OFFSET 16 |
| 106 | #define THOUSEP_OFFSET 18 |
| 107 | |
| 108 | #define EMPTY_STRING_OFFSET 3 |
| 109 | |
| 110 | /*****************************************************************************/ |
| 111 | #if FPMAX_MAX_10_EXP < -FPMAX_MIN_10_EXP |
| 112 | #error scaling code can not handle FPMAX_MAX_10_EXP < -FPMAX_MIN_10_EXP |
| 113 | #endif |
| 114 | |
| 115 | static const __fpmax_t exp10_table[] = |
| 116 | { |
| 117 | 1e1L, 1e2L, 1e4L, 1e8L, 1e16L, 1e32L, /* floats */ |
| 118 | #if FPMAX_MAX_10_EXP < 32 |
| 119 | #error unsupported FPMAX_MAX_10_EXP (< 32). ANSI/ISO C requires >= 37. |
| 120 | #endif |
| 121 | #if FPMAX_MAX_10_EXP >= 64 |
| 122 | 1e64L, |
| 123 | #endif |
| 124 | #if FPMAX_MAX_10_EXP >= 128 |
| 125 | 1e128L, |
| 126 | #endif |
| 127 | #if FPMAX_MAX_10_EXP >= 256 |
| 128 | 1e256L, |
| 129 | #endif |
| 130 | #if FPMAX_MAX_10_EXP >= 512 |
| 131 | 1e512L, |
| 132 | #endif |
| 133 | #if FPMAX_MAX_10_EXP >= 1024 |
| 134 | 1e1024L, |
| 135 | #endif |
| 136 | #if FPMAX_MAX_10_EXP >= 2048 |
| 137 | 1e2048L, |
| 138 | #endif |
| 139 | #if FPMAX_MAX_10_EXP >= 4096 |
| 140 | 1e4096L |
| 141 | #endif |
| 142 | #if FPMAX_MAX_10_EXP >= 8192 |
| 143 | #error unsupported FPMAX_MAX_10_EXP. please increase table |
| 144 | #endif |
| 145 | }; |
| 146 | |
| 147 | #define EXP10_TABLE_SIZE (sizeof(exp10_table)/sizeof(exp10_table[0])) |
| 148 | #define EXP10_TABLE_MAX (1U<<(EXP10_TABLE_SIZE-1)) |
| 149 | |
| 150 | /*****************************************************************************/ |
| 151 | #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__ |
| 152 | |
| 153 | #if FLT_RADIX != 2 |
| 154 | #error FLT_RADIX != 2 is not currently supported |
| 155 | #endif |
| 156 | |
| 157 | #if FPMAX_MAX_EXP < -FPMAX_MIN_EXP |
| 158 | #error scaling code can not handle FPMAX_MAX_EXP < -FPMAX_MIN_EXP |
| 159 | #endif |
| 160 | |
| 161 | static const __fpmax_t exp16_table[] = { |
| 162 | 0x1.0p4L, 0x1.0p8L, 0x1.0p16L, 0x1.0p32L, 0x1.0p64L, |
| 163 | #if FPMAX_MAX_EXP >= 128 |
| 164 | 0x1.0p128L, |
| 165 | #endif |
| 166 | #if FPMAX_MAX_EXP >= 256 |
| 167 | 0x1.0p256L, |
| 168 | #endif |
| 169 | #if FPMAX_MAX_EXP >= 512 |
| 170 | 0x1.0p512L, |
| 171 | #endif |
| 172 | #if FPMAX_MAX_EXP >= 1024 |
| 173 | 0x1.0p1024L, |
| 174 | #endif |
| 175 | #if FPMAX_MAX_EXP >= 2048 |
| 176 | 0x1.0p2048L, |
| 177 | #endif |
| 178 | #if FPMAX_MAX_EXP >= 4096 |
| 179 | 0x1.0p4096L, |
| 180 | #endif |
| 181 | #if FPMAX_MAX_EXP >= 8192 |
| 182 | 0x1.0p8192L, |
| 183 | #endif |
| 184 | #if FPMAX_MAX_EXP >= 16384 |
| 185 | 0x1.0p16384L |
| 186 | #endif |
| 187 | #if FPMAX_MAX_EXP >= 32768 |
| 188 | #error unsupported FPMAX_MAX_EXP. please increase table |
| 189 | #endif |
| 190 | }; |
| 191 | |
| 192 | #define EXP16_TABLE_SIZE (sizeof(exp16_table)/sizeof(exp16_table[0])) |
| 193 | #define EXP16_TABLE_MAX (1U<<(EXP16_TABLE_SIZE-1)) |
| 194 | |
| 195 | #endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */ |
| 196 | /*****************************************************************************/ |
| 197 | |
| 198 | #define FPO_ZERO_PAD (0x80 | '0') |
| 199 | #define FPO_STR_WIDTH (0x80 | ' '); |
| 200 | #define FPO_STR_PREC 'p' |
| 201 | |
| 202 | ssize_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info, |
| 203 | __fp_outfunc_t fp_outfunc) attribute_hidden; |
| 204 | ssize_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info, |
| 205 | __fp_outfunc_t fp_outfunc) |
| 206 | { |
| 207 | #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__ |
| 208 | __fpmax_t lower_bnd; |
| 209 | __fpmax_t upper_bnd = 1e9; |
| 210 | #endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */ |
| 211 | #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__ |
| 212 | uint_fast32_t base = 10; |
| 213 | const __fpmax_t *power_table; |
| 214 | int dpb = DIGITS_PER_BLOCK; |
| 215 | int ndb = NUM_DIGIT_BLOCKS; |
| 216 | int nd = DECIMAL_DIG; |
| 217 | int sufficient_precision = 0; |
| 218 | #endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */ |
| 219 | #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ |
| 220 | int num_groups = 0; |
| 221 | int initial_group; /* This does not need to be initialized. */ |
| 222 | int tslen; /* This does not need to be initialized. */ |
| 223 | int nblk2; /* This does not need to be initialized. */ |
| 224 | const char *ts; /* This does not need to be initialized. */ |
| 225 | #endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */ |
| 226 | int round, o_exp; |
| 227 | int exp; |
| 228 | int width, preci; |
| 229 | int cnt; |
| 230 | char *s; |
| 231 | char *e; |
| 232 | intptr_t pc_fwi[3*MAX_CALLS]; |
| 233 | intptr_t *ppc; |
| 234 | intptr_t *ppc_last; |
| 235 | #ifdef __UCLIBC_MJN3_ONLY__ |
| 236 | #warning TODO: The size of exp_buf[] should really be determined by the float constants. |
| 237 | #endif /* __UCLIBC_MJN3_ONLY__ */ |
| 238 | char exp_buf[16]; |
| 239 | char buf[BUF_SIZE]; |
| 240 | char sign_str[6]; /* Last 2 are for 1st digit + nul. */ |
| 241 | char o_mode; |
| 242 | char mode; |
| 243 | |
| 244 | |
| 245 | width = info->width; |
| 246 | preci = info->prec; |
| 247 | mode = info->spec; |
| 248 | |
| 249 | *exp_buf = 'e'; |
| 250 | if ((mode|0x20) == 'a') { |
| 251 | #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__ |
| 252 | *exp_buf = 'p'; |
| 253 | if (preci < 0) { |
| 254 | preci = NUM_HEX_DIGITS; |
| 255 | sufficient_precision = 1; |
| 256 | } |
| 257 | #else |
| 258 | mode += ('g' - 'a'); |
| 259 | #endif |
| 260 | } |
| 261 | |
| 262 | if (preci < 0) { |
| 263 | preci = 6; |
| 264 | } |
| 265 | |
| 266 | *sign_str = '\0'; |
| 267 | if (PRINT_INFO_FLAG_VAL(info,showsign)) { |
| 268 | *sign_str = '+'; |
| 269 | } else if (PRINT_INFO_FLAG_VAL(info,space)) { |
| 270 | *sign_str = ' '; |
| 271 | } |
| 272 | |
| 273 | *(sign_str+1) = 0; |
| 274 | pc_fwi[5] = INF_OFFSET; |
| 275 | if (isnan(x)) { /* First, check for nan. */ |
| 276 | pc_fwi[5] = NAN_OFFSET; |
| 277 | goto INF_NAN; |
| 278 | } |
| 279 | |
| 280 | if (x == 0) { /* Handle 0 now to avoid false positive. */ |
| 281 | #ifdef __UCLIBC_HAVE_SIGNED_ZERO__ |
| 282 | if (zeroisnegative(x)) { /* Handle 'signed' zero. */ |
| 283 | *sign_str = '-'; |
| 284 | } |
| 285 | #endif /* __UCLIBC_HAVE_SIGNED_ZERO__ */ |
| 286 | exp = -1; |
| 287 | goto GENERATE_DIGITS; |
| 288 | } |
| 289 | |
| 290 | if (x < 0) { /* Convert negatives to positives. */ |
| 291 | *sign_str = '-'; |
| 292 | x = -x; |
| 293 | } |
| 294 | |
| 295 | if (__FPMAX_ZERO_OR_INF_CHECK(x)) { /* Inf since zero handled above. */ |
| 296 | INF_NAN: |
| 297 | info->pad = ' '; |
| 298 | ppc = pc_fwi + 6; |
| 299 | pc_fwi[3] = FPO_STR_PREC; |
| 300 | pc_fwi[4] = 3; |
| 301 | if (mode < 'a') { |
| 302 | pc_fwi[5] += 4; |
| 303 | } |
| 304 | pc_fwi[5] = (intptr_t)(fmt + pc_fwi[5]); |
| 305 | goto EXIT_SPECIAL; |
| 306 | } |
| 307 | |
| 308 | { |
| 309 | int i, j; |
| 310 | #ifdef __UCLIBC_MJN3_ONLY__ |
| 311 | #warning TODO: Clean up defines when hexadecimal float notation is unsupported. |
| 312 | #endif /* __UCLIBC_MJN3_ONLY__ */ |
| 313 | |
| 314 | #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__ |
| 315 | |
| 316 | if ((mode|0x20) == 'a') { |
| 317 | lower_bnd = 0x1.0p31L; |
| 318 | upper_bnd = 0x1.0p32L; |
| 319 | power_table = exp16_table; |
| 320 | exp = HEX_DIGITS_PER_BLOCK - 1; |
| 321 | i = EXP16_TABLE_SIZE; |
| 322 | j = EXP16_TABLE_MAX; |
| 323 | dpb = HEX_DIGITS_PER_BLOCK; |
| 324 | ndb = NUM_HEX_DIGIT_BLOCKS; |
| 325 | nd = NUM_HEX_DIGITS; |
| 326 | base = 16; |
| 327 | } else { |
| 328 | lower_bnd = 1e8; |
| 329 | /* upper_bnd = 1e9; */ |
| 330 | power_table = exp10_table; |
| 331 | exp = DIGITS_PER_BLOCK - 1; |
| 332 | i = EXP10_TABLE_SIZE; |
| 333 | j = EXP10_TABLE_MAX; |
| 334 | /* dpb = DIGITS_PER_BLOCK; */ |
| 335 | /* ndb = NUM_DIGIT_BLOCKS; */ |
| 336 | /* base = 10; */ |
| 337 | } |
| 338 | |
| 339 | |
| 340 | |
| 341 | #else /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */ |
| 342 | |
| 343 | #define lower_bnd 1e8 |
| 344 | #define upper_bnd 1e9 |
| 345 | #define power_table exp10_table |
| 346 | #define dpb DIGITS_PER_BLOCK |
| 347 | #define base 10 |
| 348 | #define ndb NUM_DIGIT_BLOCKS |
| 349 | #define nd DECIMAL_DIG |
| 350 | |
| 351 | exp = DIGITS_PER_BLOCK - 1; |
| 352 | i = EXP10_TABLE_SIZE; |
| 353 | j = EXP10_TABLE_MAX; |
| 354 | |
| 355 | #endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */ |
| 356 | |
| 357 | { |
| 358 | int exp_neg = 0; |
| 359 | if (x < lower_bnd) { /* Do we need to scale up or down? */ |
| 360 | exp_neg = 1; |
| 361 | } |
| 362 | |
| 363 | do { |
| 364 | --i; |
| 365 | if (exp_neg) { |
| 366 | if (x * power_table[i] < upper_bnd) { |
| 367 | x *= power_table[i]; |
| 368 | exp -= j; |
| 369 | } |
| 370 | } else { |
| 371 | if (x / power_table[i] >= lower_bnd) { |
| 372 | x /= power_table[i]; |
| 373 | exp += j; |
| 374 | } |
| 375 | } |
| 376 | j >>= 1; |
| 377 | } while (i); |
| 378 | } |
| 379 | } |
| 380 | if (x >= upper_bnd) { /* Handle bad rounding case. */ |
| 381 | x /= power_table[0]; |
| 382 | ++exp; |
| 383 | } |
| 384 | assert(x < upper_bnd); |
| 385 | |
| 386 | GENERATE_DIGITS: |
| 387 | { |
| 388 | int i, j; |
| 389 | s = buf + 2; /* Leave space for '\0' and '0'. */ |
| 390 | i = 0; |
| 391 | do { |
| 392 | uint_fast32_t digit_block = (uint_fast32_t) x; |
| 393 | assert(digit_block < upper_bnd); |
| 394 | #ifdef __UCLIBC_MJN3_ONLY__ |
| 395 | #warning CONSIDER: Can rounding be a problem? |
| 396 | #endif /* __UCLIBC_MJN3_ONLY__ */ |
| 397 | x = (x - digit_block) * upper_bnd; |
| 398 | s += dpb; |
| 399 | j = 0; |
| 400 | do { |
| 401 | s[- ++j] = '0' + (digit_block % base); |
| 402 | digit_block /= base; |
| 403 | } while (j < dpb); |
| 404 | } while (++i < ndb); |
| 405 | } |
| 406 | |
| 407 | /*************************************************************************/ |
| 408 | |
| 409 | if (mode < 'a') { |
| 410 | *exp_buf -= ('a' - 'A'); /* e->E and p->P */ |
| 411 | mode += ('a' - 'A'); |
| 412 | } |
| 413 | |
| 414 | o_mode = mode; |
| 415 | if ((mode == 'g') && (preci > 0)){ |
| 416 | --preci; |
| 417 | } |
| 418 | round = preci; |
| 419 | |
| 420 | if (mode == 'f') { |
| 421 | round += exp; |
| 422 | if (round < -1) { |
| 423 | memset(buf, '0', DECIMAL_DIG); /* OK, since 'f' -> decimal case. */ |
| 424 | exp = -1; |
| 425 | round = -1; |
| 426 | } |
| 427 | } |
| 428 | |
| 429 | s = buf; |
| 430 | *s++ = 0; /* Terminator for rounding and 0-triming. */ |
| 431 | *s = '0'; /* Space to round. */ |
| 432 | |
| 433 | { |
| 434 | int i; |
| 435 | i = 0; |
| 436 | e = s + nd + 1; |
| 437 | if (round < nd) { |
| 438 | e = s + round + 2; |
| 439 | if (*e >= '0' + (base/2)) { /* NOTE: We always round away from 0! */ |
| 440 | i = 1; |
| 441 | } |
| 442 | } |
| 443 | |
| 444 | do { /* Handle rounding and trim trailing 0s. */ |
| 445 | *--e += i; /* Add the carry. */ |
| 446 | } while ((*e == '0') || (*e > '0' - 1 + base)); |
| 447 | } |
| 448 | |
| 449 | #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__ |
| 450 | if ((mode|0x20) == 'a') { |
| 451 | char *q; |
| 452 | |
| 453 | for (q = e ; *q ; --q) { |
| 454 | if (*q > '9') { |
| 455 | *q += (*exp_buf - ('p' - 'a') - '9' - 1); |
| 456 | } |
| 457 | } |
| 458 | |
| 459 | if (e > s) { |
| 460 | exp *= 4; /* Change from base 16 to base 2. */ |
| 461 | } |
| 462 | } |
| 463 | #endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */ |
| 464 | |
| 465 | o_exp = exp; |
| 466 | if (e <= s) { /* We carried into an extra digit. */ |
| 467 | ++o_exp; |
| 468 | e = s; /* Needed if all 0s. */ |
| 469 | } else { |
| 470 | ++s; |
| 471 | } |
| 472 | *++e = 0; /* Terminating nul char. */ |
| 473 | |
| 474 | if ((mode == 'g') && ((o_exp >= -4) && (o_exp <= round))) { |
| 475 | mode = 'f'; |
| 476 | preci = round - o_exp; |
| 477 | } |
| 478 | |
| 479 | exp = o_exp; |
| 480 | if (mode != 'f') { |
| 481 | o_exp = 0; |
| 482 | } |
| 483 | |
| 484 | if (o_exp < 0) { /* Exponent is < 0, so */ |
| 485 | *--s = '0'; /* fake the first 0 digit. */ |
| 486 | } |
| 487 | |
| 488 | pc_fwi[3] = FPO_ZERO_PAD; |
| 489 | pc_fwi[4] = 1; |
| 490 | pc_fwi[5] = (intptr_t)(sign_str + 4); |
| 491 | sign_str[4] = *s++; |
| 492 | sign_str[5] = 0; |
| 493 | ppc = pc_fwi + 6; |
| 494 | |
| 495 | { |
| 496 | int i = e - s; /* Total digits is 'i'. */ |
| 497 | if (o_exp >= 0) { |
| 498 | #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ |
| 499 | |
| 500 | const char *p; |
| 501 | |
| 502 | if (PRINT_INFO_FLAG_VAL(info,group) |
| 503 | && *(p = __UCLIBC_CURLOCALE->grouping) |
| 504 | ) { |
| 505 | int nblk1; |
| 506 | |
| 507 | nblk2 = nblk1 = *p; |
| 508 | if (*++p) { |
| 509 | nblk2 = *p; |
| 510 | assert(!*++p); |
| 511 | } |
| 512 | |
| 513 | if (o_exp >= nblk1) { |
| 514 | num_groups = (o_exp - nblk1) / nblk2 + 1; |
| 515 | initial_group = (o_exp - nblk1) % nblk2; |
| 516 | |
| 517 | #ifdef __UCLIBC_HAS_WCHAR__ |
| 518 | if (PRINT_INFO_FLAG_VAL(info,wide)) { |
| 519 | /* _fp_out_wide() will fix this up. */ |
| 520 | ts = fmt + THOUSEP_OFFSET; |
| 521 | tslen = 1; |
| 522 | } else { |
| 523 | #endif /* __UCLIBC_HAS_WCHAR__ */ |
| 524 | ts = __UCLIBC_CURLOCALE->thousands_sep; |
| 525 | tslen = __UCLIBC_CURLOCALE->thousands_sep_len; |
| 526 | #ifdef __UCLIBC_HAS_WCHAR__ |
| 527 | } |
| 528 | #endif /* __UCLIBC_HAS_WCHAR__ */ |
| 529 | |
| 530 | width -= num_groups * tslen; |
| 531 | } |
| 532 | } |
| 533 | |
| 534 | |
| 535 | #endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */ |
| 536 | ppc[0] = FPO_STR_PREC; |
| 537 | ppc[2] = (intptr_t)(s); |
| 538 | if (o_exp >= i) { /* all digit(s) left of decimal */ |
| 539 | ppc[1] = i; |
| 540 | ppc += 3; |
| 541 | o_exp -= i; |
| 542 | i = 0; |
| 543 | if (o_exp>0) { /* have 0s left of decimal */ |
| 544 | ppc[0] = FPO_ZERO_PAD; |
| 545 | ppc[1] = o_exp; |
| 546 | ppc[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET); |
| 547 | ppc += 3; |
| 548 | } |
| 549 | } else if (o_exp > 0) { /* decimal between digits */ |
| 550 | ppc[1] = o_exp; |
| 551 | ppc += 3; |
| 552 | s += o_exp; |
| 553 | i -= o_exp; |
| 554 | } |
| 555 | o_exp = -1; |
| 556 | } |
| 557 | |
| 558 | if (PRINT_INFO_FLAG_VAL(info,alt) |
| 559 | || (i) |
| 560 | || ((o_mode != 'g') |
| 561 | #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__ |
| 562 | && (o_mode != 'a') |
| 563 | #endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */ |
| 564 | && (preci > 0)) |
| 565 | ) { |
| 566 | ppc[0] = FPO_STR_PREC; |
| 567 | #ifdef __LOCALE_C_ONLY |
| 568 | ppc[1] = 1; |
| 569 | ppc[2] = (intptr_t)(fmt + DECPT_OFFSET); |
| 570 | #else /* __LOCALE_C_ONLY */ |
| 571 | #ifdef __UCLIBC_HAS_WCHAR__ |
| 572 | if (PRINT_INFO_FLAG_VAL(info,wide)) { |
| 573 | /* _fp_out_wide() will fix this up. */ |
| 574 | ppc[1] = 1; |
| 575 | ppc[2] = (intptr_t)(fmt + DECPT_OFFSET); |
| 576 | } else { |
| 577 | #endif /* __UCLIBC_HAS_WCHAR__ */ |
| 578 | ppc[1] = __UCLIBC_CURLOCALE->decimal_point_len; |
| 579 | ppc[2] = (intptr_t)(__UCLIBC_CURLOCALE->decimal_point); |
| 580 | #ifdef __UCLIBC_HAS_WCHAR__ |
| 581 | } |
| 582 | #endif /* __UCLIBC_HAS_WCHAR__ */ |
| 583 | #endif /* __LOCALE_C_ONLY */ |
| 584 | ppc += 3; |
| 585 | } |
| 586 | |
| 587 | if (++o_exp < 0) { /* Have 0s right of decimal. */ |
| 588 | ppc[0] = FPO_ZERO_PAD; |
| 589 | ppc[1] = -o_exp; |
| 590 | ppc[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET); |
| 591 | ppc += 3; |
| 592 | } |
| 593 | if (i) { /* Have digit(s) right of decimal. */ |
| 594 | ppc[0] = FPO_STR_PREC; |
| 595 | ppc[1] = i; |
| 596 | ppc[2] = (intptr_t)(s); |
| 597 | ppc += 3; |
| 598 | } |
| 599 | |
| 600 | if (((o_mode != 'g') || PRINT_INFO_FLAG_VAL(info,alt)) |
| 601 | #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__ |
| 602 | && !sufficient_precision |
| 603 | #endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */ |
| 604 | ) { |
| 605 | i -= o_exp; |
| 606 | if (i < preci) { /* Have 0s right of digits. */ |
| 607 | i = preci - i; |
| 608 | ppc[0] = FPO_ZERO_PAD; |
| 609 | ppc[1] = i; |
| 610 | ppc[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET); |
| 611 | ppc += 3; |
| 612 | } |
| 613 | } |
| 614 | } |
| 615 | |
| 616 | /* Build exponent string. */ |
| 617 | if (mode != 'f') { |
| 618 | char *p = exp_buf + sizeof(exp_buf); |
| 619 | int j; |
| 620 | char exp_char = *exp_buf; |
| 621 | char exp_sign = '+'; |
| 622 | #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__ |
| 623 | int min_exp_dig_plus_2 = ((o_mode != 'a') ? (2+2) : (2+1)); |
| 624 | #else /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */ |
| 625 | #define min_exp_dig_plus_2 (2+2) |
| 626 | #endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */ |
| 627 | |
| 628 | if (exp < 0) { |
| 629 | exp_sign = '-'; |
| 630 | exp = -exp; |
| 631 | } |
| 632 | |
| 633 | *--p = 0; /* nul-terminate */ |
| 634 | j = 2; /* Count exp_char and exp_sign. */ |
| 635 | do { |
| 636 | *--p = '0' + (exp % 10); |
| 637 | exp /= 10; |
| 638 | } while ((++j < min_exp_dig_plus_2) || exp); /* char+sign+mindigits */ |
| 639 | *--p = exp_sign; |
| 640 | *--p = exp_char; |
| 641 | |
| 642 | ppc[0] = FPO_STR_PREC; |
| 643 | ppc[1] = j; |
| 644 | ppc[2] = (intptr_t)(p); |
| 645 | ppc += 3; |
| 646 | } |
| 647 | |
| 648 | EXIT_SPECIAL: |
| 649 | { |
| 650 | int i; |
| 651 | ppc_last = ppc; |
| 652 | ppc = pc_fwi + 4; /* Need width fields starting with second. */ |
| 653 | do { |
| 654 | width -= *ppc; |
| 655 | ppc += 3; |
| 656 | } while (ppc < ppc_last); |
| 657 | |
| 658 | ppc = pc_fwi; |
| 659 | ppc[0] = FPO_STR_WIDTH; |
| 660 | ppc[1] = i = ((*sign_str) != 0); |
| 661 | ppc[2] = (intptr_t) sign_str; |
| 662 | |
| 663 | #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__ |
| 664 | if (((mode|0x20) == 'a') && (pc_fwi[3] >= 16)) { /* Hex sign handling. */ |
| 665 | /* Hex and not inf or nan, so prefix with 0x. */ |
| 666 | char *h = sign_str + i; |
| 667 | *h = '0'; |
| 668 | *++h = 'x' - 'p' + *exp_buf; |
| 669 | *++h = 0; |
| 670 | ppc[1] = (i += 2); |
| 671 | } |
| 672 | #endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */ |
| 673 | |
| 674 | if ((width -= i) > 0) { |
| 675 | if (PRINT_INFO_FLAG_VAL(info,left)) { /* Left-justified. */ |
| 676 | ppc_last[0] = FPO_STR_WIDTH; |
| 677 | ppc_last[1] = width; |
| 678 | ppc_last[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET); |
| 679 | ppc_last += 3; |
| 680 | } else if (info->pad == '0') { /* 0 padding */ |
| 681 | ppc[4] += width; /* Pad second field. */ |
| 682 | } else { |
| 683 | ppc[1] += width; /* Pad first (sign) field. */ |
| 684 | } |
| 685 | } |
| 686 | |
| 687 | cnt = 0; |
| 688 | } |
| 689 | |
| 690 | do { |
| 691 | #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ |
| 692 | |
| 693 | if ((ppc == pc_fwi + 6) && num_groups) { |
| 694 | const char *gp = (const char *) ppc[2]; |
| 695 | int len = ppc[1]; |
| 696 | int blk = initial_group; |
| 697 | |
| 698 | cnt += num_groups * tslen; /* Adjust count now for sep chars. */ |
| 699 | |
| 700 | /* __printf("\n"); */ |
| 701 | do { |
| 702 | if (!blk) { /* Initial group could be 0 digits long! */ |
| 703 | blk = nblk2; |
| 704 | } else if (len >= blk) { /* Enough digits for a group. */ |
| 705 | /* __printf("norm: len=%d blk=%d \"%.*s\"\n", len, blk, blk, gp); */ |
| 706 | if (fp_outfunc(fp, *ppc, blk, (intptr_t) gp) != blk) { |
| 707 | return -1; |
| 708 | } |
| 709 | assert(gp); |
| 710 | if (*gp) { |
| 711 | gp += blk; |
| 712 | } |
| 713 | len -= blk; |
| 714 | } else { /* Transition to 0s. */ |
| 715 | /* __printf("trans: len=%d blk=%d \"%.*s\"\n", len, blk, len, gp); */ |
| 716 | if (len) { |
| 717 | /* __printf("len\n"); */ |
| 718 | if (fp_outfunc(fp, *ppc, len, (intptr_t) gp) != len) { |
| 719 | return -1; |
| 720 | } |
| 721 | gp += len; |
| 722 | } |
| 723 | |
| 724 | if (ppc[3] == FPO_ZERO_PAD) { /* Need to group 0s */ |
| 725 | /* __printf("zeropad\n"); */ |
| 726 | cnt += ppc[1]; |
| 727 | ppc += 3; |
| 728 | gp = (const char *) ppc[2]; |
| 729 | blk -= len; /* blk > len, so blk still > 0. */ |
| 730 | len = ppc[1]; |
| 731 | continue; /* Don't decrement num_groups here. */ |
| 732 | } else { |
| 733 | assert(num_groups == 0); |
| 734 | break; |
| 735 | } |
| 736 | } |
| 737 | |
| 738 | if (num_groups <= 0) { |
| 739 | break; |
| 740 | } |
| 741 | --num_groups; |
| 742 | |
| 743 | if (fp_outfunc(fp, FPO_STR_PREC, tslen, (intptr_t) ts) != tslen) { |
| 744 | return -1; |
| 745 | } |
| 746 | blk = nblk2; |
| 747 | |
| 748 | /* __printf("num_groups=%d blk=%d\n", num_groups, blk); */ |
| 749 | |
| 750 | } while (1); |
| 751 | } else |
| 752 | |
| 753 | #endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */ |
| 754 | { /* NOTE: Remember 'else' above! */ |
| 755 | if (fp_outfunc(fp, *ppc, ppc[1], ppc[2]) != ppc[1]) { |
| 756 | return -1; |
| 757 | } |
| 758 | } |
| 759 | |
| 760 | cnt += ppc[1]; |
| 761 | ppc += 3; |
| 762 | } while (ppc < ppc_last); |
| 763 | |
| 764 | return cnt; |
| 765 | } |