cb6cb455eaa1249bfc948440ef853d2f0cadb25c
[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           clib_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           clib_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 #ifdef __COVERITY__
416   if (s == 0)
417     return (u8 *) "liar liar pants on fire s can't be zero!";
418 #endif
419
420   return s;
421 }
422
423 u8 *
424 format (u8 * s, const char *fmt, ...)
425 {
426   va_list va;
427   va_start (va, fmt);
428   s = va_format (s, fmt, &va);
429   va_end (va);
430 #ifdef __COVERITY__
431   if (s == 0)
432     return (u8 *) "liar liar pants on fire s can't be zero!";
433 #endif
434   return s;
435 }
436
437 word
438 va_fformat (FILE * f, char *fmt, va_list * va)
439 {
440   word ret;
441   u8 *s;
442
443   s = va_format (0, fmt, va);
444
445 #ifdef CLIB_UNIX
446   if (f)
447     {
448       ret = fwrite (s, vec_len (s), 1, f);
449     }
450   else
451 #endif /* CLIB_UNIX */
452     {
453       ret = 0;
454       os_puts (s, vec_len (s), /* is_error */ 0);
455     }
456
457   vec_free (s);
458   return ret;
459 }
460
461 word
462 fformat (FILE * f, char *fmt, ...)
463 {
464   va_list va;
465   word ret;
466
467   va_start (va, fmt);
468   ret = va_fformat (f, fmt, &va);
469   va_end (va);
470
471   return (ret);
472 }
473
474 #ifdef CLIB_UNIX
475 void
476 fformat_append_cr (FILE * ofp, const char *fmt, ...)
477 {
478   va_list va;
479
480   va_start (va, fmt);
481   (void) va_fformat (ofp, (char *) fmt, &va);
482   va_end (va);
483   fformat (ofp, "\n");
484 }
485
486 word
487 fdformat (int fd, char *fmt, ...)
488 {
489   word ret;
490   u8 *s;
491   va_list va;
492
493   va_start (va, fmt);
494   s = va_format (0, fmt, &va);
495   va_end (va);
496
497   ret = write (fd, s, vec_len (s));
498   vec_free (s);
499   return ret;
500 }
501 #endif
502
503 /* Format integral type. */
504 static u8 *
505 format_integer (u8 * s, u64 number, format_integer_options_t * options)
506 {
507   u64 q;
508   u32 r;
509   u8 digit_buffer[128];
510   u8 *d = digit_buffer + sizeof (digit_buffer);
511   word c, base;
512
513   if (options->is_signed && (i64) number < 0)
514     {
515       number = -number;
516       vec_add1 (s, '-');
517     }
518
519   if (options->n_bits < BITS (number))
520     number &= ((u64) 1 << options->n_bits) - 1;
521
522   base = options->base;
523
524   while (1)
525     {
526       q = number / base;
527       r = number % base;
528
529       if (r < 10 + 26 + 26)
530         {
531           if (r < 10)
532             c = '0' + r;
533           else if (r < 10 + 26)
534             c = 'a' + (r - 10);
535           else
536             c = 'A' + (r - 10 - 26);
537
538           if (options->uppercase_digits
539               && base <= 10 + 26 && c >= 'a' && c <= 'z')
540             c += 'A' - 'a';
541
542           *--d = c;
543         }
544       else                      /* will never happen, warning be gone */
545         {
546           *--d = '?';
547         }
548
549       if (q == 0)
550         break;
551
552       number = q;
553     }
554
555   vec_add (s, d, digit_buffer + sizeof (digit_buffer) - d);
556   return s;
557 }
558
559 /* Floating point formatting. */
560 /* Deconstruct IEEE 64 bit number into sign exponent and fraction. */
561 #define f64_down(f,sign,expon,fraction)                         \
562 do {                                                            \
563   union { u64 u; f64 f; } _f64_down_tmp;                        \
564   _f64_down_tmp.f = (f);                                        \
565   (sign) = (_f64_down_tmp.u >> 63);                             \
566   (expon) = ((_f64_down_tmp.u >> 52) & 0x7ff) - 1023;           \
567   (fraction) = ((_f64_down_tmp.u << 12) >> 12) | ((u64) 1 << 52); \
568 } while (0)
569
570 /* Construct IEEE 64 bit number. */
571 static f64
572 f64_up (uword sign, word expon, u64 fraction)
573 {
574   union
575   {
576     u64 u;
577     f64 f;
578   } tmp;
579
580   tmp.u = (u64) ((sign) != 0) << 63;
581
582   expon += 1023;
583   if (expon > 1023)
584     expon = 1023;
585   if (expon < 0)
586     expon = 0;
587   tmp.u |= (u64) expon << 52;
588
589   tmp.u |= fraction & (((u64) 1 << 52) - 1);
590
591   return tmp.f;
592 }
593
594 /* Returns approximate precision of number given its exponent. */
595 static f64
596 f64_precision (int base2_expon)
597 {
598   static int n_bits = 0;
599
600   if (!n_bits)
601     {
602       /* Compute number of significant bits in floating point representation. */
603       f64 one = 0;
604       f64 small = 1;
605
606       while (one != 1)
607         {
608           small *= .5;
609           n_bits++;
610           one = 1 + small;
611         }
612     }
613
614   return f64_up (0, base2_expon - n_bits, 0);
615 }
616
617 /* Return x 10^n */
618 static f64
619 times_power_of_ten (f64 x, int n)
620 {
621   if (n >= 0)
622     {
623       static f64 t[8] = { 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, };
624       while (n >= 8)
625         {
626           x *= 1e+8;
627           n -= 8;
628         }
629       return x * t[n];
630     }
631   else
632     {
633       static f64 t[8] = { 1e-0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, };
634       while (n <= -8)
635         {
636           x *= 1e-8;
637           n += 8;
638         }
639       return x * t[-n];
640     }
641
642 }
643
644 /* Write x = y * 10^expon with 1 < y < 10. */
645 static f64
646 normalize (f64 x, word * expon_return, f64 * prec_return)
647 {
648   word expon2, expon10;
649   CLIB_UNUSED (u64 fraction);
650   CLIB_UNUSED (word sign);
651   f64 prec;
652
653   f64_down (x, sign, expon2, fraction);
654
655   expon10 =
656     .5 +
657     expon2 * .301029995663981195213738894724493 /* Log (2) / Log (10) */ ;
658
659   prec = f64_precision (expon2);
660   x = times_power_of_ten (x, -expon10);
661   prec = times_power_of_ten (prec, -expon10);
662
663   while (x < 1)
664     {
665       x *= 10;
666       prec *= 10;
667       expon10--;
668     }
669
670   while (x > 10)
671     {
672       x *= .1;
673       prec *= .1;
674       expon10++;
675     }
676
677   if (x + prec >= 10)
678     {
679       x = 1;
680       expon10++;
681     }
682
683   *expon_return = expon10;
684   *prec_return = prec;
685
686   return x;
687 }
688
689 static u8 *
690 add_some_zeros (u8 * s, uword n_zeros)
691 {
692   while (n_zeros > 0)
693     {
694       vec_add1 (s, '0');
695       n_zeros--;
696     }
697   return s;
698 }
699
700 /* Format a floating point number with the given number of fractional
701    digits (e.g. 1.2345 with 2 fraction digits yields "1.23") and output style. */
702 static u8 *
703 format_float (u8 * s, f64 x, uword n_fraction_digits, uword output_style)
704 {
705   f64 prec;
706   word sign, expon, n_fraction_done, added_decimal_point;
707   /* Position of decimal point relative to where we are. */
708   word decimal_point;
709
710   /* Default number of digits to print when its not specified. */
711   if (n_fraction_digits == ~0)
712     n_fraction_digits = 7;
713   n_fraction_done = 0;
714   decimal_point = 0;
715   added_decimal_point = 0;
716   sign = expon = 0;
717
718   /* Special case: zero. */
719   if (x == 0)
720     {
721     do_zero:
722       vec_add1 (s, '0');
723       goto done;
724     }
725
726   if (x < 0)
727     {
728       x = -x;
729       sign = 1;
730     }
731
732   /* Check for not-a-number. */
733   if (isnan (x))
734     return format (s, "%cNaN", sign ? '-' : '+');
735
736   /* Check for infinity. */
737   if (isinf (x))
738     return format (s, "%cinfinity", sign ? '-' : '+');
739
740   x = normalize (x, &expon, &prec);
741
742   /* Not enough digits to print anything: so just print 0 */
743   if ((word) - expon > (word) n_fraction_digits
744       && (output_style == 'f' || (output_style == 'g')))
745     goto do_zero;
746
747   if (sign)
748     vec_add1 (s, '-');
749
750   if (output_style == 'f'
751       || (output_style == 'g' && expon > -10 && expon < 10))
752     {
753       if (expon < 0)
754         {
755           /* Add decimal point and leading zeros. */
756           vec_add1 (s, '.');
757           n_fraction_done = clib_min (-(expon + 1), n_fraction_digits);
758           s = add_some_zeros (s, n_fraction_done);
759           decimal_point = -n_fraction_done;
760           added_decimal_point = 1;
761         }
762       else
763         decimal_point = expon + 1;
764     }
765   else
766     {
767       /* Exponential output style. */
768       decimal_point = 1;
769       output_style = 'e';
770     }
771
772   while (1)
773     {
774       uword digit;
775
776       /* Number is smaller than precision: call it zero. */
777       if (x < prec)
778         break;
779
780       digit = x;
781       x -= digit;
782       if (x + prec >= 1)
783         {
784           digit++;
785           x -= 1;
786         }
787
788       /* Round last printed digit. */
789       if (decimal_point <= 0
790           && n_fraction_done + 1 == n_fraction_digits && digit < 9)
791         digit += x >= .5;
792
793       vec_add1 (s, '0' + digit);
794
795       /* Move rightwards towards/away from decimal point. */
796       decimal_point--;
797
798       n_fraction_done += decimal_point < 0;
799       if (decimal_point <= 0 && n_fraction_done >= n_fraction_digits)
800         break;
801
802       if (decimal_point == 0 && x != 0)
803         {
804           vec_add1 (s, '.');
805           added_decimal_point = 1;
806         }
807
808       x *= 10;
809       prec *= 10;
810     }
811
812 done:
813   if (decimal_point > 0)
814     {
815       s = add_some_zeros (s, decimal_point);
816       decimal_point = 0;
817     }
818
819   if (n_fraction_done < n_fraction_digits)
820     {
821       if (!added_decimal_point)
822         vec_add1 (s, '.');
823       s = add_some_zeros (s, n_fraction_digits - n_fraction_done);
824     }
825
826   if (output_style == 'e')
827     s = format (s, "e%wd", expon);
828
829   return s;
830 }
831
832
833 /*
834  * fd.io coding-style-patch-verification: ON
835  *
836  * Local Variables:
837  * eval: (c-set-style "gnu")
838  * End:
839  */