Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/strtol.c

    r1c9bf292 r55092672  
    4444#include <stdbool.h>
    4545#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
    5348
    5449static inline int _digit_value(int c)
     
    7469}
    7570
    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 
    12171static inline uintmax_t _strtoumax(
    12272    const char *restrict nptr, char **restrict endptr, int base,
    123     bool *restrict sgn, errno_t *err, bool nonstd)
     73    bool *restrict sgn)
    12474{
    12575        assert(nptr != NULL);
    12676        assert(sgn != NULL);
    127 
    128         const char *first = nptr;
    12977
    13078        /* Skip leading whitespace. */
     
    14896        /* Figure out the base. */
    14997
    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') {
    164115                        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;
    169119                return 0;
    170120        }
    171121
    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. */
    182123
    183124        uintmax_t result = 0;
     
    186127
    187128        while (digit = _digit_value(*nptr), digit < base) {
     129
    188130                if (result > max ||
    189131                    __builtin_add_overflow(result * base, digit, &result)) {
    190132
    191                         *err = nonstd ? EOVERFLOW : ERANGE;
     133                        errno = ERANGE;
    192134                        result = UINTMAX_MAX;
    193135                        break;
     
    203145                 * Move the pointer to the end of the number,
    204146                 * 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.
    207147                 */
    208148                while (_digit_value(*nptr) < base) {
     
    217157
    218158static 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)
    220160{
    221161        bool sgn = false;
    222         uintmax_t number = _strtoumax(nptr, endptr, base, &sgn, err, nonstd);
     162        uintmax_t number = _strtoumax(nptr, endptr, base, &sgn);
    223163
    224164        if (number > (uintmax_t) max) {
     
    227167                }
    228168
    229                 *err = nonstd ? EOVERFLOW : ERANGE;
     169                errno = ERANGE;
    230170                return (sgn ? min : max);
    231171        }
     
    235175
    236176static inline uintmax_t _strtounsigned(const char *nptr, char **endptr, int base,
    237     uintmax_t max, errno_t *err, bool nonstd)
     177    uintmax_t max)
    238178{
    239179        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                }
    246189        }
    247190
    248191        if (number > max) {
    249                 *err = nonstd ? EOVERFLOW : ERANGE;
     192                errno = ERANGE;
    250193                return max;
    251194        }
    252195
    253         return (sgn ? -number : number);
     196        return number;
    254197}
    255198
     
    269212long strtol(const char *nptr, char **endptr, int base)
    270213{
    271         return _strtosigned(nptr, endptr, base, LONG_MIN, LONG_MAX, &errno, false);
     214        return _strtosigned(nptr, endptr, base, LONG_MIN, LONG_MAX);
    272215}
    273216
     
    287230unsigned long strtoul(const char *nptr, char **endptr, int base)
    288231{
    289         return _strtounsigned(nptr, endptr, base, ULONG_MAX, &errno, false);
     232        return _strtounsigned(nptr, endptr, base, ULONG_MAX);
    290233}
    291234
    292235long long strtoll(const char *nptr, char **endptr, int base)
    293236{
    294         return _strtosigned(nptr, endptr, base, LLONG_MIN, LLONG_MAX, &errno, false);
     237        return _strtosigned(nptr, endptr, base, LLONG_MIN, LLONG_MAX);
    295238}
    296239
    297240unsigned long long strtoull(const char *nptr, char **endptr, int base)
    298241{
    299         return _strtounsigned(nptr, endptr, base, ULLONG_MAX, &errno, false);
     242        return _strtounsigned(nptr, endptr, base, ULLONG_MAX);
    300243}
    301244
    302245intmax_t strtoimax(const char *nptr, char **endptr, int base)
    303246{
    304         return _strtosigned(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX, &errno, false);
     247        return _strtosigned(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX);
    305248}
    306249
    307250uintmax_t strtoumax(const char *nptr, char **endptr, int base)
    308251{
    309         return _strtounsigned(nptr, endptr, base, UINTMAX_MAX, &errno, false);
     252        return _strtounsigned(nptr, endptr, base, UINTMAX_MAX);
    310253}
    311254
     
    325268}
    326269
    327 /** Convert string to uint8_t.
    328  *
    329  * @param nptr   Pointer to string.
    330  * @param endptr If not NULL, pointer to the first invalid character
    331  *               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 character
    366  *               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 character
    401  *               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 character
    436  *               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 character
    471  *               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 character
    506  *               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 
    537270/** @}
    538271 */
Note: See TracChangeset for help on using the changeset viewer.