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