LCOV - code coverage report
Current view: top level - vppinfra - unformat.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 407 568 71.7 %
Date: 2023-10-26 01:39:38 Functions: 23 30 76.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             :   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             : #include <fcntl.h>
      40             : 
      41             : /* Call user's function to fill input buffer. */
      42             : __clib_export uword
      43     1517470 : _unformat_fill_input (unformat_input_t * i)
      44             : {
      45             :   uword l, first_mark;
      46             : 
      47     1517470 :   if (i->index == UNFORMAT_END_OF_INPUT)
      48           0 :     return i->index;
      49             : 
      50     1517470 :   first_mark = l = vec_len (i->buffer);
      51     1517470 :   if (vec_len (i->buffer_marks) > 0)
      52     1500870 :     first_mark = i->buffer_marks[0];
      53             : 
      54             :   /* Re-use buffer when no marks. */
      55     1517470 :   if (first_mark > 0)
      56      349910 :     vec_delete (i->buffer, first_mark, 0);
      57             : 
      58     1517470 :   i->index = vec_len (i->buffer);
      59     3324720 :   for (l = 0; l < vec_len (i->buffer_marks); l++)
      60     1807250 :     i->buffer_marks[l] -= first_mark;
      61             : 
      62             :   /* Call user's function to fill the buffer. */
      63     1517470 :   if (i->fill_buffer)
      64           0 :     i->index = i->fill_buffer (i);
      65             : 
      66             :   /* If input pointer is still beyond end of buffer even after
      67             :      fill then we've run out of input. */
      68     1517470 :   if (i->index >= vec_len (i->buffer))
      69     1517470 :     i->index = UNFORMAT_END_OF_INPUT;
      70             : 
      71     1517470 :   return i->index;
      72             : }
      73             : 
      74             : /* Format function for dumping input stream. */
      75             : __clib_export u8 *
      76       19309 : format_unformat_error (u8 * s, va_list * va)
      77             : {
      78       19309 :   unformat_input_t *i = va_arg (*va, unformat_input_t *);
      79       19309 :   uword l = vec_len (i->buffer);
      80             : 
      81             :   /* Only show so much of the input buffer (it could be really large). */
      82       19309 :   uword n_max = 30;
      83             : 
      84       19309 :   if (i->index < l)
      85             :     {
      86        2627 :       uword n = l - i->index;
      87             :       u8 *p, *p_end;
      88             : 
      89        2627 :       p = i->buffer + i->index;
      90        2627 :       p_end = p + (n > n_max ? n_max : n);
      91             : 
      92             :       /* Skip white space at end. */
      93        2627 :       if (n <= n_max)
      94             :         {
      95        5254 :           while (p_end > p && is_white_space (p_end[-1]))
      96        2627 :             p_end--;
      97             :         }
      98             : 
      99       19952 :       while (p < p_end)
     100             :         {
     101       17325 :           switch (*p)
     102             :             {
     103           0 :             case '\r':
     104           0 :               vec_add (s, "\\r", 2);
     105           0 :               break;
     106           0 :             case '\n':
     107           0 :               vec_add (s, "\\n", 2);
     108           0 :               break;
     109           0 :             case '\t':
     110           0 :               vec_add (s, "\\t", 2);
     111           0 :               break;
     112       17325 :             default:
     113       17325 :               vec_add1 (s, *p);
     114       17325 :               break;
     115             :             }
     116       17325 :           p++;
     117             :         }
     118             : 
     119        2627 :       if (n > n_max)
     120           0 :         vec_add (s, "...", 3);
     121             :     }
     122             : 
     123       19309 :   return s;
     124             : }
     125             : 
     126             : /* Print everything: not just error context. */
     127             : __clib_export u8 *
     128           4 : format_unformat_input (u8 * s, va_list * va)
     129             : {
     130           4 :   unformat_input_t *i = va_arg (*va, unformat_input_t *);
     131             :   uword l, n;
     132             : 
     133           4 :   if (i->index == UNFORMAT_END_OF_INPUT)
     134           0 :     s = format (s, "{END_OF_INPUT}");
     135             :   else
     136             :     {
     137           4 :       l = vec_len (i->buffer);
     138           4 :       n = l - i->index;
     139           4 :       if (n > 0)
     140           4 :         vec_add (s, i->buffer + i->index, n);
     141             :     }
     142             : 
     143           4 :   return s;
     144             : }
     145             : 
     146             : #if CLIB_DEBUG > 0
     147             : void
     148           0 : di (unformat_input_t * i)
     149             : {
     150           0 :   fformat (stderr, "%U\n", format_unformat_input, i);
     151           0 : }
     152             : #endif
     153             : 
     154             : /* Parse delimited vector string.  If string starts with { then string
     155             :    is delimited by balanced parenthesis.  Other string is delimited by
     156             :    white space.  {} were chosen since they are special to the shell. */
     157             : static uword
     158      417693 : unformat_string (unformat_input_t * input,
     159             :                  uword delimiter_character,
     160             :                  uword format_character, va_list * va)
     161             : {
     162      417693 :   u8 **string_return = va_arg (*va, u8 **);
     163      417693 :   u8 *s = 0;
     164      417693 :   word paren = 0;
     165      417693 :   word is_paren_delimited = 0;
     166      417693 :   word backslash = 0;
     167             :   uword c;
     168             : 
     169      417693 :   switch (delimiter_character)
     170             :     {
     171      270235 :     case '%':
     172             :     case ' ':
     173             :     case '\t':
     174      270235 :       delimiter_character = 0;
     175      270235 :       break;
     176             :     }
     177             : 
     178     9471430 :   while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
     179             :     {
     180             :       word add_to_vector;
     181             : 
     182             :       /* Null return string means to skip over delimited input. */
     183     9380880 :       add_to_vector = string_return != 0;
     184             : 
     185     9380880 :       if (backslash)
     186           0 :         backslash = 0;
     187             :       else
     188     9380880 :         switch (c)
     189             :           {
     190           0 :           case '\\':
     191           0 :             backslash = 1;
     192           0 :             add_to_vector = 0;
     193           0 :             break;
     194             : 
     195       35083 :           case '{':
     196       35083 :             if (paren == 0 && vec_len (s) == 0)
     197             :               {
     198       25721 :                 is_paren_delimited = 1;
     199       25721 :                 add_to_vector = 0;
     200             :               }
     201       35083 :             paren++;
     202       35083 :             break;
     203             : 
     204       35079 :           case '}':
     205       35079 :             paren--;
     206       35079 :             if (is_paren_delimited && paren == 0)
     207       25717 :               goto done;
     208        9362 :             break;
     209             : 
     210      430652 :           case ' ':
     211             :           case '\t':
     212             :           case '\n':
     213             :           case '\r':
     214      430652 :             if (!is_paren_delimited)
     215             :               {
     216      301425 :                 unformat_put_input (input);
     217      301425 :                 goto done;
     218             :               }
     219      129227 :             break;
     220             : 
     221     8880070 :           default:
     222     8880070 :             if (!is_paren_delimited && c == delimiter_character)
     223             :               {
     224           6 :                 unformat_put_input (input);
     225           6 :                 goto done;
     226             :               }
     227             :           }
     228             : 
     229     9053730 :       if (add_to_vector)
     230     9028010 :         vec_add1 (s, c);
     231             :     }
     232             : 
     233       90545 : done:
     234      417693 :   if (string_return)
     235             :     {
     236             :       /* Match the string { END-OF-INPUT as a single brace. */
     237      417693 :       if (c == UNFORMAT_END_OF_INPUT && vec_len (s) == 0 && paren == 1)
     238           0 :         vec_add1 (s, '{');
     239             : 
     240             :       /* Don't match null string. */
     241      417693 :       if (c == UNFORMAT_END_OF_INPUT && vec_len (s) == 0)
     242        2487 :         return 0;
     243             : 
     244             :       /* Null terminate C string. */
     245      415206 :       if (format_character == 's')
     246      130408 :         vec_add1 (s, 0);
     247             : 
     248      415206 :       *string_return = s;
     249             :     }
     250             :   else
     251           0 :     vec_free (s);               /* just to make sure */
     252             : 
     253      415206 :   return 1;
     254             : }
     255             : 
     256             : __clib_export uword
     257           9 : unformat_hex_string (unformat_input_t * input, va_list * va)
     258             : {
     259           9 :   u8 **hexstring_return = va_arg (*va, u8 **);
     260             :   u8 *s;
     261             :   uword n, d, c;
     262             : 
     263           9 :   n = 0;
     264           9 :   d = 0;
     265           9 :   s = 0;
     266        1253 :   while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
     267             :     {
     268        1247 :       if (c >= '0' && c <= '9')
     269        1145 :         d = 16 * d + c - '0';
     270         102 :       else if (c >= 'a' && c <= 'f')
     271          99 :         d = 16 * d + 10 + c - 'a';
     272           3 :       else if (c >= 'A' && c <= 'F')
     273           0 :         d = 16 * d + 10 + c - 'A';
     274             :       else
     275             :         {
     276           3 :           unformat_put_input (input);
     277           3 :           break;
     278             :         }
     279        1244 :       n++;
     280             : 
     281        1244 :       if (n == 2)
     282             :         {
     283         622 :           vec_add1 (s, d);
     284         622 :           n = d = 0;
     285             :         }
     286             :     }
     287             : 
     288             :   /* Hex string must have even number of digits. */
     289           9 :   if (n % 2)
     290             :     {
     291           0 :       vec_free (s);
     292           0 :       return 0;
     293             :     }
     294             :   /* Make sure something was processed. */
     295           9 :   else if (s == 0)
     296             :     {
     297           0 :       return 0;
     298             :     }
     299             : 
     300           9 :   *hexstring_return = s;
     301           9 :   return 1;
     302             : }
     303             : 
     304             : /* unformat (input "foo%U", unformat_eof) matches terminal foo only */
     305             : __clib_export uword
     306      261580 : unformat_eof (unformat_input_t * input, va_list * va)
     307             : {
     308      261580 :   return unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
     309             : }
     310             : 
     311             : /* Parse a token containing given set of characters. */
     312             : __clib_export uword
     313          46 : unformat_token (unformat_input_t * input, va_list * va)
     314             : {
     315          46 :   u8 *token_chars = va_arg (*va, u8 *);
     316          46 :   u8 **string_return = va_arg (*va, u8 **);
     317             :   u8 *s, map[256];
     318             :   uword i, c;
     319             : 
     320          46 :   if (!token_chars)
     321           0 :     token_chars = (u8 *) "a-zA-Z0-9_";
     322             : 
     323          46 :   clib_memset (map, 0, sizeof (map));
     324         230 :   for (s = token_chars; *s;)
     325             :     {
     326             :       /*
     327             :        * Parse range.
     328             :        * The test order is important: s[1] is valid because s[0] != '\0' but
     329             :        * s[2] might not if s[1] == '\0'
     330             :        * Also, if s[1] == '-' but s[2] == '\0' the test s[0] < s[2] will
     331             :        * (correctly) fail
     332             :        */
     333         184 :       if (s[1] == '-' && s[0] < s[2])
     334             :         {
     335        2990 :           for (i = s[0]; i <= s[2]; i++)
     336        2852 :             map[i] = 1;
     337         138 :           s = s + 3;
     338             :         }
     339             :       else
     340             :         {
     341          46 :           map[s[0]] = 1;
     342          46 :           s = s + 1;
     343             :         }
     344             :     }
     345             : 
     346          46 :   s = 0;
     347         226 :   while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
     348             :     {
     349         226 :       if (!map[c])
     350             :         {
     351          46 :           unformat_put_input (input);
     352          46 :           break;
     353             :         }
     354             : 
     355         180 :       vec_add1 (s, c);
     356             :     }
     357             : 
     358          46 :   if (vec_len (s) == 0)
     359           5 :     return 0;
     360             : 
     361          41 :   *string_return = s;
     362          41 :   return 1;
     363             : }
     364             : 
     365             : /* Unformat (parse) function which reads a %s string and converts it
     366             :    to and unformat_input_t. */
     367             : __clib_export uword
     368          14 : unformat_input (unformat_input_t * i, va_list * args)
     369             : {
     370          14 :   unformat_input_t *sub_input = va_arg (*args, unformat_input_t *);
     371             :   u8 *s;
     372             : 
     373          14 :   if (unformat (i, "%v", &s))
     374             :     {
     375          14 :       unformat_init_vector (sub_input, s);
     376          14 :       return 1;
     377             :     }
     378             : 
     379           0 :   return 0;
     380             : }
     381             : 
     382             : /* Parse a line ending with \n and return it. */
     383             : __clib_export uword
     384      121930 : unformat_line (unformat_input_t * i, va_list * va)
     385             : {
     386      121930 :   u8 *line = 0, **result = va_arg (*va, u8 **);
     387             :   uword c;
     388             : 
     389     6475300 :   while ((c = unformat_get_input (i)) != '\n' && c != UNFORMAT_END_OF_INPUT)
     390             :     {
     391     6353370 :       vec_add1 (line, c);
     392             :     }
     393             : 
     394      121930 :   *result = line;
     395      121930 :   return vec_len (line);
     396             : }
     397             : 
     398             : /* Parse a line ending with \n and return it as an unformat_input_t. */
     399             : __clib_export uword
     400      121930 : unformat_line_input (unformat_input_t * i, va_list * va)
     401             : {
     402      121930 :   unformat_input_t *result = va_arg (*va, unformat_input_t *);
     403             :   u8 *line;
     404      121930 :   if (!unformat_user (i, unformat_line, &line))
     405       19112 :     return 0;
     406      102818 :   unformat_init_vector (result, line);
     407      102818 :   return 1;
     408             : }
     409             : 
     410             : /* Values for is_signed. */
     411             : #define UNFORMAT_INTEGER_SIGNED         1
     412             : #define UNFORMAT_INTEGER_UNSIGNED       0
     413             : 
     414             : static uword
     415     1671820 : unformat_integer (unformat_input_t * input,
     416             :                   va_list * va, uword base, uword is_signed, uword data_bytes)
     417             : {
     418             :   uword c, digit;
     419     1671820 :   uword value = 0;
     420     1671820 :   uword n_digits = 0;
     421     1671820 :   uword n_input = 0;
     422     1671820 :   uword sign = 0;
     423             : 
     424             :   /* We only support bases <= 64. */
     425     1671820 :   if (base < 2 || base > 64)
     426           0 :     goto error;
     427             : 
     428     6366400 :   while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
     429             :     {
     430     6180050 :       switch (c)
     431             :         {
     432       20170 :         case '-':
     433       20170 :           if (n_input == 0)
     434             :             {
     435           0 :               if (is_signed)
     436             :                 {
     437           0 :                   sign = 1;
     438           0 :                   goto next_digit;
     439             :                 }
     440             :               else
     441             :                 /* Leading sign for unsigned number. */
     442           0 :                 goto error;
     443             :             }
     444             :           /* Sign after input (e.g. 100-200). */
     445       20170 :           goto put_input_done;
     446             : 
     447           0 :         case '+':
     448           0 :           if (n_input > 0)
     449           0 :             goto put_input_done;
     450           0 :           sign = 0;
     451           0 :           goto next_digit;
     452             : 
     453     4433130 :         case '0' ... '9':
     454     4433130 :           digit = c - '0';
     455     4433130 :           break;
     456             : 
     457      262403 :         case 'a' ... 'z':
     458      262403 :           digit = 10 + (c - 'a');
     459      262403 :           break;
     460             : 
     461         113 :         case 'A' ... 'Z':
     462         113 :           digit = 10 + (base >= 36 ? 26 : 0) + (c - 'A');
     463         113 :           break;
     464             : 
     465         131 :         case '/':
     466         131 :           digit = 62;
     467         131 :           break;
     468             : 
     469           0 :         case '?':
     470           0 :           digit = 63;
     471           0 :           break;
     472             : 
     473     1464100 :         default:
     474     1464100 :           goto put_input_done;
     475             :         }
     476             : 
     477     4695780 :       if (digit >= base)
     478             :         {
     479        1203 :         put_input_done:
     480     1485470 :           unformat_put_input (input);
     481     1485470 :           goto done;
     482             :         }
     483             : 
     484             :       {
     485     4694580 :         uword new_value = base * value + digit;
     486             : 
     487             :         /* Check for overflow. */
     488     4694580 :         if (new_value < value)
     489           0 :           goto error;
     490     4694580 :         value = new_value;
     491             :       }
     492     4694580 :       n_digits += 1;
     493             : 
     494     4694580 :     next_digit:
     495     4694580 :       n_input++;
     496             :     }
     497             : 
     498      186351 : done:
     499     1671820 :   if (sign)
     500           0 :     value = -value;
     501             : 
     502     1671820 :   if (n_digits > 0)
     503             :     {
     504     1671270 :       void *v = va_arg (*va, void *);
     505             : 
     506     1671270 :       if (data_bytes == ~0)
     507     1670380 :         data_bytes = sizeof (int);
     508             : 
     509     1671270 :       switch (data_bytes)
     510             :         {
     511          20 :         case 1:
     512          20 :           *(u8 *) v = value;
     513          20 :           break;
     514           0 :         case 2:
     515           0 :           *(u16 *) v = value;
     516           0 :           break;
     517     1670380 :         case 4:
     518     1670380 :           *(u32 *) v = value;
     519     1670380 :           break;
     520         874 :         case 8:
     521         874 :           *(u64 *) v = value;
     522         874 :           break;
     523           0 :         default:
     524           0 :           goto error;
     525             :         }
     526             : 
     527     1671270 :       return 1;
     528             :     }
     529             : 
     530         552 : error:
     531         552 :   return 0;
     532             : }
     533             : 
     534             : /* Return x 10^n */
     535             : static f64
     536         236 : times_power_of_ten (f64 x, int n)
     537             : {
     538         236 :   if (n >= 0)
     539             :     {
     540             :       static f64 t[8] = { 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, };
     541         166 :       while (n >= 8)
     542             :         {
     543           0 :           x *= 1e+8;
     544           0 :           n -= 8;
     545             :         }
     546         166 :       return x * t[n];
     547             :     }
     548             :   else
     549             :     {
     550             :       static f64 t[8] = { 1e-0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, };
     551          70 :       while (n <= -8)
     552             :         {
     553           0 :           x *= 1e-8;
     554           0 :           n += 8;
     555             :         }
     556          70 :       return x * t[-n];
     557             :     }
     558             : 
     559             : }
     560             : 
     561             : static uword
     562         118 : unformat_float (unformat_input_t * input, va_list * va)
     563             : {
     564             :   uword c;
     565             :   u64 values[3];
     566         118 :   uword n_digits[3], value_index = 0;
     567         118 :   uword signs[2], sign_index = 0;
     568         118 :   uword n_input = 0;
     569             : 
     570         118 :   clib_memset (values, 0, sizeof (values));
     571         118 :   clib_memset (n_digits, 0, sizeof (n_digits));
     572         118 :   clib_memset (signs, 0, sizeof (signs));
     573             : 
     574         462 :   while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
     575             :     {
     576         459 :       switch (c)
     577             :         {
     578           0 :         case '-':
     579           0 :           if (value_index == 2 && n_digits[2] == 0)
     580             :             /* sign of exponent: it's ok. */ ;
     581             : 
     582           0 :           else if (value_index < 2 && n_digits[0] > 0)
     583             :             {
     584             :               /* 123- */
     585           0 :               unformat_put_input (input);
     586           0 :               goto done;
     587             :             }
     588             : 
     589           0 :           else if (n_input > 0)
     590           0 :             goto error;
     591             : 
     592           0 :           signs[sign_index++] = 1;
     593           0 :           goto next_digit;
     594             : 
     595           0 :         case '+':
     596           0 :           if (value_index == 2 && n_digits[2] == 0)
     597             :             /* sign of exponent: it's ok. */ ;
     598             : 
     599           0 :           else if (value_index < 2 && n_digits[0] > 0)
     600             :             {
     601             :               /* 123+ */
     602           0 :               unformat_put_input (input);
     603           0 :               goto done;
     604             :             }
     605             : 
     606           0 :           else if (n_input > 0)
     607           0 :             goto error;
     608           0 :           signs[sign_index++] = 0;
     609           0 :           goto next_digit;
     610             : 
     611           0 :         case 'e':
     612             :         case 'E':
     613           0 :           if (n_input == 0)
     614           0 :             goto error;
     615           0 :           value_index = 2;
     616           0 :           sign_index = 1;
     617           0 :           break;
     618             : 
     619          70 :         case '.':
     620          70 :           if (value_index > 0)
     621           0 :             goto error;
     622          70 :           value_index = 1;
     623          70 :           break;
     624             : 
     625         274 :         case '0' ... '9':
     626             :           {
     627             :             u64 tmp;
     628             : 
     629         274 :             tmp = values[value_index] * 10 + c - '0';
     630             : 
     631             :             /* Check for overflow. */
     632         274 :             if (tmp < values[value_index])
     633           0 :               goto error;
     634         274 :             values[value_index] = tmp;
     635         274 :             n_digits[value_index] += 1;
     636             :           }
     637         274 :           break;
     638             : 
     639         115 :         default:
     640         115 :           unformat_put_input (input);
     641         115 :           goto done;
     642             :         }
     643             : 
     644         344 :     next_digit:
     645         344 :       n_input++;
     646             :     }
     647             : 
     648           3 : done:
     649             :   {
     650             :     f64 f_values[2], *value_return;
     651             :     word expon;
     652             : 
     653             :     /* Must have either whole or fraction digits. */
     654         118 :     if (n_digits[0] + n_digits[1] <= 0)
     655           0 :       goto error;
     656             : 
     657         118 :     f_values[0] = values[0];
     658         118 :     if (signs[0])
     659           0 :       f_values[0] = -f_values[0];
     660             : 
     661         118 :     f_values[1] = values[1];
     662         118 :     f_values[1] = times_power_of_ten (f_values[1], -n_digits[1]);
     663             : 
     664         118 :     f_values[0] += f_values[1];
     665             : 
     666         118 :     expon = values[2];
     667         118 :     if (signs[1])
     668           0 :       expon = -expon;
     669             : 
     670         118 :     f_values[0] = times_power_of_ten (f_values[0], expon);
     671             : 
     672         118 :     value_return = va_arg (*va, f64 *);
     673         118 :     *value_return = f_values[0];
     674         118 :     return 1;
     675             :   }
     676             : 
     677           0 : error:
     678           0 :   return 0;
     679             : }
     680             : 
     681             : static const char *
     682     6342340 : match_input_with_format (unformat_input_t * input, const char *f)
     683             : {
     684             :   uword cf, ci;
     685             : 
     686     6342340 :   ASSERT (*f != 0);
     687             : 
     688             :   while (1)
     689             :     {
     690    13108100 :       cf = *f;
     691    13108100 :       if (cf == 0 || cf == '%' || cf == ' ')
     692             :         break;
     693    11336800 :       f++;
     694             : 
     695    11336800 :       ci = unformat_get_input (input);
     696             : 
     697    11336800 :       if (cf != ci)
     698     4571010 :         return 0;
     699             :     }
     700     1771330 :   return f;
     701             : }
     702             : 
     703             : static const char *
     704     2788010 : do_percent (unformat_input_t * input, va_list * va, const char *f)
     705             : {
     706     2788010 :   uword cf, n, data_bytes = ~0;
     707             : 
     708     2788010 :   cf = *f++;
     709             : 
     710     2788010 :   switch (cf)
     711             :     {
     712     2787140 :     default:
     713     2787140 :       break;
     714             : 
     715         667 :     case 'w':
     716             :       /* Word types. */
     717         667 :       cf = *f++;
     718         667 :       data_bytes = sizeof (uword);
     719         667 :       break;
     720             : 
     721         201 :     case 'l':
     722         201 :       cf = *f++;
     723         201 :       if (cf == 'l')
     724             :         {
     725         201 :           cf = *f++;
     726         201 :           data_bytes = sizeof (long long);
     727             :         }
     728             :       else
     729             :         {
     730           0 :           data_bytes = sizeof (long);
     731             :         }
     732         201 :       break;
     733             : 
     734           0 :     case 'L':
     735           0 :       cf = *f++;
     736           0 :       data_bytes = sizeof (long long);
     737           0 :       break;
     738             :     }
     739             : 
     740     2788010 :   n = 0;
     741     2788010 :   switch (cf)
     742             :     {
     743           6 :     case 'D':
     744           6 :       data_bytes = va_arg (*va, int);
     745      191953 :     case 'd':
     746      191953 :       n = unformat_integer (input, va, 10,
     747             :                             UNFORMAT_INTEGER_SIGNED, data_bytes);
     748      191953 :       break;
     749             : 
     750      113247 :     case 'u':
     751      113247 :       n = unformat_integer (input, va, 10,
     752             :                             UNFORMAT_INTEGER_UNSIGNED, data_bytes);
     753      113247 :       break;
     754             : 
     755           0 :     case 'b':
     756           0 :       n = unformat_integer (input, va, 2,
     757             :                             UNFORMAT_INTEGER_UNSIGNED, data_bytes);
     758           0 :       break;
     759             : 
     760           0 :     case 'o':
     761           0 :       n = unformat_integer (input, va, 8,
     762             :                             UNFORMAT_INTEGER_UNSIGNED, data_bytes);
     763           0 :       break;
     764             : 
     765          20 :     case 'X':
     766          20 :       data_bytes = va_arg (*va, int);
     767     1366620 :     case 'x':
     768     1366620 :       n = unformat_integer (input, va, 16,
     769             :                             UNFORMAT_INTEGER_UNSIGNED, data_bytes);
     770     1366620 :       break;
     771             : 
     772         118 :     case 'f':
     773         118 :       n = unformat_float (input, va);
     774         118 :       break;
     775             : 
     776      417693 :     case 's':
     777             :     case 'v':
     778      417693 :       n = unformat_string (input, f[0], cf, va);
     779      417693 :       break;
     780             : 
     781      698365 :     case 'U':
     782             :       {
     783      698365 :         unformat_function_t *f = va_arg (*va, unformat_function_t *);
     784      698365 :         n = f (input, va);
     785             :       }
     786      698365 :       break;
     787             : 
     788          12 :     case '=':
     789             :     case '|':
     790             :       {
     791          12 :         int *var = va_arg (*va, int *);
     792          12 :         uword val = va_arg (*va, int);
     793             : 
     794          12 :         if (cf == '|')
     795           0 :           val |= *var;
     796          12 :         *var = val;
     797          12 :         n = 1;
     798             :       }
     799          12 :       break;
     800             :     }
     801             : 
     802     2788010 :   return n ? f : 0;
     803             : }
     804             : 
     805             : __clib_export uword
     806    11788700 : unformat_skip_white_space (unformat_input_t * input)
     807             : {
     808    11788700 :   uword n = 0;
     809             :   uword c;
     810             : 
     811    13133900 :   while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
     812             :     {
     813    10774900 :       if (!is_white_space (c))
     814             :         {
     815     9429620 :           unformat_put_input (input);
     816     9429620 :           break;
     817             :         }
     818     1345240 :       n++;
     819             :     }
     820    11788700 :   return n;
     821             : }
     822             : 
     823             : __clib_export uword
     824     6792700 : va_unformat (unformat_input_t * input, const char *fmt, va_list * va)
     825             : {
     826             :   const char *f;
     827             :   uword input_matches_format;
     828             :   uword default_skip_input_white_space;
     829             :   uword n_input_white_space_skipped;
     830             :   uword last_non_white_space_match_percent;
     831             :   uword last_non_white_space_match_format;
     832             : 
     833     6792700 :   vec_add1_aligned (input->buffer_marks, input->index,
     834             :                     sizeof (input->buffer_marks[0]));
     835             : 
     836     6792700 :   f = fmt;
     837     6792700 :   default_skip_input_white_space = 1;
     838     6792700 :   input_matches_format = 0;
     839     6792700 :   last_non_white_space_match_percent = 0;
     840     6792700 :   last_non_white_space_match_format = 0;
     841             : 
     842             :   while (1)
     843     4669230 :     {
     844             :       char cf;
     845             :       uword is_percent, skip_input_white_space;
     846             : 
     847    11461900 :       cf = *f;
     848    11461900 :       is_percent = 0;
     849             : 
     850             :       /* Always skip input white space at start of format string.
     851             :          Otherwise use default skip value which can be changed by %_
     852             :          (see below). */
     853    11461900 :       skip_input_white_space = f == fmt || default_skip_input_white_space;
     854             : 
     855             :       /* Spaces in format request skipping input white space. */
     856    11461900 :       if (is_white_space (cf))
     857             :         {
     858      185641 :           skip_input_white_space = 1;
     859             : 
     860             :           /* Multiple format spaces are equivalent to a single white
     861             :              space. */
     862      185641 :           while (is_white_space (*++f))
     863             :             ;
     864             :         }
     865    11276300 :       else if (cf == '%')
     866             :         {
     867             :           /* %_ toggles whether or not to skip input white space. */
     868     3032350 :           switch (*++f)
     869             :             {
     870      244337 :             case '_':
     871      244337 :               default_skip_input_white_space =
     872      244337 :                 !default_skip_input_white_space;
     873      244337 :               f++;
     874             :               /* For transition from skip to no-skip in middle of format
     875             :                  string, skip input white space.  For example, the following matches:
     876             :                  fmt = "%_%d.%d%_->%_%d.%d%_"
     877             :                  input "1.2 -> 3.4"
     878             :                  Without this the space after -> does not get skipped. */
     879      244337 :               if (!default_skip_input_white_space
     880      244279 :                   && !(f == fmt + 2 || *f == 0))
     881          20 :                 unformat_skip_white_space (input);
     882      244337 :               continue;
     883             : 
     884             :               /* %% means match % */
     885           0 :             case '%':
     886           0 :               break;
     887             : 
     888             :               /* % at end of format string. */
     889           0 :             case 0:
     890           0 :               goto parse_fail;
     891             : 
     892     2788010 :             default:
     893     2788010 :               is_percent = 1;
     894     2788010 :               break;
     895             :             }
     896     8243940 :         }
     897             : 
     898    11217600 :       n_input_white_space_skipped = 0;
     899    11217600 :       if (skip_input_white_space)
     900    10971800 :         n_input_white_space_skipped = unformat_skip_white_space (input);
     901             : 
     902             :       /* End of format string. */
     903    11217600 :       if (cf == 0)
     904             :         {
     905             :           /* Force parse error when format string ends and input is
     906             :              not white or at end.  As an example, this is to prevent
     907             :              format "foo" from matching input "food".
     908             :              The last_non_white_space_match_percent is to make
     909             :              "foo %d" match input "foo 10,bletch" with %d matching 10. */
     910     2087240 :           if (skip_input_white_space
     911     1844430 :               && !last_non_white_space_match_percent
     912       61888 :               && !last_non_white_space_match_format
     913           0 :               && n_input_white_space_skipped == 0
     914           0 :               && input->index != UNFORMAT_END_OF_INPUT)
     915           0 :             goto parse_fail;
     916     2087240 :           break;
     917             :         }
     918             : 
     919     9130350 :       last_non_white_space_match_percent = is_percent;
     920     9130350 :       last_non_white_space_match_format = 0;
     921             : 
     922             :       /* Explicit spaces in format must match input white space. */
     923     9130350 :       if (cf == ' ' && !default_skip_input_white_space)
     924             :         {
     925           0 :           if (n_input_white_space_skipped == 0)
     926           0 :             goto parse_fail;
     927             :         }
     928             : 
     929     9130350 :       else if (is_percent)
     930             :         {
     931     2788010 :           if (!(f = do_percent (input, va, f)))
     932      134448 :             goto parse_fail;
     933             :         }
     934             : 
     935             :       else
     936             :         {
     937     6342340 :           const char *g = match_input_with_format (input, f);
     938     6342340 :           if (!g)
     939     4571010 :             goto parse_fail;
     940     1771330 :           last_non_white_space_match_format = g > f;
     941     1771330 :           f = g;
     942             :         }
     943             :     }
     944             : 
     945     2087240 :   input_matches_format = 1;
     946     6792700 : parse_fail:
     947             : 
     948             :   /* Rewind buffer marks. */
     949             :   {
     950     6792700 :     uword l = vec_len (input->buffer_marks);
     951             : 
     952             :     /* If we did not match back up buffer to last mark. */
     953     6792700 :     if (!input_matches_format)
     954     4705460 :       input->index = input->buffer_marks[l - 1];
     955             : 
     956     6792700 :     vec_set_len (input->buffer_marks, l - 1);
     957             :   }
     958             : 
     959     6792700 :   return input_matches_format;
     960             : }
     961             : 
     962             : __clib_export uword
     963     5916180 : unformat (unformat_input_t * input, const char *fmt, ...)
     964             : {
     965             :   va_list va;
     966             :   uword result;
     967     5916180 :   va_start (va, fmt);
     968     5916180 :   result = va_unformat (input, fmt, &va);
     969     5916180 :   va_end (va);
     970     5916180 :   return result;
     971             : }
     972             : 
     973             : __clib_export uword
     974     1564490 : unformat_user (unformat_input_t * input, unformat_function_t * func, ...)
     975             : {
     976             :   va_list va;
     977             :   uword result, l;
     978             : 
     979             :   /* Save place in input buffer in case parse fails. */
     980     1564490 :   l = vec_len (input->buffer_marks);
     981     1564490 :   vec_add1_aligned (input->buffer_marks, input->index,
     982             :                     sizeof (input->buffer_marks[0]));
     983             : 
     984     1564490 :   va_start (va, func);
     985     1564490 :   result = func (input, &va);
     986     1564490 :   va_end (va);
     987             : 
     988     1564490 :   if (!result && input->index != UNFORMAT_END_OF_INPUT)
     989      499795 :     input->index = input->buffer_marks[l];
     990             : 
     991     1564490 :   vec_set_len (input->buffer_marks, l);
     992             : 
     993     1564490 :   return result;
     994             : }
     995             : 
     996             : /* Setup for unformat of Unix style command line. */
     997             : __clib_export void
     998        2304 : unformat_init_command_line (unformat_input_t * input, char *argv[])
     999             : {
    1000             :   uword i;
    1001             : 
    1002        2304 :   unformat_init (input, 0, 0);
    1003             : 
    1004             :   /* Concatenate argument strings with space in between. */
    1005      162440 :   for (i = 1; argv[i]; i++)
    1006             :     {
    1007      160136 :       vec_add (input->buffer, argv[i], strlen (argv[i]));
    1008      160136 :       if (argv[i + 1])
    1009      157832 :         vec_add1 (input->buffer, ' ');
    1010             :     }
    1011        2304 : }
    1012             : 
    1013             : __clib_export void
    1014      433559 : unformat_init_string (unformat_input_t *input, const char *string,
    1015             :                       int string_len)
    1016             : {
    1017      433559 :   unformat_init (input, 0, 0);
    1018      433559 :   if (string_len > 0)
    1019      433557 :     vec_add (input->buffer, string, string_len);
    1020      433559 : }
    1021             : 
    1022             : __clib_export void
    1023      981709 : unformat_init_vector (unformat_input_t * input, u8 * vector_string)
    1024             : {
    1025      981709 :   unformat_init (input, 0, 0);
    1026      981709 :   input->buffer = vector_string;
    1027      981709 : }
    1028             : 
    1029             : #ifdef CLIB_UNIX
    1030             : 
    1031             : static uword
    1032           0 : clib_file_fill_buffer (unformat_input_t * input)
    1033             : {
    1034           0 :   int fd = pointer_to_uword (input->fill_buffer_arg);
    1035             :   uword l, n;
    1036             : 
    1037           0 :   l = vec_len (input->buffer);
    1038           0 :   vec_resize (input->buffer, 4096);
    1039           0 :   n = read (fd, input->buffer + l, 4096);
    1040           0 :   if (n > 0)
    1041           0 :     vec_set_len (input->buffer, l + n);
    1042             : 
    1043           0 :   if (n <= 0)
    1044           0 :     return UNFORMAT_END_OF_INPUT;
    1045             :   else
    1046           0 :     return input->index;
    1047             : }
    1048             : 
    1049             : static void
    1050           0 : unformat_close_fd (unformat_input_t *input)
    1051             : {
    1052           0 :   int fd = pointer_to_uword (input->fill_buffer_arg);
    1053           0 :   close (fd);
    1054           0 : }
    1055             : 
    1056             : __clib_export void
    1057           0 : unformat_init_clib_file (unformat_input_t * input, int file_descriptor)
    1058             : {
    1059           0 :   unformat_init (input, clib_file_fill_buffer,
    1060           0 :                  uword_to_pointer (file_descriptor, void *));
    1061           0 : }
    1062             : 
    1063             : __clib_export uword
    1064           0 : unformat_init_file (unformat_input_t *input, char *fmt, ...)
    1065             : {
    1066             :   va_list va;
    1067             :   u8 *path;
    1068             :   int fd;
    1069             : 
    1070           0 :   va_start (va, fmt);
    1071           0 :   path = va_format (0, fmt, &va);
    1072           0 :   va_end (va);
    1073           0 :   vec_add1 (path, 0);
    1074             : 
    1075           0 :   fd = open ((char *) path, 0);
    1076           0 :   vec_free (path);
    1077             : 
    1078           0 :   if (fd >= 0)
    1079             :     {
    1080           0 :       unformat_init (input, clib_file_fill_buffer,
    1081           0 :                      uword_to_pointer (fd, void *));
    1082           0 :       input->free = unformat_close_fd;
    1083           0 :       return 1;
    1084             :     }
    1085           0 :   return 0;
    1086             : }
    1087             : 
    1088             : /* Take input from Unix environment variable. */
    1089             : uword
    1090           0 : unformat_init_unix_env (unformat_input_t * input, char *var)
    1091             : {
    1092           0 :   char *val = getenv (var);
    1093           0 :   if (val)
    1094           0 :     unformat_init_string (input, val, strlen (val));
    1095           0 :   return val != 0;
    1096             : }
    1097             : 
    1098             : __clib_export uword
    1099           4 : unformat_data_size (unformat_input_t * input, va_list * args)
    1100             : {
    1101             :   u64 _a;
    1102           4 :   u64 *a = va_arg (*args, u64 *);
    1103           4 :   if (unformat (input, "%lluGb", &_a))
    1104           0 :     *a = _a << 30;
    1105           4 :   else if (unformat (input, "%lluG", &_a))
    1106           0 :     *a = _a << 30;
    1107           4 :   else if (unformat (input, "%lluMb", &_a))
    1108           0 :     *a = _a << 20;
    1109           4 :   else if (unformat (input, "%lluM", &_a))
    1110           2 :     *a = _a << 20;
    1111           2 :   else if (unformat (input, "%lluKb", &_a))
    1112           0 :     *a = _a << 10;
    1113           2 :   else if (unformat (input, "%lluK", &_a))
    1114           0 :     *a = _a << 10;
    1115           2 :   else if (unformat (input, "%llu", a))
    1116             :     ;
    1117             :   else
    1118           0 :     return 0;
    1119           4 :   return 1;
    1120             : }
    1121             : 
    1122             : __clib_export uword
    1123           0 : unformat_c_string_array (unformat_input_t *input, va_list *va)
    1124             : {
    1125           0 :   char *str = va_arg (*va, char *);
    1126           0 :   u32 array_len = va_arg (*va, u32);
    1127           0 :   uword c, rv = 0;
    1128           0 :   u8 *s = 0;
    1129             : 
    1130           0 :   if (unformat (input, "%v", &s) == 0)
    1131           0 :     return 0;
    1132             : 
    1133           0 :   c = vec_len (s);
    1134             : 
    1135           0 :   if (c > 0 && c < array_len)
    1136             :     {
    1137           0 :       clib_memcpy (str, s, c);
    1138           0 :       str[c] = 0;
    1139           0 :       rv = 1;
    1140             :     }
    1141             : 
    1142           0 :   vec_free (s);
    1143           0 :   return rv;
    1144             : }
    1145             : 
    1146             : #endif /* CLIB_UNIX */
    1147             : 
    1148             : 
    1149             : /*
    1150             :  * fd.io coding-style-patch-verification: ON
    1151             :  *
    1152             :  * Local Variables:
    1153             :  * eval: (c-set-style "gnu")
    1154             :  * End:
    1155             :  */

Generated by: LCOV version 1.14