dpdk: Add support for Mellanox ConnectX-4 devices
[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
66 typedef struct
67 {
68   /* Output number in this base. */
69   u8 base;
70
71   /* Number of show of 64 bit number. */
72   u8 n_bits;
73
74   /* Signed or unsigned. */
75   u8 is_signed;
76
77   /* Output digits uppercase (not lowercase) %X versus %x. */
78   u8 uppercase_digits;
79 } format_integer_options_t;
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. */
89   uword justify;
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. */
96   uword how_long;
97
98   /* Pad character.  Defaults to space. */
99   uword pad_char;
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);
242       format_integer_options_t o = {
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 *
484 format_integer (u8 * s, u64 number, format_integer_options_t * options)
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
598 times_power_of_ten (f64 x, int n)
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  */