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