1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation. 3 * Copyright (c) 2009, Olivier MATZ <[email protected]> 4 * All rights reserved. 5 */ 6 7 #include <stdio.h> 8 #include <stdint.h> 9 #include <inttypes.h> 10 #include <ctype.h> 11 #include <string.h> 12 #include <stdarg.h> 13 #include <errno.h> 14 #include <rte_string_fns.h> 15 16 #include "cmdline_parse.h" 17 #include "cmdline_parse_num.h" 18 19 #ifdef RTE_LIBRTE_CMDLINE_DEBUG 20 #define debug_printf(args...) printf(args) 21 #else 22 #define debug_printf(args...) do {} while(0) 23 #endif 24 25 struct cmdline_token_ops cmdline_token_num_ops = { 26 .parse = cmdline_parse_num, 27 .complete_get_nb = NULL, 28 .complete_get_elt = NULL, 29 .get_help = cmdline_get_help_num, 30 }; 31 32 33 enum num_parse_state_t { 34 START, 35 DEC_NEG, 36 BIN, 37 HEX, 38 39 ERROR, 40 41 FIRST_OK, /* not used */ 42 ZERO_OK, 43 HEX_OK, 44 OCTAL_OK, 45 BIN_OK, 46 DEC_NEG_OK, 47 DEC_POS_OK, 48 }; 49 50 /* Keep it sync with enum in .h */ 51 static const char * num_help[] = { 52 "UINT8", "UINT16", "UINT32", "UINT64", 53 "INT8", "INT16", "INT32", "INT64", 54 }; 55 56 static inline int 57 add_to_res(unsigned int c, uint64_t *res, unsigned int base) 58 { 59 /* overflow */ 60 if ( (UINT64_MAX - c) / base < *res ) { 61 return -1; 62 } 63 64 *res = (uint64_t) (*res * base + c); 65 return 0; 66 } 67 68 static int 69 check_res_size(struct cmdline_token_num_data *nd, unsigned ressize) 70 { 71 switch (nd->type) { 72 case INT8: 73 case UINT8: 74 if (ressize < sizeof(int8_t)) 75 return -1; 76 break; 77 case INT16: 78 case UINT16: 79 if (ressize < sizeof(int16_t)) 80 return -1; 81 break; 82 case INT32: 83 case UINT32: 84 if (ressize < sizeof(int32_t)) 85 return -1; 86 break; 87 case INT64: 88 case UINT64: 89 if (ressize < sizeof(int64_t)) 90 return -1; 91 break; 92 default: 93 return -1; 94 } 95 return 0; 96 } 97 98 /* parse an int */ 99 int 100 cmdline_parse_num(cmdline_parse_token_hdr_t *tk, const char *srcbuf, void *res, 101 unsigned ressize) 102 { 103 struct cmdline_token_num_data nd; 104 enum num_parse_state_t st = START; 105 const char * buf; 106 char c; 107 uint64_t res1 = 0; 108 109 if (!tk) 110 return -1; 111 112 if (!srcbuf || !*srcbuf) 113 return -1; 114 115 buf = srcbuf; 116 c = *buf; 117 118 memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd)); 119 120 /* check that we have enough room in res */ 121 if (res) { 122 if (check_res_size(&nd, ressize) < 0) 123 return -1; 124 } 125 126 while ( st != ERROR && c && ! cmdline_isendoftoken(c) ) { 127 debug_printf("%c %x -> ", c, c); 128 switch (st) { 129 case START: 130 if (c == '-') { 131 st = DEC_NEG; 132 } 133 else if (c == '0') { 134 st = ZERO_OK; 135 } 136 else if (c >= '1' && c <= '9') { 137 if (add_to_res(c - '0', &res1, 10) < 0) 138 st = ERROR; 139 else 140 st = DEC_POS_OK; 141 } 142 else { 143 st = ERROR; 144 } 145 break; 146 147 case ZERO_OK: 148 if (c == 'x') { 149 st = HEX; 150 } 151 else if (c == 'b') { 152 st = BIN; 153 } 154 else if (c >= '0' && c <= '7') { 155 if (add_to_res(c - '0', &res1, 10) < 0) 156 st = ERROR; 157 else 158 st = OCTAL_OK; 159 } 160 else { 161 st = ERROR; 162 } 163 break; 164 165 case DEC_NEG: 166 if (c >= '0' && c <= '9') { 167 if (add_to_res(c - '0', &res1, 10) < 0) 168 st = ERROR; 169 else 170 st = DEC_NEG_OK; 171 } 172 else { 173 st = ERROR; 174 } 175 break; 176 177 case DEC_NEG_OK: 178 if (c >= '0' && c <= '9') { 179 if (add_to_res(c - '0', &res1, 10) < 0) 180 st = ERROR; 181 } 182 else { 183 st = ERROR; 184 } 185 break; 186 187 case DEC_POS_OK: 188 if (c >= '0' && c <= '9') { 189 if (add_to_res(c - '0', &res1, 10) < 0) 190 st = ERROR; 191 } 192 else { 193 st = ERROR; 194 } 195 break; 196 197 case HEX: 198 st = HEX_OK; 199 /* fall-through */ 200 case HEX_OK: 201 if (c >= '0' && c <= '9') { 202 if (add_to_res(c - '0', &res1, 16) < 0) 203 st = ERROR; 204 } 205 else if (c >= 'a' && c <= 'f') { 206 if (add_to_res(c - 'a' + 10, &res1, 16) < 0) 207 st = ERROR; 208 } 209 else if (c >= 'A' && c <= 'F') { 210 if (add_to_res(c - 'A' + 10, &res1, 16) < 0) 211 st = ERROR; 212 } 213 else { 214 st = ERROR; 215 } 216 break; 217 218 219 case OCTAL_OK: 220 if (c >= '0' && c <= '7') { 221 if (add_to_res(c - '0', &res1, 8) < 0) 222 st = ERROR; 223 } 224 else { 225 st = ERROR; 226 } 227 break; 228 229 case BIN: 230 st = BIN_OK; 231 /* fall-through */ 232 case BIN_OK: 233 if (c >= '0' && c <= '1') { 234 if (add_to_res(c - '0', &res1, 2) < 0) 235 st = ERROR; 236 } 237 else { 238 st = ERROR; 239 } 240 break; 241 default: 242 debug_printf("not impl "); 243 244 } 245 246 debug_printf("(%"PRIu64")\n", res1); 247 248 buf ++; 249 c = *buf; 250 251 /* token too long */ 252 if (buf-srcbuf > 127) 253 return -1; 254 } 255 256 switch (st) { 257 case ZERO_OK: 258 case DEC_POS_OK: 259 case HEX_OK: 260 case OCTAL_OK: 261 case BIN_OK: 262 if ( nd.type == INT8 && res1 <= INT8_MAX ) { 263 if (res) *(int8_t *)res = (int8_t) res1; 264 return buf-srcbuf; 265 } 266 else if ( nd.type == INT16 && res1 <= INT16_MAX ) { 267 if (res) *(int16_t *)res = (int16_t) res1; 268 return buf-srcbuf; 269 } 270 else if ( nd.type == INT32 && res1 <= INT32_MAX ) { 271 if (res) *(int32_t *)res = (int32_t) res1; 272 return buf-srcbuf; 273 } 274 else if ( nd.type == INT64 && res1 <= INT64_MAX ) { 275 if (res) *(int64_t *)res = (int64_t) res1; 276 return buf-srcbuf; 277 } 278 else if ( nd.type == UINT8 && res1 <= UINT8_MAX ) { 279 if (res) *(uint8_t *)res = (uint8_t) res1; 280 return buf-srcbuf; 281 } 282 else if (nd.type == UINT16 && res1 <= UINT16_MAX ) { 283 if (res) *(uint16_t *)res = (uint16_t) res1; 284 return buf-srcbuf; 285 } 286 else if ( nd.type == UINT32 && res1 <= UINT32_MAX ) { 287 if (res) *(uint32_t *)res = (uint32_t) res1; 288 return buf-srcbuf; 289 } 290 else if ( nd.type == UINT64 ) { 291 if (res) *(uint64_t *)res = res1; 292 return buf-srcbuf; 293 } 294 else { 295 return -1; 296 } 297 break; 298 299 case DEC_NEG_OK: 300 if ( nd.type == INT8 && res1 <= INT8_MAX + 1 ) { 301 if (res) *(int8_t *)res = (int8_t) (-res1); 302 return buf-srcbuf; 303 } 304 else if ( nd.type == INT16 && res1 <= (uint16_t)INT16_MAX + 1 ) { 305 if (res) *(int16_t *)res = (int16_t) (-res1); 306 return buf-srcbuf; 307 } 308 else if ( nd.type == INT32 && res1 <= (uint32_t)INT32_MAX + 1 ) { 309 if (res) *(int32_t *)res = (int32_t) (-res1); 310 return buf-srcbuf; 311 } 312 else if ( nd.type == INT64 && res1 <= (uint64_t)INT64_MAX + 1 ) { 313 if (res) *(int64_t *)res = (int64_t) (-res1); 314 return buf-srcbuf; 315 } 316 else { 317 return -1; 318 } 319 break; 320 default: 321 debug_printf("error\n"); 322 return -1; 323 } 324 } 325 326 327 /* parse an int */ 328 int 329 cmdline_get_help_num(cmdline_parse_token_hdr_t *tk, char *dstbuf, unsigned int size) 330 { 331 struct cmdline_token_num_data nd; 332 int ret; 333 334 if (!tk) 335 return -1; 336 337 memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd)); 338 339 /* should not happen.... don't so this test */ 340 /* if (nd.type >= (sizeof(num_help)/sizeof(const char *))) */ 341 /* return -1; */ 342 343 ret = strlcpy(dstbuf, num_help[nd.type], size); 344 if (ret < 0) 345 return -1; 346 dstbuf[size-1] = '\0'; 347 return 0; 348 } 349