Line data Source code
1 : /*
2 : * Copyright (c) 2015 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 : /*------------------------------------------------------------------
16 : * format.c -- see notice below
17 : *
18 : * October 2003, Eliot Dresselhaus
19 : *
20 : * Modifications to this file Copyright (c) 2003 by cisco Systems, Inc.
21 : * All rights reserved.
22 : *------------------------------------------------------------------
23 : */
24 :
25 : /*
26 : Copyright (c) 2001, 2002, 2003, 2006 Eliot Dresselhaus
27 :
28 : Permission is hereby granted, free of charge, to any person obtaining
29 : a copy of this software and associated documentation files (the
30 : "Software"), to deal in the Software without restriction, including
31 : without limitation the rights to use, copy, modify, merge, publish,
32 : distribute, sublicense, and/or sell copies of the Software, and to
33 : permit persons to whom the Software is furnished to do so, subject to
34 : the following conditions:
35 :
36 : The above copyright notice and this permission notice shall be
37 : included in all copies or substantial portions of the Software.
38 :
39 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
40 : EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
41 : MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
42 : NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
43 : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
44 : OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
45 : WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
46 : */
47 :
48 : #include <stdarg.h> /* va_start, etc */
49 :
50 : #ifdef CLIB_UNIX
51 : #include <unistd.h>
52 : #include <stdio.h>
53 : #endif
54 :
55 : #ifdef CLIB_STANDALONE
56 : #include <vppinfra/standalone_stdio.h>
57 : #endif
58 :
59 : #include <vppinfra/mem.h>
60 : #include <vppinfra/format.h>
61 : #include <vppinfra/vec.h>
62 : #include <vppinfra/error.h>
63 : #include <vppinfra/string.h>
64 : #include <vppinfra/os.h> /* os_puts */
65 : #include <vppinfra/math.h>
66 :
67 : typedef struct
68 : {
69 : /* Output number in this base. */
70 : u8 base;
71 :
72 : /* Number of show of 64 bit number. */
73 : u8 n_bits;
74 :
75 : /* Signed or unsigned. */
76 : u8 is_signed;
77 :
78 : /* Output digits uppercase (not lowercase) %X versus %x. */
79 : u8 uppercase_digits;
80 : } format_integer_options_t;
81 :
82 : static u8 *format_integer (u8 * s, u64 number,
83 : format_integer_options_t * options);
84 : static u8 *format_float (u8 * s, f64 x, uword n_digits_to_print,
85 : uword output_style);
86 :
87 : typedef struct
88 : {
89 : /* String justification: + => right, - => left, = => center. */
90 : uword justify;
91 :
92 : /* Width of string (before and after decimal point for numbers).
93 : 0 => natural width. */
94 : uword width[2];
95 :
96 : /* Long => 'l', long long 'L', int 0. */
97 : uword how_long;
98 :
99 : /* Pad character. Defaults to space. */
100 : uword pad_char;
101 : } format_info_t;
102 :
103 : static u8 *
104 265098000 : justify (u8 * s, format_info_t * fi, uword s_len_orig)
105 : {
106 : uword i0, l0, l1;
107 :
108 265098000 : i0 = s_len_orig;
109 265098000 : l0 = i0 + fi->width[0];
110 265098000 : l1 = vec_len (s);
111 :
112 : /* If width is zero user returned width. */
113 265098000 : if (l0 == i0)
114 139783000 : l0 = l1;
115 :
116 265098000 : if (l1 > l0)
117 28610 : vec_set_len (s, l0);
118 265069000 : else if (l0 > l1)
119 : {
120 60308900 : uword n = l0 - l1;
121 60308900 : uword n_left = 0, n_right = 0;
122 :
123 60308900 : switch (fi->justify)
124 : {
125 744724 : case '-':
126 744724 : n_right = n;
127 744724 : break;
128 :
129 58961300 : case '+':
130 58961300 : n_left = n;
131 58961300 : break;
132 :
133 602934 : case '=':
134 602934 : n_right = n_left = n / 2;
135 602934 : if (n % 2)
136 263746 : n_left++;
137 602934 : break;
138 : }
139 60308900 : if (n_left > 0)
140 : {
141 59564200 : vec_insert (s, n_left, i0);
142 59564200 : clib_memset (s + i0, fi->pad_char, n_left);
143 59564200 : l1 = vec_len (s);
144 : }
145 60308900 : if (n_right > 0)
146 : {
147 1344450 : vec_resize (s, n_right);
148 1344450 : clib_memset (s + l1, fi->pad_char, n_right);
149 : }
150 : }
151 265098000 : return s;
152 : }
153 :
154 : static const u8 *
155 268211000 : do_percent (u8 ** _s, const u8 * fmt, va_list * va)
156 : {
157 268211000 : u8 *s = *_s;
158 : uword c;
159 :
160 268211000 : const u8 *f = fmt;
161 :
162 268211000 : format_info_t fi = {
163 : .justify = '+',
164 : .width = {0},
165 : .pad_char = ' ',
166 : .how_long = 0,
167 : };
168 :
169 : uword i;
170 :
171 268211000 : ASSERT (f[0] == '%');
172 :
173 268211000 : switch (c = *++f)
174 : {
175 3113280 : case '%':
176 : /* %% => % */
177 3113280 : vec_add1 (s, c);
178 3113280 : f++;
179 3113280 : goto done;
180 :
181 1401640 : case '-':
182 : case '+':
183 : case '=':
184 1401640 : fi.justify = c;
185 1401640 : c = *++f;
186 1401640 : break;
187 : }
188 :
189 : /* Parse width0 . width1. */
190 265098000 : {
191 265098000 : uword is_first_digit = 1;
192 :
193 265098000 : fi.width[0] = fi.width[1] = 0;
194 265506000 : for (i = 0; i < 2; i++)
195 : {
196 265506000 : if (c == '0' && i == 0 && is_first_digit)
197 122877000 : fi.pad_char = '0';
198 265506000 : is_first_digit = 0;
199 265506000 : if (c == '*')
200 : {
201 0 : fi.width[i] = va_arg (*va, int);
202 0 : c = *++f;
203 : }
204 : else
205 : {
206 516200000 : while (c >= '0' && c <= '9')
207 : {
208 250694000 : fi.width[i] = 10 * fi.width[i] + (c - '0');
209 250694000 : c = *++f;
210 : }
211 : }
212 265506000 : if (c != '.')
213 265098000 : break;
214 407796 : c = *++f;
215 : }
216 : }
217 :
218 : /* Parse %l* and %L* */
219 265098000 : switch (c)
220 : {
221 150564 : case 'w':
222 : /* word format. */
223 150564 : fi.how_long = 'w';
224 150564 : c = *++f;
225 150564 : break;
226 :
227 859403 : case 'L':
228 : case 'l':
229 859403 : fi.how_long = c;
230 859403 : c = *++f;
231 859403 : if (c == 'l' && *f == 'l')
232 : {
233 303539 : fi.how_long = 'L';
234 303539 : c = *++f;
235 : }
236 859403 : break;
237 : }
238 :
239 : /* Finally we are ready for format letter. */
240 265098000 : if (c != 0)
241 : {
242 265098000 : uword s_initial_len = vec_len (s);
243 265098000 : format_integer_options_t o = {
244 : .is_signed = 0,
245 : .base = 10,
246 : .n_bits = BITS (uword),
247 : .uppercase_digits = 0,
248 : };
249 :
250 265098000 : f++;
251 :
252 265098000 : switch (c)
253 : {
254 0 : default:
255 : {
256 : /* Try to give a helpful error message. */
257 0 : vec_free (s);
258 0 : s = format (s, "**** CLIB unknown format `%%%c' ****", c);
259 1 : goto done;
260 : }
261 :
262 4246420 : case 'c':
263 4246420 : vec_add1 (s, va_arg (*va, int));
264 4246420 : break;
265 :
266 1446 : case 'p':
267 1446 : vec_add1 (s, '0');
268 1446 : vec_add1 (s, 'x');
269 :
270 1446 : o.is_signed = 0;
271 1446 : o.n_bits = BITS (uword *);
272 1446 : o.base = 16;
273 1446 : o.uppercase_digits = 0;
274 :
275 2892 : s = format_integer (s, pointer_to_uword (va_arg (*va, void *)), &o);
276 1446 : break;
277 :
278 168180000 : case 'x':
279 : case 'X':
280 : case 'u':
281 : case 'o':
282 : case 'd':
283 : {
284 : u64 number;
285 :
286 168180000 : o.base = 10;
287 168180000 : if (c == 'x' || c == 'X')
288 113179000 : o.base = 16;
289 168180000 : o.is_signed = c == 'd';
290 168180000 : o.uppercase_digits = c == 'X';
291 :
292 168180000 : switch (fi.how_long)
293 : {
294 793327 : case 'L':
295 793327 : number = va_arg (*va, unsigned long long);
296 793327 : o.n_bits = BITS (unsigned long long);
297 793327 : break;
298 :
299 66076 : case 'l':
300 66076 : number = va_arg (*va, long);
301 66076 : o.n_bits = BITS (long);
302 66076 : break;
303 :
304 150564 : case 'w':
305 150564 : number = va_arg (*va, word);
306 150564 : o.n_bits = BITS (uword);
307 150564 : break;
308 :
309 167170000 : default:
310 167170000 : number = va_arg (*va, int);
311 167170000 : o.n_bits = BITS (int);
312 167170000 : break;
313 : }
314 :
315 168180000 : if (c == 'o')
316 0 : o.base = 8;
317 :
318 168180000 : s = format_integer (s, number, &o);
319 : }
320 168180000 : break;
321 :
322 24665200 : case 's':
323 : case 'S':
324 : {
325 24665200 : char *cstring = va_arg (*va, char *);
326 : uword len;
327 :
328 24665200 : if (!cstring)
329 : {
330 15684 : cstring = "(nil)";
331 15684 : len = 5;
332 : }
333 24649500 : else if (fi.width[1] != 0)
334 0 : len = clib_min (strlen (cstring), fi.width[1]);
335 : else
336 24649500 : len = strlen (cstring);
337 :
338 : /* %S => format string as C identifier (replace _ with space). */
339 24665200 : if (c == 'S')
340 : {
341 0 : for (i = 0; i < len; i++)
342 0 : vec_add1 (s, cstring[i] == '_' ? ' ' : cstring[i]);
343 : }
344 : else
345 24665200 : vec_add (s, cstring, len);
346 : }
347 24665200 : break;
348 :
349 17090200 : case 'v':
350 : {
351 17090200 : u8 *v = va_arg (*va, u8 *);
352 : uword len;
353 :
354 17090200 : if (fi.width[1] != 0)
355 0 : len = clib_min (vec_len (v), fi.width[1]);
356 : else
357 17090200 : len = vec_len (v);
358 :
359 17090200 : vec_add (s, v, len);
360 : }
361 17090200 : break;
362 :
363 414759 : case 'f':
364 : case 'g':
365 : case 'e':
366 : /* Floating point. */
367 414759 : ASSERT (fi.how_long == 0 || fi.how_long == 'l');
368 414759 : s = format_float (s, va_arg (*va, double), fi.width[1], c);
369 414759 : break;
370 :
371 50499400 : case 'U':
372 : /* User defined function. */
373 : {
374 : typedef u8 *(user_func_t) (u8 * s, va_list * args);
375 50499400 : user_func_t *u = va_arg (*va, user_func_t *);
376 :
377 50499400 : s = (*u) (s, va);
378 : }
379 50499400 : break;
380 : }
381 :
382 265098000 : s = justify (s, &fi, s_initial_len);
383 : }
384 :
385 0 : done:
386 268211000 : *_s = s;
387 268211000 : return f;
388 : }
389 :
390 : __clib_export u8 *
391 188250000 : va_format (u8 * s, const char *fmt, va_list * va)
392 : {
393 188250000 : const u8 *f = (u8 *) fmt, *g;
394 : u8 c;
395 :
396 188250000 : g = f;
397 : while (1)
398 : {
399 980165000 : c = *f;
400 :
401 980165000 : if (!c)
402 188250000 : break;
403 :
404 791915000 : if (c == '%')
405 : {
406 268211000 : if (f > g)
407 105343000 : vec_add (s, g, f - g);
408 268211000 : f = g = do_percent (&s, f, va);
409 : }
410 : else
411 : {
412 523704000 : f++;
413 : }
414 : }
415 :
416 188250000 : if (f > g)
417 14228700 : vec_add (s, g, f - g);
418 :
419 : #ifdef __COVERITY__
420 : if (s == 0)
421 : return (u8 *) "liar liar pants on fire s can't be zero!";
422 : #endif
423 :
424 188250000 : return s;
425 : }
426 :
427 : __clib_export u8 *
428 179885000 : format (u8 * s, const char *fmt, ...)
429 : {
430 : va_list va;
431 179885000 : va_start (va, fmt);
432 179885000 : s = va_format (s, fmt, &va);
433 179885000 : va_end (va);
434 : #ifdef __COVERITY__
435 : if (s == 0)
436 : return (u8 *) "liar liar pants on fire s can't be zero!";
437 : #endif
438 179885000 : return s;
439 : }
440 :
441 : __clib_export word
442 1178 : va_fformat (FILE * f, char *fmt, va_list * va)
443 : {
444 : word ret;
445 : u8 *s;
446 :
447 1178 : s = va_format (0, fmt, va);
448 :
449 : #ifdef CLIB_UNIX
450 1178 : if (f)
451 : {
452 1178 : ret = fwrite (s, vec_len (s), 1, f);
453 : }
454 : else
455 : #endif /* CLIB_UNIX */
456 : {
457 0 : ret = 0;
458 0 : os_puts (s, vec_len (s), /* is_error */ 0);
459 : }
460 :
461 1178 : vec_free (s);
462 1178 : return ret;
463 : }
464 :
465 : __clib_export word
466 1178 : fformat (FILE * f, char *fmt, ...)
467 : {
468 : va_list va;
469 : word ret;
470 :
471 1178 : va_start (va, fmt);
472 1178 : ret = va_fformat (f, fmt, &va);
473 1178 : va_end (va);
474 :
475 1178 : return (ret);
476 : }
477 :
478 : #ifdef CLIB_UNIX
479 : __clib_export void
480 0 : fformat_append_cr (FILE * ofp, const char *fmt, ...)
481 : {
482 : va_list va;
483 :
484 0 : va_start (va, fmt);
485 0 : (void) va_fformat (ofp, (char *) fmt, &va);
486 0 : va_end (va);
487 0 : fformat (ofp, "\n");
488 0 : }
489 :
490 : __clib_export word
491 0 : fdformat (int fd, char *fmt, ...)
492 : {
493 : word ret;
494 : u8 *s;
495 : va_list va;
496 :
497 0 : va_start (va, fmt);
498 0 : s = va_format (0, fmt, &va);
499 0 : va_end (va);
500 :
501 0 : ret = write (fd, s, vec_len (s));
502 0 : vec_free (s);
503 0 : return ret;
504 : }
505 : #endif
506 :
507 : /* Format integral type. */
508 : static u8 *
509 168182000 : format_integer (u8 * s, u64 number, format_integer_options_t * options)
510 : {
511 : u64 q;
512 : u32 r;
513 : u8 digit_buffer[128];
514 168182000 : u8 *d = digit_buffer + sizeof (digit_buffer);
515 : word c, base;
516 :
517 168182000 : if (options->is_signed && (i64) number < 0)
518 : {
519 150133 : number = -number;
520 150133 : vec_add1 (s, '-');
521 : }
522 :
523 168182000 : if (options->n_bits < BITS (number))
524 167170000 : number &= ((u64) 1 << options->n_bits) - 1;
525 :
526 168182000 : base = options->base;
527 :
528 : while (1)
529 : {
530 307420000 : q = number / base;
531 307420000 : r = number % base;
532 :
533 307420000 : if (r < 10 + 26 + 26)
534 : {
535 307420000 : if (r < 10)
536 259532000 : c = '0' + r;
537 47888200 : else if (r < 10 + 26)
538 47888200 : c = 'a' + (r - 10);
539 : else
540 0 : c = 'A' + (r - 10 - 26);
541 :
542 307420000 : if (options->uppercase_digits
543 1218 : && base <= 10 + 26 && c >= 'a' && c <= 'z')
544 64 : c += 'A' - 'a';
545 :
546 307420000 : *--d = c;
547 : }
548 : else /* will never happen, warning be gone */
549 : {
550 0 : *--d = '?';
551 : }
552 :
553 307420000 : if (q == 0)
554 168182000 : break;
555 :
556 139239000 : number = q;
557 : }
558 :
559 168182000 : vec_add (s, d, digit_buffer + sizeof (digit_buffer) - d);
560 168182000 : return s;
561 : }
562 :
563 : /* Floating point formatting. */
564 : /* Deconstruct IEEE 64 bit number into sign exponent and fraction. */
565 : #define f64_down(f,sign,expon,fraction) \
566 : do { \
567 : union { u64 u; f64 f; } _f64_down_tmp; \
568 : _f64_down_tmp.f = (f); \
569 : (sign) = (_f64_down_tmp.u >> 63); \
570 : (expon) = ((_f64_down_tmp.u >> 52) & 0x7ff) - 1023; \
571 : (fraction) = ((_f64_down_tmp.u << 12) >> 12) | ((u64) 1 << 52); \
572 : } while (0)
573 :
574 : /* Construct IEEE 64 bit number. */
575 : static f64
576 267245 : f64_up (uword sign, word expon, u64 fraction)
577 : {
578 : union
579 : {
580 : u64 u;
581 : f64 f;
582 : } tmp;
583 :
584 267245 : tmp.u = (u64) ((sign) != 0) << 63;
585 :
586 267245 : expon += 1023;
587 267245 : if (expon > 1023)
588 0 : expon = 1023;
589 267245 : if (expon < 0)
590 0 : expon = 0;
591 267245 : tmp.u |= (u64) expon << 52;
592 :
593 267245 : tmp.u |= fraction & (((u64) 1 << 52) - 1);
594 :
595 267245 : return tmp.f;
596 : }
597 :
598 : /* Returns approximate precision of number given its exponent. */
599 : static f64
600 267245 : f64_precision (int base2_expon)
601 : {
602 : static int n_bits = 0;
603 :
604 267245 : if (!n_bits)
605 : {
606 : /* Compute number of significant bits in floating point representation. */
607 551 : f64 one = 0;
608 551 : f64 small = 1;
609 :
610 29754 : while (one != 1)
611 : {
612 29203 : small *= .5;
613 29203 : n_bits++;
614 29203 : one = 1 + small;
615 : }
616 : }
617 :
618 267245 : return f64_up (0, base2_expon - n_bits, 0);
619 : }
620 :
621 : /* Return x 10^n */
622 : static f64
623 534490 : times_power_of_ten (f64 x, int n)
624 : {
625 534490 : if (n >= 0)
626 : {
627 : static f64 t[8] = { 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, };
628 106588 : while (n >= 8)
629 : {
630 0 : x *= 1e+8;
631 0 : n -= 8;
632 : }
633 106588 : return x * t[n];
634 : }
635 : else
636 : {
637 : static f64 t[8] = { 1e-0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, };
638 428360 : while (n <= -8)
639 : {
640 458 : x *= 1e-8;
641 458 : n += 8;
642 : }
643 427902 : return x * t[-n];
644 : }
645 :
646 : }
647 :
648 : /* Write x = y * 10^expon with 1 < y < 10. */
649 : static f64
650 267245 : normalize (f64 x, word * expon_return, f64 * prec_return)
651 : {
652 : word expon2, expon10;
653 : CLIB_UNUSED (u64 fraction);
654 : CLIB_UNUSED (word sign);
655 : f64 prec;
656 :
657 267245 : f64_down (x, sign, expon2, fraction);
658 :
659 267245 : expon10 =
660 267245 : .5 +
661 267245 : expon2 * .301029995663981195213738894724493 /* Log (2) / Log (10) */ ;
662 :
663 267245 : prec = f64_precision (expon2);
664 267245 : x = times_power_of_ten (x, -expon10);
665 267245 : prec = times_power_of_ten (prec, -expon10);
666 :
667 363421 : while (x < 1)
668 : {
669 96176 : x *= 10;
670 96176 : prec *= 10;
671 96176 : expon10--;
672 : }
673 :
674 267245 : while (x > 10)
675 : {
676 0 : x *= .1;
677 0 : prec *= .1;
678 0 : expon10++;
679 : }
680 :
681 267245 : if (x + prec >= 10)
682 : {
683 0 : x = 1;
684 0 : expon10++;
685 : }
686 :
687 267245 : *expon_return = expon10;
688 267245 : *prec_return = prec;
689 :
690 267245 : return x;
691 : }
692 :
693 : static u8 *
694 187742 : add_some_zeros (u8 * s, uword n_zeros)
695 : {
696 557770 : while (n_zeros > 0)
697 : {
698 370028 : vec_add1 (s, '0');
699 370028 : n_zeros--;
700 : }
701 187742 : return s;
702 : }
703 :
704 : /* Format a floating point number with the given number of fractional
705 : digits (e.g. 1.2345 with 2 fraction digits yields "1.23") and output style. */
706 : static u8 *
707 414759 : format_float (u8 * s, f64 x, uword n_fraction_digits, uword output_style)
708 : {
709 : f64 prec;
710 : word sign, expon, n_fraction_done, added_decimal_point;
711 : /* Position of decimal point relative to where we are. */
712 : word decimal_point;
713 :
714 : /* Default number of digits to print when its not specified. */
715 414759 : if (n_fraction_digits == ~0)
716 0 : n_fraction_digits = 7;
717 414759 : n_fraction_done = 0;
718 414759 : decimal_point = 0;
719 414759 : added_decimal_point = 0;
720 414759 : sign = expon = 0;
721 :
722 : /* Special case: zero. */
723 414759 : if (x == 0)
724 : {
725 147514 : do_zero:
726 147668 : vec_add1 (s, '0');
727 147668 : goto done;
728 : }
729 :
730 267245 : if (x < 0)
731 : {
732 1 : x = -x;
733 1 : sign = 1;
734 : }
735 :
736 : /* Check for not-a-number. */
737 267245 : if (isnan (x))
738 0 : return format (s, "%cNaN", sign ? '-' : '+');
739 :
740 : /* Check for infinity. */
741 267245 : if (isinf (x))
742 0 : return format (s, "%cinfinity", sign ? '-' : '+');
743 :
744 267245 : x = normalize (x, &expon, &prec);
745 :
746 : /* Not enough digits to print anything: so just print 0 */
747 267245 : if ((word) - expon > (word) n_fraction_digits
748 154 : && (output_style == 'f' || (output_style == 'g')))
749 154 : goto do_zero;
750 :
751 267091 : if (sign)
752 1 : vec_add1 (s, '-');
753 :
754 267091 : if (output_style == 'f'
755 130339 : || (output_style == 'g' && expon > -10 && expon < 10))
756 : {
757 136752 : if (expon < 0)
758 : {
759 : /* Add decimal point and leading zeros. */
760 508 : vec_add1 (s, '.');
761 508 : n_fraction_done = clib_min (-(expon + 1), n_fraction_digits);
762 508 : s = add_some_zeros (s, n_fraction_done);
763 508 : decimal_point = -n_fraction_done;
764 508 : added_decimal_point = 1;
765 : }
766 : else
767 136244 : decimal_point = expon + 1;
768 : }
769 : else
770 : {
771 : /* Exponential output style. */
772 130339 : decimal_point = 1;
773 130339 : output_style = 'e';
774 : }
775 :
776 : while (1)
777 674703 : {
778 : uword digit;
779 :
780 : /* Number is smaller than precision: call it zero. */
781 941794 : if (x < prec)
782 38419 : break;
783 :
784 903375 : digit = x;
785 903375 : x -= digit;
786 903375 : if (x + prec >= 1)
787 : {
788 3681 : digit++;
789 3681 : x -= 1;
790 : }
791 :
792 : /* Round last printed digit. */
793 903375 : if (decimal_point <= 0
794 512577 : && n_fraction_done + 1 == n_fraction_digits && digit < 9)
795 200822 : digit += x >= .5;
796 :
797 903375 : vec_add1 (s, '0' + digit);
798 :
799 : /* Move rightwards towards/away from decimal point. */
800 903375 : decimal_point--;
801 :
802 903375 : n_fraction_done += decimal_point < 0;
803 903375 : if (decimal_point <= 0 && n_fraction_done >= n_fraction_digits)
804 228672 : break;
805 :
806 674703 : if (decimal_point == 0 && x != 0)
807 : {
808 235215 : vec_add1 (s, '.');
809 235215 : added_decimal_point = 1;
810 : }
811 :
812 674703 : x *= 10;
813 674703 : prec *= 10;
814 : }
815 :
816 414759 : done:
817 414759 : if (decimal_point > 0)
818 : {
819 3273 : s = add_some_zeros (s, decimal_point);
820 3273 : decimal_point = 0;
821 : }
822 :
823 414759 : if (n_fraction_done < n_fraction_digits)
824 : {
825 183961 : if (!added_decimal_point)
826 172068 : vec_add1 (s, '.');
827 183961 : s = add_some_zeros (s, n_fraction_digits - n_fraction_done);
828 : }
829 :
830 414759 : if (output_style == 'e')
831 149181 : s = format (s, "e%wd", expon);
832 :
833 414759 : return s;
834 : }
835 :
836 :
837 : /*
838 : * fd.io coding-style-patch-verification: ON
839 : *
840 : * Local Variables:
841 : * eval: (c-set-style "gnu")
842 : * End:
843 : */
|