LCOV - code coverage report
Current view: top level - vppinfra - unformat.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 407 537 75.8 %
Date: 2023-07-05 22:20:52 Functions: 23 27 85.2 %

          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             :   Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
      17             : 
      18             :   Permission is hereby granted, free of charge, to any person obtaining
      19             :   a copy of this software and associated documentation files (the
      20             :   "Software"), to deal in the Software without restriction, including
      21             :   without limitation the rights to use, copy, modify, merge, publish,
      22             :   distribute, sublicense, and/or sell copies of the Software, and to
      23             :   permit persons to whom the Software is furnished to do so, subject to
      24             :   the following conditions:
      25             : 
      26             :   The above copyright notice and this permission notice shall be
      27             :   included in all copies or substantial portions of the Software.
      28             : 
      29             :   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      30             :   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      31             :   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      32             :   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      33             :   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
      34             :   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
      35             :   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      36             : */
      37             : 
      38             : #include <vppinfra/format.h>
      39             : 
      40             : /* Call user's function to fill input buffer. */
      41             : __clib_export uword
      42     1505920 : _unformat_fill_input (unformat_input_t * i)
      43             : {
      44             :   uword l, first_mark;
      45             : 
      46     1505920 :   if (i->index == UNFORMAT_END_OF_INPUT)
      47           0 :     return i->index;
      48             : 
      49     1505920 :   first_mark = l = vec_len (i->buffer);
      50     1505920 :   if (vec_len (i->buffer_marks) > 0)
      51     1489790 :     first_mark = i->buffer_marks[0];
      52             : 
      53             :   /* Re-use buffer when no marks. */
      54     1505920 :   if (first_mark > 0)
      55      334634 :     vec_delete (i->buffer, first_mark, 0);
      56             : 
      57     1505920 :   i->index = vec_len (i->buffer);
      58     3291400 :   for (l = 0; l < vec_len (i->buffer_marks); l++)
      59     1785480 :     i->buffer_marks[l] -= first_mark;
      60             : 
      61             :   /* Call user's function to fill the buffer. */
      62     1505920 :   if (i->fill_buffer)
      63           0 :     i->index = i->fill_buffer (i);
      64             : 
      65             :   /* If input pointer is still beyond end of buffer even after
      66             :      fill then we've run out of input. */
      67     1505920 :   if (i->index >= vec_len (i->buffer))
      68     1505920 :     i->index = UNFORMAT_END_OF_INPUT;
      69             : 
      70     1505920 :   return i->index;
      71             : }
      72             : 
      73             : /* Format function for dumping input stream. */
      74             : __clib_export u8 *
      75       18544 : format_unformat_error (u8 * s, va_list * va)
      76             : {
      77       18544 :   unformat_input_t *i = va_arg (*va, unformat_input_t *);
      78       18544 :   uword l = vec_len (i->buffer);
      79             : 
      80             :   /* Only show so much of the input buffer (it could be really large). */
      81       18544 :   uword n_max = 30;
      82             : 
      83       18544 :   if (i->index < l)
      84             :     {
      85        2559 :       uword n = l - i->index;
      86             :       u8 *p, *p_end;
      87             : 
      88        2559 :       p = i->buffer + i->index;
      89        2559 :       p_end = p + (n > n_max ? n_max : n);
      90             : 
      91             :       /* Skip white space at end. */
      92        2559 :       if (n <= n_max)
      93             :         {
      94        5116 :           while (p_end > p && is_white_space (p_end[-1]))
      95        2557 :             p_end--;
      96             :         }
      97             : 
      98       19574 :       while (p < p_end)
      99             :         {
     100       17015 :           switch (*p)
     101             :             {
     102           0 :             case '\r':
     103           0 :               vec_add (s, "\\r", 2);
     104           0 :               break;
     105           0 :             case '\n':
     106           0 :               vec_add (s, "\\n", 2);
     107           0 :               break;
     108           0 :             case '\t':
     109           0 :               vec_add (s, "\\t", 2);
     110           0 :               break;
     111       17015 :             default:
     112       17015 :               vec_add1 (s, *p);
     113       17015 :               break;
     114             :             }
     115       17015 :           p++;
     116             :         }
     117             : 
     118        2559 :       if (n > n_max)
     119           0 :         vec_add (s, "...", 3);
     120             :     }
     121             : 
     122       18544 :   return s;
     123             : }
     124             : 
     125             : /* Print everything: not just error context. */
     126             : __clib_export u8 *
     127           4 : format_unformat_input (u8 * s, va_list * va)
     128             : {
     129           4 :   unformat_input_t *i = va_arg (*va, unformat_input_t *);
     130             :   uword l, n;
     131             : 
     132           4 :   if (i->index == UNFORMAT_END_OF_INPUT)
     133           0 :     s = format (s, "{END_OF_INPUT}");
     134             :   else
     135             :     {
     136           4 :       l = vec_len (i->buffer);
     137           4 :       n = l - i->index;
     138           4 :       if (n > 0)
     139           4 :         vec_add (s, i->buffer + i->index, n);
     140             :     }
     141             : 
     142           4 :   return s;
     143             : }
     144             : 
     145             : #if CLIB_DEBUG > 0
     146             : void
     147           0 : di (unformat_input_t * i)
     148             : {
     149           0 :   fformat (stderr, "%U\n", format_unformat_input, i);
     150           0 : }
     151             : #endif
     152             : 
     153             : /* Parse delimited vector string.  If string starts with { then string
     154             :    is delimited by balanced parenthesis.  Other string is delimited by
     155             :    white space.  {} were chosen since they are special to the shell. */
     156             : static uword
     157      601963 : unformat_string (unformat_input_t * input,
     158             :                  uword delimiter_character,
     159             :                  uword format_character, va_list * va)
     160             : {
     161      601963 :   u8 **string_return = va_arg (*va, u8 **);
     162      601963 :   u8 *s = 0;
     163      601963 :   word paren = 0;
     164      601963 :   word is_paren_delimited = 0;
     165      601963 :   word backslash = 0;
     166             :   uword c;
     167             : 
     168      601963 :   switch (delimiter_character)
     169             :     {
     170      257492 :     case '%':
     171             :     case ' ':
     172             :     case '\t':
     173      257492 :       delimiter_character = 0;
     174      257492 :       break;
     175             :     }
     176             : 
     177     9876090 :   while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
     178             :     {
     179             :       word add_to_vector;
     180             : 
     181             :       /* Null return string means to skip over delimited input. */
     182     9586550 :       add_to_vector = string_return != 0;
     183             : 
     184     9586550 :       if (backslash)
     185           0 :         backslash = 0;
     186             :       else
     187     9586550 :         switch (c)
     188             :           {
     189           0 :           case '\\':
     190           0 :             backslash = 1;
     191           0 :             add_to_vector = 0;
     192           0 :             break;
     193             : 
     194       34085 :           case '{':
     195       34085 :             if (paren == 0 && vec_len (s) == 0)
     196             :               {
     197       24995 :                 is_paren_delimited = 1;
     198       24995 :                 add_to_vector = 0;
     199             :               }
     200       34085 :             paren++;
     201       34085 :             break;
     202             : 
     203       34084 :           case '}':
     204       34084 :             paren--;
     205       34084 :             if (is_paren_delimited && paren == 0)
     206       24994 :               goto done;
     207        9090 :             break;
     208             : 
     209      412660 :           case ' ':
     210             :           case '\t':
     211             :           case '\n':
     212             :           case '\r':
     213      412660 :             if (!is_paren_delimited)
     214             :               {
     215      287431 :                 unformat_put_input (input);
     216      287431 :                 goto done;
     217             :               }
     218      125229 :             break;
     219             : 
     220     9105720 :           default:
     221     9105720 :             if (!is_paren_delimited && c == delimiter_character)
     222             :               {
     223           6 :                 unformat_put_input (input);
     224           6 :                 goto done;
     225             :               }
     226             :           }
     227             : 
     228     9274120 :       if (add_to_vector)
     229     9249130 :         vec_add1 (s, c);
     230             :     }
     231             : 
     232      289532 : done:
     233      601963 :   if (string_return)
     234             :     {
     235             :       /* Match the string { END-OF-INPUT as a single brace. */
     236      601963 :       if (c == UNFORMAT_END_OF_INPUT && vec_len (s) == 0 && paren == 1)
     237           0 :         vec_add1 (s, '{');
     238             : 
     239             :       /* Don't match null string. */
     240      601963 :       if (c == UNFORMAT_END_OF_INPUT && vec_len (s) == 0)
     241        2445 :         return 0;
     242             : 
     243             :       /* Null terminate C string. */
     244      599518 :       if (format_character == 's')
     245      328148 :         vec_add1 (s, 0);
     246             : 
     247      599518 :       *string_return = s;
     248             :     }
     249             :   else
     250           0 :     vec_free (s);               /* just to make sure */
     251             : 
     252      599518 :   return 1;
     253             : }
     254             : 
     255             : __clib_export uword
     256           8 : unformat_hex_string (unformat_input_t * input, va_list * va)
     257             : {
     258           8 :   u8 **hexstring_return = va_arg (*va, u8 **);
     259             :   u8 *s;
     260             :   uword n, d, c;
     261             : 
     262           8 :   n = 0;
     263           8 :   d = 0;
     264           8 :   s = 0;
     265        1206 :   while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
     266             :     {
     267        1200 :       if (c >= '0' && c <= '9')
     268        1102 :         d = 16 * d + c - '0';
     269          98 :       else if (c >= 'a' && c <= 'f')
     270          96 :         d = 16 * d + 10 + c - 'a';
     271           2 :       else if (c >= 'A' && c <= 'F')
     272           0 :         d = 16 * d + 10 + c - 'A';
     273             :       else
     274             :         {
     275           2 :           unformat_put_input (input);
     276           2 :           break;
     277             :         }
     278        1198 :       n++;
     279             : 
     280        1198 :       if (n == 2)
     281             :         {
     282         599 :           vec_add1 (s, d);
     283         599 :           n = d = 0;
     284             :         }
     285             :     }
     286             : 
     287             :   /* Hex string must have even number of digits. */
     288           8 :   if (n % 2)
     289             :     {
     290           0 :       vec_free (s);
     291           0 :       return 0;
     292             :     }
     293             :   /* Make sure something was processed. */
     294           8 :   else if (s == 0)
     295             :     {
     296           0 :       return 0;
     297             :     }
     298             : 
     299           8 :   *hexstring_return = s;
     300           8 :   return 1;
     301             : }
     302             : 
     303             : /* unformat (input "foo%U", unformat_eof) matches terminal foo only */
     304             : __clib_export uword
     305      250775 : unformat_eof (unformat_input_t * input, va_list * va)
     306             : {
     307      250775 :   return unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
     308             : }
     309             : 
     310             : /* Parse a token containing given set of characters. */
     311             : __clib_export uword
     312          31 : unformat_token (unformat_input_t * input, va_list * va)
     313             : {
     314          31 :   u8 *token_chars = va_arg (*va, u8 *);
     315          31 :   u8 **string_return = va_arg (*va, u8 **);
     316             :   u8 *s, map[256];
     317             :   uword i, c;
     318             : 
     319          31 :   if (!token_chars)
     320           0 :     token_chars = (u8 *) "a-zA-Z0-9_";
     321             : 
     322          31 :   clib_memset (map, 0, sizeof (map));
     323         155 :   for (s = token_chars; *s;)
     324             :     {
     325             :       /*
     326             :        * Parse range.
     327             :        * The test order is important: s[1] is valid because s[0] != '\0' but
     328             :        * s[2] might not if s[1] == '\0'
     329             :        * Also, if s[1] == '-' but s[2] == '\0' the test s[0] < s[2] will
     330             :        * (correctly) fail
     331             :        */
     332         124 :       if (s[1] == '-' && s[0] < s[2])
     333             :         {
     334        2015 :           for (i = s[0]; i <= s[2]; i++)
     335        1922 :             map[i] = 1;
     336          93 :           s = s + 3;
     337             :         }
     338             :       else
     339             :         {
     340          31 :           map[s[0]] = 1;
     341          31 :           s = s + 1;
     342             :         }
     343             :     }
     344             : 
     345          31 :   s = 0;
     346         159 :   while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
     347             :     {
     348         159 :       if (!map[c])
     349             :         {
     350          31 :           unformat_put_input (input);
     351          31 :           break;
     352             :         }
     353             : 
     354         128 :       vec_add1 (s, c);
     355             :     }
     356             : 
     357          31 :   if (vec_len (s) == 0)
     358           5 :     return 0;
     359             : 
     360          26 :   *string_return = s;
     361          26 :   return 1;
     362             : }
     363             : 
     364             : /* Unformat (parse) function which reads a %s string and converts it
     365             :    to and unformat_input_t. */
     366             : __clib_export uword
     367           6 : unformat_input (unformat_input_t * i, va_list * args)
     368             : {
     369           6 :   unformat_input_t *sub_input = va_arg (*args, unformat_input_t *);
     370             :   u8 *s;
     371             : 
     372           6 :   if (unformat (i, "%v", &s))
     373             :     {
     374           6 :       unformat_init_vector (sub_input, s);
     375           6 :       return 1;
     376             :     }
     377             : 
     378           0 :   return 0;
     379             : }
     380             : 
     381             : /* Parse a line ending with \n and return it. */
     382             : __clib_export uword
     383      116277 : unformat_line (unformat_input_t * i, va_list * va)
     384             : {
     385      116277 :   u8 *line = 0, **result = va_arg (*va, u8 **);
     386             :   uword c;
     387             : 
     388     6078340 :   while ((c = unformat_get_input (i)) != '\n' && c != UNFORMAT_END_OF_INPUT)
     389             :     {
     390     5962060 :       vec_add1 (line, c);
     391             :     }
     392             : 
     393      116277 :   *result = line;
     394      116277 :   return vec_len (line);
     395             : }
     396             : 
     397             : /* Parse a line ending with \n and return it as an unformat_input_t. */
     398             : __clib_export uword
     399      116277 : unformat_line_input (unformat_input_t * i, va_list * va)
     400             : {
     401      116277 :   unformat_input_t *result = va_arg (*va, unformat_input_t *);
     402             :   u8 *line;
     403      116277 :   if (!unformat_user (i, unformat_line, &line))
     404       18466 :     return 0;
     405       97811 :   unformat_init_vector (result, line);
     406       97811 :   return 1;
     407             : }
     408             : 
     409             : /* Values for is_signed. */
     410             : #define UNFORMAT_INTEGER_SIGNED         1
     411             : #define UNFORMAT_INTEGER_UNSIGNED       0
     412             : 
     413             : static uword
     414     1458560 : unformat_integer (unformat_input_t * input,
     415             :                   va_list * va, uword base, uword is_signed, uword data_bytes)
     416             : {
     417             :   uword c, digit;
     418     1458560 :   uword value = 0;
     419     1458560 :   uword n_digits = 0;
     420     1458560 :   uword n_input = 0;
     421     1458560 :   uword sign = 0;
     422             : 
     423             :   /* We only support bases <= 64. */
     424     1458560 :   if (base < 2 || base > 64)
     425           0 :     goto error;
     426             : 
     427     5689170 :   while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
     428             :     {
     429     5508180 :       switch (c)
     430             :         {
     431       19607 :         case '-':
     432       19607 :           if (n_input == 0)
     433             :             {
     434           0 :               if (is_signed)
     435             :                 {
     436           0 :                   sign = 1;
     437           0 :                   goto next_digit;
     438             :                 }
     439             :               else
     440             :                 /* Leading sign for unsigned number. */
     441           0 :                 goto error;
     442             :             }
     443             :           /* Sign after input (e.g. 100-200). */
     444       19607 :           goto put_input_done;
     445             : 
     446           0 :         case '+':
     447           0 :           if (n_input > 0)
     448           0 :             goto put_input_done;
     449           0 :           sign = 0;
     450           0 :           goto next_digit;
     451             : 
     452     3977720 :         case '0' ... '9':
     453     3977720 :           digit = c - '0';
     454     3977720 :           break;
     455             : 
     456      253784 :         case 'a' ... 'z':
     457      253784 :           digit = 10 + (c - 'a');
     458      253784 :           break;
     459             : 
     460         106 :         case 'A' ... 'Z':
     461         106 :           digit = 10 + (base >= 36 ? 26 : 0) + (c - 'A');
     462         106 :           break;
     463             : 
     464         117 :         case '/':
     465         117 :           digit = 62;
     466         117 :           break;
     467             : 
     468           0 :         case '?':
     469           0 :           digit = 63;
     470           0 :           break;
     471             : 
     472     1256840 :         default:
     473     1256840 :           goto put_input_done;
     474             :         }
     475             : 
     476     4231720 :       if (digit >= base)
     477             :         {
     478        1107 :         put_input_done:
     479     1277560 :           unformat_put_input (input);
     480     1277560 :           goto done;
     481             :         }
     482             : 
     483             :       {
     484     4230620 :         uword new_value = base * value + digit;
     485             : 
     486             :         /* Check for overflow. */
     487     4230620 :         if (new_value < value)
     488           0 :           goto error;
     489     4230620 :         value = new_value;
     490             :       }
     491     4230620 :       n_digits += 1;
     492             : 
     493     4230620 :     next_digit:
     494     4230620 :       n_input++;
     495             :     }
     496             : 
     497      180998 : done:
     498     1458560 :   if (sign)
     499           0 :     value = -value;
     500             : 
     501     1458560 :   if (n_digits > 0)
     502             :     {
     503     1458080 :       void *v = va_arg (*va, void *);
     504             : 
     505     1458080 :       if (data_bytes == ~0)
     506     1457220 :         data_bytes = sizeof (int);
     507             : 
     508     1458080 :       switch (data_bytes)
     509             :         {
     510          14 :         case 1:
     511          14 :           *(u8 *) v = value;
     512          14 :           break;
     513           0 :         case 2:
     514           0 :           *(u16 *) v = value;
     515           0 :           break;
     516     1457220 :         case 4:
     517     1457220 :           *(u32 *) v = value;
     518     1457220 :           break;
     519         846 :         case 8:
     520         846 :           *(u64 *) v = value;
     521         846 :           break;
     522           0 :         default:
     523           0 :           goto error;
     524             :         }
     525             : 
     526     1458080 :       return 1;
     527             :     }
     528             : 
     529         471 : error:
     530         471 :   return 0;
     531             : }
     532             : 
     533             : /* Return x 10^n */
     534             : static f64
     535         220 : times_power_of_ten (f64 x, int n)
     536             : {
     537         220 :   if (n >= 0)
     538             :     {
     539             :       static f64 t[8] = { 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, };
     540         150 :       while (n >= 8)
     541             :         {
     542           0 :           x *= 1e+8;
     543           0 :           n -= 8;
     544             :         }
     545         150 :       return x * t[n];
     546             :     }
     547             :   else
     548             :     {
     549             :       static f64 t[8] = { 1e-0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, };
     550          70 :       while (n <= -8)
     551             :         {
     552           0 :           x *= 1e-8;
     553           0 :           n += 8;
     554             :         }
     555          70 :       return x * t[-n];
     556             :     }
     557             : 
     558             : }
     559             : 
     560             : static uword
     561         110 : unformat_float (unformat_input_t * input, va_list * va)
     562             : {
     563             :   uword c;
     564             :   u64 values[3];
     565         110 :   uword n_digits[3], value_index = 0;
     566         110 :   uword signs[2], sign_index = 0;
     567         110 :   uword n_input = 0;
     568             : 
     569         110 :   clib_memset (values, 0, sizeof (values));
     570         110 :   clib_memset (n_digits, 0, sizeof (n_digits));
     571         110 :   clib_memset (signs, 0, sizeof (signs));
     572             : 
     573         438 :   while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
     574             :     {
     575         435 :       switch (c)
     576             :         {
     577           0 :         case '-':
     578           0 :           if (value_index == 2 && n_digits[2] == 0)
     579             :             /* sign of exponent: it's ok. */ ;
     580             : 
     581           0 :           else if (value_index < 2 && n_digits[0] > 0)
     582             :             {
     583             :               /* 123- */
     584           0 :               unformat_put_input (input);
     585           0 :               goto done;
     586             :             }
     587             : 
     588           0 :           else if (n_input > 0)
     589           0 :             goto error;
     590             : 
     591           0 :           signs[sign_index++] = 1;
     592           0 :           goto next_digit;
     593             : 
     594           0 :         case '+':
     595           0 :           if (value_index == 2 && n_digits[2] == 0)
     596             :             /* sign of exponent: it's ok. */ ;
     597             : 
     598           0 :           else if (value_index < 2 && n_digits[0] > 0)
     599             :             {
     600             :               /* 123+ */
     601           0 :               unformat_put_input (input);
     602           0 :               goto done;
     603             :             }
     604             : 
     605           0 :           else if (n_input > 0)
     606           0 :             goto error;
     607           0 :           signs[sign_index++] = 0;
     608           0 :           goto next_digit;
     609             : 
     610           0 :         case 'e':
     611             :         case 'E':
     612           0 :           if (n_input == 0)
     613           0 :             goto error;
     614           0 :           value_index = 2;
     615           0 :           sign_index = 1;
     616           0 :           break;
     617             : 
     618          70 :         case '.':
     619          70 :           if (value_index > 0)
     620           0 :             goto error;
     621          70 :           value_index = 1;
     622          70 :           break;
     623             : 
     624         258 :         case '0' ... '9':
     625             :           {
     626             :             u64 tmp;
     627             : 
     628         258 :             tmp = values[value_index] * 10 + c - '0';
     629             : 
     630             :             /* Check for overflow. */
     631         258 :             if (tmp < values[value_index])
     632           0 :               goto error;
     633         258 :             values[value_index] = tmp;
     634         258 :             n_digits[value_index] += 1;
     635             :           }
     636         258 :           break;
     637             : 
     638         107 :         default:
     639         107 :           unformat_put_input (input);
     640         107 :           goto done;
     641             :         }
     642             : 
     643         328 :     next_digit:
     644         328 :       n_input++;
     645             :     }
     646             : 
     647           3 : done:
     648             :   {
     649             :     f64 f_values[2], *value_return;
     650             :     word expon;
     651             : 
     652             :     /* Must have either whole or fraction digits. */
     653         110 :     if (n_digits[0] + n_digits[1] <= 0)
     654           0 :       goto error;
     655             : 
     656         110 :     f_values[0] = values[0];
     657         110 :     if (signs[0])
     658           0 :       f_values[0] = -f_values[0];
     659             : 
     660         110 :     f_values[1] = values[1];
     661         110 :     f_values[1] = times_power_of_ten (f_values[1], -n_digits[1]);
     662             : 
     663         110 :     f_values[0] += f_values[1];
     664             : 
     665         110 :     expon = values[2];
     666         110 :     if (signs[1])
     667           0 :       expon = -expon;
     668             : 
     669         110 :     f_values[0] = times_power_of_ten (f_values[0], expon);
     670             : 
     671         110 :     value_return = va_arg (*va, f64 *);
     672         110 :     *value_return = f_values[0];
     673         110 :     return 1;
     674             :   }
     675             : 
     676           0 : error:
     677           0 :   return 0;
     678             : }
     679             : 
     680             : static const char *
     681     5929060 : match_input_with_format (unformat_input_t * input, const char *f)
     682             : {
     683             :   uword cf, ci;
     684             : 
     685     5929060 :   ASSERT (*f != 0);
     686             : 
     687             :   while (1)
     688             :     {
     689    12150800 :       cf = *f;
     690    12150800 :       if (cf == 0 || cf == '%' || cf == ' ')
     691             :         break;
     692    10601300 :       f++;
     693             : 
     694    10601300 :       ci = unformat_get_input (input);
     695             : 
     696    10601300 :       if (cf != ci)
     697     4379600 :         return 0;
     698             :     }
     699     1549460 :   return f;
     700             : }
     701             : 
     702             : static const char *
     703     2730540 : do_percent (unformat_input_t * input, va_list * va, const char *f)
     704             : {
     705     2730540 :   uword cf, n, data_bytes = ~0;
     706             : 
     707     2730540 :   cf = *f++;
     708             : 
     709     2730540 :   switch (cf)
     710             :     {
     711     2729700 :     default:
     712     2729700 :       break;
     713             : 
     714         651 :     case 'w':
     715             :       /* Word types. */
     716         651 :       cf = *f++;
     717         651 :       data_bytes = sizeof (uword);
     718         651 :       break;
     719             : 
     720         189 :     case 'l':
     721         189 :       cf = *f++;
     722         189 :       if (cf == 'l')
     723             :         {
     724         189 :           cf = *f++;
     725         189 :           data_bytes = sizeof (long long);
     726             :         }
     727             :       else
     728             :         {
     729           0 :           data_bytes = sizeof (long);
     730             :         }
     731         189 :       break;
     732             : 
     733           0 :     case 'L':
     734           0 :       cf = *f++;
     735           0 :       data_bytes = sizeof (long long);
     736           0 :       break;
     737             :     }
     738             : 
     739     2730540 :   n = 0;
     740     2730540 :   switch (cf)
     741             :     {
     742           6 :     case 'D':
     743           6 :       data_bytes = va_arg (*va, int);
     744      186330 :     case 'd':
     745      186330 :       n = unformat_integer (input, va, 10,
     746             :                             UNFORMAT_INTEGER_SIGNED, data_bytes);
     747      186330 :       break;
     748             : 
     749      109817 :     case 'u':
     750      109817 :       n = unformat_integer (input, va, 10,
     751             :                             UNFORMAT_INTEGER_UNSIGNED, data_bytes);
     752      109817 :       break;
     753             : 
     754           0 :     case 'b':
     755           0 :       n = unformat_integer (input, va, 2,
     756             :                             UNFORMAT_INTEGER_UNSIGNED, data_bytes);
     757           0 :       break;
     758             : 
     759           0 :     case 'o':
     760           0 :       n = unformat_integer (input, va, 8,
     761             :                             UNFORMAT_INTEGER_UNSIGNED, data_bytes);
     762           0 :       break;
     763             : 
     764          14 :     case 'X':
     765          14 :       data_bytes = va_arg (*va, int);
     766     1162410 :     case 'x':
     767     1162410 :       n = unformat_integer (input, va, 16,
     768             :                             UNFORMAT_INTEGER_UNSIGNED, data_bytes);
     769     1162410 :       break;
     770             : 
     771         110 :     case 'f':
     772         110 :       n = unformat_float (input, va);
     773         110 :       break;
     774             : 
     775      601963 :     case 's':
     776             :     case 'v':
     777      601963 :       n = unformat_string (input, f[0], cf, va);
     778      601963 :       break;
     779             : 
     780      669902 :     case 'U':
     781             :       {
     782      669902 :         unformat_function_t *f = va_arg (*va, unformat_function_t *);
     783      669902 :         n = f (input, va);
     784             :       }
     785      669902 :       break;
     786             : 
     787          10 :     case '=':
     788             :     case '|':
     789             :       {
     790          10 :         int *var = va_arg (*va, int *);
     791          10 :         uword val = va_arg (*va, int);
     792             : 
     793          10 :         if (cf == '|')
     794           0 :           val |= *var;
     795          10 :         *var = val;
     796          10 :         n = 1;
     797             :       }
     798          10 :       break;
     799             :     }
     800             : 
     801     2730540 :   return n ? f : 0;
     802             : }
     803             : 
     804             : __clib_export uword
     805    11260700 : unformat_skip_white_space (unformat_input_t * input)
     806             : {
     807    11260700 :   uword n = 0;
     808             :   uword c;
     809             : 
     810    12395700 :   while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
     811             :     {
     812    10079000 :       if (!is_white_space (c))
     813             :         {
     814     8944020 :           unformat_put_input (input);
     815     8944020 :           break;
     816             :         }
     817     1134940 :       n++;
     818             :     }
     819    11260700 :   return n;
     820             : }
     821             : 
     822             : __clib_export uword
     823     6558950 : va_unformat (unformat_input_t * input, const char *fmt, va_list * va)
     824             : {
     825             :   const char *f;
     826             :   uword input_matches_format;
     827             :   uword default_skip_input_white_space;
     828             :   uword n_input_white_space_skipped;
     829             :   uword last_non_white_space_match_percent;
     830             :   uword last_non_white_space_match_format;
     831             : 
     832     6558950 :   vec_add1_aligned (input->buffer_marks, input->index,
     833             :                     sizeof (input->buffer_marks[0]));
     834             : 
     835     6558950 :   f = fmt;
     836     6558950 :   default_skip_input_white_space = 1;
     837     6558950 :   input_matches_format = 0;
     838     6558950 :   last_non_white_space_match_percent = 0;
     839     6558950 :   last_non_white_space_match_format = 0;
     840             : 
     841             :   while (1)
     842     4384560 :     {
     843             :       char cf;
     844             :       uword is_percent, skip_input_white_space;
     845             : 
     846    10943500 :       cf = *f;
     847    10943500 :       is_percent = 0;
     848             : 
     849             :       /* Always skip input white space at start of format string.
     850             :          Otherwise use default skip value which can be changed by %_
     851             :          (see below). */
     852    10943500 :       skip_input_white_space = f == fmt || default_skip_input_white_space;
     853             : 
     854             :       /* Spaces in format request skipping input white space. */
     855    10943500 :       if (is_white_space (cf))
     856             :         {
     857      177727 :           skip_input_white_space = 1;
     858             : 
     859             :           /* Multiple format spaces are equivalent to a single white
     860             :              space. */
     861      177727 :           while (is_white_space (*++f))
     862             :             ;
     863             :         }
     864    10765800 :       else if (cf == '%')
     865             :         {
     866             :           /* %_ toggles whether or not to skip input white space. */
     867     2962720 :           switch (*++f)
     868             :             {
     869      232184 :             case '_':
     870      232184 :               default_skip_input_white_space =
     871      232184 :                 !default_skip_input_white_space;
     872      232184 :               f++;
     873             :               /* For transition from skip to no-skip in middle of format
     874             :                  string, skip input white space.  For example, the following matches:
     875             :                  fmt = "%_%d.%d%_->%_%d.%d%_"
     876             :                  input "1.2 -> 3.4"
     877             :                  Without this the space after -> does not get skipped. */
     878      232184 :               if (!default_skip_input_white_space
     879      232141 :                   && !(f == fmt + 2 || *f == 0))
     880          20 :                 unformat_skip_white_space (input);
     881      232184 :               continue;
     882             : 
     883             :               /* %% means match % */
     884           0 :             case '%':
     885           0 :               break;
     886             : 
     887             :               /* % at end of format string. */
     888           0 :             case 0:
     889           0 :               goto parse_fail;
     890             : 
     891     2730540 :             default:
     892     2730540 :               is_percent = 1;
     893     2730540 :               break;
     894             :             }
     895     7803060 :         }
     896             : 
     897    10711300 :       n_input_white_space_skipped = 0;
     898    10711300 :       if (skip_input_white_space)
     899    10477900 :         n_input_white_space_skipped = unformat_skip_white_space (input);
     900             : 
     901             :       /* End of format string. */
     902    10711300 :       if (cf == 0)
     903             :         {
     904             :           /* Force parse error when format string ends and input is
     905             :              not white or at end.  As an example, this is to prevent
     906             :              format "foo" from matching input "food".
     907             :              The last_non_white_space_match_percent is to make
     908             :              "foo %d" match input "foo 10,bletch" with %d matching 10. */
     909     2051730 :           if (skip_input_white_space
     910     1820940 :               && !last_non_white_space_match_percent
     911       59100 :               && !last_non_white_space_match_format
     912           0 :               && n_input_white_space_skipped == 0
     913           0 :               && input->index != UNFORMAT_END_OF_INPUT)
     914           0 :             goto parse_fail;
     915     2051730 :           break;
     916             :         }
     917             : 
     918     8659600 :       last_non_white_space_match_percent = is_percent;
     919     8659600 :       last_non_white_space_match_format = 0;
     920             : 
     921             :       /* Explicit spaces in format must match input white space. */
     922     8659600 :       if (cf == ' ' && !default_skip_input_white_space)
     923             :         {
     924           0 :           if (n_input_white_space_skipped == 0)
     925           0 :             goto parse_fail;
     926             :         }
     927             : 
     928     8659600 :       else if (is_percent)
     929             :         {
     930     2730540 :           if (!(f = do_percent (input, va, f)))
     931      127624 :             goto parse_fail;
     932             :         }
     933             : 
     934             :       else
     935             :         {
     936     5929060 :           const char *g = match_input_with_format (input, f);
     937     5929060 :           if (!g)
     938     4379600 :             goto parse_fail;
     939     1549460 :           last_non_white_space_match_format = g > f;
     940     1549460 :           f = g;
     941             :         }
     942             :     }
     943             : 
     944     2051730 :   input_matches_format = 1;
     945     6558950 : parse_fail:
     946             : 
     947             :   /* Rewind buffer marks. */
     948             :   {
     949     6558950 :     uword l = vec_len (input->buffer_marks);
     950             : 
     951             :     /* If we did not match back up buffer to last mark. */
     952     6558950 :     if (!input_matches_format)
     953     4507220 :       input->index = input->buffer_marks[l - 1];
     954             : 
     955     6558950 :     vec_set_len (input->buffer_marks, l - 1);
     956             :   }
     957             : 
     958     6558950 :   return input_matches_format;
     959             : }
     960             : 
     961             : __clib_export uword
     962     5872840 : unformat (unformat_input_t * input, const char *fmt, ...)
     963             : {
     964             :   va_list va;
     965             :   uword result;
     966     5872840 :   va_start (va, fmt);
     967     5872840 :   result = va_unformat (input, fmt, &va);
     968     5872840 :   va_end (va);
     969     5872840 :   return result;
     970             : }
     971             : 
     972             : __clib_export uword
     973     1495830 : unformat_user (unformat_input_t * input, unformat_function_t * func, ...)
     974             : {
     975             :   va_list va;
     976             :   uword result, l;
     977             : 
     978             :   /* Save place in input buffer in case parse fails. */
     979     1495830 :   l = vec_len (input->buffer_marks);
     980     1495830 :   vec_add1_aligned (input->buffer_marks, input->index,
     981             :                     sizeof (input->buffer_marks[0]));
     982             : 
     983     1495830 :   va_start (va, func);
     984     1495830 :   result = func (input, &va);
     985     1495830 :   va_end (va);
     986             : 
     987     1495830 :   if (!result && input->index != UNFORMAT_END_OF_INPUT)
     988      477317 :     input->index = input->buffer_marks[l];
     989             : 
     990     1495830 :   vec_set_len (input->buffer_marks, l);
     991             : 
     992     1495830 :   return result;
     993             : }
     994             : 
     995             : /* Setup for unformat of Unix style command line. */
     996             : __clib_export void
     997        2240 : unformat_init_command_line (unformat_input_t * input, char *argv[])
     998             : {
     999             :   uword i;
    1000             : 
    1001        2240 :   unformat_init (input, 0, 0);
    1002             : 
    1003             :   /* Concatenate argument strings with space in between. */
    1004      158008 :   for (i = 1; argv[i]; i++)
    1005             :     {
    1006      155768 :       vec_add (input->buffer, argv[i], strlen (argv[i]));
    1007      155768 :       if (argv[i + 1])
    1008      153528 :         vec_add1 (input->buffer, ' ');
    1009             :     }
    1010        2240 : }
    1011             : 
    1012             : __clib_export void
    1013      621404 : unformat_init_string (unformat_input_t *input, const char *string,
    1014             :                       int string_len)
    1015             : {
    1016      621404 :   unformat_init (input, 0, 0);
    1017      621404 :   if (string_len > 0)
    1018      621402 :     vec_add (input->buffer, string, string_len);
    1019      621404 : }
    1020             : 
    1021             : __clib_export void
    1022      786203 : unformat_init_vector (unformat_input_t * input, u8 * vector_string)
    1023             : {
    1024      786203 :   unformat_init (input, 0, 0);
    1025      786203 :   input->buffer = vector_string;
    1026      786203 : }
    1027             : 
    1028             : #ifdef CLIB_UNIX
    1029             : 
    1030             : static uword
    1031           0 : clib_file_fill_buffer (unformat_input_t * input)
    1032             : {
    1033           0 :   int fd = pointer_to_uword (input->fill_buffer_arg);
    1034             :   uword l, n;
    1035             : 
    1036           0 :   l = vec_len (input->buffer);
    1037           0 :   vec_resize (input->buffer, 4096);
    1038           0 :   n = read (fd, input->buffer + l, 4096);
    1039           0 :   if (n > 0)
    1040           0 :     vec_set_len (input->buffer, l + n);
    1041             : 
    1042           0 :   if (n <= 0)
    1043           0 :     return UNFORMAT_END_OF_INPUT;
    1044             :   else
    1045           0 :     return input->index;
    1046             : }
    1047             : 
    1048             : __clib_export void
    1049           0 : unformat_init_clib_file (unformat_input_t * input, int file_descriptor)
    1050             : {
    1051           0 :   unformat_init (input, clib_file_fill_buffer,
    1052           0 :                  uword_to_pointer (file_descriptor, void *));
    1053           0 : }
    1054             : 
    1055             : /* Take input from Unix environment variable. */
    1056             : uword
    1057           0 : unformat_init_unix_env (unformat_input_t * input, char *var)
    1058             : {
    1059           0 :   char *val = getenv (var);
    1060           0 :   if (val)
    1061           0 :     unformat_init_string (input, val, strlen (val));
    1062           0 :   return val != 0;
    1063             : }
    1064             : 
    1065             : __clib_export uword
    1066           4 : unformat_data_size (unformat_input_t * input, va_list * args)
    1067             : {
    1068             :   u64 _a;
    1069           4 :   u64 *a = va_arg (*args, u64 *);
    1070           4 :   if (unformat (input, "%lluGb", &_a))
    1071           0 :     *a = _a << 30;
    1072           4 :   else if (unformat (input, "%lluG", &_a))
    1073           0 :     *a = _a << 30;
    1074           4 :   else if (unformat (input, "%lluMb", &_a))
    1075           0 :     *a = _a << 20;
    1076           4 :   else if (unformat (input, "%lluM", &_a))
    1077           2 :     *a = _a << 20;
    1078           2 :   else if (unformat (input, "%lluKb", &_a))
    1079           0 :     *a = _a << 10;
    1080           2 :   else if (unformat (input, "%lluK", &_a))
    1081           0 :     *a = _a << 10;
    1082           2 :   else if (unformat (input, "%llu", a))
    1083             :     ;
    1084             :   else
    1085           0 :     return 0;
    1086           4 :   return 1;
    1087             : }
    1088             : 
    1089             : #endif /* CLIB_UNIX */
    1090             : 
    1091             : 
    1092             : /*
    1093             :  * fd.io coding-style-patch-verification: ON
    1094             :  *
    1095             :  * Local Variables:
    1096             :  * eval: (c-set-style "gnu")
    1097             :  * End:
    1098             :  */

Generated by: LCOV version 1.14