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 */
65 #include <vppinfra/math.h>
69 /* Output number in this base. */
72 /* Number of show of 64 bit number. */
75 /* Signed or unsigned. */
78 /* Output digits uppercase (not lowercase) %X versus %x. */
80 } format_integer_options_t;
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,
89 /* String justification: + => right, - => left, = => center. */
92 /* Width of string (before and after decimal point for numbers).
93 0 => natural width. */
96 /* Long => 'l', long long 'L', int 0. */
99 /* Pad character. Defaults to space. */
104 justify (u8 * s, format_info_t * fi, uword s_len_orig)
109 l0 = i0 + fi->width[0];
112 /* If width is zero user returned width. */
121 uword n_left = 0, n_right = 0;
134 n_right = n_left = n / 2;
141 vec_insert (s, n_left, i0);
142 clib_memset (s + i0, fi->pad_char, n_left);
147 vec_resize (s, n_right);
148 clib_memset (s + l1, fi->pad_char, n_right);
155 do_percent (u8 ** _s, const u8 * fmt, va_list * va)
171 ASSERT (f[0] == '%');
189 /* Parse width0 . width1. */
191 uword is_first_digit = 1;
193 fi.width[0] = fi.width[1] = 0;
194 for (i = 0; i < 2; i++)
196 if (c == '0' && i == 0 && is_first_digit)
201 fi.width[i] = va_arg (*va, int);
206 while (c >= '0' && c <= '9')
208 fi.width[i] = 10 * fi.width[i] + (c - '0');
218 /* Parse %l* and %L* */
231 if (c == 'l' && *f == 'l')
239 /* Finally we are ready for format letter. */
242 uword s_initial_len = vec_len (s);
243 format_integer_options_t o = {
246 .n_bits = BITS (uword),
247 .uppercase_digits = 0,
256 /* Try to give a helpful error message. */
258 s = format (s, "**** CLIB unknown format `%%%c' ****", c);
263 vec_add1 (s, va_arg (*va, int));
271 o.n_bits = BITS (uword *);
273 o.uppercase_digits = 0;
275 s = format_integer (s, pointer_to_uword (va_arg (*va, void *)), &o);
287 if (c == 'x' || c == 'X')
289 o.is_signed = c == 'd';
290 o.uppercase_digits = c == 'X';
295 number = va_arg (*va, unsigned long long);
296 o.n_bits = BITS (unsigned long long);
300 number = va_arg (*va, long);
301 o.n_bits = BITS (long);
305 number = va_arg (*va, word);
306 o.n_bits = BITS (uword);
310 number = va_arg (*va, int);
311 o.n_bits = BITS (int);
318 s = format_integer (s, number, &o);
325 char *cstring = va_arg (*va, char *);
333 else if (fi.width[1] != 0)
334 len = clib_min (strlen (cstring), fi.width[1]);
336 len = strlen (cstring);
338 /* %S => format string as C identifier (replace _ with space). */
341 for (i = 0; i < len; i++)
342 vec_add1 (s, cstring[i] == '_' ? ' ' : cstring[i]);
345 vec_add (s, cstring, len);
351 u8 *v = va_arg (*va, u8 *);
354 if (fi.width[1] != 0)
355 len = clib_min (vec_len (v), fi.width[1]);
366 /* Floating point. */
367 ASSERT (fi.how_long == 0 || fi.how_long == 'l');
368 s = format_float (s, va_arg (*va, double), fi.width[1], c);
372 /* User defined function. */
374 typedef u8 *(user_func_t) (u8 * s, va_list * args);
375 user_func_t *u = va_arg (*va, user_func_t *);
382 s = justify (s, &fi, s_initial_len);
391 va_format (u8 * s, const char *fmt, va_list * va)
393 const u8 *f = (u8 *) fmt, *g;
407 vec_add (s, g, f - g);
408 f = g = do_percent (&s, f, va);
417 vec_add (s, g, f - g);
421 return (u8 *) "liar liar pants on fire s can't be zero!";
428 format (u8 * s, const char *fmt, ...)
432 s = va_format (s, fmt, &va);
436 return (u8 *) "liar liar pants on fire s can't be zero!";
442 va_fformat (FILE * f, char *fmt, va_list * va)
447 s = va_format (0, fmt, va);
452 ret = fwrite (s, vec_len (s), 1, f);
455 #endif /* CLIB_UNIX */
458 os_puts (s, vec_len (s), /* is_error */ 0);
466 fformat (FILE * f, char *fmt, ...)
472 ret = va_fformat (f, fmt, &va);
480 fformat_append_cr (FILE * ofp, const char *fmt, ...)
485 (void) va_fformat (ofp, (char *) fmt, &va);
491 fdformat (int fd, char *fmt, ...)
498 s = va_format (0, fmt, &va);
501 ret = write (fd, s, vec_len (s));
507 /* Format integral type. */
509 format_integer (u8 * s, u64 number, format_integer_options_t * options)
513 u8 digit_buffer[128];
514 u8 *d = digit_buffer + sizeof (digit_buffer);
517 if (options->is_signed && (i64) number < 0)
523 if (options->n_bits < BITS (number))
524 number &= ((u64) 1 << options->n_bits) - 1;
526 base = options->base;
533 if (r < 10 + 26 + 26)
537 else if (r < 10 + 26)
540 c = 'A' + (r - 10 - 26);
542 if (options->uppercase_digits
543 && base <= 10 + 26 && c >= 'a' && c <= 'z')
548 else /* will never happen, warning be gone */
559 vec_add (s, d, digit_buffer + sizeof (digit_buffer) - d);
563 /* Floating point formatting. */
564 /* Deconstruct IEEE 64 bit number into sign exponent and fraction. */
565 #define f64_down(f,sign,expon,fraction) \
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); \
574 /* Construct IEEE 64 bit number. */
576 f64_up (uword sign, word expon, u64 fraction)
584 tmp.u = (u64) ((sign) != 0) << 63;
591 tmp.u |= (u64) expon << 52;
593 tmp.u |= fraction & (((u64) 1 << 52) - 1);
598 /* Returns approximate precision of number given its exponent. */
600 f64_precision (int base2_expon)
602 static int n_bits = 0;
606 /* Compute number of significant bits in floating point representation. */
618 return f64_up (0, base2_expon - n_bits, 0);
623 times_power_of_ten (f64 x, int n)
627 static f64 t[8] = { 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, };
637 static f64 t[8] = { 1e-0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, };
648 /* Write x = y * 10^expon with 1 < y < 10. */
650 normalize (f64 x, word * expon_return, f64 * prec_return)
652 word expon2, expon10;
653 CLIB_UNUSED (u64 fraction);
654 CLIB_UNUSED (word sign);
657 f64_down (x, sign, expon2, fraction);
661 expon2 * .301029995663981195213738894724493 /* Log (2) / Log (10) */ ;
663 prec = f64_precision (expon2);
664 x = times_power_of_ten (x, -expon10);
665 prec = times_power_of_ten (prec, -expon10);
687 *expon_return = expon10;
694 add_some_zeros (u8 * s, uword n_zeros)
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. */
707 format_float (u8 * s, f64 x, uword n_fraction_digits, uword output_style)
710 word sign, expon, n_fraction_done, added_decimal_point;
711 /* Position of decimal point relative to where we are. */
714 /* Default number of digits to print when its not specified. */
715 if (n_fraction_digits == ~0)
716 n_fraction_digits = 7;
719 added_decimal_point = 0;
722 /* Special case: zero. */
736 /* Check for not-a-number. */
738 return format (s, "%cNaN", sign ? '-' : '+');
740 /* Check for infinity. */
742 return format (s, "%cinfinity", sign ? '-' : '+');
744 x = normalize (x, &expon, &prec);
746 /* Not enough digits to print anything: so just print 0 */
747 if ((word) - expon > (word) n_fraction_digits
748 && (output_style == 'f' || (output_style == 'g')))
754 if (output_style == 'f'
755 || (output_style == 'g' && expon > -10 && expon < 10))
759 /* Add decimal point and leading zeros. */
761 n_fraction_done = clib_min (-(expon + 1), n_fraction_digits);
762 s = add_some_zeros (s, n_fraction_done);
763 decimal_point = -n_fraction_done;
764 added_decimal_point = 1;
767 decimal_point = expon + 1;
771 /* Exponential output style. */
780 /* Number is smaller than precision: call it zero. */
792 /* Round last printed digit. */
793 if (decimal_point <= 0
794 && n_fraction_done + 1 == n_fraction_digits && digit < 9)
797 vec_add1 (s, '0' + digit);
799 /* Move rightwards towards/away from decimal point. */
802 n_fraction_done += decimal_point < 0;
803 if (decimal_point <= 0 && n_fraction_done >= n_fraction_digits)
806 if (decimal_point == 0 && x != 0)
809 added_decimal_point = 1;
817 if (decimal_point > 0)
819 s = add_some_zeros (s, decimal_point);
823 if (n_fraction_done < n_fraction_digits)
825 if (!added_decimal_point)
827 s = add_some_zeros (s, n_fraction_digits - n_fraction_done);
830 if (output_style == 'e')
831 s = format (s, "e%wd", expon);
838 * fd.io coding-style-patch-verification: ON
841 * eval: (c-set-style "gnu")