| 959 } |
960 } |
| 960 size_t start = 0; |
961 size_t start = 0; |
| 961 |
962 |
| 962 // if base is 2 or 16, some leading stuff may appear |
963 // if base is 2 or 16, some leading stuff may appear |
| 963 if (base == 2) { |
964 if (base == 2) { |
| 964 if (str.ptr[0] == 'b' || str.ptr[0] == 'B') { |
965 if ((str.ptr[0] | 32) == 'b') { |
| 965 start = 1; |
966 start = 1; |
| 966 } else if (str.ptr[0] == '0' && str.length > 1) { |
967 } else if (str.ptr[0] == '0' && str.length > 1) { |
| 967 if (str.ptr[1] == 'b' || str.ptr[1] == 'B') { |
968 if ((str.ptr[1] | 32) == 'b') { |
| 968 start = 2; |
969 start = 2; |
| 969 } |
970 } |
| 970 } |
971 } |
| 971 } else if (base == 16) { |
972 } else if (base == 16) { |
| 972 if (str.ptr[0] == 'x' || str.ptr[0] == 'X' || str.ptr[0] == '#') { |
973 if ((str.ptr[0] | 32) == 'x' || str.ptr[0] == '#') { |
| 973 start = 1; |
974 start = 1; |
| 974 } else if (str.ptr[0] == '0' && str.length > 1) { |
975 } else if (str.ptr[0] == '0' && str.length > 1) { |
| 975 if (str.ptr[1] == 'x' || str.ptr[1] == 'X') { |
976 if ((str.ptr[1] | 32) == 'x') { |
| 976 start = 2; |
977 start = 2; |
| 977 } |
978 } |
| 978 } |
979 } |
| 979 } |
980 } |
| 980 |
981 |
| 1041 #error "unsupported size_t size" |
1042 #error "unsupported size_t size" |
| 1042 #endif |
1043 #endif |
| 1043 } |
1044 } |
| 1044 |
1045 |
| 1045 int cx_strtof_lc(cxstring str, float *output, char decsep, const char *groupsep) { |
1046 int cx_strtof_lc(cxstring str, float *output, char decsep, const char *groupsep) { |
| 1046 // TODO: replace temporary implementation |
1047 // use string to double and add a range check |
| 1047 (void) groupsep; // unused in temp impl |
1048 double d; |
| 1048 (void) decsep; // unused in temp impl |
1049 int ret = cx_strtod_lc(str, &d, decsep, groupsep); |
| 1049 char *s = malloc(str.length + 1); |
1050 if (ret != 0) return ret; |
| 1050 memcpy(s, str.ptr, str.length); |
1051 // note: FLT_MIN is the smallest POSITIVE number that can be represented |
| 1051 s[str.length] = '\0'; |
1052 double test = d < 0 ? -d : d; |
| 1052 char *e; |
1053 if (test < FLT_MIN || test > FLT_MAX) { |
| 1053 *output = strtof(s, &e); |
1054 errno = ERANGE; |
| 1054 int r = !(e && *e == '\0'); |
1055 return -1; |
| 1055 free(s); |
1056 } |
| 1056 return r; |
1057 *output = (float) d; |
| |
1058 return 0; |
| 1057 } |
1059 } |
| 1058 |
1060 |
| 1059 int cx_strtod_lc(cxstring str, double *output, char decsep, const char *groupsep) { |
1061 int cx_strtod_lc(cxstring str, double *output, char decsep, const char *groupsep) { |
| 1060 // TODO: replace temporary implementation |
1062 // TODO: overflow check |
| 1061 (void) groupsep; // unused in temp impl |
1063 // TODO: increase precision |
| 1062 (void) decsep; // unused in temp impl |
1064 |
| 1063 char *s = malloc(str.length + 1); |
1065 // trim and check |
| 1064 memcpy(s, str.ptr, str.length); |
1066 str = cx_strtrim(str); |
| 1065 s[str.length] = '\0'; |
1067 if (str.length == 0) { |
| 1066 char *e; |
1068 errno = EINVAL; |
| 1067 *output = strtod(s, &e); |
1069 return -1; |
| 1068 int r = !(e && *e == '\0'); |
1070 } |
| 1069 free(s); |
1071 |
| 1070 return r; |
1072 double result = 0.; |
| 1071 } |
1073 int sign = 1; |
| |
1074 |
| |
1075 // check if there is a sign |
| |
1076 if (str.ptr[0] == '-') { |
| |
1077 sign = -1; |
| |
1078 str.ptr++; |
| |
1079 str.length--; |
| |
1080 } else if (str.ptr[0] == '+') { |
| |
1081 str.ptr++; |
| |
1082 str.length--; |
| |
1083 } |
| |
1084 |
| |
1085 // there must be at least one char to parse |
| |
1086 if (str.length == 0) { |
| |
1087 errno = EINVAL; |
| |
1088 return -1; |
| |
1089 } |
| |
1090 |
| |
1091 // parse all digits until we find the decsep |
| |
1092 size_t pos = 0; |
| |
1093 do { |
| |
1094 if (isdigit(str.ptr[pos])) { |
| |
1095 result = result * 10 + (str.ptr[pos] - '0'); |
| |
1096 } else if (strchr(groupsep, str.ptr[pos]) == NULL) { |
| |
1097 break; |
| |
1098 } |
| |
1099 } while (++pos < str.length); |
| |
1100 |
| |
1101 // already done? |
| |
1102 if (pos == str.length) { |
| |
1103 *output = result * sign; |
| |
1104 return 0; |
| |
1105 } |
| |
1106 |
| |
1107 // is the next char the decsep? |
| |
1108 if (str.ptr[pos] == decsep) { |
| |
1109 pos++; |
| |
1110 // it may end with the decsep, if it did not start with it |
| |
1111 if (pos == str.length) { |
| |
1112 if (str.length == 1) { |
| |
1113 errno = EINVAL; |
| |
1114 return -1; |
| |
1115 } else { |
| |
1116 *output = result * sign; |
| |
1117 return 0; |
| |
1118 } |
| |
1119 } |
| |
1120 // parse everything until exponent or end |
| |
1121 double factor = 1.; |
| |
1122 do { |
| |
1123 if (isdigit(str.ptr[pos])) { |
| |
1124 factor *= 0.1; |
| |
1125 result = result + factor * (str.ptr[pos] - '0'); |
| |
1126 } else if (strchr(groupsep, str.ptr[pos]) == NULL) { |
| |
1127 break; |
| |
1128 } |
| |
1129 } while (++pos < str.length); |
| |
1130 } |
| |
1131 |
| |
1132 // no exponent? |
| |
1133 if (pos == str.length) { |
| |
1134 *output = result * sign; |
| |
1135 return 0; |
| |
1136 } |
| |
1137 |
| |
1138 // now the next separator MUST be the exponent separator |
| |
1139 // and at least one char must follow |
| |
1140 if ((str.ptr[pos] | 32) != 'e' || str.length <= pos + 1) { |
| |
1141 errno = EINVAL; |
| |
1142 return -1; |
| |
1143 } |
| |
1144 pos++; |
| |
1145 |
| |
1146 // check if we have a sign for the exponent |
| |
1147 double factor = 10.; |
| |
1148 if (str.ptr[pos] == '-') { |
| |
1149 factor = .1; |
| |
1150 pos++; |
| |
1151 } else if (str.ptr[pos] == '+') { |
| |
1152 pos++; |
| |
1153 } |
| |
1154 |
| |
1155 // at least one digit must follow |
| |
1156 if (pos == str.length) { |
| |
1157 errno = EINVAL; |
| |
1158 return -1; |
| |
1159 } |
| |
1160 |
| |
1161 // parse the exponent |
| |
1162 unsigned int exp = 0; |
| |
1163 do { |
| |
1164 if (isdigit(str.ptr[pos])) { |
| |
1165 exp = 10 * exp + (str.ptr[pos] - '0'); |
| |
1166 } else if (strchr(groupsep, str.ptr[pos]) == NULL) { |
| |
1167 errno = EINVAL; |
| |
1168 return -1; |
| |
1169 } |
| |
1170 } while (++pos < str.length); |
| |
1171 |
| |
1172 // apply the exponent by fast exponentiation |
| |
1173 do { |
| |
1174 if (exp & 1) { |
| |
1175 result *= factor; |
| |
1176 } |
| |
1177 factor *= factor; |
| |
1178 } while ((exp >>= 1) > 0); |
| |
1179 |
| |
1180 // store the result and exit |
| |
1181 *output = result * sign; |
| |
1182 return 0; |
| |
1183 } |