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