src/string.c

changeset 1061
c7d23892eab5
parent 1052
e997862a57d8
child 1063
e453e717876e
equal deleted inserted replaced
1060:0a7c1bb2372d 1061:c7d23892eab5
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 }

mercurial