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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
15 /*------------------------------------------------------------------
16 * format.c -- see notice below
18 * October 2003, Eliot Dresselhaus
20 * Modifications to this file Copyright (c) 2003 by cisco Systems, Inc.
21 * All rights reserved.
22 *------------------------------------------------------------------
26 Copyright (c) 2001, 2002, 2003, 2006 Eliot Dresselhaus
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:
36 The above copyright notice and this permission notice shall be
37 included in all copies or substantial portions of the Software.
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.
48 #include <stdarg.h> /* va_start, etc */
55 #ifdef CLIB_STANDALONE
56 #include <vppinfra/standalone_stdio.h>
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 */
68 /* Output number in this base. */
71 /* Number of show of 64 bit number. */
74 /* Signed or unsigned. */
77 /* Output digits uppercase (not lowercase) %X versus %x. */
79 } format_integer_options_t;
81 static u8 *format_integer (u8 * s, u64 number,
82 format_integer_options_t * options);
83 static u8 *format_float (u8 * s, f64 x, uword n_digits_to_print,
88 /* String justification: + => right, - => left, = => center. */
91 /* Width of string (before and after decimal point for numbers).
92 0 => natural width. */
95 /* Long => 'l', long long 'L', int 0. */
98 /* Pad character. Defaults to space. */
103 justify (u8 * s, format_info_t * fi, uword s_len_orig)
108 l0 = i0 + fi->width[0];
111 /* If width is zero user returned width. */
120 uword n_left = 0, n_right = 0;
133 n_right = n_left = n / 2;
140 vec_insert (s, n_left, i0);
141 memset (s + i0, fi->pad_char, n_left);
146 vec_resize (s, n_right);
147 memset (s + l1, fi->pad_char, n_right);
154 do_percent (u8 ** _s, const u8 * fmt, va_list * va)
170 ASSERT (f[0] == '%');
188 /* Parse width0 . width1. */
190 uword is_first_digit = 1;
192 fi.width[0] = fi.width[1] = 0;
193 for (i = 0; i < 2; i++)
195 if (c == '0' && i == 0 && is_first_digit)
200 fi.width[i] = va_arg (*va, int);
205 while (c >= '0' && c <= '9')
207 fi.width[i] = 10 * fi.width[i] + (c - '0');
217 /* Parse %l* and %L* */
230 if (c == 'l' && *f == 'l')
238 /* Finally we are ready for format letter. */
241 uword s_initial_len = vec_len (s);
242 format_integer_options_t o = {
245 .n_bits = BITS (uword),
246 .uppercase_digits = 0,
255 /* Try to give a helpful error message. */
257 s = format (s, "**** CLIB unknown format `%%%c' ****", c);
262 vec_add1 (s, va_arg (*va, int));
270 o.n_bits = BITS (uword *);
272 o.uppercase_digits = 0;
274 s = format_integer (s, pointer_to_uword (va_arg (*va, void *)), &o);
285 if (c == 'x' || c == 'X')
287 o.is_signed = c == 'd';
288 o.uppercase_digits = c == 'X';
293 number = va_arg (*va, unsigned long long);
294 o.n_bits = BITS (unsigned long long);
298 number = va_arg (*va, long);
299 o.n_bits = BITS (long);
303 number = va_arg (*va, word);
304 o.n_bits = BITS (uword);
308 number = va_arg (*va, int);
309 o.n_bits = BITS (int);
313 s = format_integer (s, number, &o);
320 char *cstring = va_arg (*va, char *);
328 else if (fi.width[1] != 0)
329 len = clib_min (strlen (cstring), fi.width[1]);
331 len = strlen (cstring);
333 /* %S => format string as C identifier (replace _ with space). */
336 for (i = 0; i < len; i++)
337 vec_add1 (s, cstring[i] == '_' ? ' ' : cstring[i]);
340 vec_add (s, cstring, len);
346 u8 *v = va_arg (*va, u8 *);
349 if (fi.width[1] != 0)
350 len = clib_min (vec_len (v), fi.width[1]);
361 /* Floating point. */
362 ASSERT (fi.how_long == 0 || fi.how_long == 'l');
363 s = format_float (s, va_arg (*va, double), fi.width[1], c);
367 /* User defined function. */
369 typedef u8 *(user_func_t) (u8 * s, va_list * args);
370 user_func_t *u = va_arg (*va, user_func_t *);
377 s = justify (s, &fi, s_initial_len);
386 va_format (u8 * s, const char *fmt, va_list * va)
388 const u8 *f = (u8 *) fmt, *g;
402 vec_add (s, g, f - g);
403 f = g = do_percent (&s, f, va);
412 vec_add (s, g, f - g);
418 format (u8 * s, const char *fmt, ...)
422 s = va_format (s, fmt, &va);
428 va_fformat (FILE * f, char *fmt, va_list * va)
433 s = va_format (0, fmt, va);
438 ret = fwrite (s, vec_len (s), 1, f);
441 #endif /* CLIB_UNIX */
444 os_puts (s, vec_len (s), /* is_error */ 0);
452 fformat (FILE * f, char *fmt, ...)
458 ret = va_fformat (f, fmt, &va);
466 fdformat (int fd, char *fmt, ...)
473 s = va_format (0, fmt, &va);
476 ret = write (fd, s, vec_len (s));
482 /* Format integral type. */
484 format_integer (u8 * s, u64 number, format_integer_options_t * options)
488 u8 digit_buffer[128];
489 u8 *d = digit_buffer + sizeof (digit_buffer);
492 if (options->is_signed && (i64) number < 0)
498 if (options->n_bits < BITS (number))
499 number &= ((u64) 1 << options->n_bits) - 1;
501 base = options->base;
508 if (r < 10 + 26 + 26)
512 else if (r < 10 + 26)
515 c = 'A' + (r - 10 - 26);
517 if (options->uppercase_digits
518 && base <= 10 + 26 && c >= 'a' && c <= 'z')
523 else /* will never happen, warning be gone */
534 vec_add (s, d, digit_buffer + sizeof (digit_buffer) - d);
538 /* Floating point formatting. */
539 /* Deconstruct IEEE 64 bit number into sign exponent and fraction. */
540 #define f64_down(f,sign,expon,fraction) \
542 union { u64 u; f64 f; } _f64_down_tmp; \
543 _f64_down_tmp.f = (f); \
544 (sign) = (_f64_down_tmp.u >> 63); \
545 (expon) = ((_f64_down_tmp.u >> 52) & 0x7ff) - 1023; \
546 (fraction) = ((_f64_down_tmp.u << 12) >> 12) | ((u64) 1 << 52); \
549 /* Construct IEEE 64 bit number. */
551 f64_up (uword sign, word expon, u64 fraction)
559 tmp.u = (u64) ((sign) != 0) << 63;
566 tmp.u |= (u64) expon << 52;
568 tmp.u |= fraction & (((u64) 1 << 52) - 1);
573 /* Returns approximate precision of number given its exponent. */
575 f64_precision (int base2_expon)
577 static int n_bits = 0;
581 /* Compute number of significant bits in floating point representation. */
593 return f64_up (0, base2_expon - n_bits, 0);
598 times_power_of_ten (f64 x, int n)
602 static f64 t[8] = { 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, };
612 static f64 t[8] = { 1e-0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, };
623 /* Write x = y * 10^expon with 1 < y < 10. */
625 normalize (f64 x, word * expon_return, f64 * prec_return)
627 word expon2, expon10;
628 CLIB_UNUSED (u64 fraction);
629 CLIB_UNUSED (word sign);
632 f64_down (x, sign, expon2, fraction);
636 expon2 * .301029995663981195213738894724493 /* Log (2) / Log (10) */ ;
638 prec = f64_precision (expon2);
639 x = times_power_of_ten (x, -expon10);
640 prec = times_power_of_ten (prec, -expon10);
662 *expon_return = expon10;
669 add_some_zeros (u8 * s, uword n_zeros)
679 /* Format a floating point number with the given number of fractional
680 digits (e.g. 1.2345 with 2 fraction digits yields "1.23") and output style. */
682 format_float (u8 * s, f64 x, uword n_fraction_digits, uword output_style)
685 word sign, expon, n_fraction_done, added_decimal_point;
686 /* Position of decimal point relative to where we are. */
689 /* Default number of digits to print when its not specified. */
690 if (n_fraction_digits == ~0)
691 n_fraction_digits = 7;
694 added_decimal_point = 0;
697 /* Special case: zero. */
711 /* Check for infinity. */
713 return format (s, "%cinfinity", sign ? '-' : '+');
715 x = normalize (x, &expon, &prec);
717 /* Not enough digits to print anything: so just print 0 */
718 if ((word) - expon > (word) n_fraction_digits
719 && (output_style == 'f' || (output_style == 'g')))
725 if (output_style == 'f'
726 || (output_style == 'g' && expon > -10 && expon < 10))
730 /* Add decimal point and leading zeros. */
732 n_fraction_done = clib_min (-(expon + 1), n_fraction_digits);
733 s = add_some_zeros (s, n_fraction_done);
734 decimal_point = -n_fraction_done;
735 added_decimal_point = 1;
738 decimal_point = expon + 1;
742 /* Exponential output style. */
751 /* Number is smaller than precision: call it zero. */
763 /* Round last printed digit. */
764 if (decimal_point <= 0
765 && n_fraction_done + 1 == n_fraction_digits && digit < 9)
768 vec_add1 (s, '0' + digit);
770 /* Move rightwards towards/away from decimal point. */
773 n_fraction_done += decimal_point < 0;
774 if (decimal_point <= 0 && n_fraction_done >= n_fraction_digits)
777 if (decimal_point == 0 && x != 0)
780 added_decimal_point = 1;
788 if (decimal_point > 0)
790 s = add_some_zeros (s, decimal_point);
794 if (n_fraction_done < n_fraction_digits)
796 if (!added_decimal_point)
798 s = add_some_zeros (s, n_fraction_digits - n_fraction_done);
801 if (output_style == 'e')
802 s = format (s, "e%wd", expon);
809 * fd.io coding-style-patch-verification: ON
812 * eval: (c-set-style "gnu")