diff options
Diffstat (limited to 'mpf')
-rw-r--r-- | mpf/set_str.c | 43 |
1 files changed, 38 insertions, 5 deletions
diff --git a/mpf/set_str.c b/mpf/set_str.c index cb078de60..7e2becfd4 100644 --- a/mpf/set_str.c +++ b/mpf/set_str.c @@ -22,10 +22,16 @@ along with the GNU MP Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "config.h" + #include <stdlib.h> #include <string.h> #include <ctype.h> +#if HAVE_LOCALE_H +#include <locale.h> /* for localeconv */ +#endif + #include "gmp.h" #include "gmp-impl.h" #include "longlong.h" @@ -49,6 +55,21 @@ digit_value_in_base (int c, int base) return -1; } +#if HAVE_LOCALECONV +/* Avoid memcmp for the usual case that point is one character. Don't + bother with str+1,point+1,pointlen-1 since those offsets would add to the + code size. */ +#define POINTCMP_FAST(c, str) \ + ((c) == point0 \ + && (pointlen == 1 || memcmp (str, point, pointlen) == 0)) +#define POINTCMP_SMALL(c, str) (memcmp (str, point, pointlen) == 0) +#define POINTLEN (pointlen) +#else +#define POINTCMP_FAST(c, str) ((c) == '.') +#define POINTCMP_SMALL(c, str) ((c) == '.') +#define POINTLEN 1 +#endif + int mpf_set_str (mpf_ptr x, const char *str, int base) { @@ -61,6 +82,11 @@ mpf_set_str (mpf_ptr x, const char *str, int base) char *dotpos = 0; int expflag; int decimal_exponent_flag; +#if HAVE_LOCALECONV + const char *point = localeconv()->decimal_point; + size_t pointlen = strlen (point); + int point0 = point[0]; +#endif TMP_DECL (marker); TMP_MARK (marker); @@ -81,9 +107,14 @@ mpf_set_str (mpf_ptr x, const char *str, int base) decimal_exponent_flag = base < 0; base = ABS (base); - if (digit_value_in_base (c, base == 0 ? 10 : base) < 0 - && (c != '.' || digit_value_in_base (str[1], base == 0 ? 10 : base) < 0)) - return -1; /* error if no digits */ + /* require at least one digit, possibly after an initial decimal point */ + if (digit_value_in_base (c, base == 0 ? 10 : base) < 0) + { + if (! POINTCMP_SMALL (c, str)) + return -1; + if (digit_value_in_base (str[POINTLEN], base == 0 ? 10 : base) < 0) + return -1; + } /* If BASE is 0, try to find out the base by looking at the initial characters. */ @@ -127,14 +158,16 @@ mpf_set_str (mpf_ptr x, const char *str, int base) { int dig; - if (c == '.') - { + if (POINTCMP_FAST (c, str)) + { if (dotpos != 0) { TMP_FREE (marker); return -1; } dotpos = s; + str += POINTLEN - 1; + i += POINTLEN - 1; } else { |