LCOV - code coverage report
Current view: top level - vppinfra - format.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 307 347 88.5 %
Date: 2023-10-26 01:39:38 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   265098000 : justify (u8 * s, format_info_t * fi, uword s_len_orig)
     105             : {
     106             :   uword i0, l0, l1;
     107             : 
     108   265098000 :   i0 = s_len_orig;
     109   265098000 :   l0 = i0 + fi->width[0];
     110   265098000 :   l1 = vec_len (s);
     111             : 
     112             :   /* If width is zero user returned width. */
     113   265098000 :   if (l0 == i0)
     114   139783000 :     l0 = l1;
     115             : 
     116   265098000 :   if (l1 > l0)
     117       28610 :     vec_set_len (s, l0);
     118   265069000 :   else if (l0 > l1)
     119             :     {
     120    60308900 :       uword n = l0 - l1;
     121    60308900 :       uword n_left = 0, n_right = 0;
     122             : 
     123    60308900 :       switch (fi->justify)
     124             :         {
     125      744724 :         case '-':
     126      744724 :           n_right = n;
     127      744724 :           break;
     128             : 
     129    58961300 :         case '+':
     130    58961300 :           n_left = n;
     131    58961300 :           break;
     132             : 
     133      602934 :         case '=':
     134      602934 :           n_right = n_left = n / 2;
     135      602934 :           if (n % 2)
     136      263746 :             n_left++;
     137      602934 :           break;
     138             :         }
     139    60308900 :       if (n_left > 0)
     140             :         {
     141    59564200 :           vec_insert (s, n_left, i0);
     142    59564200 :           clib_memset (s + i0, fi->pad_char, n_left);
     143    59564200 :           l1 = vec_len (s);
     144             :         }
     145    60308900 :       if (n_right > 0)
     146             :         {
     147     1344450 :           vec_resize (s, n_right);
     148     1344450 :           clib_memset (s + l1, fi->pad_char, n_right);
     149             :         }
     150             :     }
     151   265098000 :   return s;
     152             : }
     153             : 
     154             : static const u8 *
     155   268211000 : do_percent (u8 ** _s, const u8 * fmt, va_list * va)
     156             : {
     157   268211000 :   u8 *s = *_s;
     158             :   uword c;
     159             : 
     160   268211000 :   const u8 *f = fmt;
     161             : 
     162   268211000 :   format_info_t fi = {
     163             :     .justify = '+',
     164             :     .width = {0},
     165             :     .pad_char = ' ',
     166             :     .how_long = 0,
     167             :   };
     168             : 
     169             :   uword i;
     170             : 
     171   268211000 :   ASSERT (f[0] == '%');
     172             : 
     173   268211000 :   switch (c = *++f)
     174             :     {
     175     3113280 :     case '%':
     176             :       /* %% => % */
     177     3113280 :       vec_add1 (s, c);
     178     3113280 :       f++;
     179     3113280 :       goto done;
     180             : 
     181     1401640 :     case '-':
     182             :     case '+':
     183             :     case '=':
     184     1401640 :       fi.justify = c;
     185     1401640 :       c = *++f;
     186     1401640 :       break;
     187             :     }
     188             : 
     189             :   /* Parse width0 . width1. */
     190   265098000 :   {
     191   265098000 :     uword is_first_digit = 1;
     192             : 
     193   265098000 :     fi.width[0] = fi.width[1] = 0;
     194   265506000 :     for (i = 0; i < 2; i++)
     195             :       {
     196   265506000 :         if (c == '0' && i == 0 && is_first_digit)
     197   122877000 :           fi.pad_char = '0';
     198   265506000 :         is_first_digit = 0;
     199   265506000 :         if (c == '*')
     200             :           {
     201           0 :             fi.width[i] = va_arg (*va, int);
     202           0 :             c = *++f;
     203             :           }
     204             :         else
     205             :           {
     206   516200000 :             while (c >= '0' && c <= '9')
     207             :               {
     208   250694000 :                 fi.width[i] = 10 * fi.width[i] + (c - '0');
     209   250694000 :                 c = *++f;
     210             :               }
     211             :           }
     212   265506000 :         if (c != '.')
     213   265098000 :           break;
     214      407796 :         c = *++f;
     215             :       }
     216             :   }
     217             : 
     218             :   /* Parse %l* and %L* */
     219   265098000 :   switch (c)
     220             :     {
     221      150564 :     case 'w':
     222             :       /* word format. */
     223      150564 :       fi.how_long = 'w';
     224      150564 :       c = *++f;
     225      150564 :       break;
     226             : 
     227      859403 :     case 'L':
     228             :     case 'l':
     229      859403 :       fi.how_long = c;
     230      859403 :       c = *++f;
     231      859403 :       if (c == 'l' && *f == 'l')
     232             :         {
     233      303539 :           fi.how_long = 'L';
     234      303539 :           c = *++f;
     235             :         }
     236      859403 :       break;
     237             :     }
     238             : 
     239             :   /* Finally we are ready for format letter. */
     240   265098000 :   if (c != 0)
     241             :     {
     242   265098000 :       uword s_initial_len = vec_len (s);
     243   265098000 :       format_integer_options_t o = {
     244             :         .is_signed = 0,
     245             :         .base = 10,
     246             :         .n_bits = BITS (uword),
     247             :         .uppercase_digits = 0,
     248             :       };
     249             : 
     250   265098000 :       f++;
     251             : 
     252   265098000 :       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           1 :             goto done;
     260             :           }
     261             : 
     262     4246420 :         case 'c':
     263     4246420 :           vec_add1 (s, va_arg (*va, int));
     264     4246420 :           break;
     265             : 
     266        1446 :         case 'p':
     267        1446 :           vec_add1 (s, '0');
     268        1446 :           vec_add1 (s, 'x');
     269             : 
     270        1446 :           o.is_signed = 0;
     271        1446 :           o.n_bits = BITS (uword *);
     272        1446 :           o.base = 16;
     273        1446 :           o.uppercase_digits = 0;
     274             : 
     275        2892 :           s = format_integer (s, pointer_to_uword (va_arg (*va, void *)), &o);
     276        1446 :           break;
     277             : 
     278   168180000 :         case 'x':
     279             :         case 'X':
     280             :         case 'u':
     281             :         case 'o':
     282             :         case 'd':
     283             :           {
     284             :             u64 number;
     285             : 
     286   168180000 :             o.base = 10;
     287   168180000 :             if (c == 'x' || c == 'X')
     288   113179000 :               o.base = 16;
     289   168180000 :             o.is_signed = c == 'd';
     290   168180000 :             o.uppercase_digits = c == 'X';
     291             : 
     292   168180000 :             switch (fi.how_long)
     293             :               {
     294      793327 :               case 'L':
     295      793327 :                 number = va_arg (*va, unsigned long long);
     296      793327 :                 o.n_bits = BITS (unsigned long long);
     297      793327 :                 break;
     298             : 
     299       66076 :               case 'l':
     300       66076 :                 number = va_arg (*va, long);
     301       66076 :                 o.n_bits = BITS (long);
     302       66076 :                 break;
     303             : 
     304      150564 :               case 'w':
     305      150564 :                 number = va_arg (*va, word);
     306      150564 :                 o.n_bits = BITS (uword);
     307      150564 :                 break;
     308             : 
     309   167170000 :               default:
     310   167170000 :                 number = va_arg (*va, int);
     311   167170000 :                 o.n_bits = BITS (int);
     312   167170000 :                 break;
     313             :               }
     314             : 
     315   168180000 :             if (c == 'o')
     316           0 :               o.base = 8;
     317             : 
     318   168180000 :             s = format_integer (s, number, &o);
     319             :           }
     320   168180000 :           break;
     321             : 
     322    24665200 :         case 's':
     323             :         case 'S':
     324             :           {
     325    24665200 :             char *cstring = va_arg (*va, char *);
     326             :             uword len;
     327             : 
     328    24665200 :             if (!cstring)
     329             :               {
     330       15684 :                 cstring = "(nil)";
     331       15684 :                 len = 5;
     332             :               }
     333    24649500 :             else if (fi.width[1] != 0)
     334           0 :               len = clib_min (strlen (cstring), fi.width[1]);
     335             :             else
     336    24649500 :               len = strlen (cstring);
     337             : 
     338             :             /* %S => format string as C identifier (replace _ with space). */
     339    24665200 :             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    24665200 :               vec_add (s, cstring, len);
     346             :           }
     347    24665200 :           break;
     348             : 
     349    17090200 :         case 'v':
     350             :           {
     351    17090200 :             u8 *v = va_arg (*va, u8 *);
     352             :             uword len;
     353             : 
     354    17090200 :             if (fi.width[1] != 0)
     355           0 :               len = clib_min (vec_len (v), fi.width[1]);
     356             :             else
     357    17090200 :               len = vec_len (v);
     358             : 
     359    17090200 :             vec_add (s, v, len);
     360             :           }
     361    17090200 :           break;
     362             : 
     363      414759 :         case 'f':
     364             :         case 'g':
     365             :         case 'e':
     366             :           /* Floating point. */
     367      414759 :           ASSERT (fi.how_long == 0 || fi.how_long == 'l');
     368      414759 :           s = format_float (s, va_arg (*va, double), fi.width[1], c);
     369      414759 :           break;
     370             : 
     371    50499400 :         case 'U':
     372             :           /* User defined function. */
     373             :           {
     374             :             typedef u8 *(user_func_t) (u8 * s, va_list * args);
     375    50499400 :             user_func_t *u = va_arg (*va, user_func_t *);
     376             : 
     377    50499400 :             s = (*u) (s, va);
     378             :           }
     379    50499400 :           break;
     380             :         }
     381             : 
     382   265098000 :       s = justify (s, &fi, s_initial_len);
     383             :     }
     384             : 
     385           0 : done:
     386   268211000 :   *_s = s;
     387   268211000 :   return f;
     388             : }
     389             : 
     390             : __clib_export u8 *
     391   188250000 : va_format (u8 * s, const char *fmt, va_list * va)
     392             : {
     393   188250000 :   const u8 *f = (u8 *) fmt, *g;
     394             :   u8 c;
     395             : 
     396   188250000 :   g = f;
     397             :   while (1)
     398             :     {
     399   980165000 :       c = *f;
     400             : 
     401   980165000 :       if (!c)
     402   188250000 :         break;
     403             : 
     404   791915000 :       if (c == '%')
     405             :         {
     406   268211000 :           if (f > g)
     407   105343000 :             vec_add (s, g, f - g);
     408   268211000 :           f = g = do_percent (&s, f, va);
     409             :         }
     410             :       else
     411             :         {
     412   523704000 :           f++;
     413             :         }
     414             :     }
     415             : 
     416   188250000 :   if (f > g)
     417    14228700 :     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   188250000 :   return s;
     425             : }
     426             : 
     427             : __clib_export u8 *
     428   179885000 : format (u8 * s, const char *fmt, ...)
     429             : {
     430             :   va_list va;
     431   179885000 :   va_start (va, fmt);
     432   179885000 :   s = va_format (s, fmt, &va);
     433   179885000 :   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   179885000 :   return s;
     439             : }
     440             : 
     441             : __clib_export word
     442        1178 : va_fformat (FILE * f, char *fmt, va_list * va)
     443             : {
     444             :   word ret;
     445             :   u8 *s;
     446             : 
     447        1178 :   s = va_format (0, fmt, va);
     448             : 
     449             : #ifdef CLIB_UNIX
     450        1178 :   if (f)
     451             :     {
     452        1178 :       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        1178 :   vec_free (s);
     462        1178 :   return ret;
     463             : }
     464             : 
     465             : __clib_export word
     466        1178 : fformat (FILE * f, char *fmt, ...)
     467             : {
     468             :   va_list va;
     469             :   word ret;
     470             : 
     471        1178 :   va_start (va, fmt);
     472        1178 :   ret = va_fformat (f, fmt, &va);
     473        1178 :   va_end (va);
     474             : 
     475        1178 :   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   168182000 : format_integer (u8 * s, u64 number, format_integer_options_t * options)
     510             : {
     511             :   u64 q;
     512             :   u32 r;
     513             :   u8 digit_buffer[128];
     514   168182000 :   u8 *d = digit_buffer + sizeof (digit_buffer);
     515             :   word c, base;
     516             : 
     517   168182000 :   if (options->is_signed && (i64) number < 0)
     518             :     {
     519      150133 :       number = -number;
     520      150133 :       vec_add1 (s, '-');
     521             :     }
     522             : 
     523   168182000 :   if (options->n_bits < BITS (number))
     524   167170000 :     number &= ((u64) 1 << options->n_bits) - 1;
     525             : 
     526   168182000 :   base = options->base;
     527             : 
     528             :   while (1)
     529             :     {
     530   307420000 :       q = number / base;
     531   307420000 :       r = number % base;
     532             : 
     533   307420000 :       if (r < 10 + 26 + 26)
     534             :         {
     535   307420000 :           if (r < 10)
     536   259532000 :             c = '0' + r;
     537    47888200 :           else if (r < 10 + 26)
     538    47888200 :             c = 'a' + (r - 10);
     539             :           else
     540           0 :             c = 'A' + (r - 10 - 26);
     541             : 
     542   307420000 :           if (options->uppercase_digits
     543        1218 :               && base <= 10 + 26 && c >= 'a' && c <= 'z')
     544          64 :             c += 'A' - 'a';
     545             : 
     546   307420000 :           *--d = c;
     547             :         }
     548             :       else                      /* will never happen, warning be gone */
     549             :         {
     550           0 :           *--d = '?';
     551             :         }
     552             : 
     553   307420000 :       if (q == 0)
     554   168182000 :         break;
     555             : 
     556   139239000 :       number = q;
     557             :     }
     558             : 
     559   168182000 :   vec_add (s, d, digit_buffer + sizeof (digit_buffer) - d);
     560   168182000 :   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      267245 : f64_up (uword sign, word expon, u64 fraction)
     577             : {
     578             :   union
     579             :   {
     580             :     u64 u;
     581             :     f64 f;
     582             :   } tmp;
     583             : 
     584      267245 :   tmp.u = (u64) ((sign) != 0) << 63;
     585             : 
     586      267245 :   expon += 1023;
     587      267245 :   if (expon > 1023)
     588           0 :     expon = 1023;
     589      267245 :   if (expon < 0)
     590           0 :     expon = 0;
     591      267245 :   tmp.u |= (u64) expon << 52;
     592             : 
     593      267245 :   tmp.u |= fraction & (((u64) 1 << 52) - 1);
     594             : 
     595      267245 :   return tmp.f;
     596             : }
     597             : 
     598             : /* Returns approximate precision of number given its exponent. */
     599             : static f64
     600      267245 : f64_precision (int base2_expon)
     601             : {
     602             :   static int n_bits = 0;
     603             : 
     604      267245 :   if (!n_bits)
     605             :     {
     606             :       /* Compute number of significant bits in floating point representation. */
     607         551 :       f64 one = 0;
     608         551 :       f64 small = 1;
     609             : 
     610       29754 :       while (one != 1)
     611             :         {
     612       29203 :           small *= .5;
     613       29203 :           n_bits++;
     614       29203 :           one = 1 + small;
     615             :         }
     616             :     }
     617             : 
     618      267245 :   return f64_up (0, base2_expon - n_bits, 0);
     619             : }
     620             : 
     621             : /* Return x 10^n */
     622             : static f64
     623      534490 : times_power_of_ten (f64 x, int n)
     624             : {
     625      534490 :   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      106588 :       while (n >= 8)
     629             :         {
     630           0 :           x *= 1e+8;
     631           0 :           n -= 8;
     632             :         }
     633      106588 :       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      428360 :       while (n <= -8)
     639             :         {
     640         458 :           x *= 1e-8;
     641         458 :           n += 8;
     642             :         }
     643      427902 :       return x * t[-n];
     644             :     }
     645             : 
     646             : }
     647             : 
     648             : /* Write x = y * 10^expon with 1 < y < 10. */
     649             : static f64
     650      267245 : 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      267245 :   f64_down (x, sign, expon2, fraction);
     658             : 
     659      267245 :   expon10 =
     660      267245 :     .5 +
     661      267245 :     expon2 * .301029995663981195213738894724493 /* Log (2) / Log (10) */ ;
     662             : 
     663      267245 :   prec = f64_precision (expon2);
     664      267245 :   x = times_power_of_ten (x, -expon10);
     665      267245 :   prec = times_power_of_ten (prec, -expon10);
     666             : 
     667      363421 :   while (x < 1)
     668             :     {
     669       96176 :       x *= 10;
     670       96176 :       prec *= 10;
     671       96176 :       expon10--;
     672             :     }
     673             : 
     674      267245 :   while (x > 10)
     675             :     {
     676           0 :       x *= .1;
     677           0 :       prec *= .1;
     678           0 :       expon10++;
     679             :     }
     680             : 
     681      267245 :   if (x + prec >= 10)
     682             :     {
     683           0 :       x = 1;
     684           0 :       expon10++;
     685             :     }
     686             : 
     687      267245 :   *expon_return = expon10;
     688      267245 :   *prec_return = prec;
     689             : 
     690      267245 :   return x;
     691             : }
     692             : 
     693             : static u8 *
     694      187742 : add_some_zeros (u8 * s, uword n_zeros)
     695             : {
     696      557770 :   while (n_zeros > 0)
     697             :     {
     698      370028 :       vec_add1 (s, '0');
     699      370028 :       n_zeros--;
     700             :     }
     701      187742 :   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      414759 : 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      414759 :   if (n_fraction_digits == ~0)
     716           0 :     n_fraction_digits = 7;
     717      414759 :   n_fraction_done = 0;
     718      414759 :   decimal_point = 0;
     719      414759 :   added_decimal_point = 0;
     720      414759 :   sign = expon = 0;
     721             : 
     722             :   /* Special case: zero. */
     723      414759 :   if (x == 0)
     724             :     {
     725      147514 :     do_zero:
     726      147668 :       vec_add1 (s, '0');
     727      147668 :       goto done;
     728             :     }
     729             : 
     730      267245 :   if (x < 0)
     731             :     {
     732           1 :       x = -x;
     733           1 :       sign = 1;
     734             :     }
     735             : 
     736             :   /* Check for not-a-number. */
     737      267245 :   if (isnan (x))
     738           0 :     return format (s, "%cNaN", sign ? '-' : '+');
     739             : 
     740             :   /* Check for infinity. */
     741      267245 :   if (isinf (x))
     742           0 :     return format (s, "%cinfinity", sign ? '-' : '+');
     743             : 
     744      267245 :   x = normalize (x, &expon, &prec);
     745             : 
     746             :   /* Not enough digits to print anything: so just print 0 */
     747      267245 :   if ((word) - expon > (word) n_fraction_digits
     748         154 :       && (output_style == 'f' || (output_style == 'g')))
     749         154 :     goto do_zero;
     750             : 
     751      267091 :   if (sign)
     752           1 :     vec_add1 (s, '-');
     753             : 
     754      267091 :   if (output_style == 'f'
     755      130339 :       || (output_style == 'g' && expon > -10 && expon < 10))
     756             :     {
     757      136752 :       if (expon < 0)
     758             :         {
     759             :           /* Add decimal point and leading zeros. */
     760         508 :           vec_add1 (s, '.');
     761         508 :           n_fraction_done = clib_min (-(expon + 1), n_fraction_digits);
     762         508 :           s = add_some_zeros (s, n_fraction_done);
     763         508 :           decimal_point = -n_fraction_done;
     764         508 :           added_decimal_point = 1;
     765             :         }
     766             :       else
     767      136244 :         decimal_point = expon + 1;
     768             :     }
     769             :   else
     770             :     {
     771             :       /* Exponential output style. */
     772      130339 :       decimal_point = 1;
     773      130339 :       output_style = 'e';
     774             :     }
     775             : 
     776             :   while (1)
     777      674703 :     {
     778             :       uword digit;
     779             : 
     780             :       /* Number is smaller than precision: call it zero. */
     781      941794 :       if (x < prec)
     782       38419 :         break;
     783             : 
     784      903375 :       digit = x;
     785      903375 :       x -= digit;
     786      903375 :       if (x + prec >= 1)
     787             :         {
     788        3681 :           digit++;
     789        3681 :           x -= 1;
     790             :         }
     791             : 
     792             :       /* Round last printed digit. */
     793      903375 :       if (decimal_point <= 0
     794      512577 :           && n_fraction_done + 1 == n_fraction_digits && digit < 9)
     795      200822 :         digit += x >= .5;
     796             : 
     797      903375 :       vec_add1 (s, '0' + digit);
     798             : 
     799             :       /* Move rightwards towards/away from decimal point. */
     800      903375 :       decimal_point--;
     801             : 
     802      903375 :       n_fraction_done += decimal_point < 0;
     803      903375 :       if (decimal_point <= 0 && n_fraction_done >= n_fraction_digits)
     804      228672 :         break;
     805             : 
     806      674703 :       if (decimal_point == 0 && x != 0)
     807             :         {
     808      235215 :           vec_add1 (s, '.');
     809      235215 :           added_decimal_point = 1;
     810             :         }
     811             : 
     812      674703 :       x *= 10;
     813      674703 :       prec *= 10;
     814             :     }
     815             : 
     816      414759 : done:
     817      414759 :   if (decimal_point > 0)
     818             :     {
     819        3273 :       s = add_some_zeros (s, decimal_point);
     820        3273 :       decimal_point = 0;
     821             :     }
     822             : 
     823      414759 :   if (n_fraction_done < n_fraction_digits)
     824             :     {
     825      183961 :       if (!added_decimal_point)
     826      172068 :         vec_add1 (s, '.');
     827      183961 :       s = add_some_zeros (s, n_fraction_digits - n_fraction_done);
     828             :     }
     829             : 
     830      414759 :   if (output_style == 'e')
     831      149181 :     s = format (s, "e%wd", expon);
     832             : 
     833      414759 :   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