1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation. 3 * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org> 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 *res = (uint64_t) (*res * base + c); 64 return 0; 65 } 66 67 static int 68 check_res_size(struct cmdline_token_num_data *nd, unsigned ressize) 69 { 70 switch (nd->type) { 71 case RTE_INT8: 72 case RTE_UINT8: 73 if (ressize < sizeof(int8_t)) 74 return -1; 75 break; 76 case RTE_INT16: 77 case RTE_UINT16: 78 if (ressize < sizeof(int16_t)) 79 return -1; 80 break; 81 case RTE_INT32: 82 case RTE_UINT32: 83 if (ressize < sizeof(int32_t)) 84 return -1; 85 break; 86 case RTE_INT64: 87 case RTE_UINT64: 88 if (ressize < sizeof(int64_t)) 89 return -1; 90 break; 91 default: 92 return -1; 93 } 94 return 0; 95 } 96 97 /* parse an int */ 98 int 99 cmdline_parse_num(cmdline_parse_token_hdr_t *tk, const char *srcbuf, void *res, 100 unsigned ressize) 101 { 102 struct cmdline_token_num_data nd; 103 enum num_parse_state_t st = START; 104 const char * buf; 105 char c; 106 uint64_t res1 = 0; 107 108 if (!tk) 109 return -1; 110 111 if (!srcbuf || !*srcbuf) 112 return -1; 113 114 buf = srcbuf; 115 c = *buf; 116 117 memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd)); 118 119 /* check that we have enough room in res */ 120 if (res) { 121 if (check_res_size(&nd, ressize) < 0) 122 return -1; 123 } 124 125 while (st != ERROR && c && !cmdline_isendoftoken(c)) { 126 debug_printf("%c %x -> ", c, c); 127 switch (st) { 128 case START: 129 if (c == '-') { 130 st = DEC_NEG; 131 } 132 else if (c == '0') { 133 st = ZERO_OK; 134 } 135 else if (c >= '1' && c <= '9') { 136 if (add_to_res(c - '0', &res1, 10) < 0) 137 st = ERROR; 138 else 139 st = DEC_POS_OK; 140 } 141 else { 142 st = ERROR; 143 } 144 break; 145 146 case ZERO_OK: 147 if (c == 'x') { 148 st = HEX; 149 } 150 else if (c == 'b') { 151 st = BIN; 152 } 153 else if (c >= '0' && c <= '7') { 154 if (add_to_res(c - '0', &res1, 10) < 0) 155 st = ERROR; 156 else 157 st = OCTAL_OK; 158 } 159 else { 160 st = ERROR; 161 } 162 break; 163 164 case DEC_NEG: 165 if (c >= '0' && c <= '9') { 166 if (add_to_res(c - '0', &res1, 10) < 0) 167 st = ERROR; 168 else 169 st = DEC_NEG_OK; 170 } 171 else { 172 st = ERROR; 173 } 174 break; 175 176 case DEC_NEG_OK: 177 if (c >= '0' && c <= '9') { 178 if (add_to_res(c - '0', &res1, 10) < 0) 179 st = ERROR; 180 } 181 else { 182 st = ERROR; 183 } 184 break; 185 186 case DEC_POS_OK: 187 if (c >= '0' && c <= '9') { 188 if (add_to_res(c - '0', &res1, 10) < 0) 189 st = ERROR; 190 } 191 else { 192 st = ERROR; 193 } 194 break; 195 196 case HEX: 197 st = HEX_OK; 198 /* fall-through */ 199 case HEX_OK: 200 if (c >= '0' && c <= '9') { 201 if (add_to_res(c - '0', &res1, 16) < 0) 202 st = ERROR; 203 } 204 else if (c >= 'a' && c <= 'f') { 205 if (add_to_res(c - 'a' + 10, &res1, 16) < 0) 206 st = ERROR; 207 } 208 else if (c >= 'A' && c <= 'F') { 209 if (add_to_res(c - 'A' + 10, &res1, 16) < 0) 210 st = ERROR; 211 } 212 else { 213 st = ERROR; 214 } 215 break; 216 217 218 case OCTAL_OK: 219 if (c >= '0' && c <= '7') { 220 if (add_to_res(c - '0', &res1, 8) < 0) 221 st = ERROR; 222 } 223 else { 224 st = ERROR; 225 } 226 break; 227 228 case BIN: 229 st = BIN_OK; 230 /* fall-through */ 231 case BIN_OK: 232 if (c >= '0' && c <= '1') { 233 if (add_to_res(c - '0', &res1, 2) < 0) 234 st = ERROR; 235 } 236 else { 237 st = ERROR; 238 } 239 break; 240 default: 241 debug_printf("not impl "); 242 243 } 244 245 debug_printf("(%"PRIu64")\n", res1); 246 247 buf ++; 248 c = *buf; 249 250 /* token too long */ 251 if (buf-srcbuf > 127) 252 return -1; 253 } 254 255 switch (st) { 256 case ZERO_OK: 257 case DEC_POS_OK: 258 case HEX_OK: 259 case OCTAL_OK: 260 case BIN_OK: 261 if (nd.type == RTE_INT8 && res1 <= INT8_MAX) { 262 if (res) *(int8_t *)res = (int8_t) res1; 263 return buf-srcbuf; 264 } else if (nd.type == RTE_INT16 && res1 <= INT16_MAX) { 265 if (res) *(int16_t *)res = (int16_t) res1; 266 return buf-srcbuf; 267 } else if (nd.type == RTE_INT32 && res1 <= INT32_MAX) { 268 if (res) *(int32_t *)res = (int32_t) res1; 269 return buf-srcbuf; 270 } else if (nd.type == RTE_INT64 && res1 <= INT64_MAX) { 271 if (res) *(int64_t *)res = (int64_t) res1; 272 return buf-srcbuf; 273 } else if (nd.type == RTE_UINT8 && res1 <= UINT8_MAX) { 274 if (res) *(uint8_t *)res = (uint8_t) res1; 275 return buf-srcbuf; 276 } else if (nd.type == RTE_UINT16 && res1 <= UINT16_MAX) { 277 if (res) *(uint16_t *)res = (uint16_t) res1; 278 return buf-srcbuf; 279 } else if (nd.type == RTE_UINT32 && res1 <= UINT32_MAX) { 280 if (res) *(uint32_t *)res = (uint32_t) res1; 281 return buf-srcbuf; 282 } else if (nd.type == RTE_UINT64) { 283 if (res) *(uint64_t *)res = res1; 284 return buf-srcbuf; 285 } else { 286 return -1; 287 } 288 break; 289 290 case DEC_NEG_OK: 291 if (nd.type == RTE_INT8 && 292 res1 <= INT8_MAX + 1) { 293 if (res) *(int8_t *)res = (int8_t) (-res1); 294 return buf-srcbuf; 295 } else if (nd.type == RTE_INT16 && 296 res1 <= (uint16_t)INT16_MAX + 1) { 297 if (res) *(int16_t *)res = (int16_t) (-res1); 298 return buf-srcbuf; 299 } else if (nd.type == RTE_INT32 && 300 res1 <= (uint32_t)INT32_MAX + 1) { 301 if (res) *(int32_t *)res = (int32_t) (-res1); 302 return buf-srcbuf; 303 } else if (nd.type == RTE_INT64 && 304 res1 <= (uint64_t)INT64_MAX + 1) { 305 if (res) *(int64_t *)res = (int64_t) (-res1); 306 return buf-srcbuf; 307 } else { 308 return -1; 309 } 310 break; 311 default: 312 debug_printf("error\n"); 313 return -1; 314 } 315 } 316 317 318 /* parse an int */ 319 int 320 cmdline_get_help_num(cmdline_parse_token_hdr_t *tk, char *dstbuf, unsigned int size) 321 { 322 struct cmdline_token_num_data nd; 323 int ret; 324 325 if (!tk) 326 return -1; 327 328 memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd)); 329 330 /* should not happen.... don't so this test */ 331 /* if (nd.type >= (sizeof(num_help)/sizeof(const char *))) */ 332 /* return -1; */ 333 334 ret = strlcpy(dstbuf, num_help[nd.type], size); 335 if (ret < 0) 336 return -1; 337 dstbuf[size-1] = '\0'; 338 return 0; 339 } 340