From 655b56e39033df5ec41b1f1fd0065b445e8acae3 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 5 Jul 2016 23:09:12 -0400 Subject: [PATCH] Do not automatically convert floats to ints --- runtime.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/runtime.c b/runtime.c index 6c07901c..327bd60d 100644 --- a/runtime.c +++ b/runtime.c @@ -13,6 +13,8 @@ #include "cyclone/types.h" #include "cyclone/runtime.h" #include "cyclone/ck_ht_hash.h" +#include +#include //#include // TODO: only used for debugging! //int JAE_DEBUG = 0; @@ -1349,21 +1351,78 @@ object Cyc_string2number2_(void *data, object cont, int argc, object str, ...) Cyc_string2number_(data, cont, str); } +typedef enum { + STR2INT_SUCCESS, + STR2INT_OVERFLOW, + STR2INT_UNDERFLOW, + STR2INT_INCONVERTIBLE +} str2int_errno; + +/* +Convert string s to int out. + +@param[out] out The converted int. Cannot be NULL. + +@param[in] s Input string to be converted. + + The format is the same as strtol, + except that the following are inconvertible: + + - empty string + - leading whitespace + - any trailing characters that are not part of the number + + Cannot be NULL. + +@param[in] base Base to interpret string in. Same range as strtol (2 to 36). + +@return Indicates if the operation succeeded, or why it failed. +*/ +str2int_errno str2int(int *out, char *s, int base) +{ + char *end; + if (s[0] == '\0' || isspace((unsigned char) s[0])) + return STR2INT_INCONVERTIBLE; + errno = 0; + long l = strtol(s, &end, base); + /* Both checks are needed because INT_MAX == LONG_MAX is possible. */ + if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) + return STR2INT_OVERFLOW; + if (l < INT_MIN || (errno == ERANGE && l == LONG_MIN)) + return STR2INT_UNDERFLOW; + if (*end != '\0') + return STR2INT_INCONVERTIBLE; + *out = l; + return STR2INT_SUCCESS; +} + +int str2double(double *out, char *s) +{ + *out = strtold(s, NULL); + // TODO: error checking, EG: HUGE_VALL + return 0; +} + object Cyc_string2number_(void *data, object cont, object str) { - int result; + int result, rv; + long l; double n; + char *s, *end; Cyc_check_obj(data, string_tag, str); Cyc_check_str(data, str); if (type_of(str) == string_tag && ((string_type *) str)->str) { - n = atof(((string_type *) str)->str); + s = ((string_type *) str)->str; - if (ceilf(n) == n) { - result = (int)n; + rv = str2int(&result, s, 10); + if (rv == STR2INT_SUCCESS) { return_closcall1(data, cont, obj_int2obj(result)); } else { - make_double(result, n); - return_closcall1(data, cont, &result); + str2double(&n, s); + { + make_double(result, n); + return_closcall1(data, cont, &result); + } } } else { // TODO: not good enough because we do pointer comparisons to #f