837 int cx_strtol_lc(cxstring str, long *output, int base, const char *groupsep) { |
837 int cx_strtol_lc(cxstring str, long *output, int base, const char *groupsep) { |
838 cx_strtoX_signed_impl(long, LONG_MIN, LONG_MAX); |
838 cx_strtoX_signed_impl(long, LONG_MIN, LONG_MAX); |
839 } |
839 } |
840 |
840 |
841 int cx_strtoll_lc(cxstring str, long long *output, int base, const char *groupsep) { |
841 int cx_strtoll_lc(cxstring str, long long *output, int base, const char *groupsep) { |
842 // TODO: replace temporary implementation |
842 // strategy: parse as unsigned, check range, negate if required |
843 (void) groupsep; // unused in temp impl |
843 bool neg = false; |
844 char *s = malloc(str.length + 1); |
844 size_t start_unsigned = 0; |
845 memcpy(s, str.ptr, str.length); |
845 |
846 s[str.length] = '\0'; |
846 // trim already, to search for a sign character |
847 char *e; |
847 str = cx_strtrim(str); |
848 errno = 0; |
848 if (str.length == 0) { |
849 *output = strtoll(s, &e, base); |
849 errno = EINVAL; |
850 int r = errno || !(e && *e == '\0'); |
850 return -1; |
851 free(s); |
851 } |
852 return r; |
852 |
|
853 // test if we have a negative sign character |
|
854 if (str.ptr[start_unsigned] == '-') { |
|
855 neg = true; |
|
856 start_unsigned++; |
|
857 // must not be followed by positive sign character |
|
858 if (str.length == 1 || str.ptr[start_unsigned] == '+') { |
|
859 errno = EINVAL; |
|
860 return -1; |
|
861 } |
|
862 } |
|
863 |
|
864 // now parse the number with strtoull |
|
865 unsigned long long v; |
|
866 cxstring ustr = start_unsigned == 0 ? str |
|
867 : cx_strn(str.ptr + start_unsigned, str.length - start_unsigned); |
|
868 int ret = cx_strtoull_lc(ustr, &v, base, groupsep); |
|
869 if (ret != 0) return ret; |
|
870 if (neg) { |
|
871 if (v - 1 > LLONG_MAX) { |
|
872 errno = ERANGE; |
|
873 return -1; |
|
874 } |
|
875 *output = -(long long) v; |
|
876 return 0; |
|
877 } else { |
|
878 if (v > LLONG_MAX) { |
|
879 errno = ERANGE; |
|
880 return -1; |
|
881 } |
|
882 *output = (long long) v; |
|
883 return 0; |
|
884 } |
853 } |
885 } |
854 |
886 |
855 int cx_strtoi8_lc(cxstring str, int8_t *output, int base, const char *groupsep) { |
887 int cx_strtoi8_lc(cxstring str, int8_t *output, int base, const char *groupsep) { |
856 cx_strtoX_signed_impl(int8_t, INT8_MIN, INT8_MAX); |
888 cx_strtoX_signed_impl(int8_t, INT8_MIN, INT8_MAX); |
857 } |
889 } |
902 int cx_strtoul_lc(cxstring str, unsigned long *output, int base, const char *groupsep) { |
934 int cx_strtoul_lc(cxstring str, unsigned long *output, int base, const char *groupsep) { |
903 cx_strtoX_unsigned_impl(unsigned long, ULONG_MAX); |
935 cx_strtoX_unsigned_impl(unsigned long, ULONG_MAX); |
904 } |
936 } |
905 |
937 |
906 int cx_strtoull_lc(cxstring str, unsigned long long *output, int base, const char *groupsep) { |
938 int cx_strtoull_lc(cxstring str, unsigned long long *output, int base, const char *groupsep) { |
907 // TODO: replace temporary implementation |
939 // some sanity checks |
908 (void) groupsep; // unused in temp impl |
940 str = cx_strtrim(str); |
909 char *s = malloc(str.length + 1); |
941 if (str.length == 0) { |
910 memcpy(s, str.ptr, str.length); |
942 errno = EINVAL; |
911 s[str.length] = '\0'; |
943 return -1; |
912 char *e; |
944 } |
913 *output = strtoull(s, &e, base); |
945 if (!(base == 2 || base == 8 || base == 10 || base == 16)) { |
914 int r = !(e && *e == '\0'); |
946 errno = EINVAL; |
915 free(s); |
947 return -1; |
916 return r; |
948 } |
|
949 if (groupsep == NULL) groupsep = ""; |
|
950 |
|
951 // find the actual start of the number |
|
952 if (str.ptr[0] == '+') { |
|
953 str.ptr++; |
|
954 str.length--; |
|
955 if (str.length == 0) { |
|
956 errno = EINVAL; |
|
957 return -1; |
|
958 } |
|
959 } |
|
960 size_t start = 0; |
|
961 |
|
962 // if base is 2 or 16, some leading stuff may appear |
|
963 if (base == 2) { |
|
964 if (str.ptr[0] == 'b' || str.ptr[0] == 'B') { |
|
965 start = 1; |
|
966 } else if (str.ptr[0] == '0' && str.length > 1) { |
|
967 if (str.ptr[1] == 'b' || str.ptr[1] == 'B') { |
|
968 start = 2; |
|
969 } |
|
970 } |
|
971 } else if (base == 16) { |
|
972 if (str.ptr[0] == 'x' || str.ptr[0] == 'X' || str.ptr[0] == '#') { |
|
973 start = 1; |
|
974 } else if (str.ptr[0] == '0' && str.length > 1) { |
|
975 if (str.ptr[1] == 'x' || str.ptr[1] == 'X') { |
|
976 start = 2; |
|
977 } |
|
978 } |
|
979 } |
|
980 |
|
981 // check if there are digits left |
|
982 if (start >= str.length) { |
|
983 errno = EINVAL; |
|
984 return -1; |
|
985 } |
|
986 |
|
987 // now parse the number |
|
988 unsigned long long result = 0; |
|
989 for (size_t i = start; i < str.length; i++) { |
|
990 // ignore group separators |
|
991 if (strchr(groupsep, str.ptr[i])) continue; |
|
992 |
|
993 // determine the digit value of the character |
|
994 unsigned char c = str.ptr[i]; |
|
995 if (c >= 'a') c = 10 + (c - 'a'); |
|
996 else if (c >= 'A') c = 10 + (c - 'A'); |
|
997 else if (c >= '0') c = c - '0'; |
|
998 else c = 255; |
|
999 if (c >= base) { |
|
1000 errno = EINVAL; |
|
1001 return -1; |
|
1002 } |
|
1003 |
|
1004 // now combine the digit with what we already have |
|
1005 unsigned long right = (result & 0xff) * base + c; |
|
1006 unsigned long long left = (result >> 8) * base + (right >> 8); |
|
1007 if (left > (ULLONG_MAX >> 8)) { |
|
1008 errno = ERANGE; |
|
1009 return -1; |
|
1010 } |
|
1011 result = (left << 8) + (right & 0xff); |
|
1012 } |
|
1013 |
|
1014 *output = result; |
|
1015 return 0; |
917 } |
1016 } |
918 |
1017 |
919 int cx_strtou8_lc(cxstring str, uint8_t *output, int base, const char *groupsep) { |
1018 int cx_strtou8_lc(cxstring str, uint8_t *output, int base, const char *groupsep) { |
920 cx_strtoX_unsigned_impl(uint8_t, UINT8_MAX); |
1019 cx_strtoX_unsigned_impl(uint8_t, UINT8_MAX); |
921 } |
1020 } |