FD.io VPP  v18.07-rc0-415-g6c78436
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  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  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 word
467 fdformat (int fd, char *fmt, ...)
468 {
469  word ret;
470  u8 *s;
471  va_list va;
472 
473  va_start (va, fmt);
474  s = va_format (0, fmt, &va);
475  va_end (va);
476 
477  ret = write (fd, s, vec_len (s));
478  vec_free (s);
479  return ret;
480 }
481 #endif
482 
483 /* Format integral type. */
484 static u8 *
486 {
487  u64 q;
488  u32 r;
489  u8 digit_buffer[128];
490  u8 *d = digit_buffer + sizeof (digit_buffer);
491  word c, base;
492 
493  if (options->is_signed && (i64) number < 0)
494  {
495  number = -number;
496  vec_add1 (s, '-');
497  }
498 
499  if (options->n_bits < BITS (number))
500  number &= ((u64) 1 << options->n_bits) - 1;
501 
502  base = options->base;
503 
504  while (1)
505  {
506  q = number / base;
507  r = number % base;
508 
509  if (r < 10 + 26 + 26)
510  {
511  if (r < 10)
512  c = '0' + r;
513  else if (r < 10 + 26)
514  c = 'a' + (r - 10);
515  else
516  c = 'A' + (r - 10 - 26);
517 
518  if (options->uppercase_digits
519  && base <= 10 + 26 && c >= 'a' && c <= 'z')
520  c += 'A' - 'a';
521 
522  *--d = c;
523  }
524  else /* will never happen, warning be gone */
525  {
526  *--d = '?';
527  }
528 
529  if (q == 0)
530  break;
531 
532  number = q;
533  }
534 
535  vec_add (s, d, digit_buffer + sizeof (digit_buffer) - d);
536  return s;
537 }
538 
539 /* Floating point formatting. */
540 /* Deconstruct IEEE 64 bit number into sign exponent and fraction. */
541 #define f64_down(f,sign,expon,fraction) \
542 do { \
543  union { u64 u; f64 f; } _f64_down_tmp; \
544  _f64_down_tmp.f = (f); \
545  (sign) = (_f64_down_tmp.u >> 63); \
546  (expon) = ((_f64_down_tmp.u >> 52) & 0x7ff) - 1023; \
547  (fraction) = ((_f64_down_tmp.u << 12) >> 12) | ((u64) 1 << 52); \
548 } while (0)
549 
550 /* Construct IEEE 64 bit number. */
551 static f64
552 f64_up (uword sign, word expon, u64 fraction)
553 {
554  union
555  {
556  u64 u;
557  f64 f;
558  } tmp;
559 
560  tmp.u = (u64) ((sign) != 0) << 63;
561 
562  expon += 1023;
563  if (expon > 1023)
564  expon = 1023;
565  if (expon < 0)
566  expon = 0;
567  tmp.u |= (u64) expon << 52;
568 
569  tmp.u |= fraction & (((u64) 1 << 52) - 1);
570 
571  return tmp.f;
572 }
573 
574 /* Returns approximate precision of number given its exponent. */
575 static f64
576 f64_precision (int base2_expon)
577 {
578  static int n_bits = 0;
579 
580  if (!n_bits)
581  {
582  /* Compute number of significant bits in floating point representation. */
583  f64 one = 0;
584  f64 small = 1;
585 
586  while (one != 1)
587  {
588  small *= .5;
589  n_bits++;
590  one = 1 + small;
591  }
592  }
593 
594  return f64_up (0, base2_expon - n_bits, 0);
595 }
596 
597 /* Return x 10^n */
598 static f64
600 {
601  if (n >= 0)
602  {
603  static f64 t[8] = { 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, };
604  while (n >= 8)
605  {
606  x *= 1e+8;
607  n -= 8;
608  }
609  return x * t[n];
610  }
611  else
612  {
613  static f64 t[8] = { 1e-0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, };
614  while (n <= -8)
615  {
616  x *= 1e-8;
617  n += 8;
618  }
619  return x * t[-n];
620  }
621 
622 }
623 
624 /* Write x = y * 10^expon with 1 < y < 10. */
625 static f64
626 normalize (f64 x, word * expon_return, f64 * prec_return)
627 {
628  word expon2, expon10;
629  CLIB_UNUSED (u64 fraction);
630  CLIB_UNUSED (word sign);
631  f64 prec;
632 
633  f64_down (x, sign, expon2, fraction);
634 
635  expon10 =
636  .5 +
637  expon2 * .301029995663981195213738894724493 /* Log (2) / Log (10) */ ;
638 
639  prec = f64_precision (expon2);
640  x = times_power_of_ten (x, -expon10);
641  prec = times_power_of_ten (prec, -expon10);
642 
643  while (x < 1)
644  {
645  x *= 10;
646  prec *= 10;
647  expon10--;
648  }
649 
650  while (x > 10)
651  {
652  x *= .1;
653  prec *= .1;
654  expon10++;
655  }
656 
657  if (x + prec >= 10)
658  {
659  x = 1;
660  expon10++;
661  }
662 
663  *expon_return = expon10;
664  *prec_return = prec;
665 
666  return x;
667 }
668 
669 static u8 *
670 add_some_zeros (u8 * s, uword n_zeros)
671 {
672  while (n_zeros > 0)
673  {
674  vec_add1 (s, '0');
675  n_zeros--;
676  }
677  return s;
678 }
679 
680 /* Format a floating point number with the given number of fractional
681  digits (e.g. 1.2345 with 2 fraction digits yields "1.23") and output style. */
682 static u8 *
683 format_float (u8 * s, f64 x, uword n_fraction_digits, uword output_style)
684 {
685  f64 prec;
686  word sign, expon, n_fraction_done, added_decimal_point;
687  /* Position of decimal point relative to where we are. */
688  word decimal_point;
689 
690  /* Default number of digits to print when its not specified. */
691  if (n_fraction_digits == ~0)
692  n_fraction_digits = 7;
693  n_fraction_done = 0;
694  decimal_point = 0;
695  added_decimal_point = 0;
696  sign = expon = 0;
697 
698  /* Special case: zero. */
699  if (x == 0)
700  {
701  do_zero:
702  vec_add1 (s, '0');
703  goto done;
704  }
705 
706  if (x < 0)
707  {
708  x = -x;
709  sign = 1;
710  }
711 
712  /* Check for not-a-number. */
713  if (isnan (x))
714  return format (s, "%cNaN", sign ? '-' : '+');
715 
716  /* Check for infinity. */
717  if (isinf (x))
718  return format (s, "%cinfinity", sign ? '-' : '+');
719 
720  x = normalize (x, &expon, &prec);
721 
722  /* Not enough digits to print anything: so just print 0 */
723  if ((word) - expon > (word) n_fraction_digits
724  && (output_style == 'f' || (output_style == 'g')))
725  goto do_zero;
726 
727  if (sign)
728  vec_add1 (s, '-');
729 
730  if (output_style == 'f'
731  || (output_style == 'g' && expon > -10 && expon < 10))
732  {
733  if (expon < 0)
734  {
735  /* Add decimal point and leading zeros. */
736  vec_add1 (s, '.');
737  n_fraction_done = clib_min (-(expon + 1), n_fraction_digits);
738  s = add_some_zeros (s, n_fraction_done);
739  decimal_point = -n_fraction_done;
740  added_decimal_point = 1;
741  }
742  else
743  decimal_point = expon + 1;
744  }
745  else
746  {
747  /* Exponential output style. */
748  decimal_point = 1;
749  output_style = 'e';
750  }
751 
752  while (1)
753  {
754  uword digit;
755 
756  /* Number is smaller than precision: call it zero. */
757  if (x < prec)
758  break;
759 
760  digit = x;
761  x -= digit;
762  if (x + prec >= 1)
763  {
764  digit++;
765  x -= 1;
766  }
767 
768  /* Round last printed digit. */
769  if (decimal_point <= 0
770  && n_fraction_done + 1 == n_fraction_digits && digit < 9)
771  digit += x >= .5;
772 
773  vec_add1 (s, '0' + digit);
774 
775  /* Move rightwards towards/away from decimal point. */
776  decimal_point--;
777 
778  n_fraction_done += decimal_point < 0;
779  if (decimal_point <= 0 && n_fraction_done >= n_fraction_digits)
780  break;
781 
782  if (decimal_point == 0 && x != 0)
783  {
784  vec_add1 (s, '.');
785  added_decimal_point = 1;
786  }
787 
788  x *= 10;
789  prec *= 10;
790  }
791 
792 done:
793  if (decimal_point > 0)
794  {
795  s = add_some_zeros (s, decimal_point);
796  decimal_point = 0;
797  }
798 
799  if (n_fraction_done < n_fraction_digits)
800  {
801  if (!added_decimal_point)
802  vec_add1 (s, '.');
803  s = add_some_zeros (s, n_fraction_digits - n_fraction_done);
804  }
805 
806  if (output_style == 'e')
807  s = format (s, "e%wd", expon);
808 
809  return s;
810 }
811 
812 
813 /*
814  * fd.io coding-style-patch-verification: ON
815  *
816  * Local Variables:
817  * eval: (c-set-style "gnu")
818  * End:
819  */
#define clib_min(x, y)
Definition: clib.h:289
#define CLIB_UNUSED(x)
Definition: clib.h:79
word fdformat(int fd, char *fmt,...)
Definition: format.c:467
void os_puts(u8 *string, uword length, uword is_error)
Definition: unix-misc.c:191
unsigned long u64
Definition: types.h:89
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:523
static u8 * format_float(u8 *s, f64 x, uword n_digits_to_print, uword output_style)
Definition: format.c:683
int i
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:599
#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:600
static f64 f64_precision(int base2_expon)
Definition: format.c:576
i64 word
Definition: types.h:111
static u8 * format_integer(u8 *s, u64 number, format_integer_options_t *options)
Definition: format.c:485
#define vec_resize(V, N)
Resize a vector (no header, unspecified alignment) Add N elements to end of given vector V...
Definition: vec.h:240
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:687
static f64 f64_up(uword sign, word expon, u64 fraction)
Definition: format.c:552
#define v
Definition: acl.c:491
signed long i64
Definition: types.h:82
word fformat(FILE *f, char *fmt,...)
Definition: format.c:453
svmdb_client_t * c
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:339
static f64 normalize(f64 x, word *expon_return, f64 *prec_return)
Definition: format.c:626
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:541
static u8 * add_some_zeros(u8 *s, uword n_zeros)
Definition: format.c:670
#define BITS(x)
Definition: clib.h:58
CLIB vectors are ubiquitous dynamically resized arrays with by user defined "headers".