blob: b67553c6f2db17436d2f7c077c522af59cf3db81 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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
Dave Barachc3799992016-08-15 11:12:27 -040048#include <stdarg.h> /* va_start, etc */
Ed Warnickecb9cada2015-12-08 15:45:58 -070049
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>
Dave Barachc3799992016-08-15 11:12:27 -040064#include <vppinfra/os.h> /* os_puts */
Chris Lukebb18ee62017-07-09 14:30:25 -040065#include <vppinfra/math.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070066
Dave Barachc3799992016-08-15 11:12:27 -040067typedef struct
68{
69 /* Output number in this base. */
70 u8 base;
Ed Warnickecb9cada2015-12-08 15:45:58 -070071
Dave Barachc3799992016-08-15 11:12:27 -040072 /* Number of show of 64 bit number. */
73 u8 n_bits;
Ed Warnickecb9cada2015-12-08 15:45:58 -070074
Dave Barachc3799992016-08-15 11:12:27 -040075 /* Signed or unsigned. */
76 u8 is_signed;
Ed Warnickecb9cada2015-12-08 15:45:58 -070077
Dave Barachc3799992016-08-15 11:12:27 -040078 /* Output digits uppercase (not lowercase) %X versus %x. */
79 u8 uppercase_digits;
Ed Warnickecb9cada2015-12-08 15:45:58 -070080} format_integer_options_t;
81
Dave Barachc3799992016-08-15 11:12:27 -040082static u8 *format_integer (u8 * s, u64 number,
83 format_integer_options_t * options);
84static u8 *format_float (u8 * s, f64 x, uword n_digits_to_print,
85 uword output_style);
Ed Warnickecb9cada2015-12-08 15:45:58 -070086
Dave Barachc3799992016-08-15 11:12:27 -040087typedef struct
88{
Ed Warnickecb9cada2015-12-08 15:45:58 -070089 /* 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
Dave Barachc3799992016-08-15 11:12:27 -0400103static u8 *
104justify (u8 * s, format_info_t * fi, uword s_len_orig)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105{
106 uword i0, l0, l1;
107
108 i0 = s_len_orig;
109 l0 = i0 + fi->width[0];
110 l1 = vec_len (s);
111
112 /* If width is zero user returned width. */
113 if (l0 == i0)
114 l0 = l1;
115
116 if (l1 > l0)
117 _vec_len (s) = l0;
118 else if (l0 > l1)
119 {
120 uword n = l0 - l1;
121 uword n_left = 0, n_right = 0;
122
123 switch (fi->justify)
124 {
125 case '-':
126 n_right = n;
127 break;
128
129 case '+':
Dave Barachc3799992016-08-15 11:12:27 -0400130 n_left = n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131 break;
132
133 case '=':
Dave Barachc3799992016-08-15 11:12:27 -0400134 n_right = n_left = n / 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700135 if (n % 2)
136 n_left++;
137 break;
138 }
139 if (n_left > 0)
140 {
141 vec_insert (s, n_left, i0);
Dave Barachb7b92992018-10-17 10:38:51 -0400142 clib_memset (s + i0, fi->pad_char, n_left);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700143 l1 = vec_len (s);
144 }
145 if (n_right > 0)
146 {
147 vec_resize (s, n_right);
Dave Barachb7b92992018-10-17 10:38:51 -0400148 clib_memset (s + l1, fi->pad_char, n_right);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700149 }
150 }
151 return s;
152}
153
Neale Ranns32e1c012016-11-22 17:07:28 +0000154static const u8 *
155do_percent (u8 ** _s, const u8 * fmt, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700156{
Dave Barachc3799992016-08-15 11:12:27 -0400157 u8 *s = *_s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700158 uword c;
159
Neale Ranns32e1c012016-11-22 17:07:28 +0000160 const u8 *f = fmt;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700161
162 format_info_t fi = {
163 .justify = '+',
164 .width = {0},
165 .pad_char = ' ',
166 .how_long = 0,
167 };
168
169 uword i;
170
171 ASSERT (f[0] == '%');
172
173 switch (c = *++f)
174 {
175 case '%':
176 /* %% => % */
177 vec_add1 (s, c);
178 f++;
179 goto done;
180
181 case '-':
182 case '+':
183 case '=':
184 fi.justify = c;
185 c = *++f;
186 break;
187 }
188
189 /* Parse width0 . width1. */
190 {
191 uword is_first_digit = 1;
192
193 fi.width[0] = fi.width[1] = 0;
194 for (i = 0; i < 2; i++)
195 {
196 if (c == '0' && i == 0 && is_first_digit)
197 fi.pad_char = '0';
198 is_first_digit = 0;
Dave Barachc3799992016-08-15 11:12:27 -0400199 if (c == '*')
200 {
201 fi.width[i] = va_arg (*va, int);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202 c = *++f;
Dave Barachc3799992016-08-15 11:12:27 -0400203 }
204 else
205 {
206 while (c >= '0' && c <= '9')
207 {
208 fi.width[i] = 10 * fi.width[i] + (c - '0');
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209 c = *++f;
Dave Barachc3799992016-08-15 11:12:27 -0400210 }
211 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212 if (c != '.')
213 break;
214 c = *++f;
215 }
216 }
217
218 /* Parse %l* and %L* */
219 switch (c)
220 {
221 case 'w':
222 /* word format. */
223 fi.how_long = 'w';
224 c = *++f;
225 break;
226
227 case 'L':
228 case 'l':
229 fi.how_long = c;
230 c = *++f;
231 if (c == 'l' && *f == 'l')
232 {
233 fi.how_long = 'L';
234 c = *++f;
235 }
236 break;
237 }
238
239 /* Finally we are ready for format letter. */
240 if (c != 0)
241 {
242 uword s_initial_len = vec_len (s);
243 format_integer_options_t o = {
244 .is_signed = 0,
245 .base = 10,
246 .n_bits = BITS (uword),
247 .uppercase_digits = 0,
248 };
249
250 f++;
251
252 switch (c)
253 {
Dave Barachc3799992016-08-15 11:12:27 -0400254 default:
255 {
256 /* Try to give a helpful error message. */
257 vec_free (s);
258 s = format (s, "**** CLIB unknown format `%%%c' ****", c);
259 goto done;
260 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261
262 case 'c':
263 vec_add1 (s, va_arg (*va, int));
264 break;
265
266 case 'p':
267 vec_add1 (s, '0');
268 vec_add1 (s, 'x');
269
270 o.is_signed = 0;
271 o.n_bits = BITS (uword *);
272 o.base = 16;
273 o.uppercase_digits = 0;
274
275 s = format_integer (s, pointer_to_uword (va_arg (*va, void *)), &o);
276 break;
277
278 case 'x':
279 case 'X':
280 case 'u':
281 case 'd':
282 {
283 u64 number;
284
285 o.base = 10;
286 if (c == 'x' || c == 'X')
287 o.base = 16;
288 o.is_signed = c == 'd';
289 o.uppercase_digits = c == 'X';
290
291 switch (fi.how_long)
292 {
293 case 'L':
294 number = va_arg (*va, unsigned long long);
295 o.n_bits = BITS (unsigned long long);
296 break;
297
298 case 'l':
299 number = va_arg (*va, long);
300 o.n_bits = BITS (long);
301 break;
302
303 case 'w':
304 number = va_arg (*va, word);
305 o.n_bits = BITS (uword);
306 break;
307
308 default:
309 number = va_arg (*va, int);
310 o.n_bits = BITS (int);
311 break;
312 }
313
314 s = format_integer (s, number, &o);
315 }
316 break;
317
318 case 's':
319 case 'S':
320 {
Dave Barachc3799992016-08-15 11:12:27 -0400321 char *cstring = va_arg (*va, char *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700322 uword len;
323
Dave Barachc3799992016-08-15 11:12:27 -0400324 if (!cstring)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700325 {
326 cstring = "(nil)";
327 len = 5;
328 }
329 else if (fi.width[1] != 0)
330 len = clib_min (strlen (cstring), fi.width[1]);
331 else
332 len = strlen (cstring);
Dave Barachc3799992016-08-15 11:12:27 -0400333
Ed Warnickecb9cada2015-12-08 15:45:58 -0700334 /* %S => format string as C identifier (replace _ with space). */
335 if (c == 'S')
336 {
337 for (i = 0; i < len; i++)
338 vec_add1 (s, cstring[i] == '_' ? ' ' : cstring[i]);
Dave Barachc3799992016-08-15 11:12:27 -0400339 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700340 else
341 vec_add (s, cstring, len);
342 }
343 break;
344
345 case 'v':
346 {
Dave Barachc3799992016-08-15 11:12:27 -0400347 u8 *v = va_arg (*va, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700348 uword len;
349
350 if (fi.width[1] != 0)
351 len = clib_min (vec_len (v), fi.width[1]);
352 else
353 len = vec_len (v);
354
355 vec_add (s, v, len);
356 }
357 break;
358
Dave Barachc3799992016-08-15 11:12:27 -0400359 case 'f':
360 case 'g':
361 case 'e':
Ed Warnickecb9cada2015-12-08 15:45:58 -0700362 /* Floating point. */
363 ASSERT (fi.how_long == 0 || fi.how_long == 'l');
Dave Barachc3799992016-08-15 11:12:27 -0400364 s = format_float (s, va_arg (*va, double), fi.width[1], c);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700365 break;
366
367 case 'U':
368 /* User defined function. */
369 {
Dave Barachc3799992016-08-15 11:12:27 -0400370 typedef u8 *(user_func_t) (u8 * s, va_list * args);
371 user_func_t *u = va_arg (*va, user_func_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700372
Dave Barachc3799992016-08-15 11:12:27 -0400373 s = (*u) (s, va);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700374 }
375 break;
376 }
377
378 s = justify (s, &fi, s_initial_len);
379 }
380
Dave Barachc3799992016-08-15 11:12:27 -0400381done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700382 *_s = s;
383 return f;
384}
385
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200386__clib_export u8 *
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100387va_format (u8 * s, const char *fmt, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700388{
Neale Ranns32e1c012016-11-22 17:07:28 +0000389 const u8 *f = (u8 *) fmt, *g;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700390 u8 c;
391
392 g = f;
393 while (1)
394 {
395 c = *f;
396
Dave Barachc3799992016-08-15 11:12:27 -0400397 if (!c)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700398 break;
399
400 if (c == '%')
401 {
402 if (f > g)
403 vec_add (s, g, f - g);
404 f = g = do_percent (&s, f, va);
405 }
406 else
407 {
408 f++;
409 }
410 }
411
412 if (f > g)
413 vec_add (s, g, f - g);
414
Dave Barachac3b1132019-03-30 10:24:28 -0400415#ifdef __COVERITY__
416 if (s == 0)
417 return (u8 *) "liar liar pants on fire s can't be zero!";
418#endif
419
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420 return s;
421}
422
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200423__clib_export u8 *
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100424format (u8 * s, const char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700425{
426 va_list va;
427 va_start (va, fmt);
428 s = va_format (s, fmt, &va);
429 va_end (va);
Dave Barach19e540f2019-03-29 19:41:50 -0400430#ifdef __COVERITY__
431 if (s == 0)
432 return (u8 *) "liar liar pants on fire s can't be zero!";
433#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700434 return s;
435}
436
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200437__clib_export word
Dave Barachc3799992016-08-15 11:12:27 -0400438va_fformat (FILE * f, char *fmt, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700439{
440 word ret;
Dave Barachc3799992016-08-15 11:12:27 -0400441 u8 *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700442
443 s = va_format (0, fmt, va);
444
445#ifdef CLIB_UNIX
446 if (f)
447 {
448 ret = fwrite (s, vec_len (s), 1, f);
449 }
450 else
451#endif /* CLIB_UNIX */
452 {
453 ret = 0;
454 os_puts (s, vec_len (s), /* is_error */ 0);
455 }
456
457 vec_free (s);
458 return ret;
459}
460
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200461__clib_export word
Dave Barachc3799992016-08-15 11:12:27 -0400462fformat (FILE * f, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700463{
Dave Barachc3799992016-08-15 11:12:27 -0400464 va_list va;
465 word ret;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700466
Dave Barachc3799992016-08-15 11:12:27 -0400467 va_start (va, fmt);
468 ret = va_fformat (f, fmt, &va);
469 va_end (va);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700470
Dave Barachc3799992016-08-15 11:12:27 -0400471 return (ret);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700472}
473
474#ifdef CLIB_UNIX
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200475__clib_export void
Yi Hed05ce972018-07-16 13:52:00 +0800476fformat_append_cr (FILE * ofp, const char *fmt, ...)
477{
478 va_list va;
479
480 va_start (va, fmt);
481 (void) va_fformat (ofp, (char *) fmt, &va);
482 va_end (va);
483 fformat (ofp, "\n");
484}
485
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200486__clib_export word
Dave Barachc3799992016-08-15 11:12:27 -0400487fdformat (int fd, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700488{
489 word ret;
Dave Barachc3799992016-08-15 11:12:27 -0400490 u8 *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491 va_list va;
492
493 va_start (va, fmt);
494 s = va_format (0, fmt, &va);
495 va_end (va);
496
497 ret = write (fd, s, vec_len (s));
498 vec_free (s);
499 return ret;
500}
501#endif
502
503/* Format integral type. */
Dave Barachc3799992016-08-15 11:12:27 -0400504static u8 *
505format_integer (u8 * s, u64 number, format_integer_options_t * options)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700506{
507 u64 q;
508 u32 r;
509 u8 digit_buffer[128];
Dave Barachc3799992016-08-15 11:12:27 -0400510 u8 *d = digit_buffer + sizeof (digit_buffer);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700511 word c, base;
512
513 if (options->is_signed && (i64) number < 0)
514 {
515 number = -number;
516 vec_add1 (s, '-');
517 }
518
519 if (options->n_bits < BITS (number))
520 number &= ((u64) 1 << options->n_bits) - 1;
521
522 base = options->base;
523
524 while (1)
525 {
526 q = number / base;
527 r = number % base;
528
Dave Barachc3799992016-08-15 11:12:27 -0400529 if (r < 10 + 26 + 26)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700530 {
531 if (r < 10)
532 c = '0' + r;
Dave Barachc3799992016-08-15 11:12:27 -0400533 else if (r < 10 + 26)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700534 c = 'a' + (r - 10);
535 else
536 c = 'A' + (r - 10 - 26);
537
538 if (options->uppercase_digits
Dave Barachc3799992016-08-15 11:12:27 -0400539 && base <= 10 + 26 && c >= 'a' && c <= 'z')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700540 c += 'A' - 'a';
541
542 *--d = c;
543 }
Dave Barachc3799992016-08-15 11:12:27 -0400544 else /* will never happen, warning be gone */
545 {
546 *--d = '?';
547 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700548
549 if (q == 0)
550 break;
551
552 number = q;
553 }
554
555 vec_add (s, d, digit_buffer + sizeof (digit_buffer) - d);
556 return s;
557}
558
559/* Floating point formatting. */
560/* Deconstruct IEEE 64 bit number into sign exponent and fraction. */
561#define f64_down(f,sign,expon,fraction) \
562do { \
563 union { u64 u; f64 f; } _f64_down_tmp; \
564 _f64_down_tmp.f = (f); \
565 (sign) = (_f64_down_tmp.u >> 63); \
566 (expon) = ((_f64_down_tmp.u >> 52) & 0x7ff) - 1023; \
567 (fraction) = ((_f64_down_tmp.u << 12) >> 12) | ((u64) 1 << 52); \
568} while (0)
569
570/* Construct IEEE 64 bit number. */
Dave Barachc3799992016-08-15 11:12:27 -0400571static f64
572f64_up (uword sign, word expon, u64 fraction)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700573{
Dave Barachc3799992016-08-15 11:12:27 -0400574 union
575 {
576 u64 u;
577 f64 f;
578 } tmp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700579
580 tmp.u = (u64) ((sign) != 0) << 63;
581
582 expon += 1023;
583 if (expon > 1023)
584 expon = 1023;
585 if (expon < 0)
586 expon = 0;
587 tmp.u |= (u64) expon << 52;
588
589 tmp.u |= fraction & (((u64) 1 << 52) - 1);
590
591 return tmp.f;
592}
593
594/* Returns approximate precision of number given its exponent. */
Dave Barachc3799992016-08-15 11:12:27 -0400595static f64
596f64_precision (int base2_expon)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700597{
598 static int n_bits = 0;
599
Dave Barachc3799992016-08-15 11:12:27 -0400600 if (!n_bits)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700601 {
602 /* Compute number of significant bits in floating point representation. */
603 f64 one = 0;
604 f64 small = 1;
605
606 while (one != 1)
607 {
608 small *= .5;
609 n_bits++;
610 one = 1 + small;
611 }
612 }
613
614 return f64_up (0, base2_expon - n_bits, 0);
615}
616
617/* Return x 10^n */
Dave Barachc3799992016-08-15 11:12:27 -0400618static f64
619times_power_of_ten (f64 x, int n)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700620{
621 if (n >= 0)
622 {
623 static f64 t[8] = { 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, };
624 while (n >= 8)
625 {
626 x *= 1e+8;
627 n -= 8;
628 }
629 return x * t[n];
630 }
631 else
632 {
633 static f64 t[8] = { 1e-0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, };
634 while (n <= -8)
635 {
636 x *= 1e-8;
637 n += 8;
638 }
639 return x * t[-n];
640 }
Dave Barachc3799992016-08-15 11:12:27 -0400641
Ed Warnickecb9cada2015-12-08 15:45:58 -0700642}
643
644/* Write x = y * 10^expon with 1 < y < 10. */
Dave Barachc3799992016-08-15 11:12:27 -0400645static f64
646normalize (f64 x, word * expon_return, f64 * prec_return)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700647{
648 word expon2, expon10;
649 CLIB_UNUSED (u64 fraction);
650 CLIB_UNUSED (word sign);
651 f64 prec;
652
653 f64_down (x, sign, expon2, fraction);
654
Dave Barachc3799992016-08-15 11:12:27 -0400655 expon10 =
656 .5 +
657 expon2 * .301029995663981195213738894724493 /* Log (2) / Log (10) */ ;
658
Ed Warnickecb9cada2015-12-08 15:45:58 -0700659 prec = f64_precision (expon2);
660 x = times_power_of_ten (x, -expon10);
661 prec = times_power_of_ten (prec, -expon10);
662
663 while (x < 1)
664 {
665 x *= 10;
666 prec *= 10;
667 expon10--;
668 }
669
670 while (x > 10)
671 {
672 x *= .1;
673 prec *= .1;
674 expon10++;
675 }
676
677 if (x + prec >= 10)
678 {
679 x = 1;
680 expon10++;
681 }
682
683 *expon_return = expon10;
684 *prec_return = prec;
685
686 return x;
687}
688
Dave Barachc3799992016-08-15 11:12:27 -0400689static u8 *
690add_some_zeros (u8 * s, uword n_zeros)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700691{
692 while (n_zeros > 0)
693 {
694 vec_add1 (s, '0');
695 n_zeros--;
696 }
697 return s;
698}
699
700/* Format a floating point number with the given number of fractional
701 digits (e.g. 1.2345 with 2 fraction digits yields "1.23") and output style. */
702static u8 *
Dave Barachc3799992016-08-15 11:12:27 -0400703format_float (u8 * s, f64 x, uword n_fraction_digits, uword output_style)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700704{
705 f64 prec;
706 word sign, expon, n_fraction_done, added_decimal_point;
707 /* Position of decimal point relative to where we are. */
708 word decimal_point;
709
710 /* Default number of digits to print when its not specified. */
711 if (n_fraction_digits == ~0)
712 n_fraction_digits = 7;
713 n_fraction_done = 0;
714 decimal_point = 0;
715 added_decimal_point = 0;
716 sign = expon = 0;
717
718 /* Special case: zero. */
719 if (x == 0)
720 {
721 do_zero:
722 vec_add1 (s, '0');
723 goto done;
724 }
Dave Barachc3799992016-08-15 11:12:27 -0400725
Ed Warnickecb9cada2015-12-08 15:45:58 -0700726 if (x < 0)
727 {
728 x = -x;
729 sign = 1;
730 }
731
Chris Lukebb18ee62017-07-09 14:30:25 -0400732 /* Check for not-a-number. */
733 if (isnan (x))
734 return format (s, "%cNaN", sign ? '-' : '+');
735
Ed Warnickecb9cada2015-12-08 15:45:58 -0700736 /* Check for infinity. */
Chris Lukebb18ee62017-07-09 14:30:25 -0400737 if (isinf (x))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700738 return format (s, "%cinfinity", sign ? '-' : '+');
739
740 x = normalize (x, &expon, &prec);
741
742 /* Not enough digits to print anything: so just print 0 */
Dave Barachc3799992016-08-15 11:12:27 -0400743 if ((word) - expon > (word) n_fraction_digits
Ed Warnickecb9cada2015-12-08 15:45:58 -0700744 && (output_style == 'f' || (output_style == 'g')))
745 goto do_zero;
746
747 if (sign)
748 vec_add1 (s, '-');
749
750 if (output_style == 'f'
751 || (output_style == 'g' && expon > -10 && expon < 10))
752 {
753 if (expon < 0)
754 {
755 /* Add decimal point and leading zeros. */
756 vec_add1 (s, '.');
757 n_fraction_done = clib_min (-(expon + 1), n_fraction_digits);
758 s = add_some_zeros (s, n_fraction_done);
759 decimal_point = -n_fraction_done;
760 added_decimal_point = 1;
761 }
762 else
763 decimal_point = expon + 1;
764 }
765 else
766 {
767 /* Exponential output style. */
768 decimal_point = 1;
769 output_style = 'e';
770 }
771
772 while (1)
773 {
774 uword digit;
775
776 /* Number is smaller than precision: call it zero. */
777 if (x < prec)
778 break;
779
780 digit = x;
781 x -= digit;
782 if (x + prec >= 1)
783 {
784 digit++;
785 x -= 1;
786 }
787
788 /* Round last printed digit. */
789 if (decimal_point <= 0
Dave Barachc3799992016-08-15 11:12:27 -0400790 && n_fraction_done + 1 == n_fraction_digits && digit < 9)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700791 digit += x >= .5;
792
793 vec_add1 (s, '0' + digit);
794
795 /* Move rightwards towards/away from decimal point. */
796 decimal_point--;
797
798 n_fraction_done += decimal_point < 0;
Dave Barachc3799992016-08-15 11:12:27 -0400799 if (decimal_point <= 0 && n_fraction_done >= n_fraction_digits)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700800 break;
801
802 if (decimal_point == 0 && x != 0)
803 {
804 vec_add1 (s, '.');
805 added_decimal_point = 1;
806 }
807
808 x *= 10;
809 prec *= 10;
810 }
Dave Barachc3799992016-08-15 11:12:27 -0400811
812done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700813 if (decimal_point > 0)
814 {
815 s = add_some_zeros (s, decimal_point);
816 decimal_point = 0;
817 }
818
819 if (n_fraction_done < n_fraction_digits)
820 {
Dave Barachc3799992016-08-15 11:12:27 -0400821 if (!added_decimal_point)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700822 vec_add1 (s, '.');
823 s = add_some_zeros (s, n_fraction_digits - n_fraction_done);
824 }
825
826 if (output_style == 'e')
827 s = format (s, "e%wd", expon);
828
829 return s;
830}
831
Dave Barachc3799992016-08-15 11:12:27 -0400832
833/*
834 * fd.io coding-style-patch-verification: ON
835 *
836 * Local Variables:
837 * eval: (c-set-style "gnu")
838 * End:
839 */