FD.io VPP  v19.01.2-3-gf61a1a8
Vector Packet Processing
format.c
Go to the documentation of this file.
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. */
71 
72  /* Number of show of 64 bit number. */
74 
75  /* Signed or unsigned. */
77 
78  /* Output digits uppercase (not lowercase) %X versus %x. */
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. */
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. */
98 
99  /* Pad character. Defaults to space. */
101 } format_info_t;
102 
103 static u8 *
104 justify (u8 * s, format_info_t * fi, uword s_len_orig)
105 {
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 '+':
130  n_left = n;
131  break;
132 
133  case '=':
134  n_right = n_left = n / 2;
135  if (n % 2)
136  n_left++;
137  break;
138  }
139  if (n_left > 0)
140  {
141  vec_insert (s, n_left, i0);
142  clib_memset (s + i0, fi->pad_char, n_left);
143  l1 = vec_len (s);
144  }
145  if (n_right > 0)
146  {
147  vec_resize (s, n_right);
148  clib_memset (s + l1, fi->pad_char, n_right);
149  }
150  }
151  return s;
152 }
153 
154 static const u8 *
155 do_percent (u8 ** _s, const u8 * fmt, va_list * va)
156 {
157  u8 *s = *_s;
158  uword c;
159 
160  const u8 *f = fmt;
161 
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;
199  if (c == '*')
200  {
201  fi.width[i] = va_arg (*va, int);
202  c = *++f;
203  }
204  else
205  {
206  while (c >= '0' && c <= '9')
207  {
208  fi.width[i] = 10 * fi.width[i] + (c - '0');
209  c = *++f;
210  }
211  }
212  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);
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  {
254  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  }
261 
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  {
321  char *cstring = va_arg (*va, char *);
322  uword len;
323 
324  if (!cstring)
325  {
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);
333 
334  /* %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]);
339  }
340  else
341  vec_add (s, cstring, len);
342  }
343  break;
344 
345  case 'v':
346  {
347  u8 *v = va_arg (*va, u8 *);
348  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 
359  case 'f':
360  case 'g':
361  case 'e':
362  /* Floating point. */
363  ASSERT (fi.how_long == 0 || fi.how_long == 'l');
364  s = format_float (s, va_arg (*va, double), fi.width[1], c);
365  break;
366 
367  case 'U':
368  /* User defined function. */
369  {
370  typedef u8 *(user_func_t) (u8 * s, va_list * args);
371  user_func_t *u = va_arg (*va, user_func_t *);
372 
373  s = (*u) (s, va);
374  }
375  break;
376  }
377 
378  s = justify (s, &fi, s_initial_len);
379  }
380 
381 done:
382  *_s = s;
383  return f;
384 }
385 
386 u8 *
387 va_format (u8 * s, const char *fmt, va_list * va)
388 {
389  const u8 *f = (u8 *) fmt, *g;
390  u8 c;
391 
392  g = f;
393  while (1)
394  {
395  c = *f;
396 
397  if (!c)
398  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 
418 u8 *
419 format (u8 * s, const char *fmt, ...)
420 {
421  va_list va;
422  va_start (va, fmt);
423  s = va_format (s, fmt, &va);
424  va_end (va);
425  return s;
426 }
427 
428 word
429 va_fformat (FILE * f, char *fmt, va_list * va)
430 {
431  word ret;
432  u8 *s;
433 
434  s = va_format (0, fmt, va);
435 
436 #ifdef CLIB_UNIX
437  if (f)
438  {
439  ret = fwrite (s, vec_len (s), 1, f);
440  }
441  else
442 #endif /* CLIB_UNIX */
443  {
444  ret = 0;
445  os_puts (s, vec_len (s), /* is_error */ 0);
446  }
447 
448  vec_free (s);
449  return ret;
450 }
451 
452 word
453 fformat (FILE * f, char *fmt, ...)
454 {
455  va_list va;
456  word ret;
457 
458  va_start (va, fmt);
459  ret = va_fformat (f, fmt, &va);
460  va_end (va);
461 
462  return (ret);
463 }
464 
465 #ifdef CLIB_UNIX
466 void
467 fformat_append_cr (FILE * ofp, const char *fmt, ...)
468 {
469  va_list va;
470 
471  va_start (va, fmt);
472  (void) va_fformat (ofp, (char *) fmt, &va);
473  va_end (va);
474  fformat (ofp, "\n");
475 }
476 
477 word
478 fdformat (int fd, char *fmt, ...)
479 {
480  word ret;
481  u8 *s;
482  va_list va;
483 
484  va_start (va, fmt);
485  s = va_format (0, fmt, &va);
486  va_end (va);
487 
488  ret = write (fd, s, vec_len (s));
489  vec_free (s);
490  return ret;
491 }
492 #endif
493 
494 /* Format integral type. */
495 static u8 *
497 {
498  u64 q;
499  u32 r;
500  u8 digit_buffer[128];
501  u8 *d = digit_buffer + sizeof (digit_buffer);
502  word c, base;
503 
504  if (options->is_signed && (i64) number < 0)
505  {
506  number = -number;
507  vec_add1 (s, '-');
508  }
509 
510  if (options->n_bits < BITS (number))
511  number &= ((u64) 1 << options->n_bits) - 1;
512 
513  base = options->base;
514 
515  while (1)
516  {
517  q = number / base;
518  r = number % base;
519 
520  if (r < 10 + 26 + 26)
521  {
522  if (r < 10)
523  c = '0' + r;
524  else if (r < 10 + 26)
525  c = 'a' + (r - 10);
526  else
527  c = 'A' + (r - 10 - 26);
528 
529  if (options->uppercase_digits
530  && base <= 10 + 26 && c >= 'a' && c <= 'z')
531  c += 'A' - 'a';
532 
533  *--d = c;
534  }
535  else /* will never happen, warning be gone */
536  {
537  *--d = '?';
538  }
539 
540  if (q == 0)
541  break;
542 
543  number = q;
544  }
545 
546  vec_add (s, d, digit_buffer + sizeof (digit_buffer) - d);
547  return s;
548 }
549 
550 /* Floating point formatting. */
551 /* Deconstruct IEEE 64 bit number into sign exponent and fraction. */
552 #define f64_down(f,sign,expon,fraction) \
553 do { \
554  union { u64 u; f64 f; } _f64_down_tmp; \
555  _f64_down_tmp.f = (f); \
556  (sign) = (_f64_down_tmp.u >> 63); \
557  (expon) = ((_f64_down_tmp.u >> 52) & 0x7ff) - 1023; \
558  (fraction) = ((_f64_down_tmp.u << 12) >> 12) | ((u64) 1 << 52); \
559 } while (0)
560 
561 /* Construct IEEE 64 bit number. */
562 static f64
563 f64_up (uword sign, word expon, u64 fraction)
564 {
565  union
566  {
567  u64 u;
568  f64 f;
569  } tmp;
570 
571  tmp.u = (u64) ((sign) != 0) << 63;
572 
573  expon += 1023;
574  if (expon > 1023)
575  expon = 1023;
576  if (expon < 0)
577  expon = 0;
578  tmp.u |= (u64) expon << 52;
579 
580  tmp.u |= fraction & (((u64) 1 << 52) - 1);
581 
582  return tmp.f;
583 }
584 
585 /* Returns approximate precision of number given its exponent. */
586 static f64
587 f64_precision (int base2_expon)
588 {
589  static int n_bits = 0;
590 
591  if (!n_bits)
592  {
593  /* Compute number of significant bits in floating point representation. */
594  f64 one = 0;
595  f64 small = 1;
596 
597  while (one != 1)
598  {
599  small *= .5;
600  n_bits++;
601  one = 1 + small;
602  }
603  }
604 
605  return f64_up (0, base2_expon - n_bits, 0);
606 }
607 
608 /* Return x 10^n */
609 static f64
611 {
612  if (n >= 0)
613  {
614  static f64 t[8] = { 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, };
615  while (n >= 8)
616  {
617  x *= 1e+8;
618  n -= 8;
619  }
620  return x * t[n];
621  }
622  else
623  {
624  static f64 t[8] = { 1e-0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, };
625  while (n <= -8)
626  {
627  x *= 1e-8;
628  n += 8;
629  }
630  return x * t[-n];
631  }
632 
633 }
634 
635 /* Write x = y * 10^expon with 1 < y < 10. */
636 static f64
637 normalize (f64 x, word * expon_return, f64 * prec_return)
638 {
639  word expon2, expon10;
640  CLIB_UNUSED (u64 fraction);
641  CLIB_UNUSED (word sign);
642  f64 prec;
643 
644  f64_down (x, sign, expon2, fraction);
645 
646  expon10 =
647  .5 +
648  expon2 * .301029995663981195213738894724493 /* Log (2) / Log (10) */ ;
649 
650  prec = f64_precision (expon2);
651  x = times_power_of_ten (x, -expon10);
652  prec = times_power_of_ten (prec, -expon10);
653 
654  while (x < 1)
655  {
656  x *= 10;
657  prec *= 10;
658  expon10--;
659  }
660 
661  while (x > 10)
662  {
663  x *= .1;
664  prec *= .1;
665  expon10++;
666  }
667 
668  if (x + prec >= 10)
669  {
670  x = 1;
671  expon10++;
672  }
673 
674  *expon_return = expon10;
675  *prec_return = prec;
676 
677  return x;
678 }
679 
680 static u8 *
681 add_some_zeros (u8 * s, uword n_zeros)
682 {
683  while (n_zeros > 0)
684  {
685  vec_add1 (s, '0');
686  n_zeros--;
687  }
688  return s;
689 }
690 
691 /* Format a floating point number with the given number of fractional
692  digits (e.g. 1.2345 with 2 fraction digits yields "1.23") and output style. */
693 static u8 *
694 format_float (u8 * s, f64 x, uword n_fraction_digits, uword output_style)
695 {
696  f64 prec;
697  word sign, expon, n_fraction_done, added_decimal_point;
698  /* Position of decimal point relative to where we are. */
699  word decimal_point;
700 
701  /* Default number of digits to print when its not specified. */
702  if (n_fraction_digits == ~0)
703  n_fraction_digits = 7;
704  n_fraction_done = 0;
705  decimal_point = 0;
706  added_decimal_point = 0;
707  sign = expon = 0;
708 
709  /* Special case: zero. */
710  if (x == 0)
711  {
712  do_zero:
713  vec_add1 (s, '0');
714  goto done;
715  }
716 
717  if (x < 0)
718  {
719  x = -x;
720  sign = 1;
721  }
722 
723  /* Check for not-a-number. */
724  if (isnan (x))
725  return format (s, "%cNaN", sign ? '-' : '+');
726 
727  /* Check for infinity. */
728  if (isinf (x))
729  return format (s, "%cinfinity", sign ? '-' : '+');
730 
731  x = normalize (x, &expon, &prec);
732 
733  /* Not enough digits to print anything: so just print 0 */
734  if ((word) - expon > (word) n_fraction_digits
735  && (output_style == 'f' || (output_style == 'g')))
736  goto do_zero;
737 
738  if (sign)
739  vec_add1 (s, '-');
740 
741  if (output_style == 'f'
742  || (output_style == 'g' && expon > -10 && expon < 10))
743  {
744  if (expon < 0)
745  {
746  /* Add decimal point and leading zeros. */
747  vec_add1 (s, '.');
748  n_fraction_done = clib_min (-(expon + 1), n_fraction_digits);
749  s = add_some_zeros (s, n_fraction_done);
750  decimal_point = -n_fraction_done;
751  added_decimal_point = 1;
752  }
753  else
754  decimal_point = expon + 1;
755  }
756  else
757  {
758  /* Exponential output style. */
759  decimal_point = 1;
760  output_style = 'e';
761  }
762 
763  while (1)
764  {
765  uword digit;
766 
767  /* Number is smaller than precision: call it zero. */
768  if (x < prec)
769  break;
770 
771  digit = x;
772  x -= digit;
773  if (x + prec >= 1)
774  {
775  digit++;
776  x -= 1;
777  }
778 
779  /* Round last printed digit. */
780  if (decimal_point <= 0
781  && n_fraction_done + 1 == n_fraction_digits && digit < 9)
782  digit += x >= .5;
783 
784  vec_add1 (s, '0' + digit);
785 
786  /* Move rightwards towards/away from decimal point. */
787  decimal_point--;
788 
789  n_fraction_done += decimal_point < 0;
790  if (decimal_point <= 0 && n_fraction_done >= n_fraction_digits)
791  break;
792 
793  if (decimal_point == 0 && x != 0)
794  {
795  vec_add1 (s, '.');
796  added_decimal_point = 1;
797  }
798 
799  x *= 10;
800  prec *= 10;
801  }
802 
803 done:
804  if (decimal_point > 0)
805  {
806  s = add_some_zeros (s, decimal_point);
807  decimal_point = 0;
808  }
809 
810  if (n_fraction_done < n_fraction_digits)
811  {
812  if (!added_decimal_point)
813  vec_add1 (s, '.');
814  s = add_some_zeros (s, n_fraction_digits - n_fraction_done);
815  }
816 
817  if (output_style == 'e')
818  s = format (s, "e%wd", expon);
819 
820  return s;
821 }
822 
823 
824 /*
825  * fd.io coding-style-patch-verification: ON
826  *
827  * Local Variables:
828  * eval: (c-set-style "gnu")
829  * End:
830  */
#define clib_min(x, y)
Definition: clib.h:295
#define CLIB_UNUSED(x)
Definition: clib.h:82
word fdformat(int fd, char *fmt,...)
Definition: format.c:478
void os_puts(u8 *string, uword length, uword is_error)
Definition: unix-misc.c:191
Optimized string handling code, including c11-compliant "safe C library" variants.
unsigned long u64
Definition: types.h:89
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:525
static u8 * format_float(u8 *s, f64 x, uword n_digits_to_print, uword output_style)
Definition: format.c:694
void fformat_append_cr(FILE *ofp, const char *fmt,...)
Definition: format.c:467
int i
clib_memset(h->entries, 0, sizeof(h->entries[0])*entries)
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
u8 * va_format(u8 *s, const char *fmt, va_list *va)
Definition: format.c:387
uword justify
Definition: format.c:90
unsigned char u8
Definition: types.h:56
double f64
Definition: types.h:142
static f64 times_power_of_ten(f64 x, int n)
Definition: format.c:610
#define isinf(x)
Definition: math.h:60
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:602
static f64 f64_precision(int base2_expon)
Definition: format.c:587
i64 word
Definition: types.h:111
static u8 * format_integer(u8 *s, u64 number, format_integer_options_t *options)
Definition: format.c:496
#define vec_resize(V, N)
Resize a vector (no header, unspecified alignment) Add N elements to end of given vector V...
Definition: vec.h:242
unsigned int u32
Definition: types.h:88
#define vec_insert(V, N, M)
Insert N vector elements starting at element M, initialize new elements to zero (no header...
Definition: vec.h:689
static f64 f64_up(uword sign, word expon, u64 fraction)
Definition: format.c:563
signed long i64
Definition: types.h:78
word fformat(FILE *f, char *fmt,...)
Definition: format.c:453
u8 len
Definition: ip_types.api:49
svmdb_client_t * c
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
static f64 normalize(f64 x, word *expon_return, f64 *prec_return)
Definition: format.c:637
uword pad_char
Definition: format.c:100
static const u8 * do_percent(u8 **_s, const u8 *fmt, va_list *va)
Definition: format.c:155
#define ASSERT(truth)
#define isnan(x)
Definition: math.h:56
static u8 * justify(u8 *s, format_info_t *fi, uword s_len_orig)
Definition: format.c:104
static uword pointer_to_uword(const void *p)
Definition: types.h:131
uword how_long
Definition: format.c:97
uword width[2]
Definition: format.c:94
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
word va_fformat(FILE *f, char *fmt, va_list *va)
Definition: format.c:429
u64 uword
Definition: types.h:112
#define f64_down(f, sign, expon, fraction)
Definition: format.c:552
static u8 * add_some_zeros(u8 *s, uword n_zeros)
Definition: format.c:681
#define BITS(x)
Definition: clib.h:61
CLIB vectors are ubiquitous dynamically resized arrays with by user defined "headers".