1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Copyright (c) 2009, Olivier MATZ <[email protected]> 36 * All rights reserved. 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions are met: 39 * 40 * * Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * * Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * * Neither the name of the University of California, Berkeley nor the 46 * names of its contributors may be used to endorse or promote products 47 * derived from this software without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 50 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 51 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 52 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 53 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 54 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 55 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 56 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 57 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 58 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 59 */ 60 61 #include <stdio.h> 62 #include <stdint.h> 63 #include <inttypes.h> 64 #include <ctype.h> 65 #include <string.h> 66 #include <stdarg.h> 67 #include <errno.h> 68 #include <rte_string_fns.h> 69 70 #include "cmdline_parse.h" 71 #include "cmdline_parse_num.h" 72 73 #ifdef RTE_LIBRTE_CMDLINE_DEBUG 74 #define debug_printf(args...) printf(args) 75 #else 76 #define debug_printf(args...) do {} while(0) 77 #endif 78 79 struct cmdline_token_ops cmdline_token_num_ops = { 80 .parse = cmdline_parse_num, 81 .complete_get_nb = NULL, 82 .complete_get_elt = NULL, 83 .get_help = cmdline_get_help_num, 84 }; 85 86 87 enum num_parse_state_t { 88 START, 89 DEC_NEG, 90 BIN, 91 HEX, 92 93 ERROR, 94 95 FIRST_OK, /* not used */ 96 ZERO_OK, 97 HEX_OK, 98 OCTAL_OK, 99 BIN_OK, 100 DEC_NEG_OK, 101 DEC_POS_OK, 102 }; 103 104 /* Keep it sync with enum in .h */ 105 static const char * num_help[] = { 106 "UINT8", "UINT16", "UINT32", "UINT64", 107 "INT8", "INT16", "INT32", "INT64", 108 }; 109 110 static inline int 111 add_to_res(unsigned int c, uint64_t *res, unsigned int base) 112 { 113 /* overflow */ 114 if ( (UINT64_MAX - c) / base < *res ) { 115 return -1; 116 } 117 118 *res = (uint64_t) (*res * base + c); 119 return 0; 120 } 121 122 static int 123 check_res_size(struct cmdline_token_num_data *nd, unsigned ressize) 124 { 125 switch (nd->type) { 126 case INT8: 127 case UINT8: 128 if (ressize < sizeof(int8_t)) 129 return -1; 130 break; 131 case INT16: 132 case UINT16: 133 if (ressize < sizeof(int16_t)) 134 return -1; 135 break; 136 case INT32: 137 case UINT32: 138 if (ressize < sizeof(int32_t)) 139 return -1; 140 break; 141 case INT64: 142 case UINT64: 143 if (ressize < sizeof(int64_t)) 144 return -1; 145 break; 146 default: 147 return -1; 148 } 149 return 0; 150 } 151 152 /* parse an int */ 153 int 154 cmdline_parse_num(cmdline_parse_token_hdr_t *tk, const char *srcbuf, void *res, 155 unsigned ressize) 156 { 157 struct cmdline_token_num_data nd; 158 enum num_parse_state_t st = START; 159 const char * buf; 160 char c; 161 uint64_t res1 = 0; 162 163 if (!tk) 164 return -1; 165 166 if (!srcbuf || !*srcbuf) 167 return -1; 168 169 buf = srcbuf; 170 c = *buf; 171 172 memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd)); 173 174 /* check that we have enough room in res */ 175 if (res) { 176 if (check_res_size(&nd, ressize) < 0) 177 return -1; 178 } 179 180 while ( st != ERROR && c && ! cmdline_isendoftoken(c) ) { 181 debug_printf("%c %x -> ", c, c); 182 switch (st) { 183 case START: 184 if (c == '-') { 185 st = DEC_NEG; 186 } 187 else if (c == '0') { 188 st = ZERO_OK; 189 } 190 else if (c >= '1' && c <= '9') { 191 if (add_to_res(c - '0', &res1, 10) < 0) 192 st = ERROR; 193 else 194 st = DEC_POS_OK; 195 } 196 else { 197 st = ERROR; 198 } 199 break; 200 201 case ZERO_OK: 202 if (c == 'x') { 203 st = HEX; 204 } 205 else if (c == 'b') { 206 st = BIN; 207 } 208 else if (c >= '0' && c <= '7') { 209 if (add_to_res(c - '0', &res1, 10) < 0) 210 st = ERROR; 211 else 212 st = OCTAL_OK; 213 } 214 else { 215 st = ERROR; 216 } 217 break; 218 219 case DEC_NEG: 220 if (c >= '0' && c <= '9') { 221 if (add_to_res(c - '0', &res1, 10) < 0) 222 st = ERROR; 223 else 224 st = DEC_NEG_OK; 225 } 226 else { 227 st = ERROR; 228 } 229 break; 230 231 case DEC_NEG_OK: 232 if (c >= '0' && c <= '9') { 233 if (add_to_res(c - '0', &res1, 10) < 0) 234 st = ERROR; 235 } 236 else { 237 st = ERROR; 238 } 239 break; 240 241 case DEC_POS_OK: 242 if (c >= '0' && c <= '9') { 243 if (add_to_res(c - '0', &res1, 10) < 0) 244 st = ERROR; 245 } 246 else { 247 st = ERROR; 248 } 249 break; 250 251 case HEX: 252 st = HEX_OK; 253 /* fall-through no break */ 254 case HEX_OK: 255 if (c >= '0' && c <= '9') { 256 if (add_to_res(c - '0', &res1, 16) < 0) 257 st = ERROR; 258 } 259 else if (c >= 'a' && c <= 'f') { 260 if (add_to_res(c - 'a' + 10, &res1, 16) < 0) 261 st = ERROR; 262 } 263 else if (c >= 'A' && c <= 'F') { 264 if (add_to_res(c - 'A' + 10, &res1, 16) < 0) 265 st = ERROR; 266 } 267 else { 268 st = ERROR; 269 } 270 break; 271 272 273 case OCTAL_OK: 274 if (c >= '0' && c <= '7') { 275 if (add_to_res(c - '0', &res1, 8) < 0) 276 st = ERROR; 277 } 278 else { 279 st = ERROR; 280 } 281 break; 282 283 case BIN: 284 st = BIN_OK; 285 /* fall-through */ 286 case BIN_OK: 287 if (c >= '0' && c <= '1') { 288 if (add_to_res(c - '0', &res1, 2) < 0) 289 st = ERROR; 290 } 291 else { 292 st = ERROR; 293 } 294 break; 295 default: 296 debug_printf("not impl "); 297 298 } 299 300 debug_printf("(%"PRIu64")\n", res1); 301 302 buf ++; 303 c = *buf; 304 305 /* token too long */ 306 if (buf-srcbuf > 127) 307 return -1; 308 } 309 310 switch (st) { 311 case ZERO_OK: 312 case DEC_POS_OK: 313 case HEX_OK: 314 case OCTAL_OK: 315 case BIN_OK: 316 if ( nd.type == INT8 && res1 <= INT8_MAX ) { 317 if (res) *(int8_t *)res = (int8_t) res1; 318 return buf-srcbuf; 319 } 320 else if ( nd.type == INT16 && res1 <= INT16_MAX ) { 321 if (res) *(int16_t *)res = (int16_t) res1; 322 return buf-srcbuf; 323 } 324 else if ( nd.type == INT32 && res1 <= INT32_MAX ) { 325 if (res) *(int32_t *)res = (int32_t) res1; 326 return buf-srcbuf; 327 } 328 else if ( nd.type == INT64 && res1 <= INT64_MAX ) { 329 if (res) *(int64_t *)res = (int64_t) res1; 330 return buf-srcbuf; 331 } 332 else if ( nd.type == UINT8 && res1 <= UINT8_MAX ) { 333 if (res) *(uint8_t *)res = (uint8_t) res1; 334 return buf-srcbuf; 335 } 336 else if (nd.type == UINT16 && res1 <= UINT16_MAX ) { 337 if (res) *(uint16_t *)res = (uint16_t) res1; 338 return buf-srcbuf; 339 } 340 else if ( nd.type == UINT32 && res1 <= UINT32_MAX ) { 341 if (res) *(uint32_t *)res = (uint32_t) res1; 342 return buf-srcbuf; 343 } 344 else if ( nd.type == UINT64 ) { 345 if (res) *(uint64_t *)res = res1; 346 return buf-srcbuf; 347 } 348 else { 349 return -1; 350 } 351 break; 352 353 case DEC_NEG_OK: 354 if ( nd.type == INT8 && res1 <= INT8_MAX + 1 ) { 355 if (res) *(int8_t *)res = (int8_t) (-res1); 356 return buf-srcbuf; 357 } 358 else if ( nd.type == INT16 && res1 <= (uint16_t)INT16_MAX + 1 ) { 359 if (res) *(int16_t *)res = (int16_t) (-res1); 360 return buf-srcbuf; 361 } 362 else if ( nd.type == INT32 && res1 <= (uint32_t)INT32_MAX + 1 ) { 363 if (res) *(int32_t *)res = (int32_t) (-res1); 364 return buf-srcbuf; 365 } 366 else if ( nd.type == INT64 && res1 <= (uint64_t)INT64_MAX + 1 ) { 367 if (res) *(int64_t *)res = (int64_t) (-res1); 368 return buf-srcbuf; 369 } 370 else { 371 return -1; 372 } 373 break; 374 default: 375 debug_printf("error\n"); 376 return -1; 377 } 378 } 379 380 381 /* parse an int */ 382 int 383 cmdline_get_help_num(cmdline_parse_token_hdr_t *tk, char *dstbuf, unsigned int size) 384 { 385 struct cmdline_token_num_data nd; 386 int ret; 387 388 if (!tk) 389 return -1; 390 391 memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd)); 392 393 /* should not happen.... don't so this test */ 394 /* if (nd.type >= (sizeof(num_help)/sizeof(const char *))) */ 395 /* return -1; */ 396 397 ret = snprintf(dstbuf, size, "%s", num_help[nd.type]); 398 if (ret < 0) 399 return -1; 400 dstbuf[size-1] = '\0'; 401 return 0; 402 } 403