| 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); |