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 245473000 : justify (u8 * s, format_info_t * fi, uword s_len_orig)
105 : {
106 : uword i0, l0, l1;
107 :
108 245473000 : i0 = s_len_orig;
109 245473000 : l0 = i0 + fi->width[0];
110 245473000 : l1 = vec_len (s);
111 :
112 : /* If width is zero user returned width. */
113 245473000 : if (l0 == i0)
114 129278000 : l0 = l1;
115 :
116 245473000 : if (l1 > l0)
117 27632 : vec_set_len (s, l0);
118 245445000 : else if (l0 > l1)
119 : {
120 56123900 : uword n = l0 - l1;
121 56123900 : uword n_left = 0, n_right = 0;
122 :
123 56123900 : switch (fi->justify)
124 : {
125 727120 : case '-':
126 727120 : n_right = n;
127 727120 : break;
128 :
129 54821800 : case '+':
130 54821800 : n_left = n;
131 54821800 : break;
132 :
133 575003 : case '=':
134 575003 : n_right = n_left = n / 2;
135 575003 : if (n % 2)
136 248842 : n_left++;
137 575003 : break;
138 : }
139 56123900 : if (n_left > 0)
140 : {
141 55396800 : vec_insert (s, n_left, i0);
142 55396800 : clib_memset (s + i0, fi->pad_char, n_left);
143 55396800 : l1 = vec_len (s);
144 : }
145 56123900 : if (n_right > 0)
146 : {
147 1299010 : vec_resize (s, n_right);
148 1299010 : clib_memset (s + l1, fi->pad_char, n_right);
149 : }
150 : }
151 245473000 : return s;
152 : }
153 :
154 : static const u8 *
155 248483000 : do_percent (u8 ** _s, const u8 * fmt, va_list * va)
156 : {
157 248483000 : u8 *s = *_s;
158 : uword c;
159 :
160 248483000 : const u8 *f = fmt;
161 :
162 248483000 : format_info_t fi = {
163 : .justify = '+',
164 : .width = {0},
165 : .pad_char = ' ',
166 : .how_long = 0,
167 : };
168 :
169 : uword i;
170 :
171 248483000 : ASSERT (f[0] == '%');
172 :
173 248483000 : switch (c = *++f)
174 : {
175 3010210 : case '%':
176 : /* %% => % */
177 3010210 : vec_add1 (s, c);
178 3010210 : f++;
179 3010210 : goto done;
180 :
181 1355070 : case '-':
182 : case '+':
183 : case '=':
184 1355070 : fi.justify = c;
185 1355070 : c = *++f;
186 1355070 : break;
187 : }
188 :
189 : /* Parse width0 . width1. */
190 245473000 : {
191 245473000 : uword is_first_digit = 1;
192 :
193 245473000 : fi.width[0] = fi.width[1] = 0;
194 245875000 : for (i = 0; i < 2; i++)
195 : {
196 245875000 : if (c == '0' && i == 0 && is_first_digit)
197 113827000 : fi.pad_char = '0';
198 245875000 : is_first_digit = 0;
199 245875000 : if (c == '*')
200 : {
201 0 : fi.width[i] = va_arg (*va, int);
202 0 : c = *++f;
203 : }
204 : else
205 : {
206 478331000 : while (c >= '0' && c <= '9')
207 : {
208 232456000 : fi.width[i] = 10 * fi.width[i] + (c - '0');
209 232456000 : c = *++f;
210 : }
211 : }
212 245875000 : if (c != '.')
213 245473000 : break;
214 402733 : c = *++f;
215 : }
216 : }
217 :
218 : /* Parse %l* and %L* */
219 245473000 : switch (c)
220 : {
221 147886 : case 'w':
222 : /* word format. */
223 147886 : fi.how_long = 'w';
224 147886 : c = *++f;
225 147886 : break;
226 :
227 840301 : case 'L':
228 : case 'l':
229 840301 : fi.how_long = c;
230 840301 : c = *++f;
231 840301 : if (c == 'l' && *f == 'l')
232 : {
233 297458 : fi.how_long = 'L';
234 297458 : c = *++f;
235 : }
236 840301 : break;
237 : }
238 :
239 : /* Finally we are ready for format letter. */
240 245473000 : if (c != 0)
241 : {
242 245473000 : uword s_initial_len = vec_len (s);
243 245473000 : format_integer_options_t o = {
244 : .is_signed = 0,
245 : .base = 10,
246 : .n_bits = BITS (uword),
247 : .uppercase_digits = 0,
248 : };
249 :
250 245473000 : f++;
251 :
252 245473000 : 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 0 : goto done;
260 : }
261 :
262 4264600 : case 'c':
263 4264600 : vec_add1 (s, va_arg (*va, int));
264 4264600 : break;
265 :
266 1417 : case 'p':
267 1417 : vec_add1 (s, '0');
268 1417 : vec_add1 (s, 'x');
269 :
270 1417 : o.is_signed = 0;
271 1417 : o.n_bits = BITS (uword *);
272 1417 : o.base = 16;
273 1417 : o.uppercase_digits = 0;
274 :
275 2834 : s = format_integer (s, pointer_to_uword (va_arg (*va, void *)), &o);
276 1417 : break;
277 :
278 154847000 : case 'x':
279 : case 'X':
280 : case 'u':
281 : case 'o':
282 : case 'd':
283 : {
284 : u64 number;
285 :
286 154847000 : o.base = 10;
287 154847000 : if (c == 'x' || c == 'X')
288 104702000 : o.base = 16;
289 154847000 : o.is_signed = c == 'd';
290 154847000 : o.uppercase_digits = c == 'X';
291 :
292 154847000 : switch (fi.how_long)
293 : {
294 779527 : case 'L':
295 779527 : number = va_arg (*va, unsigned long long);
296 779527 : o.n_bits = BITS (unsigned long long);
297 779527 : break;
298 :
299 60774 : case 'l':
300 60774 : number = va_arg (*va, long);
301 60774 : o.n_bits = BITS (long);
302 60774 : break;
303 :
304 147886 : case 'w':
305 147886 : number = va_arg (*va, word);
306 147886 : o.n_bits = BITS (uword);
307 147886 : break;
308 :
309 153859000 : default:
310 153859000 : number = va_arg (*va, int);
311 153859000 : o.n_bits = BITS (int);
312 153859000 : break;
313 : }
314 :
315 154847000 : if (c == 'o')
316 0 : o.base = 8;
317 :
318 154847000 : s = format_integer (s, number, &o);
319 : }
320 154847000 : break;
321 :
322 22997900 : case 's':
323 : case 'S':
324 : {
325 22997900 : char *cstring = va_arg (*va, char *);
326 : uword len;
327 :
328 22997900 : if (!cstring)
329 : {
330 15251 : cstring = "(nil)";
331 15251 : len = 5;
332 : }
333 22982700 : else if (fi.width[1] != 0)
334 0 : len = clib_min (strlen (cstring), fi.width[1]);
335 : else
336 22982700 : len = strlen (cstring);
337 :
338 : /* %S => format string as C identifier (replace _ with space). */
339 22997900 : 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 22997900 : vec_add (s, cstring, len);
346 : }
347 22997900 : break;
348 :
349 16103600 : case 'v':
350 : {
351 16103600 : u8 *v = va_arg (*va, u8 *);
352 : uword len;
353 :
354 16103600 : if (fi.width[1] != 0)
355 0 : len = clib_min (vec_len (v), fi.width[1]);
356 : else
357 16103600 : len = vec_len (v);
358 :
359 16103600 : vec_add (s, v, len);
360 : }
361 16103600 : break;
362 :
363 409299 : case 'f':
364 : case 'g':
365 : case 'e':
366 : /* Floating point. */
367 409299 : ASSERT (fi.how_long == 0 || fi.how_long == 'l');
368 409299 : s = format_float (s, va_arg (*va, double), fi.width[1], c);
369 409299 : break;
370 :
371 46848900 : case 'U':
372 : /* User defined function. */
373 : {
374 : typedef u8 *(user_func_t) (u8 * s, va_list * args);
375 46848900 : user_func_t *u = va_arg (*va, user_func_t *);
376 :
377 46848900 : s = (*u) (s, va);
378 : }
379 46848900 : break;
380 : }
381 :
382 245473000 : s = justify (s, &fi, s_initial_len);
383 : }
384 :
385 0 : done:
386 248483000 : *_s = s;
387 248483000 : return f;
388 : }
389 :
390 : __clib_export u8 *
391 173831000 : va_format (u8 * s, const char *fmt, va_list * va)
392 : {
393 173831000 : const u8 *f = (u8 *) fmt, *g;
394 : u8 c;
395 :
396 173831000 : g = f;
397 : while (1)
398 : {
399 899462000 : c = *f;
400 :
401 899462000 : if (!c)
402 173831000 : break;
403 :
404 725631000 : if (c == '%')
405 : {
406 248483000 : if (f > g)
407 97428300 : vec_add (s, g, f - g);
408 248483000 : f = g = do_percent (&s, f, va);
409 : }
410 : else
411 : {
412 477148000 : f++;
413 : }
414 : }
415 :
416 173831000 : if (f > g)
417 12147600 : 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 173831000 : return s;
425 : }
426 :
427 : __clib_export u8 *
428 166085000 : format (u8 * s, const char *fmt, ...)
429 : {
430 : va_list va;
431 166085000 : va_start (va, fmt);
432 166085000 : s = va_format (s, fmt, &va);
433 166085000 : 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 166085000 : return s;
439 : }
440 :
441 : __clib_export word
442 966 : va_fformat (FILE * f, char *fmt, va_list * va)
443 : {
444 : word ret;
445 : u8 *s;
446 :
447 966 : s = va_format (0, fmt, va);
448 :
449 : #ifdef CLIB_UNIX
450 966 : if (f)
451 : {
452 966 : 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 966 : vec_free (s);
462 966 : return ret;
463 : }
464 :
465 : __clib_export word
466 966 : fformat (FILE * f, char *fmt, ...)
467 : {
468 : va_list va;
469 : word ret;
470 :
471 966 : va_start (va, fmt);
472 966 : ret = va_fformat (f, fmt, &va);
473 966 : va_end (va);
474 :
475 966 : 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 154848000 : format_integer (u8 * s, u64 number, format_integer_options_t * options)
510 : {
511 : u64 q;
512 : u32 r;
513 : u8 digit_buffer[128];
514 154848000 : u8 *d = digit_buffer + sizeof (digit_buffer);
515 : word c, base;
516 :
517 154848000 : if (options->is_signed && (i64) number < 0)
518 : {
519 138332 : number = -number;
520 138332 : vec_add1 (s, '-');
521 : }
522 :
523 154848000 : if (options->n_bits < BITS (number))
524 153859000 : number &= ((u64) 1 << options->n_bits) - 1;
525 :
526 154848000 : base = options->base;
527 :
528 : while (1)
529 : {
530 279917000 : q = number / base;
531 279917000 : r = number % base;
532 :
533 279917000 : if (r < 10 + 26 + 26)
534 : {
535 279917000 : if (r < 10)
536 234843000 : c = '0' + r;
537 45074400 : else if (r < 10 + 26)
538 45074400 : c = 'a' + (r - 10);
539 : else
540 0 : c = 'A' + (r - 10 - 26);
541 :
542 279917000 : if (options->uppercase_digits
543 1218 : && base <= 10 + 26 && c >= 'a' && c <= 'z')
544 64 : c += 'A' - 'a';
545 :
546 279917000 : *--d = c;
547 : }
548 : else /* will never happen, warning be gone */
549 : {
550 0 : *--d = '?';
551 : }
552 :
553 279917000 : if (q == 0)
554 154848000 : break;
555 :
556 125069000 : number = q;
557 : }
558 :
559 154848000 : vec_add (s, d, digit_buffer + sizeof (digit_buffer) - d);
560 154848000 : 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 264147 : f64_up (uword sign, word expon, u64 fraction)
577 : {
578 : union
579 : {
580 : u64 u;
581 : f64 f;
582 : } tmp;
583 :
584 264147 : tmp.u = (u64) ((sign) != 0) << 63;
585 :
586 264147 : expon += 1023;
587 264147 : if (expon > 1023)
588 0 : expon = 1023;
589 264147 : if (expon < 0)
590 0 : expon = 0;
591 264147 : tmp.u |= (u64) expon << 52;
592 :
593 264147 : tmp.u |= fraction & (((u64) 1 << 52) - 1);
594 :
595 264147 : return tmp.f;
596 : }
597 :
598 : /* Returns approximate precision of number given its exponent. */
599 : static f64
600 264147 : f64_precision (int base2_expon)
601 : {
602 : static int n_bits = 0;
603 :
604 264147 : if (!n_bits)
605 : {
606 : /* Compute number of significant bits in floating point representation. */
607 535 : f64 one = 0;
608 535 : f64 small = 1;
609 :
610 28890 : while (one != 1)
611 : {
612 28355 : small *= .5;
613 28355 : n_bits++;
614 28355 : one = 1 + small;
615 : }
616 : }
617 :
618 264147 : return f64_up (0, base2_expon - n_bits, 0);
619 : }
620 :
621 : /* Return x 10^n */
622 : static f64
623 528294 : times_power_of_ten (f64 x, int n)
624 : {
625 528294 : 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 106488 : while (n >= 8)
629 : {
630 0 : x *= 1e+8;
631 0 : n -= 8;
632 : }
633 106488 : 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 422394 : while (n <= -8)
639 : {
640 588 : x *= 1e-8;
641 588 : n += 8;
642 : }
643 421806 : return x * t[-n];
644 : }
645 :
646 : }
647 :
648 : /* Write x = y * 10^expon with 1 < y < 10. */
649 : static f64
650 264147 : 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 264147 : f64_down (x, sign, expon2, fraction);
658 :
659 264147 : expon10 =
660 264147 : .5 +
661 264147 : expon2 * .301029995663981195213738894724493 /* Log (2) / Log (10) */ ;
662 :
663 264147 : prec = f64_precision (expon2);
664 264147 : x = times_power_of_ten (x, -expon10);
665 264147 : prec = times_power_of_ten (prec, -expon10);
666 :
667 357763 : while (x < 1)
668 : {
669 93616 : x *= 10;
670 93616 : prec *= 10;
671 93616 : expon10--;
672 : }
673 :
674 264147 : while (x > 10)
675 : {
676 0 : x *= .1;
677 0 : prec *= .1;
678 0 : expon10++;
679 : }
680 :
681 264147 : if (x + prec >= 10)
682 : {
683 0 : x = 1;
684 0 : expon10++;
685 : }
686 :
687 264147 : *expon_return = expon10;
688 264147 : *prec_return = prec;
689 :
690 264147 : return x;
691 : }
692 :
693 : static u8 *
694 185810 : add_some_zeros (u8 * s, uword n_zeros)
695 : {
696 551870 : while (n_zeros > 0)
697 : {
698 366060 : vec_add1 (s, '0');
699 366060 : n_zeros--;
700 : }
701 185810 : 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 409299 : 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 409299 : if (n_fraction_digits == ~0)
716 0 : n_fraction_digits = 7;
717 409299 : n_fraction_done = 0;
718 409299 : decimal_point = 0;
719 409299 : added_decimal_point = 0;
720 409299 : sign = expon = 0;
721 :
722 : /* Special case: zero. */
723 409299 : if (x == 0)
724 : {
725 145152 : do_zero:
726 145306 : vec_add1 (s, '0');
727 145306 : goto done;
728 : }
729 :
730 264147 : if (x < 0)
731 : {
732 1 : x = -x;
733 1 : sign = 1;
734 : }
735 :
736 : /* Check for not-a-number. */
737 264147 : if (isnan (x))
738 0 : return format (s, "%cNaN", sign ? '-' : '+');
739 :
740 : /* Check for infinity. */
741 264147 : if (isinf (x))
742 0 : return format (s, "%cinfinity", sign ? '-' : '+');
743 :
744 264147 : x = normalize (x, &expon, &prec);
745 :
746 : /* Not enough digits to print anything: so just print 0 */
747 264147 : if ((word) - expon > (word) n_fraction_digits
748 154 : && (output_style == 'f' || (output_style == 'g')))
749 154 : goto do_zero;
750 :
751 263993 : if (sign)
752 1 : vec_add1 (s, '-');
753 :
754 263993 : if (output_style == 'f'
755 128362 : || (output_style == 'g' && expon > -10 && expon < 10))
756 : {
757 135631 : if (expon < 0)
758 : {
759 : /* Add decimal point and leading zeros. */
760 520 : vec_add1 (s, '.');
761 520 : n_fraction_done = clib_min (-(expon + 1), n_fraction_digits);
762 520 : s = add_some_zeros (s, n_fraction_done);
763 520 : decimal_point = -n_fraction_done;
764 520 : added_decimal_point = 1;
765 : }
766 : else
767 135111 : decimal_point = expon + 1;
768 : }
769 : else
770 : {
771 : /* Exponential output style. */
772 128362 : decimal_point = 1;
773 128362 : output_style = 'e';
774 : }
775 :
776 : while (1)
777 666207 : {
778 : uword digit;
779 :
780 : /* Number is smaller than precision: call it zero. */
781 930200 : if (x < prec)
782 38837 : break;
783 :
784 891363 : digit = x;
785 891363 : x -= digit;
786 891363 : if (x + prec >= 1)
787 : {
788 4214 : digit++;
789 4214 : x -= 1;
790 : }
791 :
792 : /* Round last printed digit. */
793 891363 : if (decimal_point <= 0
794 504562 : && n_fraction_done + 1 == n_fraction_digits && digit < 9)
795 199502 : digit += x >= .5;
796 :
797 891363 : vec_add1 (s, '0' + digit);
798 :
799 : /* Move rightwards towards/away from decimal point. */
800 891363 : decimal_point--;
801 :
802 891363 : n_fraction_done += decimal_point < 0;
803 891363 : if (decimal_point <= 0 && n_fraction_done >= n_fraction_digits)
804 225156 : break;
805 :
806 666207 : if (decimal_point == 0 && x != 0)
807 : {
808 232069 : vec_add1 (s, '.');
809 232069 : added_decimal_point = 1;
810 : }
811 :
812 666207 : x *= 10;
813 666207 : prec *= 10;
814 : }
815 :
816 409299 : done:
817 409299 : if (decimal_point > 0)
818 : {
819 3249 : s = add_some_zeros (s, decimal_point);
820 3249 : decimal_point = 0;
821 : }
822 :
823 409299 : if (n_fraction_done < n_fraction_digits)
824 : {
825 182041 : if (!added_decimal_point)
826 170142 : vec_add1 (s, '.');
827 182041 : s = add_some_zeros (s, n_fraction_digits - n_fraction_done);
828 : }
829 :
830 409299 : if (output_style == 'e')
831 146562 : s = format (s, "e%wd", expon);
832 :
833 409299 : 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 : */
|