blob: fe1a46e4a1269fd41fa80d8a76c731c6d88bb9ff [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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>
Damjan Marion8d0c0c62023-08-06 20:39:38 +020039#include <fcntl.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070040
41/* Call user's function to fill input buffer. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +020042__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -040043_unformat_fill_input (unformat_input_t * i)
Ed Warnickecb9cada2015-12-08 15:45:58 -070044{
45 uword l, first_mark;
46
47 if (i->index == UNFORMAT_END_OF_INPUT)
48 return i->index;
49
50 first_mark = l = vec_len (i->buffer);
51 if (vec_len (i->buffer_marks) > 0)
52 first_mark = i->buffer_marks[0];
53
54 /* Re-use buffer when no marks. */
55 if (first_mark > 0)
56 vec_delete (i->buffer, first_mark, 0);
57
58 i->index = vec_len (i->buffer);
59 for (l = 0; l < vec_len (i->buffer_marks); l++)
60 i->buffer_marks[l] -= first_mark;
61
62 /* Call user's function to fill the buffer. */
63 if (i->fill_buffer)
64 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 if (i->index >= vec_len (i->buffer))
69 i->index = UNFORMAT_END_OF_INPUT;
70
71 return i->index;
72}
73
Ed Warnickecb9cada2015-12-08 15:45:58 -070074/* Format function for dumping input stream. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +020075__clib_export u8 *
Dave Barachc3799992016-08-15 11:12:27 -040076format_unformat_error (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -070077{
Dave Barachc3799992016-08-15 11:12:27 -040078 unformat_input_t *i = va_arg (*va, unformat_input_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -070079 uword l = vec_len (i->buffer);
80
81 /* Only show so much of the input buffer (it could be really large). */
82 uword n_max = 30;
83
84 if (i->index < l)
85 {
86 uword n = l - i->index;
Dave Barachc3799992016-08-15 11:12:27 -040087 u8 *p, *p_end;
Ed Warnickecb9cada2015-12-08 15:45:58 -070088
89 p = i->buffer + i->index;
90 p_end = p + (n > n_max ? n_max : n);
91
92 /* Skip white space at end. */
93 if (n <= n_max)
94 {
95 while (p_end > p && is_white_space (p_end[-1]))
96 p_end--;
97 }
98
99 while (p < p_end)
100 {
101 switch (*p)
102 {
Dave Barachc3799992016-08-15 11:12:27 -0400103 case '\r':
104 vec_add (s, "\\r", 2);
105 break;
106 case '\n':
107 vec_add (s, "\\n", 2);
108 break;
109 case '\t':
110 vec_add (s, "\\t", 2);
111 break;
112 default:
113 vec_add1 (s, *p);
114 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115 }
116 p++;
117 }
118
119 if (n > n_max)
120 vec_add (s, "...", 3);
121 }
122
123 return s;
124}
125
126/* Print everything: not just error context. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200127__clib_export u8 *
Dave Barachc3799992016-08-15 11:12:27 -0400128format_unformat_input (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700129{
Dave Barachc3799992016-08-15 11:12:27 -0400130 unformat_input_t *i = va_arg (*va, unformat_input_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131 uword l, n;
132
133 if (i->index == UNFORMAT_END_OF_INPUT)
134 s = format (s, "{END_OF_INPUT}");
135 else
136 {
137 l = vec_len (i->buffer);
138 n = l - i->index;
139 if (n > 0)
140 vec_add (s, i->buffer + i->index, n);
141 }
142
143 return s;
144}
145
146#if CLIB_DEBUG > 0
Dave Barachc3799992016-08-15 11:12:27 -0400147void
148di (unformat_input_t * i)
149{
150 fformat (stderr, "%U\n", format_unformat_input, i);
151}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700152#endif
153
154/* Parse delimited vector string. If string starts with { then string
Paul Vinciguerraec11b132018-09-24 05:25:00 -0700155 is delimited by balanced parenthesis. Other string is delimited by
Ed Warnickecb9cada2015-12-08 15:45:58 -0700156 white space. {} were chosen since they are special to the shell. */
157static uword
158unformat_string (unformat_input_t * input,
159 uword delimiter_character,
Dave Barachc3799992016-08-15 11:12:27 -0400160 uword format_character, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700161{
Dave Barachc3799992016-08-15 11:12:27 -0400162 u8 **string_return = va_arg (*va, u8 **);
163 u8 *s = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164 word paren = 0;
165 word is_paren_delimited = 0;
166 word backslash = 0;
167 uword c;
168
169 switch (delimiter_character)
170 {
171 case '%':
172 case ' ':
173 case '\t':
174 delimiter_character = 0;
175 break;
176 }
177
178 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 add_to_vector = string_return != 0;
184
185 if (backslash)
186 backslash = 0;
187 else
188 switch (c)
189 {
190 case '\\':
191 backslash = 1;
192 add_to_vector = 0;
193 break;
194
195 case '{':
196 if (paren == 0 && vec_len (s) == 0)
197 {
198 is_paren_delimited = 1;
199 add_to_vector = 0;
200 }
201 paren++;
202 break;
203
204 case '}':
205 paren--;
206 if (is_paren_delimited && paren == 0)
207 goto done;
208 break;
209
210 case ' ':
211 case '\t':
212 case '\n':
213 case '\r':
Dave Barachc3799992016-08-15 11:12:27 -0400214 if (!is_paren_delimited)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215 {
216 unformat_put_input (input);
217 goto done;
218 }
219 break;
220
221 default:
Dave Barachc3799992016-08-15 11:12:27 -0400222 if (!is_paren_delimited && c == delimiter_character)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223 {
224 unformat_put_input (input);
225 goto done;
226 }
227 }
228
229 if (add_to_vector)
230 vec_add1 (s, c);
231 }
232
Dave Barachc3799992016-08-15 11:12:27 -0400233done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234 if (string_return)
235 {
236 /* Match the string { END-OF-INPUT as a single brace. */
237 if (c == UNFORMAT_END_OF_INPUT && vec_len (s) == 0 && paren == 1)
Dave Barachc3799992016-08-15 11:12:27 -0400238 vec_add1 (s, '{');
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239
240 /* Don't match null string. */
241 if (c == UNFORMAT_END_OF_INPUT && vec_len (s) == 0)
242 return 0;
Dave Barachc3799992016-08-15 11:12:27 -0400243
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244 /* Null terminate C string. */
245 if (format_character == 's')
246 vec_add1 (s, 0);
247
248 *string_return = s;
249 }
250 else
251 vec_free (s); /* just to make sure */
252
253 return 1;
254}
255
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200256__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400257unformat_hex_string (unformat_input_t * input, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700258{
Dave Barachc3799992016-08-15 11:12:27 -0400259 u8 **hexstring_return = va_arg (*va, u8 **);
260 u8 *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261 uword n, d, c;
262
263 n = 0;
264 d = 0;
265 s = 0;
266 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
267 {
268 if (c >= '0' && c <= '9')
Dave Barachc3799992016-08-15 11:12:27 -0400269 d = 16 * d + c - '0';
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270 else if (c >= 'a' && c <= 'f')
Dave Barachc3799992016-08-15 11:12:27 -0400271 d = 16 * d + 10 + c - 'a';
Ed Warnickecb9cada2015-12-08 15:45:58 -0700272 else if (c >= 'A' && c <= 'F')
Dave Barachc3799992016-08-15 11:12:27 -0400273 d = 16 * d + 10 + c - 'A';
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274 else
275 {
276 unformat_put_input (input);
277 break;
278 }
279 n++;
280
281 if (n == 2)
282 {
283 vec_add1 (s, d);
284 n = d = 0;
285 }
286 }
287
288 /* Hex string must have even number of digits. */
289 if (n % 2)
290 {
291 vec_free (s);
292 return 0;
293 }
Billy McFall205e9342017-02-15 09:03:06 -0500294 /* Make sure something was processed. */
295 else if (s == 0)
296 {
297 return 0;
298 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299
300 *hexstring_return = s;
301 return 1;
302}
303
304/* unformat (input "foo%U", unformat_eof) matches terminal foo only */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200305__clib_export uword
Ed Warnickecb9cada2015-12-08 15:45:58 -0700306unformat_eof (unformat_input_t * input, va_list * va)
307{
308 return unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
309}
310
311/* Parse a token containing given set of characters. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200312__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400313unformat_token (unformat_input_t * input, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700314{
Dave Barachc3799992016-08-15 11:12:27 -0400315 u8 *token_chars = va_arg (*va, u8 *);
316 u8 **string_return = va_arg (*va, u8 **);
317 u8 *s, map[256];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318 uword i, c;
319
Dave Barachc3799992016-08-15 11:12:27 -0400320 if (!token_chars)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700321 token_chars = (u8 *) "a-zA-Z0-9_";
322
Dave Barachb7b92992018-10-17 10:38:51 -0400323 clib_memset (map, 0, sizeof (map));
Dave Barachc3799992016-08-15 11:12:27 -0400324 for (s = token_chars; *s;)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700325 {
Benoît Ganne052bda32019-04-18 17:42:24 +0200326 /*
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 if (s[1] == '-' && s[0] < s[2])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700334 {
335 for (i = s[0]; i <= s[2]; i++)
336 map[i] = 1;
337 s = s + 3;
Dave Barachc3799992016-08-15 11:12:27 -0400338 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339 else
340 {
341 map[s[0]] = 1;
342 s = s + 1;
343 }
344 }
345
346 s = 0;
347 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
348 {
Dave Barachc3799992016-08-15 11:12:27 -0400349 if (!map[c])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700350 {
351 unformat_put_input (input);
352 break;
353 }
Dave Barachc3799992016-08-15 11:12:27 -0400354
Ed Warnickecb9cada2015-12-08 15:45:58 -0700355 vec_add1 (s, c);
356 }
357
358 if (vec_len (s) == 0)
359 return 0;
360
361 *string_return = s;
362 return 1;
363}
364
365/* Unformat (parse) function which reads a %s string and converts it
366 to and unformat_input_t. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200367__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400368unformat_input (unformat_input_t * i, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700369{
Dave Barachc3799992016-08-15 11:12:27 -0400370 unformat_input_t *sub_input = va_arg (*args, unformat_input_t *);
371 u8 *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700372
373 if (unformat (i, "%v", &s))
374 {
375 unformat_init_vector (sub_input, s);
376 return 1;
377 }
378
379 return 0;
380}
381
382/* Parse a line ending with \n and return it. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200383__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400384unformat_line (unformat_input_t * i, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700385{
Dave Barachc3799992016-08-15 11:12:27 -0400386 u8 *line = 0, **result = va_arg (*va, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700387 uword c;
388
Dave Barachc3799992016-08-15 11:12:27 -0400389 while ((c = unformat_get_input (i)) != '\n' && c != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700390 {
391 vec_add1 (line, c);
392 }
393
394 *result = line;
Alexander Kotov28160f32017-07-10 18:23:31 +0300395 return vec_len (line);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700396}
397
398/* Parse a line ending with \n and return it as an unformat_input_t. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200399__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400400unformat_line_input (unformat_input_t * i, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700401{
Dave Barachc3799992016-08-15 11:12:27 -0400402 unformat_input_t *result = va_arg (*va, unformat_input_t *);
403 u8 *line;
Alexander Kotov28160f32017-07-10 18:23:31 +0300404 if (!unformat_user (i, unformat_line, &line))
405 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700406 unformat_init_vector (result, line);
407 return 1;
408}
409
410/* Values for is_signed. */
411#define UNFORMAT_INTEGER_SIGNED 1
412#define UNFORMAT_INTEGER_UNSIGNED 0
413
414static uword
415unformat_integer (unformat_input_t * input,
Dave Barachc3799992016-08-15 11:12:27 -0400416 va_list * va, uword base, uword is_signed, uword data_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700417{
418 uword c, digit;
419 uword value = 0;
420 uword n_digits = 0;
421 uword n_input = 0;
422 uword sign = 0;
423
424 /* We only support bases <= 64. */
425 if (base < 2 || base > 64)
426 goto error;
427
428 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
429 {
430 switch (c)
431 {
432 case '-':
433 if (n_input == 0)
434 {
435 if (is_signed)
436 {
437 sign = 1;
438 goto next_digit;
439 }
440 else
441 /* Leading sign for unsigned number. */
442 goto error;
443 }
444 /* Sign after input (e.g. 100-200). */
445 goto put_input_done;
446
447 case '+':
Dave Barachc3799992016-08-15 11:12:27 -0400448 if (n_input > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700449 goto put_input_done;
450 sign = 0;
451 goto next_digit;
452
453 case '0' ... '9':
454 digit = c - '0';
455 break;
456
457 case 'a' ... 'z':
458 digit = 10 + (c - 'a');
459 break;
460
461 case 'A' ... 'Z':
462 digit = 10 + (base >= 36 ? 26 : 0) + (c - 'A');
463 break;
464
465 case '/':
466 digit = 62;
467 break;
468
469 case '?':
470 digit = 63;
471 break;
472
473 default:
474 goto put_input_done;
475 }
476
477 if (digit >= base)
478 {
479 put_input_done:
480 unformat_put_input (input);
481 goto done;
482 }
483
484 {
Dave Barachc3799992016-08-15 11:12:27 -0400485 uword new_value = base * value + digit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700486
487 /* Check for overflow. */
488 if (new_value < value)
489 goto error;
490 value = new_value;
491 }
492 n_digits += 1;
493
494 next_digit:
495 n_input++;
496 }
497
Dave Barachc3799992016-08-15 11:12:27 -0400498done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700499 if (sign)
500 value = -value;
501
502 if (n_digits > 0)
503 {
Dave Barachc3799992016-08-15 11:12:27 -0400504 void *v = va_arg (*va, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700505
506 if (data_bytes == ~0)
Dave Barachc3799992016-08-15 11:12:27 -0400507 data_bytes = sizeof (int);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700508
509 switch (data_bytes)
510 {
Dave Barachc3799992016-08-15 11:12:27 -0400511 case 1:
512 *(u8 *) v = value;
513 break;
514 case 2:
515 *(u16 *) v = value;
516 break;
517 case 4:
518 *(u32 *) v = value;
519 break;
520 case 8:
521 *(u64 *) v = value;
522 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700523 default:
Dave Barachc3799992016-08-15 11:12:27 -0400524 goto error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700525 }
526
527 return 1;
528 }
529
Dave Barachc3799992016-08-15 11:12:27 -0400530error:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700531 return 0;
532}
533
534/* Return x 10^n */
Dave Barachc3799992016-08-15 11:12:27 -0400535static f64
536times_power_of_ten (f64 x, int n)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700537{
538 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 while (n >= 8)
542 {
543 x *= 1e+8;
544 n -= 8;
545 }
546 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 while (n <= -8)
552 {
553 x *= 1e-8;
554 n += 8;
555 }
556 return x * t[-n];
557 }
Dave Barachc3799992016-08-15 11:12:27 -0400558
Ed Warnickecb9cada2015-12-08 15:45:58 -0700559}
560
561static uword
Dave Barachc3799992016-08-15 11:12:27 -0400562unformat_float (unformat_input_t * input, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700563{
564 uword c;
565 u64 values[3];
566 uword n_digits[3], value_index = 0;
567 uword signs[2], sign_index = 0;
568 uword n_input = 0;
569
Dave Barachb7b92992018-10-17 10:38:51 -0400570 clib_memset (values, 0, sizeof (values));
571 clib_memset (n_digits, 0, sizeof (n_digits));
572 clib_memset (signs, 0, sizeof (signs));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700573
574 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
575 {
576 switch (c)
577 {
578 case '-':
579 if (value_index == 2 && n_digits[2] == 0)
Dave Barachc3799992016-08-15 11:12:27 -0400580 /* sign of exponent: it's ok. */ ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700581
582 else if (value_index < 2 && n_digits[0] > 0)
583 {
584 /* 123- */
585 unformat_put_input (input);
586 goto done;
587 }
588
589 else if (n_input > 0)
590 goto error;
591
592 signs[sign_index++] = 1;
593 goto next_digit;
594
595 case '+':
596 if (value_index == 2 && n_digits[2] == 0)
Dave Barachc3799992016-08-15 11:12:27 -0400597 /* sign of exponent: it's ok. */ ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700598
599 else if (value_index < 2 && n_digits[0] > 0)
600 {
601 /* 123+ */
602 unformat_put_input (input);
603 goto done;
604 }
605
606 else if (n_input > 0)
607 goto error;
608 signs[sign_index++] = 0;
609 goto next_digit;
610
611 case 'e':
612 case 'E':
613 if (n_input == 0)
614 goto error;
615 value_index = 2;
616 sign_index = 1;
617 break;
618
619 case '.':
620 if (value_index > 0)
621 goto error;
622 value_index = 1;
623 break;
624
625 case '0' ... '9':
626 {
627 u64 tmp;
628
629 tmp = values[value_index] * 10 + c - '0';
630
631 /* Check for overflow. */
632 if (tmp < values[value_index])
633 goto error;
634 values[value_index] = tmp;
635 n_digits[value_index] += 1;
636 }
637 break;
638
639 default:
640 unformat_put_input (input);
641 goto done;
642 }
643
644 next_digit:
645 n_input++;
646 }
647
Dave Barachc3799992016-08-15 11:12:27 -0400648done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700649 {
Dave Barachc3799992016-08-15 11:12:27 -0400650 f64 f_values[2], *value_return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700651 word expon;
652
653 /* Must have either whole or fraction digits. */
654 if (n_digits[0] + n_digits[1] <= 0)
655 goto error;
656
657 f_values[0] = values[0];
658 if (signs[0])
659 f_values[0] = -f_values[0];
660
661 f_values[1] = values[1];
662 f_values[1] = times_power_of_ten (f_values[1], -n_digits[1]);
663
664 f_values[0] += f_values[1];
665
666 expon = values[2];
667 if (signs[1])
668 expon = -expon;
669
670 f_values[0] = times_power_of_ten (f_values[0], expon);
671
672 value_return = va_arg (*va, f64 *);
673 *value_return = f_values[0];
674 return 1;
675 }
676
Dave Barachc3799992016-08-15 11:12:27 -0400677error:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700678 return 0;
679}
680
Neale Ranns32e1c012016-11-22 17:07:28 +0000681static const char *
682match_input_with_format (unformat_input_t * input, const char *f)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700683{
684 uword cf, ci;
685
686 ASSERT (*f != 0);
687
688 while (1)
689 {
690 cf = *f;
691 if (cf == 0 || cf == '%' || cf == ' ')
692 break;
693 f++;
694
695 ci = unformat_get_input (input);
696
697 if (cf != ci)
698 return 0;
699 }
700 return f;
701}
702
Neale Ranns32e1c012016-11-22 17:07:28 +0000703static const char *
704do_percent (unformat_input_t * input, va_list * va, const char *f)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700705{
706 uword cf, n, data_bytes = ~0;
707
708 cf = *f++;
709
710 switch (cf)
711 {
712 default:
713 break;
714
715 case 'w':
716 /* Word types. */
717 cf = *f++;
718 data_bytes = sizeof (uword);
719 break;
720
721 case 'l':
722 cf = *f++;
723 if (cf == 'l')
724 {
725 cf = *f++;
726 data_bytes = sizeof (long long);
727 }
728 else
729 {
730 data_bytes = sizeof (long);
731 }
732 break;
Dave Barachc3799992016-08-15 11:12:27 -0400733
Ed Warnickecb9cada2015-12-08 15:45:58 -0700734 case 'L':
735 cf = *f++;
736 data_bytes = sizeof (long long);
737 break;
738 }
739
740 n = 0;
741 switch (cf)
742 {
743 case 'D':
744 data_bytes = va_arg (*va, int);
745 case 'd':
746 n = unformat_integer (input, va, 10,
747 UNFORMAT_INTEGER_SIGNED, data_bytes);
748 break;
749
750 case 'u':
751 n = unformat_integer (input, va, 10,
752 UNFORMAT_INTEGER_UNSIGNED, data_bytes);
753 break;
754
755 case 'b':
756 n = unformat_integer (input, va, 2,
757 UNFORMAT_INTEGER_UNSIGNED, data_bytes);
758 break;
759
760 case 'o':
761 n = unformat_integer (input, va, 8,
762 UNFORMAT_INTEGER_UNSIGNED, data_bytes);
763 break;
764
765 case 'X':
766 data_bytes = va_arg (*va, int);
767 case 'x':
768 n = unformat_integer (input, va, 16,
769 UNFORMAT_INTEGER_UNSIGNED, data_bytes);
770 break;
771
772 case 'f':
773 n = unformat_float (input, va);
774 break;
775
776 case 's':
777 case 'v':
778 n = unformat_string (input, f[0], cf, va);
779 break;
780
781 case 'U':
782 {
Dave Barachc3799992016-08-15 11:12:27 -0400783 unformat_function_t *f = va_arg (*va, unformat_function_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700784 n = f (input, va);
785 }
786 break;
787
788 case '=':
789 case '|':
790 {
Dave Barachc3799992016-08-15 11:12:27 -0400791 int *var = va_arg (*va, int *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700792 uword val = va_arg (*va, int);
793
794 if (cf == '|')
795 val |= *var;
796 *var = val;
797 n = 1;
798 }
799 break;
800 }
801
802 return n ? f : 0;
803}
804
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200805__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400806unformat_skip_white_space (unformat_input_t * input)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700807{
808 uword n = 0;
809 uword c;
810
811 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
812 {
Dave Barachc3799992016-08-15 11:12:27 -0400813 if (!is_white_space (c))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700814 {
815 unformat_put_input (input);
816 break;
817 }
818 n++;
819 }
820 return n;
821}
822
Juraj Linkeš7aa76d42020-10-22 13:29:28 +0200823__clib_export uword
Neale Ranns32e1c012016-11-22 17:07:28 +0000824va_unformat (unformat_input_t * input, const char *fmt, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700825{
Neale Ranns32e1c012016-11-22 17:07:28 +0000826 const char *f;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700827 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
Dave Barachc3799992016-08-15 11:12:27 -0400833 vec_add1_aligned (input->buffer_marks, input->index,
834 sizeof (input->buffer_marks[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700835
836 f = fmt;
837 default_skip_input_white_space = 1;
838 input_matches_format = 0;
839 last_non_white_space_match_percent = 0;
840 last_non_white_space_match_format = 0;
Dave Barachc3799992016-08-15 11:12:27 -0400841
Ed Warnickecb9cada2015-12-08 15:45:58 -0700842 while (1)
843 {
844 char cf;
845 uword is_percent, skip_input_white_space;
846
847 cf = *f;
848 is_percent = 0;
849
850 /* Always skip input white space at start of format string.
Dave Barachc3799992016-08-15 11:12:27 -0400851 Otherwise use default skip value which can be changed by %_
852 (see below). */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700853 skip_input_white_space = f == fmt || default_skip_input_white_space;
854
855 /* Spaces in format request skipping input white space. */
856 if (is_white_space (cf))
857 {
858 skip_input_white_space = 1;
859
860 /* Multiple format spaces are equivalent to a single white
861 space. */
862 while (is_white_space (*++f))
863 ;
864 }
865 else if (cf == '%')
866 {
867 /* %_ toggles whether or not to skip input white space. */
868 switch (*++f)
869 {
870 case '_':
Dave Barachc3799992016-08-15 11:12:27 -0400871 default_skip_input_white_space =
872 !default_skip_input_white_space;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700873 f++;
874 /* For transition from skip to no-skip in middle of format
Dave Barachc3799992016-08-15 11:12:27 -0400875 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 if (!default_skip_input_white_space
880 && !(f == fmt + 2 || *f == 0))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700881 unformat_skip_white_space (input);
882 continue;
883
Dave Barachc3799992016-08-15 11:12:27 -0400884 /* %% means match % */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700885 case '%':
886 break;
887
Dave Barachc3799992016-08-15 11:12:27 -0400888 /* % at end of format string. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700889 case 0:
890 goto parse_fail;
891
892 default:
893 is_percent = 1;
894 break;
895 }
896 }
897
898 n_input_white_space_skipped = 0;
899 if (skip_input_white_space)
900 n_input_white_space_skipped = unformat_skip_white_space (input);
901
902 /* End of format string. */
903 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 if (skip_input_white_space
Dave Barachc3799992016-08-15 11:12:27 -0400911 && !last_non_white_space_match_percent
912 && !last_non_white_space_match_format
Ed Warnickecb9cada2015-12-08 15:45:58 -0700913 && n_input_white_space_skipped == 0
914 && input->index != UNFORMAT_END_OF_INPUT)
915 goto parse_fail;
916 break;
917 }
918
919 last_non_white_space_match_percent = is_percent;
920 last_non_white_space_match_format = 0;
921
922 /* Explicit spaces in format must match input white space. */
923 if (cf == ' ' && !default_skip_input_white_space)
924 {
925 if (n_input_white_space_skipped == 0)
926 goto parse_fail;
927 }
928
929 else if (is_percent)
930 {
Dave Barachc3799992016-08-15 11:12:27 -0400931 if (!(f = do_percent (input, va, f)))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700932 goto parse_fail;
933 }
934
935 else
936 {
Neale Ranns32e1c012016-11-22 17:07:28 +0000937 const char *g = match_input_with_format (input, f);
Dave Barachc3799992016-08-15 11:12:27 -0400938 if (!g)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700939 goto parse_fail;
940 last_non_white_space_match_format = g > f;
941 f = g;
942 }
943 }
944
945 input_matches_format = 1;
Dave Barachc3799992016-08-15 11:12:27 -0400946parse_fail:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700947
948 /* Rewind buffer marks. */
949 {
950 uword l = vec_len (input->buffer_marks);
951
952 /* If we did not match back up buffer to last mark. */
Dave Barachc3799992016-08-15 11:12:27 -0400953 if (!input_matches_format)
954 input->index = input->buffer_marks[l - 1];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700955
Damjan Marion8bea5892022-04-04 22:40:45 +0200956 vec_set_len (input->buffer_marks, l - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700957 }
958
959 return input_matches_format;
960}
961
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200962__clib_export uword
Neale Ranns32e1c012016-11-22 17:07:28 +0000963unformat (unformat_input_t * input, const char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700964{
965 va_list va;
966 uword result;
967 va_start (va, fmt);
968 result = va_unformat (input, fmt, &va);
969 va_end (va);
970 return result;
971}
972
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200973__clib_export uword
Ed Warnickecb9cada2015-12-08 15:45:58 -0700974unformat_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 l = vec_len (input->buffer_marks);
Dave Barachc3799992016-08-15 11:12:27 -0400981 vec_add1_aligned (input->buffer_marks, input->index,
982 sizeof (input->buffer_marks[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700983
984 va_start (va, func);
985 result = func (input, &va);
986 va_end (va);
987
Dave Barachdddccea2016-10-26 14:03:20 -0400988 if (!result && input->index != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700989 input->index = input->buffer_marks[l];
990
Damjan Marion8bea5892022-04-04 22:40:45 +0200991 vec_set_len (input->buffer_marks, l);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700992
993 return result;
994}
995
996/* Setup for unformat of Unix style command line. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200997__clib_export void
Dave Barachc3799992016-08-15 11:12:27 -0400998unformat_init_command_line (unformat_input_t * input, char *argv[])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700999{
1000 uword i;
1001
1002 unformat_init (input, 0, 0);
1003
1004 /* Concatenate argument strings with space in between. */
1005 for (i = 1; argv[i]; i++)
1006 {
1007 vec_add (input->buffer, argv[i], strlen (argv[i]));
1008 if (argv[i + 1])
1009 vec_add1 (input->buffer, ' ');
1010 }
1011}
1012
Damjan Mariondae1c7e2020-10-17 13:32:25 +02001013__clib_export void
Benoît Ganne82f618c2021-10-13 11:35:15 +02001014unformat_init_string (unformat_input_t *input, const char *string,
1015 int string_len)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001016{
1017 unformat_init (input, 0, 0);
1018 if (string_len > 0)
1019 vec_add (input->buffer, string, string_len);
1020}
1021
Damjan Mariondae1c7e2020-10-17 13:32:25 +02001022__clib_export void
Dave Barachc3799992016-08-15 11:12:27 -04001023unformat_init_vector (unformat_input_t * input, u8 * vector_string)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001024{
1025 unformat_init (input, 0, 0);
1026 input->buffer = vector_string;
1027}
1028
1029#ifdef CLIB_UNIX
1030
Dave Barachc3799992016-08-15 11:12:27 -04001031static uword
Dave Barach59b25652017-09-10 15:04:27 -04001032clib_file_fill_buffer (unformat_input_t * input)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033{
1034 int fd = pointer_to_uword (input->fill_buffer_arg);
1035 uword l, n;
1036
1037 l = vec_len (input->buffer);
1038 vec_resize (input->buffer, 4096);
1039 n = read (fd, input->buffer + l, 4096);
1040 if (n > 0)
Damjan Marion8bea5892022-04-04 22:40:45 +02001041 vec_set_len (input->buffer, l + n);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001042
1043 if (n <= 0)
1044 return UNFORMAT_END_OF_INPUT;
1045 else
1046 return input->index;
1047}
1048
Damjan Marion8d0c0c62023-08-06 20:39:38 +02001049static void
1050unformat_close_fd (unformat_input_t *input)
1051{
1052 int fd = pointer_to_uword (input->fill_buffer_arg);
1053 close (fd);
1054}
1055
Damjan Mariondae1c7e2020-10-17 13:32:25 +02001056__clib_export void
Dave Barach59b25652017-09-10 15:04:27 -04001057unformat_init_clib_file (unformat_input_t * input, int file_descriptor)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001058{
Dave Barach59b25652017-09-10 15:04:27 -04001059 unformat_init (input, clib_file_fill_buffer,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001060 uword_to_pointer (file_descriptor, void *));
1061}
1062
Damjan Marion8d0c0c62023-08-06 20:39:38 +02001063__clib_export uword
1064unformat_init_file (unformat_input_t *input, char *fmt, ...)
1065{
1066 va_list va;
1067 u8 *path;
1068 int fd;
1069
1070 va_start (va, fmt);
1071 path = va_format (0, fmt, &va);
1072 va_end (va);
1073 vec_add1 (path, 0);
1074
1075 fd = open ((char *) path, 0);
1076 vec_free (path);
1077
1078 if (fd >= 0)
1079 {
1080 unformat_init (input, clib_file_fill_buffer,
1081 uword_to_pointer (fd, void *));
1082 input->free = unformat_close_fd;
1083 return 1;
1084 }
1085 return 0;
1086}
1087
Ed Warnickecb9cada2015-12-08 15:45:58 -07001088/* Take input from Unix environment variable. */
Dave Barachc3799992016-08-15 11:12:27 -04001089uword
1090unformat_init_unix_env (unformat_input_t * input, char *var)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001091{
Dave Barachc3799992016-08-15 11:12:27 -04001092 char *val = getenv (var);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001093 if (val)
1094 unformat_init_string (input, val, strlen (val));
1095 return val != 0;
1096}
1097
Damjan Mariondae1c7e2020-10-17 13:32:25 +02001098__clib_export uword
MathiasRaoul579b1652019-10-04 09:53:45 +00001099unformat_data_size (unformat_input_t * input, va_list * args)
1100{
1101 u64 _a;
1102 u64 *a = va_arg (*args, u64 *);
1103 if (unformat (input, "%lluGb", &_a))
1104 *a = _a << 30;
1105 else if (unformat (input, "%lluG", &_a))
1106 *a = _a << 30;
1107 else if (unformat (input, "%lluMb", &_a))
1108 *a = _a << 20;
1109 else if (unformat (input, "%lluM", &_a))
1110 *a = _a << 20;
1111 else if (unformat (input, "%lluKb", &_a))
1112 *a = _a << 10;
1113 else if (unformat (input, "%lluK", &_a))
1114 *a = _a << 10;
1115 else if (unformat (input, "%llu", a))
1116 ;
1117 else
1118 return 0;
1119 return 1;
1120}
1121
Damjan Marionf5665242023-07-31 20:07:31 +02001122__clib_export uword
1123unformat_c_string_array (unformat_input_t *input, va_list *va)
1124{
1125 char *str = va_arg (*va, char *);
1126 u32 array_len = va_arg (*va, u32);
1127 uword c, rv = 0;
1128 u8 *s = 0;
1129
1130 if (unformat (input, "%v", &s) == 0)
1131 return 0;
1132
1133 c = vec_len (s);
1134
1135 if (c > 0 && c < array_len)
1136 {
1137 clib_memcpy (str, s, c);
1138 str[c] = 0;
1139 rv = 1;
1140 }
1141
1142 vec_free (s);
1143 return rv;
1144}
1145
Damjan Marionf6f21db2023-11-13 21:43:17 +00001146static uword
1147__unformat_quoted_string (unformat_input_t *input, u8 **sp, char quote)
1148{
1149 u8 *s = 0;
1150 uword c, p = 0;
1151
1152 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
1153 if (!is_white_space (c))
1154 break;
1155
1156 if (c != quote)
1157 return 0;
1158
1159 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
1160 {
1161 if (c == quote && p != '\\')
1162 {
1163 *sp = s;
1164 return 1;
1165 }
1166 vec_add1 (s, c);
1167 p = c;
1168 }
1169 vec_free (s);
1170
1171 return 0;
1172}
1173
1174__clib_export uword
1175unformat_single_quoted_string (unformat_input_t *input, va_list *va)
1176{
1177 return __unformat_quoted_string (input, va_arg (*va, u8 **), '\'');
1178}
1179
1180__clib_export uword
1181unformat_double_quoted_string (unformat_input_t *input, va_list *va)
1182{
1183 return __unformat_quoted_string (input, va_arg (*va, u8 **), '"');
1184}
1185
Ed Warnickecb9cada2015-12-08 15:45:58 -07001186#endif /* CLIB_UNIX */
1187
Dave Barachc3799992016-08-15 11:12:27 -04001188
1189/*
1190 * fd.io coding-style-patch-verification: ON
1191 *
1192 * Local Variables:
1193 * eval: (c-set-style "gnu")
1194 * End:
1195 */