Initial commit of vpp code.
[vpp.git] / vppinfra / 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     /* Output number in this base. */
68     u8 base;
69
70     /* Number of show of 64 bit number. */
71     u8 n_bits;
72
73     /* Signed or unsigned. */
74     u8 is_signed;
75
76     /* Output digits uppercase (not lowercase) %X versus %x. */
77     u8 uppercase_digits;
78 } format_integer_options_t;
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. */
85   uword justify;
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. */
92   uword how_long;
93
94   /* Pad character.  Defaults to space. */
95   uword pad_char;
96 } format_info_t;
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);
232       format_integer_options_t o = {
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 *
655 format_float (u8 * s, f64 x,
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