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