Changeset 5ee9692 in mainline for uspace/lib/posix/stdlib/strtold.c


Ignore:
Timestamp:
2011-06-19T13:23:54Z (14 years ago)
Author:
Jiří Zárevúcky <zarevucky.jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
918e236f
Parents:
63fc519
Message:

strtold(): fix problem with leading zeros and exponent overflow

File:
1 edited

Legend:

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

    r63fc519 r5ee9692  
    5353#endif
    5454
    55 // TODO: documentation
     55// TODO: clean up, documentation
    5656
    5757// FIXME: ensure it builds and works on all platforms
     
    238238        /* digits before decimal point */
    239239        while (isdigit(str[i])) {
    240                 if (parsed_digits < PARSE_DECIMAL_DIGS) {
     240                if (parsed_digits == 0 && str[i] == '0') {
     241                        /* Nothing, just skip leading zeros. */
     242                } else if (parsed_digits < PARSE_DECIMAL_DIGS) {
    241243                        significand *= DEC_BASE;
    242244                        significand += str[i] - '0';
     
    254256                /* digits after decimal point */
    255257                while (isdigit(str[i])) {
    256                         if (parsed_digits < PARSE_DECIMAL_DIGS) {
     258                        if (parsed_digits == 0 && str[i] == '0') {
     259                                /* Skip leading zeros and decrement exponent. */
     260                                exponent--;
     261                        } else if (parsed_digits < PARSE_DECIMAL_DIGS) {
    257262                                significand *= DEC_BASE;
    258263                                significand += str[i] - '0';
     
    282287                }
    283288               
    284                 while (isdigit(str[i])) {
     289                while (isdigit(str[i]) && exp < 65536) {
    285290                        exp *= DEC_BASE;
    286291                        exp += str[i] - '0';
     
    306311}
    307312
    308 static inline int hex_value(char ch) {
     313static inline int hex_value(char ch)
     314{
    309315        if (ch <= '9') {
    310316                return ch - '0';
     
    312318                return 10 + tolower(ch) - 'a';
    313319        }
     320}
     321
     322/**
     323 * @param val Integer value.
     324 * @return How many leading zero bits there are. (Maximum is 3)
     325 */
     326static inline int leading_zeros(uint64_t val)
     327{
     328        for (int i = 3; i > 0; --i) {
     329                if ((val >> (64 - i)) == 0) {
     330                        return i;
     331                }
     332        }
     333       
     334        return 0;
    314335}
    315336
     
    345366        /* digits before decimal point */
    346367        while (posix_isxdigit(str[i])) {
    347                 if (parsed_digits < PARSE_HEX_DIGS) {
     368                if (parsed_digits == 0 && str[i] == '0') {
     369                        /* Nothing, just skip leading zeros. */
     370                } else if (parsed_digits < PARSE_HEX_DIGS) {
    348371                        significand *= HEX_BASE;
    349372                        significand += hex_value(str[i]);
    350373                        parsed_digits++;
     374                } else if (parsed_digits == PARSE_HEX_DIGS) {
     375                        /* The first digit may have had leading zeros,
     376                         * so we need to parse one more digit and shift
     377                         * the value accordingly.
     378                         */
     379                       
     380                        int zeros = leading_zeros(significand);
     381                        significand = (significand << zeros) |
     382                            (hex_value(str[i]) >> (4 - zeros));
     383                       
     384                        exponent += (4 - zeros);
     385                        parsed_digits++;
    351386                } else {
    352387                        exponent += 4;
     
    361396                /* digits after decimal point */
    362397                while (posix_isxdigit(str[i])) {
    363                         if (parsed_digits < PARSE_HEX_DIGS) {
     398                        if (parsed_digits == 0 && str[i] == '0') {
     399                                /* Skip leading zeros and decrement exponent. */
     400                                exponent -= 4;
     401                        } else if (parsed_digits < PARSE_HEX_DIGS) {
    364402                                significand *= HEX_BASE;
    365403                                significand += hex_value(str[i]);
    366404                                exponent -= 4;
     405                                parsed_digits++;
     406                        } else if (parsed_digits == PARSE_HEX_DIGS) {
     407                                /* The first digit may have had leading zeros,
     408                                 * so we need to parse one more digit and shift
     409                                 * the value accordingly.
     410                                 */
     411                               
     412                                int zeros = leading_zeros(significand);
     413                                significand = (significand << zeros) |
     414                                    (hex_value(str[i]) >> (4 - zeros));
     415                               
     416                                exponent -= zeros;
    367417                                parsed_digits++;
    368418                        } else {
     
    389439                }
    390440               
    391                 while (isdigit(str[i])) {
     441                while (isdigit(str[i]) && exp < 65536) {
    392442                        exp *= DEC_BASE;
    393443                        exp += str[i] - '0';
Note: See TracChangeset for help on using the changeset viewer.