Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 31a566b in mainline


Ignore:
Timestamp:
2019-05-27T16:17:24Z (20 months ago)
Author:
Jiří Zárevúcky <zarevucky.jiri@…>
Branches:
master
Children:
0260034
Parents:
af5037d
git-author:
Jiří Zárevúcky <zarevucky.jiri@…> (2019-02-25 16:35:41)
git-committer:
Jiří Zárevúcky <zarevucky.jiri@…> (2019-05-27 16:17:24)
Message:

Generalize and fix strtol() and friends

Added the option to recognize prefixes used by str_uint() (unused atm).
Allow the error variable be something else than errno.
Fix behavior of strtoul()/strtoull() on unsigned input. The standard
doesn't consider negative input "out of range", the expected behavior
is to just negate the unsigned input value (wraparound).

File:
1 edited

Legend:

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

    raf5037d r31a566b  
    6969}
    7070
     71static inline int _prefixbase(const char *restrict *nptrptr, bool nonstandard_prefixes)
     72{
     73        const char *nptr = *nptrptr;
     74
     75        if (nptr[0] != '0')
     76                return 10;
     77
     78        if (nptr[1] == 'x' || nptr[1] == 'X') {
     79                *nptrptr += 2;
     80                return 16;
     81        }
     82
     83        if (nonstandard_prefixes) {
     84                switch (nptr[1]) {
     85                case 'b':
     86                case 'B':
     87                        *nptrptr += 2;
     88                        return 2;
     89                case 'o':
     90                case 'O':
     91                        *nptrptr += 2;
     92                        return 8;
     93                case 'd':
     94                case 'D':
     95                case 't':
     96                case 'T':
     97                        *nptrptr += 2;
     98                        return 10;
     99                }
     100        }
     101
     102        return 8;
     103}
     104
    71105static inline uintmax_t _strtoumax(
    72106    const char *restrict nptr, char **restrict endptr, int base,
    73     bool *restrict sgn)
     107    bool *restrict sgn, errno_t *err, bool nonstandard_prefixes)
    74108{
    75109        assert(nptr != NULL);
     
    96130        /* Figure out the base. */
    97131
    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') {
     132        if (base == 0)
     133                base = _prefixbase(&nptr, nonstandard_prefixes);
     134
     135        if (base == 16 && !nonstandard_prefixes) {
     136                /*
     137                 * Standard strto* functions allow hexadecimal prefix to be
     138                 * present when base is explicitly set to 16.
     139                 * Our nonstandard str_* functions don't allow it.
     140                 */
     141
     142                if (nptr[0] == '0' && (nptr[1] == 'x' || nptr[1] == 'X'))
    115143                        nptr += 2;
    116                 }
    117         } else if (base < 0 || base == 1 || base > 36) {
    118                 errno = EINVAL;
     144        }
     145
     146        if (base < 2 || base > 36) {
     147                *err = EINVAL;
    119148                return 0;
    120149        }
     
    127156
    128157        while (digit = _digit_value(*nptr), digit < base) {
    129 
    130158                if (result > max ||
    131159                    __builtin_add_overflow(result * base, digit, &result)) {
    132160
    133                         errno = ERANGE;
     161                        *err = ERANGE;
    134162                        result = UINTMAX_MAX;
    135163                        break;
     
    145173                 * Move the pointer to the end of the number,
    146174                 * in case it isn't there already.
     175                 * This can happen when the number has legal formatting,
     176                 * but is out of range of the target type.
    147177                 */
    148178                while (_digit_value(*nptr) < base) {
     
    157187
    158188static inline intmax_t _strtosigned(const char *nptr, char **endptr, int base,
    159     intmax_t min, intmax_t max)
     189    intmax_t min, intmax_t max, errno_t *err, bool nonstandard_prefixes)
    160190{
    161191        bool sgn = false;
    162         uintmax_t number = _strtoumax(nptr, endptr, base, &sgn);
     192        uintmax_t number = _strtoumax(nptr, endptr, base, &sgn, err,
     193            nonstandard_prefixes);
    163194
    164195        if (number > (uintmax_t) max) {
     
    167198                }
    168199
    169                 errno = ERANGE;
     200                *err = ERANGE;
    170201                return (sgn ? min : max);
    171202        }
     
    175206
    176207static inline uintmax_t _strtounsigned(const char *nptr, char **endptr, int base,
    177     uintmax_t max)
     208    uintmax_t max, errno_t *err, bool nonstandard_prefixes)
    178209{
    179210        bool sgn = false;
    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                 }
    189         }
     211        uintmax_t number = _strtoumax(nptr, endptr, base, &sgn, err,
     212            nonstandard_prefixes);
    190213
    191214        if (number > max) {
    192                 errno = ERANGE;
     215                *err = ERANGE;
    193216                return max;
    194217        }
    195218
    196         return number;
     219        return (sgn ? -number : number);
    197220}
    198221
     
    212235long strtol(const char *nptr, char **endptr, int base)
    213236{
    214         return _strtosigned(nptr, endptr, base, LONG_MIN, LONG_MAX);
     237        return _strtosigned(nptr, endptr, base, LONG_MIN, LONG_MAX, &errno, false);
    215238}
    216239
     
    230253unsigned long strtoul(const char *nptr, char **endptr, int base)
    231254{
    232         return _strtounsigned(nptr, endptr, base, ULONG_MAX);
     255        return _strtounsigned(nptr, endptr, base, ULONG_MAX, &errno, false);
    233256}
    234257
    235258long long strtoll(const char *nptr, char **endptr, int base)
    236259{
    237         return _strtosigned(nptr, endptr, base, LLONG_MIN, LLONG_MAX);
     260        return _strtosigned(nptr, endptr, base, LLONG_MIN, LLONG_MAX, &errno, false);
    238261}
    239262
    240263unsigned long long strtoull(const char *nptr, char **endptr, int base)
    241264{
    242         return _strtounsigned(nptr, endptr, base, ULLONG_MAX);
     265        return _strtounsigned(nptr, endptr, base, ULLONG_MAX, &errno, false);
    243266}
    244267
    245268intmax_t strtoimax(const char *nptr, char **endptr, int base)
    246269{
    247         return _strtosigned(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX);
     270        return _strtosigned(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX, &errno, false);
    248271}
    249272
    250273uintmax_t strtoumax(const char *nptr, char **endptr, int base)
    251274{
    252         return _strtounsigned(nptr, endptr, base, UINTMAX_MAX);
     275        return _strtounsigned(nptr, endptr, base, UINTMAX_MAX, &errno, false);
    253276}
    254277
Note: See TracChangeset for help on using the changeset viewer.