23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 * POSSIBILITY OF SUCH DAMAGE. |
26 * POSSIBILITY OF SUCH DAMAGE. |
27 */ |
27 */ |
28 #define CX_STR_IMPLEMENTATION |
|
29 #include "cx/string.h" |
28 #include "cx/string.h" |
30 |
29 |
31 #include <string.h> |
30 #include <string.h> |
32 #include <stdarg.h> |
31 #include <stdarg.h> |
33 #include <assert.h> |
32 #include <assert.h> |
830 return -1; \ |
829 return -1; \ |
831 } \ |
830 } \ |
832 *output = (rtype) result; \ |
831 *output = (rtype) result; \ |
833 return 0 |
832 return 0 |
834 |
833 |
835 int cx_strtos_lc(cxstring str, short *output, int base, const char *groupsep) { |
834 int cx_strtos_lc_(cxstring str, short *output, int base, const char *groupsep) { |
836 cx_strtoX_signed_impl(short, SHRT_MIN, SHRT_MAX); |
835 cx_strtoX_signed_impl(short, SHRT_MIN, SHRT_MAX); |
837 } |
836 } |
838 |
837 |
839 int cx_strtoi_lc(cxstring str, int *output, int base, const char *groupsep) { |
838 int cx_strtoi_lc_(cxstring str, int *output, int base, const char *groupsep) { |
840 cx_strtoX_signed_impl(int, INT_MIN, INT_MAX); |
839 cx_strtoX_signed_impl(int, INT_MIN, INT_MAX); |
841 } |
840 } |
842 |
841 |
843 int cx_strtol_lc(cxstring str, long *output, int base, const char *groupsep) { |
842 int cx_strtol_lc_(cxstring str, long *output, int base, const char *groupsep) { |
844 cx_strtoX_signed_impl(long, LONG_MIN, LONG_MAX); |
843 cx_strtoX_signed_impl(long, LONG_MIN, LONG_MAX); |
845 } |
844 } |
846 |
845 |
847 int cx_strtoll_lc(cxstring str, long long *output, int base, const char *groupsep) { |
846 int cx_strtoll_lc_(cxstring str, long long *output, int base, const char *groupsep) { |
848 // strategy: parse as unsigned, check range, negate if required |
847 // strategy: parse as unsigned, check range, negate if required |
849 bool neg = false; |
848 bool neg = false; |
850 size_t start_unsigned = 0; |
849 size_t start_unsigned = 0; |
851 |
850 |
852 // trim already, to search for a sign character |
851 // trim already, to search for a sign character |
888 *output = (long long) v; |
887 *output = (long long) v; |
889 return 0; |
888 return 0; |
890 } |
889 } |
891 } |
890 } |
892 |
891 |
893 int cx_strtoi8_lc(cxstring str, int8_t *output, int base, const char *groupsep) { |
892 int cx_strtoi8_lc_(cxstring str, int8_t *output, int base, const char *groupsep) { |
894 cx_strtoX_signed_impl(int8_t, INT8_MIN, INT8_MAX); |
893 cx_strtoX_signed_impl(int8_t, INT8_MIN, INT8_MAX); |
895 } |
894 } |
896 |
895 |
897 int cx_strtoi16_lc(cxstring str, int16_t *output, int base, const char *groupsep) { |
896 int cx_strtoi16_lc_(cxstring str, int16_t *output, int base, const char *groupsep) { |
898 cx_strtoX_signed_impl(int16_t, INT16_MIN, INT16_MAX); |
897 cx_strtoX_signed_impl(int16_t, INT16_MIN, INT16_MAX); |
899 } |
898 } |
900 |
899 |
901 int cx_strtoi32_lc(cxstring str, int32_t *output, int base, const char *groupsep) { |
900 int cx_strtoi32_lc_(cxstring str, int32_t *output, int base, const char *groupsep) { |
902 cx_strtoX_signed_impl(int32_t, INT32_MIN, INT32_MAX); |
901 cx_strtoX_signed_impl(int32_t, INT32_MIN, INT32_MAX); |
903 } |
902 } |
904 |
903 |
905 int cx_strtoi64_lc(cxstring str, int64_t *output, int base, const char *groupsep) { |
904 int cx_strtoi64_lc_(cxstring str, int64_t *output, int base, const char *groupsep) { |
906 assert(sizeof(long long) == sizeof(int64_t)); // should be true on all platforms |
905 assert(sizeof(long long) == sizeof(int64_t)); // should be true on all platforms |
907 return cx_strtoll_lc(str, (long long*) output, base, groupsep); |
906 return cx_strtoll_lc(str, (long long*) output, base, groupsep); |
908 } |
907 } |
909 |
908 |
910 int cx_strtoz_lc(cxstring str, ssize_t *output, int base, const char *groupsep) { |
909 int cx_strtoz_lc_(cxstring str, ssize_t *output, int base, const char *groupsep) { |
911 #if SSIZE_MAX == INT32_MAX |
910 #if SSIZE_MAX == INT32_MAX |
912 return cx_strtoi32_lc(str, (int32_t*) output, base, groupsep); |
911 return cx_strtoi32_lc_(str, (int32_t*) output, base, groupsep); |
913 #elif SSIZE_MAX == INT64_MAX |
912 #elif SSIZE_MAX == INT64_MAX |
914 return cx_strtoll_lc(str, (long long*) output, base, groupsep); |
913 return cx_strtoll_lc_(str, (long long*) output, base, groupsep); |
915 #else |
914 #else |
916 #error "unsupported ssize_t size" |
915 #error "unsupported ssize_t size" |
917 #endif |
916 #endif |
918 } |
917 } |
919 |
918 |
927 return -1; \ |
926 return -1; \ |
928 } \ |
927 } \ |
929 *output = (rtype) result; \ |
928 *output = (rtype) result; \ |
930 return 0 |
929 return 0 |
931 |
930 |
932 int cx_strtous_lc(cxstring str, unsigned short *output, int base, const char *groupsep) { |
931 int cx_strtous_lc_(cxstring str, unsigned short *output, int base, const char *groupsep) { |
933 cx_strtoX_unsigned_impl(unsigned short, USHRT_MAX); |
932 cx_strtoX_unsigned_impl(unsigned short, USHRT_MAX); |
934 } |
933 } |
935 |
934 |
936 int cx_strtou_lc(cxstring str, unsigned int *output, int base, const char *groupsep) { |
935 int cx_strtou_lc_(cxstring str, unsigned int *output, int base, const char *groupsep) { |
937 cx_strtoX_unsigned_impl(unsigned int, UINT_MAX); |
936 cx_strtoX_unsigned_impl(unsigned int, UINT_MAX); |
938 } |
937 } |
939 |
938 |
940 int cx_strtoul_lc(cxstring str, unsigned long *output, int base, const char *groupsep) { |
939 int cx_strtoul_lc_(cxstring str, unsigned long *output, int base, const char *groupsep) { |
941 cx_strtoX_unsigned_impl(unsigned long, ULONG_MAX); |
940 cx_strtoX_unsigned_impl(unsigned long, ULONG_MAX); |
942 } |
941 } |
943 |
942 |
944 int cx_strtoull_lc(cxstring str, unsigned long long *output, int base, const char *groupsep) { |
943 int cx_strtoull_lc_(cxstring str, unsigned long long *output, int base, const char *groupsep) { |
945 // some sanity checks |
944 // some sanity checks |
946 str = cx_strtrim(str); |
945 str = cx_strtrim(str); |
947 if (str.length == 0) { |
946 if (str.length == 0) { |
948 errno = EINVAL; |
947 errno = EINVAL; |
949 return -1; |
948 return -1; |
1019 |
1018 |
1020 *output = result; |
1019 *output = result; |
1021 return 0; |
1020 return 0; |
1022 } |
1021 } |
1023 |
1022 |
1024 int cx_strtou8_lc(cxstring str, uint8_t *output, int base, const char *groupsep) { |
1023 int cx_strtou8_lc_(cxstring str, uint8_t *output, int base, const char *groupsep) { |
1025 cx_strtoX_unsigned_impl(uint8_t, UINT8_MAX); |
1024 cx_strtoX_unsigned_impl(uint8_t, UINT8_MAX); |
1026 } |
1025 } |
1027 |
1026 |
1028 int cx_strtou16_lc(cxstring str, uint16_t *output, int base, const char *groupsep) { |
1027 int cx_strtou16_lc_(cxstring str, uint16_t *output, int base, const char *groupsep) { |
1029 cx_strtoX_unsigned_impl(uint16_t, UINT16_MAX); |
1028 cx_strtoX_unsigned_impl(uint16_t, UINT16_MAX); |
1030 } |
1029 } |
1031 |
1030 |
1032 int cx_strtou32_lc(cxstring str, uint32_t *output, int base, const char *groupsep) { |
1031 int cx_strtou32_lc_(cxstring str, uint32_t *output, int base, const char *groupsep) { |
1033 cx_strtoX_unsigned_impl(uint32_t, UINT32_MAX); |
1032 cx_strtoX_unsigned_impl(uint32_t, UINT32_MAX); |
1034 } |
1033 } |
1035 |
1034 |
1036 int cx_strtou64_lc(cxstring str, uint64_t *output, int base, const char *groupsep) { |
1035 int cx_strtou64_lc_(cxstring str, uint64_t *output, int base, const char *groupsep) { |
1037 assert(sizeof(unsigned long long) == sizeof(uint64_t)); // should be true on all platforms |
1036 assert(sizeof(unsigned long long) == sizeof(uint64_t)); // should be true on all platforms |
1038 return cx_strtoull_lc(str, (unsigned long long*) output, base, groupsep); |
1037 return cx_strtoull_lc(str, (unsigned long long*) output, base, groupsep); |
1039 } |
1038 } |
1040 |
1039 |
1041 int cx_strtouz_lc(cxstring str, size_t *output, int base, const char *groupsep) { |
1040 int cx_strtouz_lc_(cxstring str, size_t *output, int base, const char *groupsep) { |
1042 #if SIZE_MAX == UINT32_MAX |
1041 #if SIZE_MAX == UINT32_MAX |
1043 return cx_strtou32_lc(str, (uint32_t*) output, base, groupsep); |
1042 return cx_strtou32_lc_(str, (uint32_t*) output, base, groupsep); |
1044 #elif SIZE_MAX == UINT64_MAX |
1043 #elif SIZE_MAX == UINT64_MAX |
1045 return cx_strtoull_lc(str, (unsigned long long *) output, base, groupsep); |
1044 return cx_strtoull_lc_(str, (unsigned long long *) output, base, groupsep); |
1046 #else |
1045 #else |
1047 #error "unsupported size_t size" |
1046 #error "unsupported size_t size" |
1048 #endif |
1047 #endif |
1049 } |
1048 } |
1050 |
1049 |
1051 int cx_strtof_lc(cxstring str, float *output, char decsep, const char *groupsep) { |
1050 int cx_strtof_lc_(cxstring str, float *output, char decsep, const char *groupsep) { |
1052 // use string to double and add a range check |
1051 // use string to double and add a range check |
1053 double d; |
1052 double d; |
1054 int ret = cx_strtod_lc(str, &d, decsep, groupsep); |
1053 int ret = cx_strtod_lc_(str, &d, decsep, groupsep); |
1055 if (ret != 0) return ret; |
1054 if (ret != 0) return ret; |
1056 // note: FLT_MIN is the smallest POSITIVE number that can be represented |
1055 // note: FLT_MIN is the smallest POSITIVE number that can be represented |
1057 double test = d < 0 ? -d : d; |
1056 double test = d < 0 ? -d : d; |
1058 if (test < FLT_MIN || test > FLT_MAX) { |
1057 if (test < FLT_MIN || test > FLT_MAX) { |
1059 errno = ERANGE; |
1058 errno = ERANGE; |
1066 static bool str_isdigit(char c) { |
1065 static bool str_isdigit(char c) { |
1067 // TODO: remove once UCX has public API for this |
1066 // TODO: remove once UCX has public API for this |
1068 return c >= '0' && c <= '9'; |
1067 return c >= '0' && c <= '9'; |
1069 } |
1068 } |
1070 |
1069 |
1071 int cx_strtod_lc(cxstring str, double *output, char decsep, const char *groupsep) { |
1070 int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupsep) { |
1072 // TODO: overflow check |
1071 // TODO: overflow check |
1073 // TODO: increase precision |
1072 // TODO: increase precision |
1074 |
1073 |
1075 // trim and check |
1074 // trim and check |
1076 str = cx_strtrim(str); |
1075 str = cx_strtrim(str); |