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