Changes in uspace/lib/c/generic/strtol.c [1c9bf292:55092672] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/strtol.c
r1c9bf292 r55092672 44 44 #include <stdbool.h> 45 45 #include <stdlib.h> 46 #include <str.h> 47 48 // FIXME: The original HelenOS functions return EOVERFLOW instead 49 // of ERANGE. It's a pointless distinction from standard functions, 50 // so we should change that. Beware the callers though. 51 52 // TODO: more unit tests 46 47 // TODO: unit tests 53 48 54 49 static inline int _digit_value(int c) … … 74 69 } 75 70 76 static inline int _prefixbase(const char *restrict *nptrptr, bool nonstd)77 {78 const char *nptr = *nptrptr;79 80 if (nptr[0] != '0')81 return 10;82 83 if (nptr[1] == 'x' || nptr[1] == 'X') {84 if (_digit_value(nptr[2]) < 16) {85 *nptrptr += 2;86 return 16;87 }88 }89 90 if (nonstd) {91 switch (nptr[1]) {92 case 'b':93 case 'B':94 if (_digit_value(nptr[2]) < 2) {95 *nptrptr += 2;96 return 2;97 }98 break;99 case 'o':100 case 'O':101 if (_digit_value(nptr[2]) < 8) {102 *nptrptr += 2;103 return 8;104 }105 break;106 case 'd':107 case 'D':108 case 't':109 case 'T':110 if (_digit_value(nptr[2]) < 10) {111 *nptrptr += 2;112 return 10;113 }114 break;115 }116 }117 118 return 8;119 }120 121 71 static inline uintmax_t _strtoumax( 122 72 const char *restrict nptr, char **restrict endptr, int base, 123 bool *restrict sgn , errno_t *err, bool nonstd)73 bool *restrict sgn) 124 74 { 125 75 assert(nptr != NULL); 126 76 assert(sgn != NULL); 127 128 const char *first = nptr;129 77 130 78 /* Skip leading whitespace. */ … … 148 96 /* Figure out the base. */ 149 97 150 if (base == 0) 151 base = _prefixbase(&nptr, nonstd); 152 153 if (base == 16 && !nonstd) { 154 /* 155 * Standard strto* functions allow hexadecimal prefix to be 156 * present when base is explicitly set to 16. 157 * Our nonstandard str_* functions don't allow it. 158 * I don't know if that is intended, just matching the original 159 * functionality here. 160 */ 161 162 if (nptr[0] == '0' && (nptr[1] == 'x' || nptr[1] == 'X') && 163 _digit_value(nptr[2]) < base) 98 if (base == 0) { 99 if (*nptr == '0') { 100 if (tolower(nptr[1]) == 'x') { 101 /* 0x... is hex. */ 102 base = 16; 103 nptr += 2; 104 } else { 105 /* 0... is octal. */ 106 base = 8; 107 } 108 } else { 109 /* Anything else is decimal by default. */ 110 base = 10; 111 } 112 } else if (base == 16) { 113 /* Allow hex number to be prefixed with "0x". */ 114 if (nptr[0] == '0' && tolower(nptr[1]) == 'x') { 164 115 nptr += 2; 165 } 166 167 if (base < 2 || base > 36) { 168 *err = EINVAL; 116 } 117 } else if (base < 0 || base == 1 || base > 36) { 118 errno = EINVAL; 169 119 return 0; 170 120 } 171 121 172 /* Must be at least one digit. */ 173 174 if (_digit_value(*nptr) >= base) { 175 /* No digits on input. */ 176 if (endptr != NULL) 177 *endptr = (char *) first; 178 return 0; 179 } 180 181 /* Read the value. */ 122 /* Read the value. */ 182 123 183 124 uintmax_t result = 0; … … 186 127 187 128 while (digit = _digit_value(*nptr), digit < base) { 129 188 130 if (result > max || 189 131 __builtin_add_overflow(result * base, digit, &result)) { 190 132 191 *err = nonstd ? EOVERFLOW :ERANGE;133 errno = ERANGE; 192 134 result = UINTMAX_MAX; 193 135 break; … … 203 145 * Move the pointer to the end of the number, 204 146 * in case it isn't there already. 205 * This can happen when the number has legal formatting,206 * but is out of range of the target type.207 147 */ 208 148 while (_digit_value(*nptr) < base) { … … 217 157 218 158 static inline intmax_t _strtosigned(const char *nptr, char **endptr, int base, 219 intmax_t min, intmax_t max , errno_t *err, bool nonstd)159 intmax_t min, intmax_t max) 220 160 { 221 161 bool sgn = false; 222 uintmax_t number = _strtoumax(nptr, endptr, base, &sgn , err, nonstd);162 uintmax_t number = _strtoumax(nptr, endptr, base, &sgn); 223 163 224 164 if (number > (uintmax_t) max) { … … 227 167 } 228 168 229 *err = nonstd ? EOVERFLOW :ERANGE;169 errno = ERANGE; 230 170 return (sgn ? min : max); 231 171 } … … 235 175 236 176 static inline uintmax_t _strtounsigned(const char *nptr, char **endptr, int base, 237 uintmax_t max , errno_t *err, bool nonstd)177 uintmax_t max) 238 178 { 239 179 bool sgn = false; 240 uintmax_t number = _strtoumax(nptr, endptr, base, &sgn, err, nonstd); 241 242 if (nonstd && sgn) { 243 /* Do not allow negative values */ 244 *err = EINVAL; 245 return 0; 180 uintmax_t number = _strtoumax(nptr, endptr, base, &sgn); 181 182 if (sgn) { 183 if (number == 0) { 184 return 0; 185 } else { 186 errno = ERANGE; 187 return max; 188 } 246 189 } 247 190 248 191 if (number > max) { 249 *err = nonstd ? EOVERFLOW :ERANGE;192 errno = ERANGE; 250 193 return max; 251 194 } 252 195 253 return (sgn ? -number : number);196 return number; 254 197 } 255 198 … … 269 212 long strtol(const char *nptr, char **endptr, int base) 270 213 { 271 return _strtosigned(nptr, endptr, base, LONG_MIN, LONG_MAX , &errno, false);214 return _strtosigned(nptr, endptr, base, LONG_MIN, LONG_MAX); 272 215 } 273 216 … … 287 230 unsigned long strtoul(const char *nptr, char **endptr, int base) 288 231 { 289 return _strtounsigned(nptr, endptr, base, ULONG_MAX , &errno, false);232 return _strtounsigned(nptr, endptr, base, ULONG_MAX); 290 233 } 291 234 292 235 long long strtoll(const char *nptr, char **endptr, int base) 293 236 { 294 return _strtosigned(nptr, endptr, base, LLONG_MIN, LLONG_MAX , &errno, false);237 return _strtosigned(nptr, endptr, base, LLONG_MIN, LLONG_MAX); 295 238 } 296 239 297 240 unsigned long long strtoull(const char *nptr, char **endptr, int base) 298 241 { 299 return _strtounsigned(nptr, endptr, base, ULLONG_MAX , &errno, false);242 return _strtounsigned(nptr, endptr, base, ULLONG_MAX); 300 243 } 301 244 302 245 intmax_t strtoimax(const char *nptr, char **endptr, int base) 303 246 { 304 return _strtosigned(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX , &errno, false);247 return _strtosigned(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX); 305 248 } 306 249 307 250 uintmax_t strtoumax(const char *nptr, char **endptr, int base) 308 251 { 309 return _strtounsigned(nptr, endptr, base, UINTMAX_MAX , &errno, false);252 return _strtounsigned(nptr, endptr, base, UINTMAX_MAX); 310 253 } 311 254 … … 325 268 } 326 269 327 /** Convert string to uint8_t.328 *329 * @param nptr Pointer to string.330 * @param endptr If not NULL, pointer to the first invalid character331 * is stored here.332 * @param base Zero or number between 2 and 36 inclusive.333 * @param strict Do not allow any trailing characters.334 * @param result Result of the conversion.335 *336 * @return EOK if conversion was successful.337 *338 */339 errno_t str_uint8_t(const char *nptr, const char **endptr, unsigned int base,340 bool strict, uint8_t *result)341 {342 assert(result != NULL);343 344 errno_t rc = EOK;345 char *lendptr = (char *) nptr;346 347 uintmax_t r = _strtounsigned(nptr, &lendptr, base, UINT8_MAX, &rc, true);348 349 if (endptr)350 *endptr = lendptr;351 352 if (rc != EOK)353 return rc;354 355 if (strict && *lendptr != '\0')356 return EINVAL;357 358 *result = r;359 return EOK;360 }361 362 /** Convert string to uint16_t.363 *364 * @param nptr Pointer to string.365 * @param endptr If not NULL, pointer to the first invalid character366 * is stored here.367 * @param base Zero or number between 2 and 36 inclusive.368 * @param strict Do not allow any trailing characters.369 * @param result Result of the conversion.370 *371 * @return EOK if conversion was successful.372 *373 */374 errno_t str_uint16_t(const char *nptr, const char **endptr, unsigned int base,375 bool strict, uint16_t *result)376 {377 assert(result != NULL);378 379 errno_t rc = EOK;380 char *lendptr = (char *) nptr;381 382 uintmax_t r = _strtounsigned(nptr, &lendptr, base, UINT16_MAX, &rc, true);383 384 if (endptr)385 *endptr = lendptr;386 387 if (rc != EOK)388 return rc;389 390 if (strict && *lendptr != '\0')391 return EINVAL;392 393 *result = r;394 return EOK;395 }396 397 /** Convert string to uint32_t.398 *399 * @param nptr Pointer to string.400 * @param endptr If not NULL, pointer to the first invalid character401 * is stored here.402 * @param base Zero or number between 2 and 36 inclusive.403 * @param strict Do not allow any trailing characters.404 * @param result Result of the conversion.405 *406 * @return EOK if conversion was successful.407 *408 */409 errno_t str_uint32_t(const char *nptr, const char **endptr, unsigned int base,410 bool strict, uint32_t *result)411 {412 assert(result != NULL);413 414 errno_t rc = EOK;415 char *lendptr = (char *) nptr;416 417 uintmax_t r = _strtounsigned(nptr, &lendptr, base, UINT32_MAX, &rc, true);418 419 if (endptr)420 *endptr = lendptr;421 422 if (rc != EOK)423 return rc;424 425 if (strict && *lendptr != '\0')426 return EINVAL;427 428 *result = r;429 return EOK;430 }431 432 /** Convert string to uint64_t.433 *434 * @param nptr Pointer to string.435 * @param endptr If not NULL, pointer to the first invalid character436 * is stored here.437 * @param base Zero or number between 2 and 36 inclusive.438 * @param strict Do not allow any trailing characters.439 * @param result Result of the conversion.440 *441 * @return EOK if conversion was successful.442 *443 */444 errno_t str_uint64_t(const char *nptr, const char **endptr, unsigned int base,445 bool strict, uint64_t *result)446 {447 assert(result != NULL);448 449 errno_t rc = EOK;450 char *lendptr = (char *) nptr;451 452 uintmax_t r = _strtounsigned(nptr, &lendptr, base, UINT64_MAX, &rc, true);453 454 if (endptr)455 *endptr = lendptr;456 457 if (rc != EOK)458 return rc;459 460 if (strict && *lendptr != '\0')461 return EINVAL;462 463 *result = r;464 return EOK;465 }466 467 /** Convert string to int64_t.468 *469 * @param nptr Pointer to string.470 * @param endptr If not NULL, pointer to the first invalid character471 * is stored here.472 * @param base Zero or number between 2 and 36 inclusive.473 * @param strict Do not allow any trailing characters.474 * @param result Result of the conversion.475 *476 * @return EOK if conversion was successful.477 *478 */479 errno_t str_int64_t(const char *nptr, const char **endptr, unsigned int base,480 bool strict, int64_t *result)481 {482 assert(result != NULL);483 484 errno_t rc = EOK;485 char *lendptr = (char *) nptr;486 487 intmax_t r = _strtosigned(nptr, &lendptr, base, INT64_MIN, INT64_MAX, &rc, true);488 489 if (endptr)490 *endptr = lendptr;491 492 if (rc != EOK)493 return rc;494 495 if (strict && *lendptr != '\0')496 return EINVAL;497 498 *result = r;499 return EOK;500 }501 502 /** Convert string to size_t.503 *504 * @param nptr Pointer to string.505 * @param endptr If not NULL, pointer to the first invalid character506 * is stored here.507 * @param base Zero or number between 2 and 36 inclusive.508 * @param strict Do not allow any trailing characters.509 * @param result Result of the conversion.510 *511 * @return EOK if conversion was successful.512 *513 */514 errno_t str_size_t(const char *nptr, const char **endptr, unsigned int base,515 bool strict, size_t *result)516 {517 assert(result != NULL);518 519 errno_t rc = EOK;520 char *lendptr = (char *) nptr;521 522 uintmax_t r = _strtounsigned(nptr, &lendptr, base, SIZE_MAX, &rc, true);523 524 if (endptr)525 *endptr = lendptr;526 527 if (rc != EOK)528 return rc;529 530 if (strict && *lendptr != '\0')531 return EINVAL;532 533 *result = r;534 return EOK;535 }536 537 270 /** @} 538 271 */
Note:
See TracChangeset
for help on using the changeset viewer.