diff options
author | unknown <monty@mysql.com> | 2005-01-15 12:28:38 +0200 |
---|---|---|
committer | unknown <monty@mysql.com> | 2005-01-15 12:28:38 +0200 |
commit | 5437a90dfafacee48603f8977d2018796c35f526 (patch) | |
tree | e3a0da70f844473e00b8fb81958bb7d0607dc880 /strings | |
parent | 7222ac501454363f7d3df59ab7feac50265336f7 (diff) | |
download | mariadb-git-5437a90dfafacee48603f8977d2018796c35f526.tar.gz |
Changed interface for my_strntod() to make it more general and more portable
BUILD/compile-solaris-sparc-purify:
Cleanup (Changes from Kent)
include/m_string.h:
New interface for my_strtod()
mysql-test/mysql-test-run.sh:
Added option --use-old-data to allow one to run a test case on an existing table
(Good for debugging)
mysql-test/r/strict.result:
Updated results
mysql-test/r/type_float.result:
More tests
mysql-test/t/strict.test:
Safety fix
mysql-test/t/type_float.test:
More tests
mysys/mf_iocache.c:
Change flush_io_cache() to my_b_flush_io_cache()
More debugging
mysys/thr_lock.c:
Added comment
sql/field.cc:
Use new my_strntod()
sql/filesort.cc:
Indentation fixes
sql/item.cc:
Use new my_strntod()
sql/item_strfunc.cc:
Use new my_strntod()
sql/item_sum.cc:
Use new my_strntod()
strings/ctype-cp932.c:
strnncollsp was missing one argument
strings/ctype-simple.c:
Use new my_strntod()
strings/ctype-ucs2.c:
Use new my_strntod()
strings/strtod.c:
Changed interface:
- Force user to supply pointer to end of string (eliminates the need for an end \0)
- More strict error checking (depend less off if INF is set), which makes this more portable
- Better handling of numbers of type 0.000000....E+...
- Return pointer to + in case of '+.'
The above should fix a that strict.test failed on Solaris-sparc.
Diffstat (limited to 'strings')
-rw-r--r-- | strings/ctype-cp932.c | 6 | ||||
-rw-r--r-- | strings/ctype-simple.c | 27 | ||||
-rw-r--r-- | strings/ctype-ucs2.c | 18 | ||||
-rw-r--r-- | strings/strtod.c | 162 |
4 files changed, 130 insertions, 83 deletions
diff --git a/strings/ctype-cp932.c b/strings/ctype-cp932.c index 218fc72ad17..e5429148970 100644 --- a/strings/ctype-cp932.c +++ b/strings/ctype-cp932.c @@ -243,8 +243,10 @@ static int my_strnncoll_cp932(CHARSET_INFO *cs __attribute__((unused)), static int my_strnncollsp_cp932(CHARSET_INFO *cs __attribute__((unused)), - const uchar *a, uint a_length, - const uchar *b, uint b_length) + const uchar *a, uint a_length, + const uchar *b, uint b_length, + my_bool diff_if_only_endspace_difference + __attribute__((unused))) { const uchar *a_end= a + a_length; const uchar *b_end= b + b_length; diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 0659cb5d387..fdfe72864b2 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -750,31 +750,10 @@ double my_strntod_8bit(CHARSET_INFO *cs __attribute__((unused)), char *str, uint length, char **end, int *err) { - char end_char; - double result; - - errno= 0; /* Safety */ - - /* - The following define is to avoid warnings from valgrind as str[length] - may not be defined (which is not fatal in real life) - */ - -#ifdef HAVE_purify if (length == INT_MAX32) -#else - if (length == INT_MAX32 || str[length] == 0) -#endif - result= my_strtod(str, end); - else - { - end_char= str[length]; - str[length]= 0; - result= my_strtod(str, end); - str[length]= end_char; /* Restore end char */ - } - *err= errno; - return result; + length= 65535; /* Should be big enough */ + *end= str + length; + return my_strtod(str, end, err); } diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index d21b340e768..7b9a7ab3020 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -925,15 +925,16 @@ bs: return (negative ? -((longlong) res) : (longlong) res); } -double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), - char *nptr, uint length, - char **endptr, int *err) + +double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), + char *nptr, uint length, + char **endptr, int *err) { char buf[256]; double res; register char *b=buf; register const uchar *s= (const uchar*) nptr; - register const uchar *end; + const uchar *end; my_wc_t wc; int cnv; @@ -950,13 +951,10 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), break; /* Can't be part of double */ *b++= (char) wc; } - *b= 0; - errno= 0; - res=my_strtod(buf, endptr); - *err= errno; - if (endptr) - *endptr=(char*) (*endptr-buf+nptr); + *endptr= b; + res= my_strtod(buf, endptr, err); + *endptr= nptr + (uint) (*endptr- buf); return res; } diff --git a/strings/strtod.c b/strings/strtod.c index bc8105b8040..92d93612dd0 100644 --- a/strings/strtod.c +++ b/strings/strtod.c @@ -2,7 +2,7 @@ An alternative implementation of "strtod()" that is both simplier, and thread-safe. - From mit-threads as bundled with MySQL 3.23 + Original code from mit-threads as bundled with MySQL 3.23 SQL:2003 specifies a number as @@ -29,6 +29,8 @@ #include "my_base.h" /* Includes errno.h */ #include "m_ctype.h" +#define MAX_DBL_EXP 308 +#define MAX_RESULT_FOR_MAX_EXP 1.79769313486232 static double scaler10[] = { 1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90 }; @@ -37,89 +39,154 @@ static double scaler1[] = { }; -double my_strtod(const char *str, char **end) +/* + Convert string to double (string doesn't have to be null terminated) + + SYNOPSIS + my_strtod() + str String to convert + end_ptr Pointer to pointer that points to end of string + Will be updated to point to end of double. + error Will contain error number in case of error (else 0) + + RETURN + value of str as double +*/ + +double my_strtod(const char *str, char **end_ptr, int *error) { double result= 0.0; - int negative, ndigits; - const char *old_str; + uint negative= 0, ndigits, dec_digits= 0, pre_zero, neg_exp= 0; + int exp= 0; + const char *old_str, *end= *end_ptr, *start_of_number; + char next_char; my_bool overflow=0; + *error= 0; + if (str >= end) + goto done; + while (my_isspace(&my_charset_latin1, *str)) - str++; + { + if (++str == end) + goto done; + } + start_of_number= str; if ((negative= (*str == '-')) || *str=='+') - str++; + { + if (++str == end) + goto done; /* Could be changed to error */ + } + + /* Skip pre-zero for easier calculation of overflows */ + while (*str == '0') + { + if (++str == end) + goto done; + start_of_number= 0; /* Found digit */ + } old_str= str; - while (my_isdigit (&my_charset_latin1, *str)) + while ((next_char= *str) >= '0' && next_char <= '9') { - result= result*10.0 + (*str - '0'); - str++; + result= result*10.0 + (next_char - '0'); + if (++str == end) + { + next_char= 0; /* Found end of string */ + break; + } + start_of_number= 0; /* Found digit */ } - ndigits= str-old_str; + ndigits= (uint) (str-old_str); - if (*str == '.') + pre_zero= 0; + if (next_char == '.' && str < end-1) { - double p10=10; - str++; - old_str= str; - while (my_isdigit (&my_charset_latin1, *str)) + double p10= 10; + old_str= ++str; + while (my_isdigit(&my_charset_latin1, (next_char= *str))) { - result+= (*str++ - '0')/p10; - p10*=10; + result+= (next_char - '0')/p10; + if (!result) + pre_zero++; + else + p10*= 10; + if (++str == end) + { + next_char= 0; + break; + } } - ndigits+= str-old_str; - if (!ndigits) str--; + /* If we found just '+.' or '.' then point at first character */ + if (!(dec_digits= (uint) (str-old_str)) && start_of_number) + str= start_of_number; /* Point at '+' or '.' */ } - if (ndigits && (*str=='e' || *str=='E')) + if ((next_char == 'e' || next_char == 'E') && + dec_digits + ndigits != 0 && str < end-1) { - int exp= 0; - int neg= 0; const char *old_str= str++; - if ((neg= (*str == '-')) || *str == '+') + if ((neg_exp= (*str == '-')) || *str == '+') str++; - if (!my_isdigit (&my_charset_latin1, *str)) + if (str == end || !my_isdigit(&my_charset_latin1, *str)) str= old_str; else { - double scaler= 1.0; - while (my_isdigit (&my_charset_latin1, *str)) + do { - if (exp < 9999) /* protection against exp overflow */ + if (exp < 9999) /* protec against exp overfl. */ exp= exp*10 + *str - '0'; str++; - } - if (exp >= 1000) + } while (str < end && my_isdigit(&my_charset_latin1, *str)); + } + } + if ((exp= neg_exp ? exp + pre_zero : exp - pre_zero)) + { + double scaler; + if (exp < 0) + { + exp= -exp; + neg_exp= 1; /* neg_exp was 0 before */ + } + if (exp + ndigits >= MAX_DBL_EXP + 1 && result) + { + /* + This is not 100 % as we actually will give an owerflow for + 17E307 but not for 1.7E308 but lets cut some corners to make life + simpler + */ + if (exp + ndigits > MAX_DBL_EXP + 1 || + result >= MAX_RESULT_FOR_MAX_EXP) { - if (neg) - result= 0.0; - else + if (neg_exp) + result= 0.0; + else overflow= 1; goto done; } - while (exp >= 100) - { - scaler*= 1.0e100; - exp-= 100; - } - scaler*= scaler10[exp/10]*scaler1[exp%10]; - if (neg) - result/= scaler; - else - result*= scaler; } + scaler= 1.0; + while (exp >= 100) + { + scaler*= 1.0e100; + exp-= 100; + } + scaler*= scaler10[exp/10]*scaler1[exp%10]; + if (neg_exp) + result/= scaler; + else + result*= scaler; } done: - if (end) - *end = (char *)str; + *end_ptr= (char*) str; /* end of number */ if (overflow || isinf(result)) { result= DBL_MAX; - errno= EOVERFLOW; + *error= EOVERFLOW; } return negative ? -result : result; @@ -127,6 +194,7 @@ done: double my_atof(const char *nptr) { - return (my_strtod(nptr, 0)); + int error; + const char *end= nptr+65535; /* Should be enough */ + return (my_strtod(nptr, (char**) &end, &error)); } - |