LCOV - code coverage report
Current view: top level - vppinfra - format.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 306 347 88.2 %
Date: 2023-07-05 22:20:52 Functions: 13 15 86.7 %

          Line data    Source code
       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   245473000 : justify (u8 * s, format_info_t * fi, uword s_len_orig)
     105             : {
     106             :   uword i0, l0, l1;
     107             : 
     108   245473000 :   i0 = s_len_orig;
     109   245473000 :   l0 = i0 + fi->width[0];
     110   245473000 :   l1 = vec_len (s);
     111             : 
     112             :   /* If width is zero user returned width. */
     113   245473000 :   if (l0 == i0)
     114   129278000 :     l0 = l1;
     115             : 
     116   245473000 :   if (l1 > l0)
     117       27632 :     vec_set_len (s, l0);
     118   245445000 :   else if (l0 > l1)
     119             :     {
     120    56123900 :       uword n = l0 - l1;
     121    56123900 :       uword n_left = 0, n_right = 0;
     122             : 
     123    56123900 :       switch (fi->justify)
     124             :         {
     125      727120 :         case '-':
     126      727120 :           n_right = n;
     127      727120 :           break;
     128             : 
     129    54821800 :         case '+':
     130    54821800 :           n_left = n;
     131    54821800 :           break;
     132             : 
     133      575003 :         case '=':
     134      575003 :           n_right = n_left = n / 2;
     135      575003 :           if (n % 2)
     136      248842 :             n_left++;
     137      575003 :           break;
     138             :         }
     139    56123900 :       if (n_left > 0)
     140             :         {
     141    55396800 :           vec_insert (s, n_left, i0);
     142    55396800 :           clib_memset (s + i0, fi->pad_char, n_left);
     143    55396800 :           l1 = vec_len (s);
     144             :         }
     145    56123900 :       if (n_right > 0)
     146             :         {
     147     1299010 :           vec_resize (s, n_right);
     148     1299010 :           clib_memset (s + l1, fi->pad_char, n_right);
     149             :         }
     150             :     }
     151   245473000 :   return s;
     152             : }
     153             : 
     154             : static const u8 *
     155   248483000 : do_percent (u8 ** _s, const u8 * fmt, va_list * va)
     156             : {
     157   248483000 :   u8 *s = *_s;
     158             :   uword c;
     159             : 
     160   248483000 :   const u8 *f = fmt;
     161             : 
     162   248483000 :   format_info_t fi = {
     163             :     .justify = '+',
     164             :     .width = {0},
     165             :     .pad_char = ' ',
     166             :     .how_long = 0,
     167             :   };
     168             : 
     169             :   uword i;
     170             : 
     171   248483000 :   ASSERT (f[0] == '%');
     172             : 
     173   248483000 :   switch (c = *++f)
     174             :     {
     175     3010210 :     case '%':
     176             :       /* %% => % */
     177     3010210 :       vec_add1 (s, c);
     178     3010210 :       f++;
     179     3010210 :       goto done;
     180             : 
     181     1355070 :     case '-':
     182             :     case '+':
     183             :     case '=':
     184     1355070 :       fi.justify = c;
     185     1355070 :       c = *++f;
     186     1355070 :       break;
     187             :     }
     188             : 
     189             :   /* Parse width0 . width1. */
     190   245473000 :   {
     191   245473000 :     uword is_first_digit = 1;
     192             : 
     193   245473000 :     fi.width[0] = fi.width[1] = 0;
     194   245875000 :     for (i = 0; i < 2; i++)
     195             :       {
     196   245875000 :         if (c == '0' && i == 0 && is_first_digit)
     197   113827000 :           fi.pad_char = '0';
     198   245875000 :         is_first_digit = 0;
     199   245875000 :         if (c == '*')
     200             :           {
     201           0 :             fi.width[i] = va_arg (*va, int);
     202           0 :             c = *++f;
     203             :           }
     204             :         else
     205             :           {
     206   478331000 :             while (c >= '0' && c <= '9')
     207             :               {
     208   232456000 :                 fi.width[i] = 10 * fi.width[i] + (c - '0');
     209   232456000 :                 c = *++f;
     210             :               }
     211             :           }
     212   245875000 :         if (c != '.')
     213   245473000 :           break;
     214      402733 :         c = *++f;
     215             :       }
     216             :   }
     217             : 
     218             :   /* Parse %l* and %L* */
     219   245473000 :   switch (c)
     220             :     {
     221      147886 :     case 'w':
     222             :       /* word format. */
     223      147886 :       fi.how_long = 'w';
     224      147886 :       c = *++f;
     225      147886 :       break;
     226             : 
     227      840301 :     case 'L':
     228             :     case 'l':
     229      840301 :       fi.how_long = c;
     230      840301 :       c = *++f;
     231      840301 :       if (c == 'l' && *f == 'l')
     232             :         {
     233      297458 :           fi.how_long = 'L';
     234      297458 :           c = *++f;
     235             :         }
     236      840301 :       break;
     237             :     }
     238             : 
     239             :   /* Finally we are ready for format letter. */
     240   245473000 :   if (c != 0)
     241             :     {
     242   245473000 :       uword s_initial_len = vec_len (s);
     243   245473000 :       format_integer_options_t o = {
     244             :         .is_signed = 0,
     245             :         .base = 10,
     246             :         .n_bits = BITS (uword),
     247             :         .uppercase_digits = 0,
     248             :       };
     249             : 
     250   245473000 :       f++;
     251             : 
     252   245473000 :       switch (c)
     253             :         {
     254           0 :         default:
     255             :           {
     256             :             /* Try to give a helpful error message. */
     257           0 :             vec_free (s);
     258           0 :             s = format (s, "**** CLIB unknown format `%%%c' ****", c);
     259           0 :             goto done;
     260             :           }
     261             : 
     262     4264600 :         case 'c':
     263     4264600 :           vec_add1 (s, va_arg (*va, int));
     264     4264600 :           break;
     265             : 
     266        1417 :         case 'p':
     267        1417 :           vec_add1 (s, '0');
     268        1417 :           vec_add1 (s, 'x');
     269             : 
     270        1417 :           o.is_signed = 0;
     271        1417 :           o.n_bits = BITS (uword *);
     272        1417 :           o.base = 16;
     273        1417 :           o.uppercase_digits = 0;
     274             : 
     275        2834 :           s = format_integer (s, pointer_to_uword (va_arg (*va, void *)), &o);
     276        1417 :           break;
     277             : 
     278   154847000 :         case 'x':
     279             :         case 'X':
     280             :         case 'u':
     281             :         case 'o':
     282             :         case 'd':
     283             :           {
     284             :             u64 number;
     285             : 
     286   154847000 :             o.base = 10;
     287   154847000 :             if (c == 'x' || c == 'X')
     288   104702000 :               o.base = 16;
     289   154847000 :             o.is_signed = c == 'd';
     290   154847000 :             o.uppercase_digits = c == 'X';
     291             : 
     292   154847000 :             switch (fi.how_long)
     293             :               {
     294      779527 :               case 'L':
     295      779527 :                 number = va_arg (*va, unsigned long long);
     296      779527 :                 o.n_bits = BITS (unsigned long long);
     297      779527 :                 break;
     298             : 
     299       60774 :               case 'l':
     300       60774 :                 number = va_arg (*va, long);
     301       60774 :                 o.n_bits = BITS (long);
     302       60774 :                 break;
     303             : 
     304      147886 :               case 'w':
     305      147886 :                 number = va_arg (*va, word);
     306      147886 :                 o.n_bits = BITS (uword);
     307      147886 :                 break;
     308             : 
     309   153859000 :               default:
     310   153859000 :                 number = va_arg (*va, int);
     311   153859000 :                 o.n_bits = BITS (int);
     312   153859000 :                 break;
     313             :               }
     314             : 
     315   154847000 :             if (c == 'o')
     316           0 :               o.base = 8;
     317             : 
     318   154847000 :             s = format_integer (s, number, &o);
     319             :           }
     320   154847000 :           break;
     321             : 
     322    22997900 :         case 's':
     323             :         case 'S':
     324             :           {
     325    22997900 :             char *cstring = va_arg (*va, char *);
     326             :             uword len;
     327             : 
     328    22997900 :             if (!cstring)
     329             :               {
     330       15251 :                 cstring = "(nil)";
     331       15251 :                 len = 5;
     332             :               }
     333    22982700 :             else if (fi.width[1] != 0)
     334           0 :               len = clib_min (strlen (cstring), fi.width[1]);
     335             :             else
     336    22982700 :               len = strlen (cstring);
     337             : 
     338             :             /* %S => format string as C identifier (replace _ with space). */
     339    22997900 :             if (c == 'S')
     340             :               {
     341           0 :                 for (i = 0; i < len; i++)
     342           0 :                   vec_add1 (s, cstring[i] == '_' ? ' ' : cstring[i]);
     343             :               }
     344             :             else
     345    22997900 :               vec_add (s, cstring, len);
     346             :           }
     347    22997900 :           break;
     348             : 
     349    16103600 :         case 'v':
     350             :           {
     351    16103600 :             u8 *v = va_arg (*va, u8 *);
     352             :             uword len;
     353             : 
     354    16103600 :             if (fi.width[1] != 0)
     355           0 :               len = clib_min (vec_len (v), fi.width[1]);
     356             :             else
     357    16103600 :               len = vec_len (v);
     358             : 
     359    16103600 :             vec_add (s, v, len);
     360             :           }
     361    16103600 :           break;
     362             : 
     363      409299 :         case 'f':
     364             :         case 'g':
     365             :         case 'e':
     366             :           /* Floating point. */
     367      409299 :           ASSERT (fi.how_long == 0 || fi.how_long == 'l');
     368      409299 :           s = format_float (s, va_arg (*va, double), fi.width[1], c);
     369      409299 :           break;
     370             : 
     371    46848900 :         case 'U':
     372             :           /* User defined function. */
     373             :           {
     374             :             typedef u8 *(user_func_t) (u8 * s, va_list * args);
     375    46848900 :             user_func_t *u = va_arg (*va, user_func_t *);
     376             : 
     377    46848900 :             s = (*u) (s, va);
     378             :           }
     379    46848900 :           break;
     380             :         }
     381             : 
     382   245473000 :       s = justify (s, &fi, s_initial_len);
     383             :     }
     384             : 
     385           0 : done:
     386   248483000 :   *_s = s;
     387   248483000 :   return f;
     388             : }
     389             : 
     390             : __clib_export u8 *
     391   173831000 : va_format (u8 * s, const char *fmt, va_list * va)
     392             : {
     393   173831000 :   const u8 *f = (u8 *) fmt, *g;
     394             :   u8 c;
     395             : 
     396   173831000 :   g = f;
     397             :   while (1)
     398             :     {
     399   899462000 :       c = *f;
     400             : 
     401   899462000 :       if (!c)
     402   173831000 :         break;
     403             : 
     404   725631000 :       if (c == '%')
     405             :         {
     406   248483000 :           if (f > g)
     407    97428300 :             vec_add (s, g, f - g);
     408   248483000 :           f = g = do_percent (&s, f, va);
     409             :         }
     410             :       else
     411             :         {
     412   477148000 :           f++;
     413             :         }
     414             :     }
     415             : 
     416   173831000 :   if (f > g)
     417    12147600 :     vec_add (s, g, f - g);
     418             : 
     419             : #ifdef __COVERITY__
     420             :   if (s == 0)
     421             :     return (u8 *) "liar liar pants on fire s can't be zero!";
     422             : #endif
     423             : 
     424   173831000 :   return s;
     425             : }
     426             : 
     427             : __clib_export u8 *
     428   166085000 : format (u8 * s, const char *fmt, ...)
     429             : {
     430             :   va_list va;
     431   166085000 :   va_start (va, fmt);
     432   166085000 :   s = va_format (s, fmt, &va);
     433   166085000 :   va_end (va);
     434             : #ifdef __COVERITY__
     435             :   if (s == 0)
     436             :     return (u8 *) "liar liar pants on fire s can't be zero!";
     437             : #endif
     438   166085000 :   return s;
     439             : }
     440             : 
     441             : __clib_export word
     442         966 : va_fformat (FILE * f, char *fmt, va_list * va)
     443             : {
     444             :   word ret;
     445             :   u8 *s;
     446             : 
     447         966 :   s = va_format (0, fmt, va);
     448             : 
     449             : #ifdef CLIB_UNIX
     450         966 :   if (f)
     451             :     {
     452         966 :       ret = fwrite (s, vec_len (s), 1, f);
     453             :     }
     454             :   else
     455             : #endif /* CLIB_UNIX */
     456             :     {
     457           0 :       ret = 0;
     458           0 :       os_puts (s, vec_len (s), /* is_error */ 0);
     459             :     }
     460             : 
     461         966 :   vec_free (s);
     462         966 :   return ret;
     463             : }
     464             : 
     465             : __clib_export word
     466         966 : fformat (FILE * f, char *fmt, ...)
     467             : {
     468             :   va_list va;
     469             :   word ret;
     470             : 
     471         966 :   va_start (va, fmt);
     472         966 :   ret = va_fformat (f, fmt, &va);
     473         966 :   va_end (va);
     474             : 
     475         966 :   return (ret);
     476             : }
     477             : 
     478             : #ifdef CLIB_UNIX
     479             : __clib_export void
     480           0 : fformat_append_cr (FILE * ofp, const char *fmt, ...)
     481             : {
     482             :   va_list va;
     483             : 
     484           0 :   va_start (va, fmt);
     485           0 :   (void) va_fformat (ofp, (char *) fmt, &va);
     486           0 :   va_end (va);
     487           0 :   fformat (ofp, "\n");
     488           0 : }
     489             : 
     490             : __clib_export word
     491           0 : fdformat (int fd, char *fmt, ...)
     492             : {
     493             :   word ret;
     494             :   u8 *s;
     495             :   va_list va;
     496             : 
     497           0 :   va_start (va, fmt);
     498           0 :   s = va_format (0, fmt, &va);
     499           0 :   va_end (va);
     500             : 
     501           0 :   ret = write (fd, s, vec_len (s));
     502           0 :   vec_free (s);
     503           0 :   return ret;
     504             : }
     505             : #endif
     506             : 
     507             : /* Format integral type. */
     508             : static u8 *
     509   154848000 : format_integer (u8 * s, u64 number, format_integer_options_t * options)
     510             : {
     511             :   u64 q;
     512             :   u32 r;
     513             :   u8 digit_buffer[128];
     514   154848000 :   u8 *d = digit_buffer + sizeof (digit_buffer);
     515             :   word c, base;
     516             : 
     517   154848000 :   if (options->is_signed && (i64) number < 0)
     518             :     {
     519      138332 :       number = -number;
     520      138332 :       vec_add1 (s, '-');
     521             :     }
     522             : 
     523   154848000 :   if (options->n_bits < BITS (number))
     524   153859000 :     number &= ((u64) 1 << options->n_bits) - 1;
     525             : 
     526   154848000 :   base = options->base;
     527             : 
     528             :   while (1)
     529             :     {
     530   279917000 :       q = number / base;
     531   279917000 :       r = number % base;
     532             : 
     533   279917000 :       if (r < 10 + 26 + 26)
     534             :         {
     535   279917000 :           if (r < 10)
     536   234843000 :             c = '0' + r;
     537    45074400 :           else if (r < 10 + 26)
     538    45074400 :             c = 'a' + (r - 10);
     539             :           else
     540           0 :             c = 'A' + (r - 10 - 26);
     541             : 
     542   279917000 :           if (options->uppercase_digits
     543        1218 :               && base <= 10 + 26 && c >= 'a' && c <= 'z')
     544          64 :             c += 'A' - 'a';
     545             : 
     546   279917000 :           *--d = c;
     547             :         }
     548             :       else                      /* will never happen, warning be gone */
     549             :         {
     550           0 :           *--d = '?';
     551             :         }
     552             : 
     553   279917000 :       if (q == 0)
     554   154848000 :         break;
     555             : 
     556   125069000 :       number = q;
     557             :     }
     558             : 
     559   154848000 :   vec_add (s, d, digit_buffer + sizeof (digit_buffer) - d);
     560   154848000 :   return s;
     561             : }
     562             : 
     563             : /* Floating point formatting. */
     564             : /* Deconstruct IEEE 64 bit number into sign exponent and fraction. */
     565             : #define f64_down(f,sign,expon,fraction)                         \
     566             : do {                                                            \
     567             :   union { u64 u; f64 f; } _f64_down_tmp;                        \
     568             :   _f64_down_tmp.f = (f);                                        \
     569             :   (sign) = (_f64_down_tmp.u >> 63);                               \
     570             :   (expon) = ((_f64_down_tmp.u >> 52) & 0x7ff) - 1023;         \
     571             :   (fraction) = ((_f64_down_tmp.u << 12) >> 12) | ((u64) 1 << 52); \
     572             : } while (0)
     573             : 
     574             : /* Construct IEEE 64 bit number. */
     575             : static f64
     576      264147 : f64_up (uword sign, word expon, u64 fraction)
     577             : {
     578             :   union
     579             :   {
     580             :     u64 u;
     581             :     f64 f;
     582             :   } tmp;
     583             : 
     584      264147 :   tmp.u = (u64) ((sign) != 0) << 63;
     585             : 
     586      264147 :   expon += 1023;
     587      264147 :   if (expon > 1023)
     588           0 :     expon = 1023;
     589      264147 :   if (expon < 0)
     590           0 :     expon = 0;
     591      264147 :   tmp.u |= (u64) expon << 52;
     592             : 
     593      264147 :   tmp.u |= fraction & (((u64) 1 << 52) - 1);
     594             : 
     595      264147 :   return tmp.f;
     596             : }
     597             : 
     598             : /* Returns approximate precision of number given its exponent. */
     599             : static f64
     600      264147 : f64_precision (int base2_expon)
     601             : {
     602             :   static int n_bits = 0;
     603             : 
     604      264147 :   if (!n_bits)
     605             :     {
     606             :       /* Compute number of significant bits in floating point representation. */
     607         535 :       f64 one = 0;
     608         535 :       f64 small = 1;
     609             : 
     610       28890 :       while (one != 1)
     611             :         {
     612       28355 :           small *= .5;
     613       28355 :           n_bits++;
     614       28355 :           one = 1 + small;
     615             :         }
     616             :     }
     617             : 
     618      264147 :   return f64_up (0, base2_expon - n_bits, 0);
     619             : }
     620             : 
     621             : /* Return x 10^n */
     622             : static f64
     623      528294 : times_power_of_ten (f64 x, int n)
     624             : {
     625      528294 :   if (n >= 0)
     626             :     {
     627             :       static f64 t[8] = { 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, };
     628      106488 :       while (n >= 8)
     629             :         {
     630           0 :           x *= 1e+8;
     631           0 :           n -= 8;
     632             :         }
     633      106488 :       return x * t[n];
     634             :     }
     635             :   else
     636             :     {
     637             :       static f64 t[8] = { 1e-0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, };
     638      422394 :       while (n <= -8)
     639             :         {
     640         588 :           x *= 1e-8;
     641         588 :           n += 8;
     642             :         }
     643      421806 :       return x * t[-n];
     644             :     }
     645             : 
     646             : }
     647             : 
     648             : /* Write x = y * 10^expon with 1 < y < 10. */
     649             : static f64
     650      264147 : normalize (f64 x, word * expon_return, f64 * prec_return)
     651             : {
     652             :   word expon2, expon10;
     653             :   CLIB_UNUSED (u64 fraction);
     654             :   CLIB_UNUSED (word sign);
     655             :   f64 prec;
     656             : 
     657      264147 :   f64_down (x, sign, expon2, fraction);
     658             : 
     659      264147 :   expon10 =
     660      264147 :     .5 +
     661      264147 :     expon2 * .301029995663981195213738894724493 /* Log (2) / Log (10) */ ;
     662             : 
     663      264147 :   prec = f64_precision (expon2);
     664      264147 :   x = times_power_of_ten (x, -expon10);
     665      264147 :   prec = times_power_of_ten (prec, -expon10);
     666             : 
     667      357763 :   while (x < 1)
     668             :     {
     669       93616 :       x *= 10;
     670       93616 :       prec *= 10;
     671       93616 :       expon10--;
     672             :     }
     673             : 
     674      264147 :   while (x > 10)
     675             :     {
     676           0 :       x *= .1;
     677           0 :       prec *= .1;
     678           0 :       expon10++;
     679             :     }
     680             : 
     681      264147 :   if (x + prec >= 10)
     682             :     {
     683           0 :       x = 1;
     684           0 :       expon10++;
     685             :     }
     686             : 
     687      264147 :   *expon_return = expon10;
     688      264147 :   *prec_return = prec;
     689             : 
     690      264147 :   return x;
     691             : }
     692             : 
     693             : static u8 *
     694      185810 : add_some_zeros (u8 * s, uword n_zeros)
     695             : {
     696      551870 :   while (n_zeros > 0)
     697             :     {
     698      366060 :       vec_add1 (s, '0');
     699      366060 :       n_zeros--;
     700             :     }
     701      185810 :   return s;
     702             : }
     703             : 
     704             : /* Format a floating point number with the given number of fractional
     705             :    digits (e.g. 1.2345 with 2 fraction digits yields "1.23") and output style. */
     706             : static u8 *
     707      409299 : format_float (u8 * s, f64 x, uword n_fraction_digits, uword output_style)
     708             : {
     709             :   f64 prec;
     710             :   word sign, expon, n_fraction_done, added_decimal_point;
     711             :   /* Position of decimal point relative to where we are. */
     712             :   word decimal_point;
     713             : 
     714             :   /* Default number of digits to print when its not specified. */
     715      409299 :   if (n_fraction_digits == ~0)
     716           0 :     n_fraction_digits = 7;
     717      409299 :   n_fraction_done = 0;
     718      409299 :   decimal_point = 0;
     719      409299 :   added_decimal_point = 0;
     720      409299 :   sign = expon = 0;
     721             : 
     722             :   /* Special case: zero. */
     723      409299 :   if (x == 0)
     724             :     {
     725      145152 :     do_zero:
     726      145306 :       vec_add1 (s, '0');
     727      145306 :       goto done;
     728             :     }
     729             : 
     730      264147 :   if (x < 0)
     731             :     {
     732           1 :       x = -x;
     733           1 :       sign = 1;
     734             :     }
     735             : 
     736             :   /* Check for not-a-number. */
     737      264147 :   if (isnan (x))
     738           0 :     return format (s, "%cNaN", sign ? '-' : '+');
     739             : 
     740             :   /* Check for infinity. */
     741      264147 :   if (isinf (x))
     742           0 :     return format (s, "%cinfinity", sign ? '-' : '+');
     743             : 
     744      264147 :   x = normalize (x, &expon, &prec);
     745             : 
     746             :   /* Not enough digits to print anything: so just print 0 */
     747      264147 :   if ((word) - expon > (word) n_fraction_digits
     748         154 :       && (output_style == 'f' || (output_style == 'g')))
     749         154 :     goto do_zero;
     750             : 
     751      263993 :   if (sign)
     752           1 :     vec_add1 (s, '-');
     753             : 
     754      263993 :   if (output_style == 'f'
     755      128362 :       || (output_style == 'g' && expon > -10 && expon < 10))
     756             :     {
     757      135631 :       if (expon < 0)
     758             :         {
     759             :           /* Add decimal point and leading zeros. */
     760         520 :           vec_add1 (s, '.');
     761         520 :           n_fraction_done = clib_min (-(expon + 1), n_fraction_digits);
     762         520 :           s = add_some_zeros (s, n_fraction_done);
     763         520 :           decimal_point = -n_fraction_done;
     764         520 :           added_decimal_point = 1;
     765             :         }
     766             :       else
     767      135111 :         decimal_point = expon + 1;
     768             :     }
     769             :   else
     770             :     {
     771             :       /* Exponential output style. */
     772      128362 :       decimal_point = 1;
     773      128362 :       output_style = 'e';
     774             :     }
     775             : 
     776             :   while (1)
     777      666207 :     {
     778             :       uword digit;
     779             : 
     780             :       /* Number is smaller than precision: call it zero. */
     781      930200 :       if (x < prec)
     782       38837 :         break;
     783             : 
     784      891363 :       digit = x;
     785      891363 :       x -= digit;
     786      891363 :       if (x + prec >= 1)
     787             :         {
     788        4214 :           digit++;
     789        4214 :           x -= 1;
     790             :         }
     791             : 
     792             :       /* Round last printed digit. */
     793      891363 :       if (decimal_point <= 0
     794      504562 :           && n_fraction_done + 1 == n_fraction_digits && digit < 9)
     795      199502 :         digit += x >= .5;
     796             : 
     797      891363 :       vec_add1 (s, '0' + digit);
     798             : 
     799             :       /* Move rightwards towards/away from decimal point. */
     800      891363 :       decimal_point--;
     801             : 
     802      891363 :       n_fraction_done += decimal_point < 0;
     803      891363 :       if (decimal_point <= 0 && n_fraction_done >= n_fraction_digits)
     804      225156 :         break;
     805             : 
     806      666207 :       if (decimal_point == 0 && x != 0)
     807             :         {
     808      232069 :           vec_add1 (s, '.');
     809      232069 :           added_decimal_point = 1;
     810             :         }
     811             : 
     812      666207 :       x *= 10;
     813      666207 :       prec *= 10;
     814             :     }
     815             : 
     816      409299 : done:
     817      409299 :   if (decimal_point > 0)
     818             :     {
     819        3249 :       s = add_some_zeros (s, decimal_point);
     820        3249 :       decimal_point = 0;
     821             :     }
     822             : 
     823      409299 :   if (n_fraction_done < n_fraction_digits)
     824             :     {
     825      182041 :       if (!added_decimal_point)
     826      170142 :         vec_add1 (s, '.');
     827      182041 :       s = add_some_zeros (s, n_fraction_digits - n_fraction_done);
     828             :     }
     829             : 
     830      409299 :   if (output_style == 'e')
     831      146562 :     s = format (s, "e%wd", expon);
     832             : 
     833      409299 :   return s;
     834             : }
     835             : 
     836             : 
     837             : /*
     838             :  * fd.io coding-style-patch-verification: ON
     839             :  *
     840             :  * Local Variables:
     841             :  * eval: (c-set-style "gnu")
     842             :  * End:
     843             :  */

Generated by: LCOV version 1.14