Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/posix/stdlib/strtol.c

    raa5acd47 rec18957a  
    3030 * @{
    3131 */
    32 /** @file Backend for integer conversions.
     32/** @file
    3333 */
    3434
     
    3838#include "../stdlib.h"
    3939
     40#include "../limits.h"
    4041#include "../ctype.h"
    4142#include "../errno.h"
    42 #include "../inttypes.h"
    43 #include "../limits.h"
    44 
    45 #define intmax_t posix_intmax_t
    46 #define uintmax_t posix_uintmax_t
    47 
    48 /**
    49  * Decides whether a digit belongs to a particular base.
    50  *
    51  * @param c Character representation of the digit.
    52  * @param base Base against which the digit shall be tested.
    53  * @return True if the digit belongs to the base, false otherwise.
    54  */
     43
     44// TODO: documentation
     45
    5546static inline bool is_digit_in_base(int c, int base)
    5647{
     
    6354}
    6455
    65 /**
    66  * Derive a digit from its character representation.
    67  *
    68  * @param c Character representation of the digit.
    69  * @return Digit value represented by an integer.
    70  */
    71 static inline int digit_value(int c)
     56static inline int get_digit_in_base(int c, int base)
    7257{
    7358        if (c <= '9') {
     
    7863}
    7964
    80 /**
    81  * Generic function for parsing an integer from it's string representation.
    82  * Different variants differ in lower and upper bounds.
    83  * The parsed string returned by this function is always positive, sign
    84  * information is provided via a dedicated parameter.
    85  *
    86  * @param nptr Input string.
    87  * @param endptr If non-NULL, *endptr is set to the position of the first
    88  *     unrecognized character. If no digit has been parsed, value of
    89  *     nptr is stored there (regardless of any skipped characters at the
    90  *     beginning).
    91  * @param base Expected base of the string representation. If 0, base is
    92  *    determined to be decimal, octal or hexadecimal using the same rules
    93  *    as C syntax. Otherwise, value must be between 2 and 36, inclusive.
    94  * @param min_value Lower bound for the resulting conversion.
    95  * @param max_value Upper bound for the resulting conversion.
    96  * @param out_negative Either NULL for unsigned conversion or a pointer to the
    97  *     bool variable into which shall be placed the negativity of the resulting
    98  *     converted value.
    99  * @return The absolute value of the parsed value, or the closest in-range value
    100  *     if the parsed value is out of range. If the input is invalid, zero is
    101  *     returned and errno is set to EINVAL.
    102  */
    103 static inline uintmax_t internal_strtol(
     65static inline unsigned long long internal_strtol(
    10466    const char *restrict nptr, char **restrict endptr, int base,
    105     const intmax_t min_value, const uintmax_t max_value,
     67    const long long min_value, const unsigned long long max_value,
    10668    bool *restrict out_negative)
    10769{
     
    11678        }
    11779       
    118         /* The maximal absolute value that can be returned in this run.
    119          * Depends on sign.
    120          */
    121         uintmax_t real_max_value = max_value;
     80        unsigned long long real_max_value = max_value;
    12281       
    12382        /* Current index in the input string. */
    124         size_t i = 0;
     83        int i = 0;
    12584        bool negative = false;
    12685       
     
    13493        case '-':
    13594                negative = true;
    136                
    137                 /* The strange computation is are there to avoid a corner case
    138                  * where -min_value can't be represented in intmax_t.
    139                  * (I'm not exactly sure what the semantics are in such a
    140                  *  case, but this should be safe for any case.)
    141                  */
    142                 real_max_value = (min_value == 0)
    143                     ? 0
    144                     :(((uintmax_t) -(min_value + 1)) + 1);
    145                
     95                real_max_value = -min_value;
    14696                /* fallthrough */
    14797        case '+':
     
    154104                if (nptr[i] == '0') {
    155105                        if (tolower(nptr[i + 1]) == 'x') {
    156                                 /* 0x... is hex. */
    157106                                base = 16;
    158107                                i += 2;
    159108                        } else {
    160                                 /* 0... is octal. */
    161109                                base = 8;
    162110                        }
    163111                } else {
    164                         /* Anything else is decimal by default. */
    165112                        base = 10;
    166113                }
    167114                break;
    168115        case 16:
    169                 /* Allow hex number to be prefixed with "0x". */
    170116                if (nptr[i] == '0' && tolower(nptr[i + 1]) == 'x') {
    171117                        i += 2;
     
    187133         * of overflow.
    188134         */
    189         uintmax_t max_safe_value = (real_max_value - base + 1) / base;
    190        
    191         uintmax_t result = 0;
     135        unsigned long long max_safe_value = (real_max_value - base + 1) / base;
     136       
     137        unsigned long long result = 0;
    192138       
    193139        if (real_max_value == 0) {
     
    199145                        if (nptr[i] != '0') {
    200146                                errno = ERANGE;
    201                                 result = 0;
     147                                result = max_value;
    202148                        }
    203149                        i++;
     
    206152       
    207153        while (is_digit_in_base(nptr[i], base)) {
    208                 int digit = digit_value(nptr[i]);
     154                int digit = get_digit_in_base(nptr[i], base);
    209155               
    210156                if (result > max_safe_value) {
    211157                        /* corner case, check for overflow */
    212158                       
    213                         uintmax_t boundary = (real_max_value - digit) / base;
     159                        unsigned long long
     160                            boundary = (real_max_value - digit) / base;
    214161                       
    215162                        if (result > boundary) {
    216163                                /* overflow */
    217164                                errno = ERANGE;
    218                                 result = real_max_value;
     165                                result = max_value;
    219166                                break;
    220167                        }
     
    241188}
    242189
    243 /**
    244  * Convert a string to an integer.
    245  *
    246  * @param nptr Input string.
    247  * @return Result of the conversion.
    248  */
    249190int posix_atoi(const char *nptr)
    250191{
    251192        bool neg = false;
    252         uintmax_t result =
     193        unsigned long long result =
    253194            internal_strtol(nptr, NULL, 10, INT_MIN, INT_MAX, &neg);
    254195
    255         return (neg ? ((int) -result) : (int) result);
    256 }
    257 
    258 /**
    259  * Convert a string to a long integer.
    260  *
    261  * @param nptr Input string.
    262  * @return Result of the conversion.
    263  */
     196        return (int) (neg ? -result : result);
     197}
     198
    264199long posix_atol(const char *nptr)
    265200{
    266201        bool neg = false;
    267         uintmax_t result =
     202        unsigned long long result =
    268203            internal_strtol(nptr, NULL, 10, LONG_MIN, LONG_MAX, &neg);
    269204
    270         return (neg ? ((long) -result) : (long) result);
    271 }
    272 
    273 /**
    274  * Convert a string to a long long integer.
    275  *
    276  * @param nptr Input string.
    277  * @return Result of the conversion.
    278  */
     205        return (long) (neg ? -result : result);
     206}
     207
    279208long long posix_atoll(const char *nptr)
    280209{
    281210        bool neg = false;
    282         uintmax_t result =
     211        unsigned long long result =
    283212            internal_strtol(nptr, NULL, 10, LLONG_MIN, LLONG_MAX, &neg);
    284213
    285         return (neg ? ((long long) -result) : (long long) result);
    286 }
    287 
    288 /**
    289  * Convert a string to a long integer.
    290  *
    291  * @param nptr Input string.
    292  * @param endptr Pointer to the final part of the string which
    293  *     was not used for conversion.
    294  * @param base Expected base of the string representation.
    295  * @return Result of the conversion.
    296  */
     214        return (long long) (neg ? -result : result);
     215}
     216
    297217long posix_strtol(const char *restrict nptr, char **restrict endptr, int base)
    298218{
    299219        bool neg = false;
    300         uintmax_t result =
     220        unsigned long long result =
    301221            internal_strtol(nptr, endptr, base, LONG_MIN, LONG_MAX, &neg);
    302222
    303         return (neg ? ((long) -result) : ((long) result));
    304 }
    305 
    306 /**
    307  * Convert a string to a long long integer.
    308  *
    309  * @param nptr Input string.
    310  * @param endptr Pointer to the final part of the string which
    311  *     was not used for conversion.
    312  * @param base Expected base of the string representation.
    313  * @return Result of the conversion.
    314  */
     223        return (long) (neg ? -result : result);
     224}
     225
    315226long long posix_strtoll(
    316227    const char *restrict nptr, char **restrict endptr, int base)
    317228{
    318229        bool neg = false;
    319         uintmax_t result =
     230        unsigned long long result =
    320231            internal_strtol(nptr, endptr, base, LLONG_MIN, LLONG_MAX, &neg);
    321232
    322         return (neg ? ((long long) -result) : (long long) result);
    323 }
    324 
    325 /**
    326  * Convert a string to a largest signed integer type.
    327  *
    328  * @param nptr Input string.
    329  * @param endptr Pointer to the final part of the string which
    330  *     was not used for conversion.
    331  * @param base Expected base of the string representation.
    332  * @return Result of the conversion.
    333  */
    334 intmax_t posix_strtoimax(
    335     const char *restrict nptr, char **restrict endptr, int base)
    336 {
    337         bool neg = false;
    338         uintmax_t result =
    339             internal_strtol(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX, &neg);
    340 
    341         return (neg ? ((intmax_t) -result) : (intmax_t) result);
    342 }
    343 
    344 /**
    345  * Convert a string to an unsigned long integer.
    346  *
    347  * @param nptr Input string.
    348  * @param endptr Pointer to the final part of the string which
    349  *     was not used for conversion.
    350  * @param base Expected base of the string representation.
    351  * @return Result of the conversion.
    352  */
     233        return (long long) (neg ? -result : result);
     234}
     235
    353236unsigned long posix_strtoul(
    354237    const char *restrict nptr, char **restrict endptr, int base)
    355238{
    356         uintmax_t result =
     239        unsigned long long result =
    357240            internal_strtol(nptr, endptr, base, 0, ULONG_MAX, NULL);
    358241
     
    360243}
    361244
    362 /**
    363  * Convert a string to an unsigned long long integer.
    364  *
    365  * @param nptr Input string.
    366  * @param endptr Pointer to the final part of the string which
    367  *     was not used for conversion.
    368  * @param base Expected base of the string representation.
    369  * @return Result of the conversion.
    370  */
    371245unsigned long long posix_strtoull(
    372246    const char *restrict nptr, char **restrict endptr, int base)
    373247{
    374         uintmax_t result =
    375             internal_strtol(nptr, endptr, base, 0, ULLONG_MAX, NULL);
    376 
    377         return (unsigned long long) result;
    378 }
    379 
    380 /**
    381  * Convert a string to a largest unsigned integer type.
    382  *
    383  * @param nptr Input string.
    384  * @param endptr Pointer to the final part of the string which
    385  *     was not used for conversion.
    386  * @param base Expected base of the string representation.
    387  * @return Result of the conversion.
    388  */
    389 uintmax_t posix_strtoumax(
    390     const char *restrict nptr, char **restrict endptr, int base)
    391 {
    392         uintmax_t result =
    393             internal_strtol(nptr, endptr, base, 0, UINTMAX_MAX, NULL);
    394 
    395         return result;
    396 }
     248        return internal_strtol(nptr, endptr, base, 0, ULLONG_MAX, NULL);
     249}
     250
    397251
    398252/** @}
    399253 */
     254
Note: See TracChangeset for help on using the changeset viewer.