blob: e8e5c28ea8c68b35ee8b2c25a187e3a4878564ab [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>
39
40/* Call user's function to fill input buffer. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +020041__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -040042_unformat_fill_input (unformat_input_t * i)
Ed Warnickecb9cada2015-12-08 15:45:58 -070043{
44 uword l, first_mark;
45
46 if (i->index == UNFORMAT_END_OF_INPUT)
47 return i->index;
48
49 first_mark = l = vec_len (i->buffer);
50 if (vec_len (i->buffer_marks) > 0)
51 first_mark = i->buffer_marks[0];
52
53 /* Re-use buffer when no marks. */
54 if (first_mark > 0)
55 vec_delete (i->buffer, first_mark, 0);
56
57 i->index = vec_len (i->buffer);
58 for (l = 0; l < vec_len (i->buffer_marks); l++)
59 i->buffer_marks[l] -= first_mark;
60
61 /* Call user's function to fill the buffer. */
62 if (i->fill_buffer)
63 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 if (i->index >= vec_len (i->buffer))
68 i->index = UNFORMAT_END_OF_INPUT;
69
70 return i->index;
71}
72
Ed Warnickecb9cada2015-12-08 15:45:58 -070073/* Format function for dumping input stream. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +020074__clib_export u8 *
Dave Barachc3799992016-08-15 11:12:27 -040075format_unformat_error (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -070076{
Dave Barachc3799992016-08-15 11:12:27 -040077 unformat_input_t *i = va_arg (*va, unformat_input_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -070078 uword l = vec_len (i->buffer);
79
80 /* Only show so much of the input buffer (it could be really large). */
81 uword n_max = 30;
82
83 if (i->index < l)
84 {
85 uword n = l - i->index;
Dave Barachc3799992016-08-15 11:12:27 -040086 u8 *p, *p_end;
Ed Warnickecb9cada2015-12-08 15:45:58 -070087
88 p = i->buffer + i->index;
89 p_end = p + (n > n_max ? n_max : n);
90
91 /* Skip white space at end. */
92 if (n <= n_max)
93 {
94 while (p_end > p && is_white_space (p_end[-1]))
95 p_end--;
96 }
97
98 while (p < p_end)
99 {
100 switch (*p)
101 {
Dave Barachc3799992016-08-15 11:12:27 -0400102 case '\r':
103 vec_add (s, "\\r", 2);
104 break;
105 case '\n':
106 vec_add (s, "\\n", 2);
107 break;
108 case '\t':
109 vec_add (s, "\\t", 2);
110 break;
111 default:
112 vec_add1 (s, *p);
113 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114 }
115 p++;
116 }
117
118 if (n > n_max)
119 vec_add (s, "...", 3);
120 }
121
122 return s;
123}
124
125/* Print everything: not just error context. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200126__clib_export u8 *
Dave Barachc3799992016-08-15 11:12:27 -0400127format_unformat_input (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700128{
Dave Barachc3799992016-08-15 11:12:27 -0400129 unformat_input_t *i = va_arg (*va, unformat_input_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130 uword l, n;
131
132 if (i->index == UNFORMAT_END_OF_INPUT)
133 s = format (s, "{END_OF_INPUT}");
134 else
135 {
136 l = vec_len (i->buffer);
137 n = l - i->index;
138 if (n > 0)
139 vec_add (s, i->buffer + i->index, n);
140 }
141
142 return s;
143}
144
145#if CLIB_DEBUG > 0
Dave Barachc3799992016-08-15 11:12:27 -0400146void
147di (unformat_input_t * i)
148{
149 fformat (stderr, "%U\n", format_unformat_input, i);
150}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151#endif
152
153/* Parse delimited vector string. If string starts with { then string
Paul Vinciguerraec11b132018-09-24 05:25:00 -0700154 is delimited by balanced parenthesis. Other string is delimited by
Ed Warnickecb9cada2015-12-08 15:45:58 -0700155 white space. {} were chosen since they are special to the shell. */
156static uword
157unformat_string (unformat_input_t * input,
158 uword delimiter_character,
Dave Barachc3799992016-08-15 11:12:27 -0400159 uword format_character, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700160{
Dave Barachc3799992016-08-15 11:12:27 -0400161 u8 **string_return = va_arg (*va, u8 **);
162 u8 *s = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700163 word paren = 0;
164 word is_paren_delimited = 0;
165 word backslash = 0;
166 uword c;
167
168 switch (delimiter_character)
169 {
170 case '%':
171 case ' ':
172 case '\t':
173 delimiter_character = 0;
174 break;
175 }
176
177 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 add_to_vector = string_return != 0;
183
184 if (backslash)
185 backslash = 0;
186 else
187 switch (c)
188 {
189 case '\\':
190 backslash = 1;
191 add_to_vector = 0;
192 break;
193
194 case '{':
195 if (paren == 0 && vec_len (s) == 0)
196 {
197 is_paren_delimited = 1;
198 add_to_vector = 0;
199 }
200 paren++;
201 break;
202
203 case '}':
204 paren--;
205 if (is_paren_delimited && paren == 0)
206 goto done;
207 break;
208
209 case ' ':
210 case '\t':
211 case '\n':
212 case '\r':
Dave Barachc3799992016-08-15 11:12:27 -0400213 if (!is_paren_delimited)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700214 {
215 unformat_put_input (input);
216 goto done;
217 }
218 break;
219
220 default:
Dave Barachc3799992016-08-15 11:12:27 -0400221 if (!is_paren_delimited && c == delimiter_character)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700222 {
223 unformat_put_input (input);
224 goto done;
225 }
226 }
227
228 if (add_to_vector)
229 vec_add1 (s, c);
230 }
231
Dave Barachc3799992016-08-15 11:12:27 -0400232done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233 if (string_return)
234 {
235 /* Match the string { END-OF-INPUT as a single brace. */
236 if (c == UNFORMAT_END_OF_INPUT && vec_len (s) == 0 && paren == 1)
Dave Barachc3799992016-08-15 11:12:27 -0400237 vec_add1 (s, '{');
Ed Warnickecb9cada2015-12-08 15:45:58 -0700238
239 /* Don't match null string. */
240 if (c == UNFORMAT_END_OF_INPUT && vec_len (s) == 0)
241 return 0;
Dave Barachc3799992016-08-15 11:12:27 -0400242
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243 /* Null terminate C string. */
244 if (format_character == 's')
245 vec_add1 (s, 0);
246
247 *string_return = s;
248 }
249 else
250 vec_free (s); /* just to make sure */
251
252 return 1;
253}
254
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200255__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400256unformat_hex_string (unformat_input_t * input, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257{
Dave Barachc3799992016-08-15 11:12:27 -0400258 u8 **hexstring_return = va_arg (*va, u8 **);
259 u8 *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260 uword n, d, c;
261
262 n = 0;
263 d = 0;
264 s = 0;
265 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
266 {
267 if (c >= '0' && c <= '9')
Dave Barachc3799992016-08-15 11:12:27 -0400268 d = 16 * d + c - '0';
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269 else if (c >= 'a' && c <= 'f')
Dave Barachc3799992016-08-15 11:12:27 -0400270 d = 16 * d + 10 + c - 'a';
Ed Warnickecb9cada2015-12-08 15:45:58 -0700271 else if (c >= 'A' && c <= 'F')
Dave Barachc3799992016-08-15 11:12:27 -0400272 d = 16 * d + 10 + c - 'A';
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273 else
274 {
275 unformat_put_input (input);
276 break;
277 }
278 n++;
279
280 if (n == 2)
281 {
282 vec_add1 (s, d);
283 n = d = 0;
284 }
285 }
286
287 /* Hex string must have even number of digits. */
288 if (n % 2)
289 {
290 vec_free (s);
291 return 0;
292 }
Billy McFall205e9342017-02-15 09:03:06 -0500293 /* Make sure something was processed. */
294 else if (s == 0)
295 {
296 return 0;
297 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700298
299 *hexstring_return = s;
300 return 1;
301}
302
303/* unformat (input "foo%U", unformat_eof) matches terminal foo only */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200304__clib_export uword
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305unformat_eof (unformat_input_t * input, va_list * va)
306{
307 return unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
308}
309
310/* Parse a token containing given set of characters. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200311__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400312unformat_token (unformat_input_t * input, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700313{
Dave Barachc3799992016-08-15 11:12:27 -0400314 u8 *token_chars = va_arg (*va, u8 *);
315 u8 **string_return = va_arg (*va, u8 **);
316 u8 *s, map[256];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700317 uword i, c;
318
Dave Barachc3799992016-08-15 11:12:27 -0400319 if (!token_chars)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700320 token_chars = (u8 *) "a-zA-Z0-9_";
321
Dave Barachb7b92992018-10-17 10:38:51 -0400322 clib_memset (map, 0, sizeof (map));
Dave Barachc3799992016-08-15 11:12:27 -0400323 for (s = token_chars; *s;)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700324 {
BenoƮt Ganne052bda32019-04-18 17:42:24 +0200325 /*
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 if (s[1] == '-' && s[0] < s[2])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700333 {
334 for (i = s[0]; i <= s[2]; i++)
335 map[i] = 1;
336 s = s + 3;
Dave Barachc3799992016-08-15 11:12:27 -0400337 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700338 else
339 {
340 map[s[0]] = 1;
341 s = s + 1;
342 }
343 }
344
345 s = 0;
346 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
347 {
Dave Barachc3799992016-08-15 11:12:27 -0400348 if (!map[c])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700349 {
350 unformat_put_input (input);
351 break;
352 }
Dave Barachc3799992016-08-15 11:12:27 -0400353
Ed Warnickecb9cada2015-12-08 15:45:58 -0700354 vec_add1 (s, c);
355 }
356
357 if (vec_len (s) == 0)
358 return 0;
359
360 *string_return = s;
361 return 1;
362}
363
364/* Unformat (parse) function which reads a %s string and converts it
365 to and unformat_input_t. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200366__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400367unformat_input (unformat_input_t * i, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700368{
Dave Barachc3799992016-08-15 11:12:27 -0400369 unformat_input_t *sub_input = va_arg (*args, unformat_input_t *);
370 u8 *s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700371
372 if (unformat (i, "%v", &s))
373 {
374 unformat_init_vector (sub_input, s);
375 return 1;
376 }
377
378 return 0;
379}
380
381/* Parse a line ending with \n and return it. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200382__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400383unformat_line (unformat_input_t * i, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700384{
Dave Barachc3799992016-08-15 11:12:27 -0400385 u8 *line = 0, **result = va_arg (*va, u8 **);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700386 uword c;
387
Dave Barachc3799992016-08-15 11:12:27 -0400388 while ((c = unformat_get_input (i)) != '\n' && c != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700389 {
390 vec_add1 (line, c);
391 }
392
393 *result = line;
Alexander Kotov28160f32017-07-10 18:23:31 +0300394 return vec_len (line);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700395}
396
397/* Parse a line ending with \n and return it as an unformat_input_t. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200398__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400399unformat_line_input (unformat_input_t * i, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700400{
Dave Barachc3799992016-08-15 11:12:27 -0400401 unformat_input_t *result = va_arg (*va, unformat_input_t *);
402 u8 *line;
Alexander Kotov28160f32017-07-10 18:23:31 +0300403 if (!unformat_user (i, unformat_line, &line))
404 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700405 unformat_init_vector (result, line);
406 return 1;
407}
408
409/* Values for is_signed. */
410#define UNFORMAT_INTEGER_SIGNED 1
411#define UNFORMAT_INTEGER_UNSIGNED 0
412
413static uword
414unformat_integer (unformat_input_t * input,
Dave Barachc3799992016-08-15 11:12:27 -0400415 va_list * va, uword base, uword is_signed, uword data_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700416{
417 uword c, digit;
418 uword value = 0;
419 uword n_digits = 0;
420 uword n_input = 0;
421 uword sign = 0;
422
423 /* We only support bases <= 64. */
424 if (base < 2 || base > 64)
425 goto error;
426
427 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
428 {
429 switch (c)
430 {
431 case '-':
432 if (n_input == 0)
433 {
434 if (is_signed)
435 {
436 sign = 1;
437 goto next_digit;
438 }
439 else
440 /* Leading sign for unsigned number. */
441 goto error;
442 }
443 /* Sign after input (e.g. 100-200). */
444 goto put_input_done;
445
446 case '+':
Dave Barachc3799992016-08-15 11:12:27 -0400447 if (n_input > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700448 goto put_input_done;
449 sign = 0;
450 goto next_digit;
451
452 case '0' ... '9':
453 digit = c - '0';
454 break;
455
456 case 'a' ... 'z':
457 digit = 10 + (c - 'a');
458 break;
459
460 case 'A' ... 'Z':
461 digit = 10 + (base >= 36 ? 26 : 0) + (c - 'A');
462 break;
463
464 case '/':
465 digit = 62;
466 break;
467
468 case '?':
469 digit = 63;
470 break;
471
472 default:
473 goto put_input_done;
474 }
475
476 if (digit >= base)
477 {
478 put_input_done:
479 unformat_put_input (input);
480 goto done;
481 }
482
483 {
Dave Barachc3799992016-08-15 11:12:27 -0400484 uword new_value = base * value + digit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700485
486 /* Check for overflow. */
487 if (new_value < value)
488 goto error;
489 value = new_value;
490 }
491 n_digits += 1;
492
493 next_digit:
494 n_input++;
495 }
496
Dave Barachc3799992016-08-15 11:12:27 -0400497done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700498 if (sign)
499 value = -value;
500
501 if (n_digits > 0)
502 {
Dave Barachc3799992016-08-15 11:12:27 -0400503 void *v = va_arg (*va, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700504
505 if (data_bytes == ~0)
Dave Barachc3799992016-08-15 11:12:27 -0400506 data_bytes = sizeof (int);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700507
508 switch (data_bytes)
509 {
Dave Barachc3799992016-08-15 11:12:27 -0400510 case 1:
511 *(u8 *) v = value;
512 break;
513 case 2:
514 *(u16 *) v = value;
515 break;
516 case 4:
517 *(u32 *) v = value;
518 break;
519 case 8:
520 *(u64 *) v = value;
521 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700522 default:
Dave Barachc3799992016-08-15 11:12:27 -0400523 goto error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700524 }
525
526 return 1;
527 }
528
Dave Barachc3799992016-08-15 11:12:27 -0400529error:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700530 return 0;
531}
532
533/* Return x 10^n */
Dave Barachc3799992016-08-15 11:12:27 -0400534static f64
535times_power_of_ten (f64 x, int n)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700536{
537 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 while (n >= 8)
541 {
542 x *= 1e+8;
543 n -= 8;
544 }
545 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 while (n <= -8)
551 {
552 x *= 1e-8;
553 n += 8;
554 }
555 return x * t[-n];
556 }
Dave Barachc3799992016-08-15 11:12:27 -0400557
Ed Warnickecb9cada2015-12-08 15:45:58 -0700558}
559
560static uword
Dave Barachc3799992016-08-15 11:12:27 -0400561unformat_float (unformat_input_t * input, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700562{
563 uword c;
564 u64 values[3];
565 uword n_digits[3], value_index = 0;
566 uword signs[2], sign_index = 0;
567 uword n_input = 0;
568
Dave Barachb7b92992018-10-17 10:38:51 -0400569 clib_memset (values, 0, sizeof (values));
570 clib_memset (n_digits, 0, sizeof (n_digits));
571 clib_memset (signs, 0, sizeof (signs));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700572
573 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
574 {
575 switch (c)
576 {
577 case '-':
578 if (value_index == 2 && n_digits[2] == 0)
Dave Barachc3799992016-08-15 11:12:27 -0400579 /* sign of exponent: it's ok. */ ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700580
581 else if (value_index < 2 && n_digits[0] > 0)
582 {
583 /* 123- */
584 unformat_put_input (input);
585 goto done;
586 }
587
588 else if (n_input > 0)
589 goto error;
590
591 signs[sign_index++] = 1;
592 goto next_digit;
593
594 case '+':
595 if (value_index == 2 && n_digits[2] == 0)
Dave Barachc3799992016-08-15 11:12:27 -0400596 /* sign of exponent: it's ok. */ ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700597
598 else if (value_index < 2 && n_digits[0] > 0)
599 {
600 /* 123+ */
601 unformat_put_input (input);
602 goto done;
603 }
604
605 else if (n_input > 0)
606 goto error;
607 signs[sign_index++] = 0;
608 goto next_digit;
609
610 case 'e':
611 case 'E':
612 if (n_input == 0)
613 goto error;
614 value_index = 2;
615 sign_index = 1;
616 break;
617
618 case '.':
619 if (value_index > 0)
620 goto error;
621 value_index = 1;
622 break;
623
624 case '0' ... '9':
625 {
626 u64 tmp;
627
628 tmp = values[value_index] * 10 + c - '0';
629
630 /* Check for overflow. */
631 if (tmp < values[value_index])
632 goto error;
633 values[value_index] = tmp;
634 n_digits[value_index] += 1;
635 }
636 break;
637
638 default:
639 unformat_put_input (input);
640 goto done;
641 }
642
643 next_digit:
644 n_input++;
645 }
646
Dave Barachc3799992016-08-15 11:12:27 -0400647done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700648 {
Dave Barachc3799992016-08-15 11:12:27 -0400649 f64 f_values[2], *value_return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700650 word expon;
651
652 /* Must have either whole or fraction digits. */
653 if (n_digits[0] + n_digits[1] <= 0)
654 goto error;
655
656 f_values[0] = values[0];
657 if (signs[0])
658 f_values[0] = -f_values[0];
659
660 f_values[1] = values[1];
661 f_values[1] = times_power_of_ten (f_values[1], -n_digits[1]);
662
663 f_values[0] += f_values[1];
664
665 expon = values[2];
666 if (signs[1])
667 expon = -expon;
668
669 f_values[0] = times_power_of_ten (f_values[0], expon);
670
671 value_return = va_arg (*va, f64 *);
672 *value_return = f_values[0];
673 return 1;
674 }
675
Dave Barachc3799992016-08-15 11:12:27 -0400676error:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700677 return 0;
678}
679
Neale Ranns32e1c012016-11-22 17:07:28 +0000680static const char *
681match_input_with_format (unformat_input_t * input, const char *f)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700682{
683 uword cf, ci;
684
685 ASSERT (*f != 0);
686
687 while (1)
688 {
689 cf = *f;
690 if (cf == 0 || cf == '%' || cf == ' ')
691 break;
692 f++;
693
694 ci = unformat_get_input (input);
695
696 if (cf != ci)
697 return 0;
698 }
699 return f;
700}
701
Neale Ranns32e1c012016-11-22 17:07:28 +0000702static const char *
703do_percent (unformat_input_t * input, va_list * va, const char *f)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700704{
705 uword cf, n, data_bytes = ~0;
706
707 cf = *f++;
708
709 switch (cf)
710 {
711 default:
712 break;
713
714 case 'w':
715 /* Word types. */
716 cf = *f++;
717 data_bytes = sizeof (uword);
718 break;
719
720 case 'l':
721 cf = *f++;
722 if (cf == 'l')
723 {
724 cf = *f++;
725 data_bytes = sizeof (long long);
726 }
727 else
728 {
729 data_bytes = sizeof (long);
730 }
731 break;
Dave Barachc3799992016-08-15 11:12:27 -0400732
Ed Warnickecb9cada2015-12-08 15:45:58 -0700733 case 'L':
734 cf = *f++;
735 data_bytes = sizeof (long long);
736 break;
737 }
738
739 n = 0;
740 switch (cf)
741 {
742 case 'D':
743 data_bytes = va_arg (*va, int);
744 case 'd':
745 n = unformat_integer (input, va, 10,
746 UNFORMAT_INTEGER_SIGNED, data_bytes);
747 break;
748
749 case 'u':
750 n = unformat_integer (input, va, 10,
751 UNFORMAT_INTEGER_UNSIGNED, data_bytes);
752 break;
753
754 case 'b':
755 n = unformat_integer (input, va, 2,
756 UNFORMAT_INTEGER_UNSIGNED, data_bytes);
757 break;
758
759 case 'o':
760 n = unformat_integer (input, va, 8,
761 UNFORMAT_INTEGER_UNSIGNED, data_bytes);
762 break;
763
764 case 'X':
765 data_bytes = va_arg (*va, int);
766 case 'x':
767 n = unformat_integer (input, va, 16,
768 UNFORMAT_INTEGER_UNSIGNED, data_bytes);
769 break;
770
771 case 'f':
772 n = unformat_float (input, va);
773 break;
774
775 case 's':
776 case 'v':
777 n = unformat_string (input, f[0], cf, va);
778 break;
779
780 case 'U':
781 {
Dave Barachc3799992016-08-15 11:12:27 -0400782 unformat_function_t *f = va_arg (*va, unformat_function_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700783 n = f (input, va);
784 }
785 break;
786
787 case '=':
788 case '|':
789 {
Dave Barachc3799992016-08-15 11:12:27 -0400790 int *var = va_arg (*va, int *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700791 uword val = va_arg (*va, int);
792
793 if (cf == '|')
794 val |= *var;
795 *var = val;
796 n = 1;
797 }
798 break;
799 }
800
801 return n ? f : 0;
802}
803
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200804__clib_export uword
Dave Barachc3799992016-08-15 11:12:27 -0400805unformat_skip_white_space (unformat_input_t * input)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700806{
807 uword n = 0;
808 uword c;
809
810 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
811 {
Dave Barachc3799992016-08-15 11:12:27 -0400812 if (!is_white_space (c))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700813 {
814 unformat_put_input (input);
815 break;
816 }
817 n++;
818 }
819 return n;
820}
821
Juraj LinkeŔ7aa76d42020-10-22 13:29:28 +0200822__clib_export uword
Neale Ranns32e1c012016-11-22 17:07:28 +0000823va_unformat (unformat_input_t * input, const char *fmt, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700824{
Neale Ranns32e1c012016-11-22 17:07:28 +0000825 const char *f;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700826 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
Dave Barachc3799992016-08-15 11:12:27 -0400832 vec_add1_aligned (input->buffer_marks, input->index,
833 sizeof (input->buffer_marks[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700834
835 f = fmt;
836 default_skip_input_white_space = 1;
837 input_matches_format = 0;
838 last_non_white_space_match_percent = 0;
839 last_non_white_space_match_format = 0;
Dave Barachc3799992016-08-15 11:12:27 -0400840
Ed Warnickecb9cada2015-12-08 15:45:58 -0700841 while (1)
842 {
843 char cf;
844 uword is_percent, skip_input_white_space;
845
846 cf = *f;
847 is_percent = 0;
848
849 /* Always skip input white space at start of format string.
Dave Barachc3799992016-08-15 11:12:27 -0400850 Otherwise use default skip value which can be changed by %_
851 (see below). */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700852 skip_input_white_space = f == fmt || default_skip_input_white_space;
853
854 /* Spaces in format request skipping input white space. */
855 if (is_white_space (cf))
856 {
857 skip_input_white_space = 1;
858
859 /* Multiple format spaces are equivalent to a single white
860 space. */
861 while (is_white_space (*++f))
862 ;
863 }
864 else if (cf == '%')
865 {
866 /* %_ toggles whether or not to skip input white space. */
867 switch (*++f)
868 {
869 case '_':
Dave Barachc3799992016-08-15 11:12:27 -0400870 default_skip_input_white_space =
871 !default_skip_input_white_space;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700872 f++;
873 /* For transition from skip to no-skip in middle of format
Dave Barachc3799992016-08-15 11:12:27 -0400874 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 if (!default_skip_input_white_space
879 && !(f == fmt + 2 || *f == 0))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700880 unformat_skip_white_space (input);
881 continue;
882
Dave Barachc3799992016-08-15 11:12:27 -0400883 /* %% means match % */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700884 case '%':
885 break;
886
Dave Barachc3799992016-08-15 11:12:27 -0400887 /* % at end of format string. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700888 case 0:
889 goto parse_fail;
890
891 default:
892 is_percent = 1;
893 break;
894 }
895 }
896
897 n_input_white_space_skipped = 0;
898 if (skip_input_white_space)
899 n_input_white_space_skipped = unformat_skip_white_space (input);
900
901 /* End of format string. */
902 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 if (skip_input_white_space
Dave Barachc3799992016-08-15 11:12:27 -0400910 && !last_non_white_space_match_percent
911 && !last_non_white_space_match_format
Ed Warnickecb9cada2015-12-08 15:45:58 -0700912 && n_input_white_space_skipped == 0
913 && input->index != UNFORMAT_END_OF_INPUT)
914 goto parse_fail;
915 break;
916 }
917
918 last_non_white_space_match_percent = is_percent;
919 last_non_white_space_match_format = 0;
920
921 /* Explicit spaces in format must match input white space. */
922 if (cf == ' ' && !default_skip_input_white_space)
923 {
924 if (n_input_white_space_skipped == 0)
925 goto parse_fail;
926 }
927
928 else if (is_percent)
929 {
Dave Barachc3799992016-08-15 11:12:27 -0400930 if (!(f = do_percent (input, va, f)))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700931 goto parse_fail;
932 }
933
934 else
935 {
Neale Ranns32e1c012016-11-22 17:07:28 +0000936 const char *g = match_input_with_format (input, f);
Dave Barachc3799992016-08-15 11:12:27 -0400937 if (!g)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700938 goto parse_fail;
939 last_non_white_space_match_format = g > f;
940 f = g;
941 }
942 }
943
944 input_matches_format = 1;
Dave Barachc3799992016-08-15 11:12:27 -0400945parse_fail:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700946
947 /* Rewind buffer marks. */
948 {
949 uword l = vec_len (input->buffer_marks);
950
951 /* If we did not match back up buffer to last mark. */
Dave Barachc3799992016-08-15 11:12:27 -0400952 if (!input_matches_format)
953 input->index = input->buffer_marks[l - 1];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700954
Damjan Marion8bea5892022-04-04 22:40:45 +0200955 vec_set_len (input->buffer_marks, l - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700956 }
957
958 return input_matches_format;
959}
960
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200961__clib_export uword
Neale Ranns32e1c012016-11-22 17:07:28 +0000962unformat (unformat_input_t * input, const char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700963{
964 va_list va;
965 uword result;
966 va_start (va, fmt);
967 result = va_unformat (input, fmt, &va);
968 va_end (va);
969 return result;
970}
971
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200972__clib_export uword
Ed Warnickecb9cada2015-12-08 15:45:58 -0700973unformat_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 l = vec_len (input->buffer_marks);
Dave Barachc3799992016-08-15 11:12:27 -0400980 vec_add1_aligned (input->buffer_marks, input->index,
981 sizeof (input->buffer_marks[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700982
983 va_start (va, func);
984 result = func (input, &va);
985 va_end (va);
986
Dave Barachdddccea2016-10-26 14:03:20 -0400987 if (!result && input->index != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700988 input->index = input->buffer_marks[l];
989
Damjan Marion8bea5892022-04-04 22:40:45 +0200990 vec_set_len (input->buffer_marks, l);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700991
992 return result;
993}
994
995/* Setup for unformat of Unix style command line. */
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200996__clib_export void
Dave Barachc3799992016-08-15 11:12:27 -0400997unformat_init_command_line (unformat_input_t * input, char *argv[])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700998{
999 uword i;
1000
1001 unformat_init (input, 0, 0);
1002
1003 /* Concatenate argument strings with space in between. */
1004 for (i = 1; argv[i]; i++)
1005 {
1006 vec_add (input->buffer, argv[i], strlen (argv[i]));
1007 if (argv[i + 1])
1008 vec_add1 (input->buffer, ' ');
1009 }
1010}
1011
Damjan Mariondae1c7e2020-10-17 13:32:25 +02001012__clib_export void
BenoƮt Ganne82f618c2021-10-13 11:35:15 +02001013unformat_init_string (unformat_input_t *input, const char *string,
1014 int string_len)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001015{
1016 unformat_init (input, 0, 0);
1017 if (string_len > 0)
1018 vec_add (input->buffer, string, string_len);
1019}
1020
Damjan Mariondae1c7e2020-10-17 13:32:25 +02001021__clib_export void
Dave Barachc3799992016-08-15 11:12:27 -04001022unformat_init_vector (unformat_input_t * input, u8 * vector_string)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001023{
1024 unformat_init (input, 0, 0);
1025 input->buffer = vector_string;
1026}
1027
1028#ifdef CLIB_UNIX
1029
Dave Barachc3799992016-08-15 11:12:27 -04001030static uword
Dave Barach59b25652017-09-10 15:04:27 -04001031clib_file_fill_buffer (unformat_input_t * input)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001032{
1033 int fd = pointer_to_uword (input->fill_buffer_arg);
1034 uword l, n;
1035
1036 l = vec_len (input->buffer);
1037 vec_resize (input->buffer, 4096);
1038 n = read (fd, input->buffer + l, 4096);
1039 if (n > 0)
Damjan Marion8bea5892022-04-04 22:40:45 +02001040 vec_set_len (input->buffer, l + n);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001041
1042 if (n <= 0)
1043 return UNFORMAT_END_OF_INPUT;
1044 else
1045 return input->index;
1046}
1047
Damjan Mariondae1c7e2020-10-17 13:32:25 +02001048__clib_export void
Dave Barach59b25652017-09-10 15:04:27 -04001049unformat_init_clib_file (unformat_input_t * input, int file_descriptor)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001050{
Dave Barach59b25652017-09-10 15:04:27 -04001051 unformat_init (input, clib_file_fill_buffer,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001052 uword_to_pointer (file_descriptor, void *));
1053}
1054
1055/* Take input from Unix environment variable. */
Dave Barachc3799992016-08-15 11:12:27 -04001056uword
1057unformat_init_unix_env (unformat_input_t * input, char *var)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001058{
Dave Barachc3799992016-08-15 11:12:27 -04001059 char *val = getenv (var);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001060 if (val)
1061 unformat_init_string (input, val, strlen (val));
1062 return val != 0;
1063}
1064
Damjan Mariondae1c7e2020-10-17 13:32:25 +02001065__clib_export uword
MathiasRaoul579b1652019-10-04 09:53:45 +00001066unformat_data_size (unformat_input_t * input, va_list * args)
1067{
1068 u64 _a;
1069 u64 *a = va_arg (*args, u64 *);
1070 if (unformat (input, "%lluGb", &_a))
1071 *a = _a << 30;
1072 else if (unformat (input, "%lluG", &_a))
1073 *a = _a << 30;
1074 else if (unformat (input, "%lluMb", &_a))
1075 *a = _a << 20;
1076 else if (unformat (input, "%lluM", &_a))
1077 *a = _a << 20;
1078 else if (unformat (input, "%lluKb", &_a))
1079 *a = _a << 10;
1080 else if (unformat (input, "%lluK", &_a))
1081 *a = _a << 10;
1082 else if (unformat (input, "%llu", a))
1083 ;
1084 else
1085 return 0;
1086 return 1;
1087}
1088
Ed Warnickecb9cada2015-12-08 15:45:58 -07001089#endif /* CLIB_UNIX */
1090
Dave Barachc3799992016-08-15 11:12:27 -04001091
1092/*
1093 * fd.io coding-style-patch-verification: ON
1094 *
1095 * Local Variables:
1096 * eval: (c-set-style "gnu")
1097 * End:
1098 */