FD.io VPP  v17.01.1-3-gc6833f8
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 
66 typedef struct
67 {
68  /* Output number in this base. */
70 
71  /* Number of show of 64 bit number. */
73 
74  /* Signed or unsigned. */
76 
77  /* Output digits uppercase (not lowercase) %X versus %x. */
80 
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,
84  uword output_style);
85 
86 typedef struct
87 {
88  /* String justification: + => right, - => left, = => center. */
90 
91  /* Width of string (before and after decimal point for numbers).
92  0 => natural width. */
93  uword width[2];
94 
95  /* Long => 'l', long long 'L', int 0. */
97 
98  /* Pad character. Defaults to space. */
100 } format_info_t;
101 
102 static u8 *
103 justify (u8 * s, format_info_t * fi, uword s_len_orig)
104 {
105  uword i0, l0, l1;
106 
107  i0 = s_len_orig;
108  l0 = i0 + fi->width[0];
109  l1 = vec_len (s);
110 
111  /* If width is zero user returned width. */
112  if (l0 == i0)
113  l0 = l1;
114 
115  if (l1 > l0)
116  _vec_len (s) = l0;
117  else if (l0 > l1)
118  {
119  uword n = l0 - l1;
120  uword n_left = 0, n_right = 0;
121 
122  switch (fi->justify)
123  {
124  case '-':
125  n_right = n;
126  break;
127 
128  case '+':
129  n_left = n;
130  break;
131 
132  case '=':
133  n_right = n_left = n / 2;
134  if (n % 2)
135  n_left++;
136  break;
137  }
138  if (n_left > 0)
139  {
140  vec_insert (s, n_left, i0);
141  memset (s + i0, fi->pad_char, n_left);
142  l1 = vec_len (s);
143  }
144  if (n_right > 0)
145  {
146  vec_resize (s, n_right);
147  memset (s + l1, fi->pad_char, n_right);
148  }
149  }
150  return s;
151 }
152 
153 static u8 *
154 do_percent (u8 ** _s, u8 * fmt, va_list * va)
155 {
156  u8 *s = *_s;
157  uword c;
158 
159  u8 *f = fmt;
160 
161  format_info_t fi = {
162  .justify = '+',
163  .width = {0},
164  .pad_char = ' ',
165  .how_long = 0,
166  };
167 
168  uword i;
169 
170  ASSERT (f[0] == '%');
171 
172  switch (c = *++f)
173  {
174  case '%':
175  /* %% => % */
176  vec_add1 (s, c);
177  f++;
178  goto done;
179 
180  case '-':
181  case '+':
182  case '=':
183  fi.justify = c;
184  c = *++f;
185  break;
186  }
187 
188  /* Parse width0 . width1. */
189  {
190  uword is_first_digit = 1;
191 
192  fi.width[0] = fi.width[1] = 0;
193  for (i = 0; i < 2; i++)
194  {
195  if (c == '0' && i == 0 && is_first_digit)
196  fi.pad_char = '0';
197  is_first_digit = 0;
198  if (c == '*')
199  {
200  fi.width[i] = va_arg (*va, int);
201  c = *++f;
202  }
203  else
204  {
205  while (c >= '0' && c <= '9')
206  {
207  fi.width[i] = 10 * fi.width[i] + (c - '0');
208  c = *++f;
209  }
210  }
211  if (c != '.')
212  break;
213  c = *++f;
214  }
215  }
216 
217  /* Parse %l* and %L* */
218  switch (c)
219  {
220  case 'w':
221  /* word format. */
222  fi.how_long = 'w';
223  c = *++f;
224  break;
225 
226  case 'L':
227  case 'l':
228  fi.how_long = c;
229  c = *++f;
230  if (c == 'l' && *f == 'l')
231  {
232  fi.how_long = 'L';
233  c = *++f;
234  }
235  break;
236  }
237 
238  /* Finally we are ready for format letter. */
239  if (c != 0)
240  {
241  uword s_initial_len = vec_len (s);
243  .is_signed = 0,
244  .base = 10,
245  .n_bits = BITS (uword),
246  .uppercase_digits = 0,
247  };
248 
249  f++;
250 
251  switch (c)
252  {
253  default:
254  {
255  /* Try to give a helpful error message. */
256  vec_free (s);
257  s = format (s, "**** CLIB unknown format `%%%c' ****", c);
258  goto done;
259  }
260 
261  case 'c':
262  vec_add1 (s, va_arg (*va, int));
263  break;
264 
265  case 'p':
266  vec_add1 (s, '0');
267  vec_add1 (s, 'x');
268 
269  o.is_signed = 0;
270  o.n_bits = BITS (uword *);
271  o.base = 16;
272  o.uppercase_digits = 0;
273 
274  s = format_integer (s, pointer_to_uword (va_arg (*va, void *)), &o);
275  break;
276 
277  case 'x':
278  case 'X':
279  case 'u':
280  case 'd':
281  {
282  u64 number;
283 
284  o.base = 10;
285  if (c == 'x' || c == 'X')
286  o.base = 16;
287  o.is_signed = c == 'd';
288  o.uppercase_digits = c == 'X';
289 
290  switch (fi.how_long)
291  {
292  case 'L':
293  number = va_arg (*va, unsigned long long);
294  o.n_bits = BITS (unsigned long long);
295  break;
296 
297  case 'l':
298  number = va_arg (*va, long);
299  o.n_bits = BITS (long);
300  break;
301 
302  case 'w':
303  number = va_arg (*va, word);
304  o.n_bits = BITS (uword);
305  break;
306 
307  default:
308  number = va_arg (*va, int);
309  o.n_bits = BITS (int);
310  break;
311  }
312 
313  s = format_integer (s, number, &o);
314  }
315  break;
316 
317  case 's':
318  case 'S':
319  {
320  char *cstring = va_arg (*va, char *);
321  uword len;
322 
323  if (!cstring)
324  {
325  cstring = "(nil)";
326  len = 5;
327  }
328  else if (fi.width[1] != 0)
329  len = clib_min (strlen (cstring), fi.width[1]);
330  else
331  len = strlen (cstring);
332 
333  /* %S => format string as C identifier (replace _ with space). */
334  if (c == 'S')
335  {
336  for (i = 0; i < len; i++)
337  vec_add1 (s, cstring[i] == '_' ? ' ' : cstring[i]);
338  }
339  else
340  vec_add (s, cstring, len);
341  }
342  break;
343 
344  case 'v':
345  {
346  u8 *v = va_arg (*va, u8 *);
347  uword len;
348 
349  if (fi.width[1] != 0)
350  len = clib_min (vec_len (v), fi.width[1]);
351  else
352  len = vec_len (v);
353 
354  vec_add (s, v, len);
355  }
356  break;
357 
358  case 'f':
359  case 'g':
360  case 'e':
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);
364  break;
365 
366  case 'U':
367  /* User defined function. */
368  {
369  typedef u8 *(user_func_t) (u8 * s, va_list * args);
370  user_func_t *u = va_arg (*va, user_func_t *);
371 
372  s = (*u) (s, va);
373  }
374  break;
375  }
376 
377  s = justify (s, &fi, s_initial_len);
378  }
379 
380 done:
381  *_s = s;
382  return f;
383 }
384 
385 u8 *
386 va_format (u8 * s, const char *fmt, va_list * va)
387 {
388  u8 *f = (u8 *) fmt, *g;
389  u8 c;
390 
391  g = f;
392  while (1)
393  {
394  c = *f;
395 
396  if (!c)
397  break;
398 
399  if (c == '%')
400  {
401  if (f > g)
402  vec_add (s, g, f - g);
403  f = g = do_percent (&s, f, va);
404  }
405  else
406  {
407  f++;
408  }
409  }
410 
411  if (f > g)
412  vec_add (s, g, f - g);
413 
414  return s;
415 }
416 
417 u8 *
418 format (u8 * s, const char *fmt, ...)
419 {
420  va_list va;
421  va_start (va, fmt);
422  s = va_format (s, fmt, &va);
423  va_end (va);
424  return s;
425 }
426 
427 word
428 va_fformat (FILE * f, char *fmt, va_list * va)
429 {
430  word ret;
431  u8 *s;
432 
433  s = va_format (0, fmt, va);
434 
435 #ifdef CLIB_UNIX
436  if (f)
437  {
438  ret = fwrite (s, vec_len (s), 1, f);
439  }
440  else
441 #endif /* CLIB_UNIX */
442  {
443  ret = 0;
444  os_puts (s, vec_len (s), /* is_error */ 0);
445  }
446 
447  vec_free (s);
448  return ret;
449 }
450 
451 word
452 fformat (FILE * f, char *fmt, ...)
453 {
454  va_list va;
455  word ret;
456 
457  va_start (va, fmt);
458  ret = va_fformat (f, fmt, &va);
459  va_end (va);
460 
461  return (ret);
462 }
463 
464 #ifdef CLIB_UNIX
465 word
466 fdformat (int fd, char *fmt, ...)
467 {
468  word ret;
469  u8 *s;
470  va_list va;
471 
472  va_start (va, fmt);
473  s = va_format (0, fmt, &va);
474  va_end (va);
475 
476  ret = write (fd, s, vec_len (s));
477  vec_free (s);
478  return ret;
479 }
480 #endif
481 
482 /* Format integral type. */
483 static u8 *
485 {
486  u64 q;
487  u32 r;
488  u8 digit_buffer[128];
489  u8 *d = digit_buffer + sizeof (digit_buffer);
490  word c, base;
491 
492  if (options->is_signed && (i64) number < 0)
493  {
494  number = -number;
495  vec_add1 (s, '-');
496  }
497 
498  if (options->n_bits < BITS (number))
499  number &= ((u64) 1 << options->n_bits) - 1;
500 
501  base = options->base;
502 
503  while (1)
504  {
505  q = number / base;
506  r = number % base;
507 
508  if (r < 10 + 26 + 26)
509  {
510  if (r < 10)
511  c = '0' + r;
512  else if (r < 10 + 26)
513  c = 'a' + (r - 10);
514  else
515  c = 'A' + (r - 10 - 26);
516 
517  if (options->uppercase_digits
518  && base <= 10 + 26 && c >= 'a' && c <= 'z')
519  c += 'A' - 'a';
520 
521  *--d = c;
522  }
523  else /* will never happen, warning be gone */
524  {
525  *--d = '?';
526  }
527 
528  if (q == 0)
529  break;
530 
531  number = q;
532  }
533 
534  vec_add (s, d, digit_buffer + sizeof (digit_buffer) - d);
535  return s;
536 }
537 
538 /* Floating point formatting. */
539 /* Deconstruct IEEE 64 bit number into sign exponent and fraction. */
540 #define f64_down(f,sign,expon,fraction) \
541 do { \
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); \
547 } while (0)
548 
549 /* Construct IEEE 64 bit number. */
550 static f64
551 f64_up (uword sign, word expon, u64 fraction)
552 {
553  union
554  {
555  u64 u;
556  f64 f;
557  } tmp;
558 
559  tmp.u = (u64) ((sign) != 0) << 63;
560 
561  expon += 1023;
562  if (expon > 1023)
563  expon = 1023;
564  if (expon < 0)
565  expon = 0;
566  tmp.u |= (u64) expon << 52;
567 
568  tmp.u |= fraction & (((u64) 1 << 52) - 1);
569 
570  return tmp.f;
571 }
572 
573 /* Returns approximate precision of number given its exponent. */
574 static f64
575 f64_precision (int base2_expon)
576 {
577  static int n_bits = 0;
578 
579  if (!n_bits)
580  {
581  /* Compute number of significant bits in floating point representation. */
582  f64 one = 0;
583  f64 small = 1;
584 
585  while (one != 1)
586  {
587  small *= .5;
588  n_bits++;
589  one = 1 + small;
590  }
591  }
592 
593  return f64_up (0, base2_expon - n_bits, 0);
594 }
595 
596 /* Return x 10^n */
597 static f64
599 {
600  if (n >= 0)
601  {
602  static f64 t[8] = { 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, };
603  while (n >= 8)
604  {
605  x *= 1e+8;
606  n -= 8;
607  }
608  return x * t[n];
609  }
610  else
611  {
612  static f64 t[8] = { 1e-0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, };
613  while (n <= -8)
614  {
615  x *= 1e-8;
616  n += 8;
617  }
618  return x * t[-n];
619  }
620 
621 }
622 
623 /* Write x = y * 10^expon with 1 < y < 10. */
624 static f64
625 normalize (f64 x, word * expon_return, f64 * prec_return)
626 {
627  word expon2, expon10;
628  CLIB_UNUSED (u64 fraction);
629  CLIB_UNUSED (word sign);
630  f64 prec;
631 
632  f64_down (x, sign, expon2, fraction);
633 
634  expon10 =
635  .5 +
636  expon2 * .301029995663981195213738894724493 /* Log (2) / Log (10) */ ;
637 
638  prec = f64_precision (expon2);
639  x = times_power_of_ten (x, -expon10);
640  prec = times_power_of_ten (prec, -expon10);
641 
642  while (x < 1)
643  {
644  x *= 10;
645  prec *= 10;
646  expon10--;
647  }
648 
649  while (x > 10)
650  {
651  x *= .1;
652  prec *= .1;
653  expon10++;
654  }
655 
656  if (x + prec >= 10)
657  {
658  x = 1;
659  expon10++;
660  }
661 
662  *expon_return = expon10;
663  *prec_return = prec;
664 
665  return x;
666 }
667 
668 static u8 *
669 add_some_zeros (u8 * s, uword n_zeros)
670 {
671  while (n_zeros > 0)
672  {
673  vec_add1 (s, '0');
674  n_zeros--;
675  }
676  return s;
677 }
678 
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. */
681 static u8 *
682 format_float (u8 * s, f64 x, uword n_fraction_digits, uword output_style)
683 {
684  f64 prec;
685  word sign, expon, n_fraction_done, added_decimal_point;
686  /* Position of decimal point relative to where we are. */
687  word decimal_point;
688 
689  /* Default number of digits to print when its not specified. */
690  if (n_fraction_digits == ~0)
691  n_fraction_digits = 7;
692  n_fraction_done = 0;
693  decimal_point = 0;
694  added_decimal_point = 0;
695  sign = expon = 0;
696 
697  /* Special case: zero. */
698  if (x == 0)
699  {
700  do_zero:
701  vec_add1 (s, '0');
702  goto done;
703  }
704 
705  if (x < 0)
706  {
707  x = -x;
708  sign = 1;
709  }
710 
711  /* Check for infinity. */
712  if (x == x / 2)
713  return format (s, "%cinfinity", sign ? '-' : '+');
714 
715  x = normalize (x, &expon, &prec);
716 
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')))
720  goto do_zero;
721 
722  if (sign)
723  vec_add1 (s, '-');
724 
725  if (output_style == 'f'
726  || (output_style == 'g' && expon > -10 && expon < 10))
727  {
728  if (expon < 0)
729  {
730  /* Add decimal point and leading zeros. */
731  vec_add1 (s, '.');
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;
736  }
737  else
738  decimal_point = expon + 1;
739  }
740  else
741  {
742  /* Exponential output style. */
743  decimal_point = 1;
744  output_style = 'e';
745  }
746 
747  while (1)
748  {
749  uword digit;
750 
751  /* Number is smaller than precision: call it zero. */
752  if (x < prec)
753  break;
754 
755  digit = x;
756  x -= digit;
757  if (x + prec >= 1)
758  {
759  digit++;
760  x -= 1;
761  }
762 
763  /* Round last printed digit. */
764  if (decimal_point <= 0
765  && n_fraction_done + 1 == n_fraction_digits && digit < 9)
766  digit += x >= .5;
767 
768  vec_add1 (s, '0' + digit);
769 
770  /* Move rightwards towards/away from decimal point. */
771  decimal_point--;
772 
773  n_fraction_done += decimal_point < 0;
774  if (decimal_point <= 0 && n_fraction_done >= n_fraction_digits)
775  break;
776 
777  if (decimal_point == 0 && x != 0)
778  {
779  vec_add1 (s, '.');
780  added_decimal_point = 1;
781  }
782 
783  x *= 10;
784  prec *= 10;
785  }
786 
787 done:
788  if (decimal_point > 0)
789  {
790  s = add_some_zeros (s, decimal_point);
791  decimal_point = 0;
792  }
793 
794  if (n_fraction_done < n_fraction_digits)
795  {
796  if (!added_decimal_point)
797  vec_add1 (s, '.');
798  s = add_some_zeros (s, n_fraction_digits - n_fraction_done);
799  }
800 
801  if (output_style == 'e')
802  s = format (s, "e%wd", expon);
803 
804  return s;
805 }
806 
807 
808 /*
809  * fd.io coding-style-patch-verification: ON
810  *
811  * Local Variables:
812  * eval: (c-set-style "gnu")
813  * End:
814  */
#define f64_down(f, sign, expon, fraction)
Definition: format.c:540
static u8 * do_percent(u8 **_s, u8 *fmt, va_list *va)
Definition: format.c:154
static u8 * add_some_zeros(u8 *s, uword n_zeros)
Definition: format.c:669
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
#define clib_min(x, y)
Definition: clib.h:326
#define CLIB_UNUSED(x)
Definition: clib.h:79
u8 * va_format(u8 *s, const char *fmt, va_list *va)
Definition: format.c:386
static f64 f64_precision(int base2_expon)
Definition: format.c:575
void os_puts(u8 *string, uword length, uword is_error)
Definition: unix-misc.c:189
word va_fformat(FILE *f, char *fmt, va_list *va)
Definition: format.c:428
static f64 f64_up(uword sign, word expon, u64 fraction)
Definition: format.c:551
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
uword justify
Definition: format.c:89
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:559
static u8 * format_float(u8 *s, f64 x, uword n_digits_to_print, uword output_style)
Definition: format.c:682
unsigned long u64
Definition: types.h:89
#define vec_resize(V, N)
Resize a vector (no header, unspecified alignment) Add N elements to end of given vector V...
Definition: vec.h:201
static uword pointer_to_uword(const void *p)
Definition: types.h:131
#define vec_insert(V, N, M)
Insert N vector elements starting at element M, initialize new elements to zero (no header...
Definition: vec.h:646
#define v
Definition: acl.c:314
word fdformat(int fd, char *fmt,...)
Definition: format.c:466
long i64
Definition: types.h:82
svmdb_client_t * c
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
uword pad_char
Definition: format.c:99
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
static u8 * justify(u8 *s, format_info_t *fi, uword s_len_orig)
Definition: format.c:103
static f64 times_power_of_ten(f64 x, int n)
Definition: format.c:598
static u8 * format_integer(u8 *s, u64 number, format_integer_options_t *options)
Definition: format.c:484
uword how_long
Definition: format.c:96
u64 uword
Definition: types.h:112
i64 word
Definition: types.h:111
uword width[2]
Definition: format.c:93
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
word fformat(FILE *f, char *fmt,...)
Definition: format.c:452
static f64 normalize(f64 x, word *expon_return, f64 *prec_return)
Definition: format.c:625
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
#define BITS(x)
Definition: clib.h:58
CLIB vectors are ubiquitous dynamically resized arrays with by user defined "headers".