lisp-cp: fix handling of ndp without source link addr VPP-1159
[vpp.git] / src / vppinfra / format.c
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. */
70   u8 base;
71
72   /* Number of show of 64 bit number. */
73   u8 n_bits;
74
75   /* Signed or unsigned. */
76   u8 is_signed;
77
78   /* Output digits uppercase (not lowercase) %X versus %x. */
79   u8 uppercase_digits;
80 } format_integer_options_t;
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. */
90   uword justify;
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. */
97   uword how_long;
98
99   /* Pad character.  Defaults to space. */
100   uword pad_char;
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);
243       format_integer_options_t o = {
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 *
485 format_integer (u8 * s, u64 number, format_integer_options_t * options)
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
599 times_power_of_ten (f64 x, int n)
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  */