Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 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 | #ifndef included_format_h |
| 39 | #define included_format_h |
| 40 | |
| 41 | #include <stdarg.h> |
| 42 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 43 | #include <vppinfra/clib.h> /* for CLIB_UNIX, etc. */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 44 | #include <vppinfra/vec.h> |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 45 | #include <vppinfra/error.h> /* for ASSERT */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 46 | #include <vppinfra/string.h> |
| 47 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 48 | typedef u8 *(format_function_t) (u8 * s, va_list * args); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 49 | |
Neale Ranns | 0bfe5d8 | 2016-08-25 15:29:12 +0100 | [diff] [blame] | 50 | u8 *va_format (u8 * s, const char *format, va_list * args); |
| 51 | u8 *format (u8 * s, const char *format, ...); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 52 | |
| 53 | #ifdef CLIB_UNIX |
| 54 | |
| 55 | #include <stdio.h> |
| 56 | |
| 57 | #else /* ! CLIB_UNIX */ |
| 58 | |
| 59 | /* We're not Unix and have not stdio.h */ |
| 60 | #define FILE void |
| 61 | #define stdin ((FILE *) 0) |
| 62 | #define stdout ((FILE *) 1) |
| 63 | #define stderr ((FILE *) 2) |
| 64 | |
| 65 | #endif |
| 66 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 67 | word va_fformat (FILE * f, char *fmt, va_list * va); |
| 68 | word fformat (FILE * f, char *fmt, ...); |
| 69 | word fdformat (int fd, char *fmt, ...); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 70 | |
Christophe Fontaine | d3c008d | 2017-10-02 18:10:54 +0200 | [diff] [blame] | 71 | always_inline u32 |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 72 | format_get_indent (u8 * s) |
| 73 | { |
Christophe Fontaine | d3c008d | 2017-10-02 18:10:54 +0200 | [diff] [blame] | 74 | u32 indent = 0; |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 75 | u8 *nl; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 76 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 77 | if (!s) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 78 | return indent; |
| 79 | |
| 80 | nl = vec_end (s) - 1; |
| 81 | while (nl >= s) |
| 82 | { |
| 83 | if (*nl-- == '\n') |
| 84 | break; |
| 85 | indent++; |
| 86 | } |
| 87 | return indent; |
| 88 | } |
| 89 | |
| 90 | #define _(f) u8 * f (u8 * s, va_list * va) |
| 91 | |
| 92 | /* Standard user-defined formats. */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 93 | _(format_vec32); |
| 94 | _(format_vec_uword); |
| 95 | _(format_ascii_bytes); |
| 96 | _(format_hex_bytes); |
Damjan Marion | 3860a77 | 2019-06-17 23:20:27 +0200 | [diff] [blame] | 97 | _(format_hex_bytes_no_wrap); |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 98 | _(format_white_space); |
| 99 | _(format_f64); |
| 100 | _(format_time_interval); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 101 | |
| 102 | #ifdef CLIB_UNIX |
| 103 | /* Unix specific formats. */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 104 | _(format_address_family); |
| 105 | _(format_unix_arphrd); |
| 106 | _(format_unix_interface_flags); |
| 107 | _(format_network_address); |
| 108 | _(format_network_protocol); |
| 109 | _(format_network_port); |
| 110 | _(format_sockaddr); |
| 111 | _(format_ip4_tos_byte); |
| 112 | _(format_ip4_packet); |
| 113 | _(format_icmp4_type_and_code); |
| 114 | _(format_ethernet_packet); |
| 115 | _(format_hostname); |
| 116 | _(format_timeval); |
| 117 | _(format_time_float); |
| 118 | _(format_signal); |
| 119 | _(format_ucontext_pc); |
Damjan Marion | 926b564 | 2018-07-02 21:33:31 +0200 | [diff] [blame] | 120 | _(format_page_map); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 121 | #endif |
| 122 | |
| 123 | #undef _ |
| 124 | |
| 125 | /* Unformat. */ |
| 126 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 127 | typedef struct _unformat_input_t |
| 128 | { |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 129 | /* Input buffer (vector). */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 130 | u8 *buffer; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 131 | |
| 132 | /* Current index in input buffer. */ |
| 133 | uword index; |
| 134 | |
| 135 | /* Vector of buffer marks. Used to delineate pieces of the buffer |
| 136 | for error reporting and for parse recovery. */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 137 | uword *buffer_marks; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 138 | |
| 139 | /* User's function to fill the buffer when its empty |
| 140 | (and argument). */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 141 | uword (*fill_buffer) (struct _unformat_input_t * i); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 142 | |
| 143 | /* Return values for fill buffer function which indicate whether not |
| 144 | input has been exhausted. */ |
| 145 | #define UNFORMAT_END_OF_INPUT (~0) |
| 146 | #define UNFORMAT_MORE_INPUT 0 |
| 147 | |
| 148 | /* User controlled argument to fill buffer function. */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 149 | void *fill_buffer_arg; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 150 | } unformat_input_t; |
| 151 | |
| 152 | always_inline void |
| 153 | unformat_init (unformat_input_t * i, |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 154 | uword (*fill_buffer) (unformat_input_t *), |
| 155 | void *fill_buffer_arg) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 156 | { |
Dave Barach | b7b9299 | 2018-10-17 10:38:51 -0400 | [diff] [blame] | 157 | clib_memset (i, 0, sizeof (i[0])); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 158 | i->fill_buffer = fill_buffer; |
| 159 | i->fill_buffer_arg = fill_buffer_arg; |
| 160 | } |
| 161 | |
| 162 | always_inline void |
| 163 | unformat_free (unformat_input_t * i) |
| 164 | { |
| 165 | vec_free (i->buffer); |
| 166 | vec_free (i->buffer_marks); |
Dave Barach | b7b9299 | 2018-10-17 10:38:51 -0400 | [diff] [blame] | 167 | clib_memset (i, 0, sizeof (i[0])); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 168 | } |
| 169 | |
| 170 | always_inline uword |
| 171 | unformat_check_input (unformat_input_t * i) |
| 172 | { |
| 173 | /* Low level fill input function. */ |
| 174 | extern uword _unformat_fill_input (unformat_input_t * i); |
| 175 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 176 | if (i->index >= vec_len (i->buffer) && i->index != UNFORMAT_END_OF_INPUT) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 177 | _unformat_fill_input (i); |
| 178 | |
| 179 | return i->index; |
| 180 | } |
| 181 | |
| 182 | /* Return true if input is exhausted */ |
| 183 | always_inline uword |
| 184 | unformat_is_eof (unformat_input_t * input) |
| 185 | { |
| 186 | return unformat_check_input (input) == UNFORMAT_END_OF_INPUT; |
| 187 | } |
| 188 | |
| 189 | /* Return next element in input vector, |
| 190 | possibly calling fill input to get more. */ |
| 191 | always_inline uword |
| 192 | unformat_get_input (unformat_input_t * input) |
| 193 | { |
| 194 | uword i = unformat_check_input (input); |
| 195 | if (i < vec_len (input->buffer)) |
| 196 | { |
| 197 | input->index = i + 1; |
| 198 | i = input->buffer[i]; |
| 199 | } |
| 200 | return i; |
| 201 | } |
| 202 | |
| 203 | /* Back up input pointer by one. */ |
| 204 | always_inline void |
| 205 | unformat_put_input (unformat_input_t * input) |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 206 | { |
| 207 | input->index -= 1; |
| 208 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 209 | |
| 210 | /* Peek current input character without advancing. */ |
| 211 | always_inline uword |
| 212 | unformat_peek_input (unformat_input_t * input) |
| 213 | { |
| 214 | uword c = unformat_get_input (input); |
| 215 | if (c != UNFORMAT_END_OF_INPUT) |
| 216 | unformat_put_input (input); |
| 217 | return c; |
| 218 | } |
| 219 | |
| 220 | /* Skip current input line. */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 221 | always_inline void |
| 222 | unformat_skip_line (unformat_input_t * i) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 223 | { |
| 224 | uword c; |
| 225 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 226 | while ((c = unformat_get_input (i)) != UNFORMAT_END_OF_INPUT && c != '\n') |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 227 | ; |
| 228 | } |
| 229 | |
| 230 | uword unformat_skip_white_space (unformat_input_t * input); |
| 231 | |
| 232 | /* Unformat function. */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 233 | typedef uword (unformat_function_t) (unformat_input_t * input, |
| 234 | va_list * args); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 235 | |
| 236 | /* External functions. */ |
| 237 | |
| 238 | /* General unformatting function with programmable input stream. */ |
Neale Ranns | 32e1c01 | 2016-11-22 17:07:28 +0000 | [diff] [blame] | 239 | uword unformat (unformat_input_t * i, const char *fmt, ...); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 240 | |
| 241 | /* Call user defined parse function. |
| 242 | unformat_user (i, f, ...) is equivalent to unformat (i, "%U", f, ...) */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 243 | uword unformat_user (unformat_input_t * input, unformat_function_t * func, |
| 244 | ...); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 245 | |
| 246 | /* Alternate version which allows for extensions. */ |
Neale Ranns | 32e1c01 | 2016-11-22 17:07:28 +0000 | [diff] [blame] | 247 | uword va_unformat (unformat_input_t * i, const char *fmt, va_list * args); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 248 | |
| 249 | /* Setup for unformat of Unix style command line. */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 250 | void unformat_init_command_line (unformat_input_t * input, char *argv[]); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 251 | |
| 252 | /* Setup for unformat of given string. */ |
| 253 | void unformat_init_string (unformat_input_t * input, |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 254 | char *string, int string_len); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 255 | |
| 256 | always_inline void |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 257 | unformat_init_cstring (unformat_input_t * input, char *string) |
| 258 | { |
| 259 | unformat_init_string (input, string, strlen (string)); |
| 260 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 261 | |
| 262 | /* Setup for unformat of given vector string; vector will be freed by unformat_string. */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 263 | void unformat_init_vector (unformat_input_t * input, u8 * vector_string); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 264 | |
| 265 | /* Format function for unformat input usable when an unformat error |
| 266 | has occurred. */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 267 | u8 *format_unformat_error (u8 * s, va_list * va); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 268 | |
| 269 | #define unformat_parse_error(input) \ |
| 270 | clib_error_return (0, "parse error `%U'", format_unformat_error, input) |
| 271 | |
| 272 | /* Print all input: not just error context. */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 273 | u8 *format_unformat_input (u8 * s, va_list * va); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 274 | |
| 275 | /* Unformat (parse) function which reads a %s string and converts it |
| 276 | to and unformat_input_t. */ |
| 277 | unformat_function_t unformat_input; |
| 278 | |
| 279 | /* Parse a line ending with \n and return it. */ |
| 280 | unformat_function_t unformat_line; |
| 281 | |
| 282 | /* Parse a line ending with \n and return it as an unformat_input_t. */ |
| 283 | unformat_function_t unformat_line_input; |
| 284 | |
| 285 | /* Parse a token containing given set of characters. */ |
| 286 | unformat_function_t unformat_token; |
| 287 | |
| 288 | /* Parses a hexstring into a vector of bytes. */ |
| 289 | unformat_function_t unformat_hex_string; |
| 290 | |
| 291 | /* Returns non-zero match if input is exhausted. |
| 292 | Useful to ensure that the entire input matches with no trailing junk. */ |
| 293 | unformat_function_t unformat_eof; |
| 294 | |
| 295 | /* Parse memory size e.g. 100, 100k, 100m, 100g. */ |
| 296 | unformat_function_t unformat_memory_size; |
| 297 | |
| 298 | /* Unparse memory size e.g. 100, 100k, 100m, 100g. */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 299 | u8 *format_memory_size (u8 * s, va_list * va); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 300 | |
| 301 | /* Format c identifier: e.g. a_name -> "a name". */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 302 | u8 *format_c_identifier (u8 * s, va_list * va); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 303 | |
Damjan Marion | a7e83ce | 2016-06-09 12:38:22 +0200 | [diff] [blame] | 304 | /* Format hexdump with both hex and printable chars - compatible with text2pcap */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 305 | u8 *format_hexdump (u8 * s, va_list * va); |
Damjan Marion | a7e83ce | 2016-06-09 12:38:22 +0200 | [diff] [blame] | 306 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 307 | /* Unix specific formats. */ |
| 308 | #ifdef CLIB_UNIX |
| 309 | /* Setup input from Unix file. */ |
Dave Barach | 59b2565 | 2017-09-10 15:04:27 -0400 | [diff] [blame] | 310 | void unformat_init_clib_file (unformat_input_t * input, int file_descriptor); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 311 | |
| 312 | /* Take input from Unix environment variable; returns |
| 313 | 1 if variable exists zero otherwise. */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 314 | uword unformat_init_unix_env (unformat_input_t * input, char *var); |
Damjan Marion | a54230d | 2017-06-21 11:57:07 +0200 | [diff] [blame] | 315 | |
| 316 | /* Unformat unix group id (gid) specified as integer or string */ |
| 317 | unformat_function_t unformat_unix_gid; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 318 | #endif /* CLIB_UNIX */ |
| 319 | |
| 320 | /* Test code. */ |
| 321 | int test_format_main (unformat_input_t * input); |
| 322 | int test_unformat_main (unformat_input_t * input); |
| 323 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 324 | /* This is not the right place for this, but putting it in vec.h |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 325 | created circular dependency problems. */ |
| 326 | int test_vec_main (unformat_input_t * input); |
| 327 | |
| 328 | #endif /* included_format_h */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 329 | |
| 330 | /* |
| 331 | * fd.io coding-style-patch-verification: ON |
| 332 | * |
| 333 | * Local Variables: |
| 334 | * eval: (c-set-style "gnu") |
| 335 | * End: |
| 336 | */ |