blob: 072ff3b33625c4922372cb61edecbb6547ebd1de [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
Dave Barachc3799992016-08-15 11:12:27 -0400386u8 *
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
415 return s;
416}
417
Dave Barachc3799992016-08-15 11:12:27 -0400418u8 *
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100419format (u8 * s, const char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420{
421 va_list va;
422 va_start (va, fmt);
423 s = va_format (s, fmt, &va);
424 va_end (va);
Dave Barach19e540f2019-03-29 19:41:50 -0400425#ifdef __COVERITY__
426 if (s == 0)
427 return (u8 *) "liar liar pants on fire s can't be zero!";
428#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700429 return s;
430}
431
Dave Barachc3799992016-08-15 11:12:27 -0400432word
433va_fformat (FILE * f, char *fmt, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700434{
435 word ret;
Dave Barachc3799992016-08-15 11:12:27 -0400436 u8 *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700437
438 s = va_format (0, fmt, va);
439
440#ifdef CLIB_UNIX
441 if (f)
442 {
443 ret = fwrite (s, vec_len (s), 1, f);
444 }
445 else
446#endif /* CLIB_UNIX */
447 {
448 ret = 0;
449 os_puts (s, vec_len (s), /* is_error */ 0);
450 }
451
452 vec_free (s);
453 return ret;
454}
455
Dave Barachc3799992016-08-15 11:12:27 -0400456word
457fformat (FILE * f, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700458{
Dave Barachc3799992016-08-15 11:12:27 -0400459 va_list va;
460 word ret;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700461
Dave Barachc3799992016-08-15 11:12:27 -0400462 va_start (va, fmt);
463 ret = va_fformat (f, fmt, &va);
464 va_end (va);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700465
Dave Barachc3799992016-08-15 11:12:27 -0400466 return (ret);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700467}
468
469#ifdef CLIB_UNIX
Yi Hed05ce972018-07-16 13:52:00 +0800470void
471fformat_append_cr (FILE * ofp, const char *fmt, ...)
472{
473 va_list va;
474
475 va_start (va, fmt);
476 (void) va_fformat (ofp, (char *) fmt, &va);
477 va_end (va);
478 fformat (ofp, "\n");
479}
480
Dave Barachc3799992016-08-15 11:12:27 -0400481word
482fdformat (int fd, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700483{
484 word ret;
Dave Barachc3799992016-08-15 11:12:27 -0400485 u8 *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700486 va_list va;
487
488 va_start (va, fmt);
489 s = va_format (0, fmt, &va);
490 va_end (va);
491
492 ret = write (fd, s, vec_len (s));
493 vec_free (s);
494 return ret;
495}
496#endif
497
498/* Format integral type. */
Dave Barachc3799992016-08-15 11:12:27 -0400499static u8 *
500format_integer (u8 * s, u64 number, format_integer_options_t * options)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700501{
502 u64 q;
503 u32 r;
504 u8 digit_buffer[128];
Dave Barachc3799992016-08-15 11:12:27 -0400505 u8 *d = digit_buffer + sizeof (digit_buffer);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700506 word c, base;
507
508 if (options->is_signed && (i64) number < 0)
509 {
510 number = -number;
511 vec_add1 (s, '-');
512 }
513
514 if (options->n_bits < BITS (number))
515 number &= ((u64) 1 << options->n_bits) - 1;
516
517 base = options->base;
518
519 while (1)
520 {
521 q = number / base;
522 r = number % base;
523
Dave Barachc3799992016-08-15 11:12:27 -0400524 if (r < 10 + 26 + 26)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700525 {
526 if (r < 10)
527 c = '0' + r;
Dave Barachc3799992016-08-15 11:12:27 -0400528 else if (r < 10 + 26)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700529 c = 'a' + (r - 10);
530 else
531 c = 'A' + (r - 10 - 26);
532
533 if (options->uppercase_digits
Dave Barachc3799992016-08-15 11:12:27 -0400534 && base <= 10 + 26 && c >= 'a' && c <= 'z')
Ed Warnickecb9cada2015-12-08 15:45:58 -0700535 c += 'A' - 'a';
536
537 *--d = c;
538 }
Dave Barachc3799992016-08-15 11:12:27 -0400539 else /* will never happen, warning be gone */
540 {
541 *--d = '?';
542 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700543
544 if (q == 0)
545 break;
546
547 number = q;
548 }
549
550 vec_add (s, d, digit_buffer + sizeof (digit_buffer) - d);
551 return s;
552}
553
554/* Floating point formatting. */
555/* Deconstruct IEEE 64 bit number into sign exponent and fraction. */
556#define f64_down(f,sign,expon,fraction) \
557do { \
558 union { u64 u; f64 f; } _f64_down_tmp; \
559 _f64_down_tmp.f = (f); \
560 (sign) = (_f64_down_tmp.u >> 63); \
561 (expon) = ((_f64_down_tmp.u >> 52) & 0x7ff) - 1023; \
562 (fraction) = ((_f64_down_tmp.u << 12) >> 12) | ((u64) 1 << 52); \
563} while (0)
564
565/* Construct IEEE 64 bit number. */
Dave Barachc3799992016-08-15 11:12:27 -0400566static f64
567f64_up (uword sign, word expon, u64 fraction)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700568{
Dave Barachc3799992016-08-15 11:12:27 -0400569 union
570 {
571 u64 u;
572 f64 f;
573 } tmp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700574
575 tmp.u = (u64) ((sign) != 0) << 63;
576
577 expon += 1023;
578 if (expon > 1023)
579 expon = 1023;
580 if (expon < 0)
581 expon = 0;
582 tmp.u |= (u64) expon << 52;
583
584 tmp.u |= fraction & (((u64) 1 << 52) - 1);
585
586 return tmp.f;
587}
588
589/* Returns approximate precision of number given its exponent. */
Dave Barachc3799992016-08-15 11:12:27 -0400590static f64
591f64_precision (int base2_expon)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700592{
593 static int n_bits = 0;
594
Dave Barachc3799992016-08-15 11:12:27 -0400595 if (!n_bits)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700596 {
597 /* Compute number of significant bits in floating point representation. */
598 f64 one = 0;
599 f64 small = 1;
600
601 while (one != 1)
602 {
603 small *= .5;
604 n_bits++;
605 one = 1 + small;
606 }
607 }
608
609 return f64_up (0, base2_expon - n_bits, 0);
610}
611
612/* Return x 10^n */
Dave Barachc3799992016-08-15 11:12:27 -0400613static f64
614times_power_of_ten (f64 x, int n)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700615{
616 if (n >= 0)
617 {
618 static f64 t[8] = { 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, };
619 while (n >= 8)
620 {
621 x *= 1e+8;
622 n -= 8;
623 }
624 return x * t[n];
625 }
626 else
627 {
628 static f64 t[8] = { 1e-0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, };
629 while (n <= -8)
630 {
631 x *= 1e-8;
632 n += 8;
633 }
634 return x * t[-n];
635 }
Dave Barachc3799992016-08-15 11:12:27 -0400636
Ed Warnickecb9cada2015-12-08 15:45:58 -0700637}
638
639/* Write x = y * 10^expon with 1 < y < 10. */
Dave Barachc3799992016-08-15 11:12:27 -0400640static f64
641normalize (f64 x, word * expon_return, f64 * prec_return)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700642{
643 word expon2, expon10;
644 CLIB_UNUSED (u64 fraction);
645 CLIB_UNUSED (word sign);
646 f64 prec;
647
648 f64_down (x, sign, expon2, fraction);
649
Dave Barachc3799992016-08-15 11:12:27 -0400650 expon10 =
651 .5 +
652 expon2 * .301029995663981195213738894724493 /* Log (2) / Log (10) */ ;
653
Ed Warnickecb9cada2015-12-08 15:45:58 -0700654 prec = f64_precision (expon2);
655 x = times_power_of_ten (x, -expon10);
656 prec = times_power_of_ten (prec, -expon10);
657
658 while (x < 1)
659 {
660 x *= 10;
661 prec *= 10;
662 expon10--;
663 }
664
665 while (x > 10)
666 {
667 x *= .1;
668 prec *= .1;
669 expon10++;
670 }
671
672 if (x + prec >= 10)
673 {
674 x = 1;
675 expon10++;
676 }
677
678 *expon_return = expon10;
679 *prec_return = prec;
680
681 return x;
682}
683
Dave Barachc3799992016-08-15 11:12:27 -0400684static u8 *
685add_some_zeros (u8 * s, uword n_zeros)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700686{
687 while (n_zeros > 0)
688 {
689 vec_add1 (s, '0');
690 n_zeros--;
691 }
692 return s;
693}
694
695/* Format a floating point number with the given number of fractional
696 digits (e.g. 1.2345 with 2 fraction digits yields "1.23") and output style. */
697static u8 *
Dave Barachc3799992016-08-15 11:12:27 -0400698format_float (u8 * s, f64 x, uword n_fraction_digits, uword output_style)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700699{
700 f64 prec;
701 word sign, expon, n_fraction_done, added_decimal_point;
702 /* Position of decimal point relative to where we are. */
703 word decimal_point;
704
705 /* Default number of digits to print when its not specified. */
706 if (n_fraction_digits == ~0)
707 n_fraction_digits = 7;
708 n_fraction_done = 0;
709 decimal_point = 0;
710 added_decimal_point = 0;
711 sign = expon = 0;
712
713 /* Special case: zero. */
714 if (x == 0)
715 {
716 do_zero:
717 vec_add1 (s, '0');
718 goto done;
719 }
Dave Barachc3799992016-08-15 11:12:27 -0400720
Ed Warnickecb9cada2015-12-08 15:45:58 -0700721 if (x < 0)
722 {
723 x = -x;
724 sign = 1;
725 }
726
Chris Lukebb18ee62017-07-09 14:30:25 -0400727 /* Check for not-a-number. */
728 if (isnan (x))
729 return format (s, "%cNaN", sign ? '-' : '+');
730
Ed Warnickecb9cada2015-12-08 15:45:58 -0700731 /* Check for infinity. */
Chris Lukebb18ee62017-07-09 14:30:25 -0400732 if (isinf (x))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700733 return format (s, "%cinfinity", sign ? '-' : '+');
734
735 x = normalize (x, &expon, &prec);
736
737 /* Not enough digits to print anything: so just print 0 */
Dave Barachc3799992016-08-15 11:12:27 -0400738 if ((word) - expon > (word) n_fraction_digits
Ed Warnickecb9cada2015-12-08 15:45:58 -0700739 && (output_style == 'f' || (output_style == 'g')))
740 goto do_zero;
741
742 if (sign)
743 vec_add1 (s, '-');
744
745 if (output_style == 'f'
746 || (output_style == 'g' && expon > -10 && expon < 10))
747 {
748 if (expon < 0)
749 {
750 /* Add decimal point and leading zeros. */
751 vec_add1 (s, '.');
752 n_fraction_done = clib_min (-(expon + 1), n_fraction_digits);
753 s = add_some_zeros (s, n_fraction_done);
754 decimal_point = -n_fraction_done;
755 added_decimal_point = 1;
756 }
757 else
758 decimal_point = expon + 1;
759 }
760 else
761 {
762 /* Exponential output style. */
763 decimal_point = 1;
764 output_style = 'e';
765 }
766
767 while (1)
768 {
769 uword digit;
770
771 /* Number is smaller than precision: call it zero. */
772 if (x < prec)
773 break;
774
775 digit = x;
776 x -= digit;
777 if (x + prec >= 1)
778 {
779 digit++;
780 x -= 1;
781 }
782
783 /* Round last printed digit. */
784 if (decimal_point <= 0
Dave Barachc3799992016-08-15 11:12:27 -0400785 && n_fraction_done + 1 == n_fraction_digits && digit < 9)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700786 digit += x >= .5;
787
788 vec_add1 (s, '0' + digit);
789
790 /* Move rightwards towards/away from decimal point. */
791 decimal_point--;
792
793 n_fraction_done += decimal_point < 0;
Dave Barachc3799992016-08-15 11:12:27 -0400794 if (decimal_point <= 0 && n_fraction_done >= n_fraction_digits)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700795 break;
796
797 if (decimal_point == 0 && x != 0)
798 {
799 vec_add1 (s, '.');
800 added_decimal_point = 1;
801 }
802
803 x *= 10;
804 prec *= 10;
805 }
Dave Barachc3799992016-08-15 11:12:27 -0400806
807done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700808 if (decimal_point > 0)
809 {
810 s = add_some_zeros (s, decimal_point);
811 decimal_point = 0;
812 }
813
814 if (n_fraction_done < n_fraction_digits)
815 {
Dave Barachc3799992016-08-15 11:12:27 -0400816 if (!added_decimal_point)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700817 vec_add1 (s, '.');
818 s = add_some_zeros (s, n_fraction_digits - n_fraction_done);
819 }
820
821 if (output_style == 'e')
822 s = format (s, "e%wd", expon);
823
824 return s;
825}
826
Dave Barachc3799992016-08-15 11:12:27 -0400827
828/*
829 * fd.io coding-style-patch-verification: ON
830 *
831 * Local Variables:
832 * eval: (c-set-style "gnu")
833 * End:
834 */