| 87 if (count == 0) return 0; |
89 if (count == 0) return 0; |
| 88 |
90 |
| 89 va_list ap; |
91 va_list ap; |
| 90 va_start(ap, count); |
92 va_start(ap, count); |
| 91 size_t size = 0; |
93 size_t size = 0; |
| 92 cx_for_n(i, count) { |
94 for (size_t i = 0; i < count; i++) { |
| 93 cxstring str = va_arg(ap, cxstring); |
95 cxstring str = va_arg(ap, cxstring); |
| |
96 if (size > SIZE_MAX - str.length) errno = EOVERFLOW; |
| 94 size += str.length; |
97 size += str.length; |
| 95 } |
98 } |
| 96 va_end(ap); |
99 va_end(ap); |
| 97 |
100 |
| 98 return size; |
101 return size; |
| 99 } |
102 } |
| 100 |
103 |
| 101 cxmutstr cx_strcat_ma( |
104 cxmutstr cx_strcat_ma( |
| 102 CxAllocator const *alloc, |
105 const CxAllocator *alloc, |
| 103 cxmutstr str, |
106 cxmutstr str, |
| 104 size_t count, |
107 size_t count, |
| 105 ... |
108 ... |
| 106 ) { |
109 ) { |
| 107 if (count == 0) return str; |
110 if (count == 0) return str; |
| 108 |
111 |
| 109 cxstring *strings = calloc(count, sizeof(cxstring)); |
112 cxstring strings_stack[8]; |
| 110 if (!strings) abort(); |
113 cxstring *strings; |
| |
114 if (count > 8) { |
| |
115 strings = calloc(count, sizeof(cxstring)); |
| |
116 if (strings == NULL) { |
| |
117 return (cxmutstr) {NULL, 0}; |
| |
118 } |
| |
119 } else { |
| |
120 strings = strings_stack; |
| |
121 } |
| 111 |
122 |
| 112 va_list ap; |
123 va_list ap; |
| 113 va_start(ap, count); |
124 va_start(ap, count); |
| 114 |
125 |
| 115 // get all args and overall length |
126 // get all args and overall length |
| |
127 bool overflow = false; |
| 116 size_t slen = str.length; |
128 size_t slen = str.length; |
| 117 cx_for_n(i, count) { |
129 for (size_t i = 0; i < count; i++) { |
| 118 cxstring s = va_arg (ap, cxstring); |
130 cxstring s = va_arg (ap, cxstring); |
| 119 strings[i] = s; |
131 strings[i] = s; |
| |
132 if (slen > SIZE_MAX - str.length) overflow = true; |
| 120 slen += s.length; |
133 slen += s.length; |
| 121 } |
134 } |
| 122 va_end(ap); |
135 va_end(ap); |
| 123 |
136 |
| |
137 // abort in case of overflow |
| |
138 if (overflow) { |
| |
139 errno = EOVERFLOW; |
| |
140 if (strings != strings_stack) { |
| |
141 free(strings); |
| |
142 } |
| |
143 return (cxmutstr) { NULL, 0 }; |
| |
144 } |
| |
145 |
| 124 // reallocate or create new string |
146 // reallocate or create new string |
| |
147 char *newstr; |
| 125 if (str.ptr == NULL) { |
148 if (str.ptr == NULL) { |
| 126 str.ptr = cxMalloc(alloc, slen + 1); |
149 newstr = cxMalloc(alloc, slen + 1); |
| 127 } else { |
150 } else { |
| 128 str.ptr = cxRealloc(alloc, str.ptr, slen + 1); |
151 newstr = cxRealloc(alloc, str.ptr, slen + 1); |
| 129 } |
152 } |
| 130 if (str.ptr == NULL) abort(); |
153 if (newstr == NULL) { |
| |
154 if (strings != strings_stack) { |
| |
155 free(strings); |
| |
156 } |
| |
157 return (cxmutstr) {NULL, 0}; |
| |
158 } |
| |
159 str.ptr = newstr; |
| 131 |
160 |
| 132 // concatenate strings |
161 // concatenate strings |
| 133 size_t pos = str.length; |
162 size_t pos = str.length; |
| 134 str.length = slen; |
163 str.length = slen; |
| 135 cx_for_n(i, count) { |
164 for (size_t i = 0; i < count; i++) { |
| 136 cxstring s = strings[i]; |
165 cxstring s = strings[i]; |
| 137 memcpy(str.ptr + pos, s.ptr, s.length); |
166 memcpy(str.ptr + pos, s.ptr, s.length); |
| 138 pos += s.length; |
167 pos += s.length; |
| 139 } |
168 } |
| 140 |
169 |
| 141 // terminate string |
170 // terminate string |
| 142 str.ptr[str.length] = '\0'; |
171 str.ptr[str.length] = '\0'; |
| 143 |
172 |
| 144 // free temporary array |
173 // free temporary array |
| 145 free(strings); |
174 if (strings != strings_stack) { |
| |
175 free(strings); |
| |
176 } |
| 146 |
177 |
| 147 return str; |
178 return str; |
| 148 } |
179 } |
| 149 |
180 |
| 150 cxstring cx_strsubs( |
181 cxstring cx_strsubs( |
| 432 int cx_strcmp( |
463 int cx_strcmp( |
| 433 cxstring s1, |
464 cxstring s1, |
| 434 cxstring s2 |
465 cxstring s2 |
| 435 ) { |
466 ) { |
| 436 if (s1.length == s2.length) { |
467 if (s1.length == s2.length) { |
| 437 return memcmp(s1.ptr, s2.ptr, s1.length); |
468 return strncmp(s1.ptr, s2.ptr, s1.length); |
| 438 } else if (s1.length > s2.length) { |
469 } else if (s1.length > s2.length) { |
| |
470 int r = strncmp(s1.ptr, s2.ptr, s2.length); |
| |
471 if (r != 0) return r; |
| 439 return 1; |
472 return 1; |
| 440 } else { |
473 } else { |
| |
474 int r = strncmp(s1.ptr, s2.ptr, s1.length); |
| |
475 if (r != 0) return r; |
| 441 return -1; |
476 return -1; |
| 442 } |
477 } |
| 443 } |
478 } |
| 444 |
479 |
| 445 int cx_strcasecmp( |
480 int cx_strcasecmp( |
| 446 cxstring s1, |
481 cxstring s1, |
| 447 cxstring s2 |
482 cxstring s2 |
| 448 ) { |
483 ) { |
| 449 if (s1.length == s2.length) { |
484 if (s1.length == s2.length) { |
| 450 #ifdef _WIN32 |
485 return cx_strcasecmp_impl(s1.ptr, s2.ptr, s1.length); |
| 451 return _strnicmp(s1.ptr, s2.ptr, s1.length); |
|
| 452 #else |
|
| 453 return strncasecmp(s1.ptr, s2.ptr, s1.length); |
|
| 454 #endif |
|
| 455 } else if (s1.length > s2.length) { |
486 } else if (s1.length > s2.length) { |
| |
487 int r = cx_strcasecmp_impl(s1.ptr, s2.ptr, s2.length); |
| |
488 if (r != 0) return r; |
| 456 return 1; |
489 return 1; |
| 457 } else { |
490 } else { |
| |
491 int r = cx_strcasecmp_impl(s1.ptr, s2.ptr, s1.length); |
| |
492 if (r != 0) return r; |
| 458 return -1; |
493 return -1; |
| 459 } |
494 } |
| 460 } |
495 } |
| 461 |
496 |
| 462 int cx_strcmp_p( |
497 int cx_strcmp_p( |
| 463 void const *s1, |
498 const void *s1, |
| 464 void const *s2 |
499 const void *s2 |
| 465 ) { |
500 ) { |
| 466 cxstring const *left = s1; |
501 const cxstring *left = s1; |
| 467 cxstring const *right = s2; |
502 const cxstring *right = s2; |
| 468 return cx_strcmp(*left, *right); |
503 return cx_strcmp(*left, *right); |
| 469 } |
504 } |
| 470 |
505 |
| 471 int cx_strcasecmp_p( |
506 int cx_strcasecmp_p( |
| 472 void const *s1, |
507 const void *s1, |
| 473 void const *s2 |
508 const void *s2 |
| 474 ) { |
509 ) { |
| 475 cxstring const *left = s1; |
510 const cxstring *left = s1; |
| 476 cxstring const *right = s2; |
511 const cxstring *right = s2; |
| 477 return cx_strcasecmp(*left, *right); |
512 return cx_strcasecmp(*left, *right); |
| 478 } |
513 } |
| 479 |
514 |
| 480 cxmutstr cx_strdup_a( |
515 cxmutstr cx_strdup_a( |
| 481 CxAllocator const *allocator, |
516 const CxAllocator *allocator, |
| 482 cxstring string |
517 cxstring string |
| 483 ) { |
518 ) { |
| 484 cxmutstr result = { |
519 cxmutstr result = { |
| 485 cxMalloc(allocator, string.length + 1), |
520 cxMalloc(allocator, string.length + 1), |
| 486 string.length |
521 string.length |
| 776 return cx_strtok_next(ctx, (cxstring *) token); |
811 return cx_strtok_next(ctx, (cxstring *) token); |
| 777 } |
812 } |
| 778 |
813 |
| 779 void cx_strtok_delim( |
814 void cx_strtok_delim( |
| 780 CxStrtokCtx *ctx, |
815 CxStrtokCtx *ctx, |
| 781 cxstring const *delim, |
816 const cxstring *delim, |
| 782 size_t count |
817 size_t count |
| 783 ) { |
818 ) { |
| 784 ctx->delim_more = delim; |
819 ctx->delim_more = delim; |
| 785 ctx->delim_more_count = count; |
820 ctx->delim_more_count = count; |
| 786 } |
821 } |
| |
822 |
| |
823 #define cx_strtoX_signed_impl(rtype, rmin, rmax) \ |
| |
824 long long result; \ |
| |
825 if (cx_strtoll_lc(str, &result, base, groupsep)) { \ |
| |
826 return -1; \ |
| |
827 } \ |
| |
828 if (result < rmin || result > rmax) { \ |
| |
829 errno = ERANGE; \ |
| |
830 return -1; \ |
| |
831 } \ |
| |
832 *output = (rtype) result; \ |
| |
833 return 0 |
| |
834 |
| |
835 int cx_strtos_lc(cxstring str, short *output, int base, const char *groupsep) { |
| |
836 cx_strtoX_signed_impl(short, SHRT_MIN, SHRT_MAX); |
| |
837 } |
| |
838 |
| |
839 int cx_strtoi_lc(cxstring str, int *output, int base, const char *groupsep) { |
| |
840 cx_strtoX_signed_impl(int, INT_MIN, INT_MAX); |
| |
841 } |
| |
842 |
| |
843 int cx_strtol_lc(cxstring str, long *output, int base, const char *groupsep) { |
| |
844 cx_strtoX_signed_impl(long, LONG_MIN, LONG_MAX); |
| |
845 } |
| |
846 |
| |
847 int cx_strtoll_lc(cxstring str, long long *output, int base, const char *groupsep) { |
| |
848 // strategy: parse as unsigned, check range, negate if required |
| |
849 bool neg = false; |
| |
850 size_t start_unsigned = 0; |
| |
851 |
| |
852 // trim already, to search for a sign character |
| |
853 str = cx_strtrim(str); |
| |
854 if (str.length == 0) { |
| |
855 errno = EINVAL; |
| |
856 return -1; |
| |
857 } |
| |
858 |
| |
859 // test if we have a negative sign character |
| |
860 if (str.ptr[start_unsigned] == '-') { |
| |
861 neg = true; |
| |
862 start_unsigned++; |
| |
863 // must not be followed by positive sign character |
| |
864 if (str.length == 1 || str.ptr[start_unsigned] == '+') { |
| |
865 errno = EINVAL; |
| |
866 return -1; |
| |
867 } |
| |
868 } |
| |
869 |
| |
870 // now parse the number with strtoull |
| |
871 unsigned long long v; |
| |
872 cxstring ustr = start_unsigned == 0 ? str |
| |
873 : cx_strn(str.ptr + start_unsigned, str.length - start_unsigned); |
| |
874 int ret = cx_strtoull_lc(ustr, &v, base, groupsep); |
| |
875 if (ret != 0) return ret; |
| |
876 if (neg) { |
| |
877 if (v - 1 > LLONG_MAX) { |
| |
878 errno = ERANGE; |
| |
879 return -1; |
| |
880 } |
| |
881 *output = -(long long) v; |
| |
882 return 0; |
| |
883 } else { |
| |
884 if (v > LLONG_MAX) { |
| |
885 errno = ERANGE; |
| |
886 return -1; |
| |
887 } |
| |
888 *output = (long long) v; |
| |
889 return 0; |
| |
890 } |
| |
891 } |
| |
892 |
| |
893 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); |
| |
895 } |
| |
896 |
| |
897 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); |
| |
899 } |
| |
900 |
| |
901 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); |
| |
903 } |
| |
904 |
| |
905 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 |
| |
907 return cx_strtoll_lc(str, (long long*) output, base, groupsep); |
| |
908 } |
| |
909 |
| |
910 int cx_strtoz_lc(cxstring str, ssize_t *output, int base, const char *groupsep) { |
| |
911 #if SSIZE_MAX == INT32_MAX |
| |
912 return cx_strtoi32_lc(str, (int32_t*) output, base, groupsep); |
| |
913 #elif SSIZE_MAX == INT64_MAX |
| |
914 return cx_strtoll_lc(str, (long long*) output, base, groupsep); |
| |
915 #else |
| |
916 #error "unsupported ssize_t size" |
| |
917 #endif |
| |
918 } |
| |
919 |
| |
920 #define cx_strtoX_unsigned_impl(rtype, rmax) \ |
| |
921 uint64_t result; \ |
| |
922 if (cx_strtou64_lc(str, &result, base, groupsep)) { \ |
| |
923 return -1; \ |
| |
924 } \ |
| |
925 if (result > rmax) { \ |
| |
926 errno = ERANGE; \ |
| |
927 return -1; \ |
| |
928 } \ |
| |
929 *output = (rtype) result; \ |
| |
930 return 0 |
| |
931 |
| |
932 int cx_strtous_lc(cxstring str, unsigned short *output, int base, const char *groupsep) { |
| |
933 cx_strtoX_unsigned_impl(unsigned short, USHRT_MAX); |
| |
934 } |
| |
935 |
| |
936 int cx_strtou_lc(cxstring str, unsigned int *output, int base, const char *groupsep) { |
| |
937 cx_strtoX_unsigned_impl(unsigned int, UINT_MAX); |
| |
938 } |
| |
939 |
| |
940 int cx_strtoul_lc(cxstring str, unsigned long *output, int base, const char *groupsep) { |
| |
941 cx_strtoX_unsigned_impl(unsigned long, ULONG_MAX); |
| |
942 } |
| |
943 |
| |
944 int cx_strtoull_lc(cxstring str, unsigned long long *output, int base, const char *groupsep) { |
| |
945 // some sanity checks |
| |
946 str = cx_strtrim(str); |
| |
947 if (str.length == 0) { |
| |
948 errno = EINVAL; |
| |
949 return -1; |
| |
950 } |
| |
951 if (!(base == 2 || base == 8 || base == 10 || base == 16)) { |
| |
952 errno = EINVAL; |
| |
953 return -1; |
| |
954 } |
| |
955 if (groupsep == NULL) groupsep = ""; |
| |
956 |
| |
957 // find the actual start of the number |
| |
958 if (str.ptr[0] == '+') { |
| |
959 str.ptr++; |
| |
960 str.length--; |
| |
961 if (str.length == 0) { |
| |
962 errno = EINVAL; |
| |
963 return -1; |
| |
964 } |
| |
965 } |
| |
966 size_t start = 0; |
| |
967 |
| |
968 // if base is 2 or 16, some leading stuff may appear |
| |
969 if (base == 2) { |
| |
970 if ((str.ptr[0] | 32) == 'b') { |
| |
971 start = 1; |
| |
972 } else if (str.ptr[0] == '0' && str.length > 1) { |
| |
973 if ((str.ptr[1] | 32) == 'b') { |
| |
974 start = 2; |
| |
975 } |
| |
976 } |
| |
977 } else if (base == 16) { |
| |
978 if ((str.ptr[0] | 32) == 'x' || str.ptr[0] == '#') { |
| |
979 start = 1; |
| |
980 } else if (str.ptr[0] == '0' && str.length > 1) { |
| |
981 if ((str.ptr[1] | 32) == 'x') { |
| |
982 start = 2; |
| |
983 } |
| |
984 } |
| |
985 } |
| |
986 |
| |
987 // check if there are digits left |
| |
988 if (start >= str.length) { |
| |
989 errno = EINVAL; |
| |
990 return -1; |
| |
991 } |
| |
992 |
| |
993 // now parse the number |
| |
994 unsigned long long result = 0; |
| |
995 for (size_t i = start; i < str.length; i++) { |
| |
996 // ignore group separators |
| |
997 if (strchr(groupsep, str.ptr[i])) continue; |
| |
998 |
| |
999 // determine the digit value of the character |
| |
1000 unsigned char c = str.ptr[i]; |
| |
1001 if (c >= 'a') c = 10 + (c - 'a'); |
| |
1002 else if (c >= 'A') c = 10 + (c - 'A'); |
| |
1003 else if (c >= '0') c = c - '0'; |
| |
1004 else c = 255; |
| |
1005 if (c >= base) { |
| |
1006 errno = EINVAL; |
| |
1007 return -1; |
| |
1008 } |
| |
1009 |
| |
1010 // now combine the digit with what we already have |
| |
1011 unsigned long right = (result & 0xff) * base + c; |
| |
1012 unsigned long long left = (result >> 8) * base + (right >> 8); |
| |
1013 if (left > (ULLONG_MAX >> 8)) { |
| |
1014 errno = ERANGE; |
| |
1015 return -1; |
| |
1016 } |
| |
1017 result = (left << 8) + (right & 0xff); |
| |
1018 } |
| |
1019 |
| |
1020 *output = result; |
| |
1021 return 0; |
| |
1022 } |
| |
1023 |
| |
1024 int cx_strtou8_lc(cxstring str, uint8_t *output, int base, const char *groupsep) { |
| |
1025 cx_strtoX_unsigned_impl(uint8_t, UINT8_MAX); |
| |
1026 } |
| |
1027 |
| |
1028 int cx_strtou16_lc(cxstring str, uint16_t *output, int base, const char *groupsep) { |
| |
1029 cx_strtoX_unsigned_impl(uint16_t, UINT16_MAX); |
| |
1030 } |
| |
1031 |
| |
1032 int cx_strtou32_lc(cxstring str, uint32_t *output, int base, const char *groupsep) { |
| |
1033 cx_strtoX_unsigned_impl(uint32_t, UINT32_MAX); |
| |
1034 } |
| |
1035 |
| |
1036 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 |
| |
1038 return cx_strtoull_lc(str, (unsigned long long*) output, base, groupsep); |
| |
1039 } |
| |
1040 |
| |
1041 int cx_strtouz_lc(cxstring str, size_t *output, int base, const char *groupsep) { |
| |
1042 #if SIZE_MAX == UINT32_MAX |
| |
1043 return cx_strtou32_lc(str, (uint32_t*) output, base, groupsep); |
| |
1044 #elif SIZE_MAX == UINT64_MAX |
| |
1045 return cx_strtoull_lc(str, (unsigned long long *) output, base, groupsep); |
| |
1046 #else |
| |
1047 #error "unsupported size_t size" |
| |
1048 #endif |
| |
1049 } |
| |
1050 |
| |
1051 int cx_strtof_lc(cxstring str, float *output, char decsep, const char *groupsep) { |
| |
1052 // use string to double and add a range check |
| |
1053 double d; |
| |
1054 int ret = cx_strtod_lc(str, &d, decsep, groupsep); |
| |
1055 if (ret != 0) return ret; |
| |
1056 // note: FLT_MIN is the smallest POSITIVE number that can be represented |
| |
1057 double test = d < 0 ? -d : d; |
| |
1058 if (test < FLT_MIN || test > FLT_MAX) { |
| |
1059 errno = ERANGE; |
| |
1060 return -1; |
| |
1061 } |
| |
1062 *output = (float) d; |
| |
1063 return 0; |
| |
1064 } |
| |
1065 |
| |
1066 int cx_strtod_lc(cxstring str, double *output, char decsep, const char *groupsep) { |
| |
1067 // TODO: overflow check |
| |
1068 // TODO: increase precision |
| |
1069 |
| |
1070 // trim and check |
| |
1071 str = cx_strtrim(str); |
| |
1072 if (str.length == 0) { |
| |
1073 errno = EINVAL; |
| |
1074 return -1; |
| |
1075 } |
| |
1076 |
| |
1077 double result = 0.; |
| |
1078 int sign = 1; |
| |
1079 |
| |
1080 // check if there is a sign |
| |
1081 if (str.ptr[0] == '-') { |
| |
1082 sign = -1; |
| |
1083 str.ptr++; |
| |
1084 str.length--; |
| |
1085 } else if (str.ptr[0] == '+') { |
| |
1086 str.ptr++; |
| |
1087 str.length--; |
| |
1088 } |
| |
1089 |
| |
1090 // there must be at least one char to parse |
| |
1091 if (str.length == 0) { |
| |
1092 errno = EINVAL; |
| |
1093 return -1; |
| |
1094 } |
| |
1095 |
| |
1096 // parse all digits until we find the decsep |
| |
1097 size_t pos = 0; |
| |
1098 do { |
| |
1099 if (isdigit(str.ptr[pos])) { |
| |
1100 result = result * 10 + (str.ptr[pos] - '0'); |
| |
1101 } else if (strchr(groupsep, str.ptr[pos]) == NULL) { |
| |
1102 break; |
| |
1103 } |
| |
1104 } while (++pos < str.length); |
| |
1105 |
| |
1106 // already done? |
| |
1107 if (pos == str.length) { |
| |
1108 *output = result * sign; |
| |
1109 return 0; |
| |
1110 } |
| |
1111 |
| |
1112 // is the next char the decsep? |
| |
1113 if (str.ptr[pos] == decsep) { |
| |
1114 pos++; |
| |
1115 // it may end with the decsep, if it did not start with it |
| |
1116 if (pos == str.length) { |
| |
1117 if (str.length == 1) { |
| |
1118 errno = EINVAL; |
| |
1119 return -1; |
| |
1120 } else { |
| |
1121 *output = result * sign; |
| |
1122 return 0; |
| |
1123 } |
| |
1124 } |
| |
1125 // parse everything until exponent or end |
| |
1126 double factor = 1.; |
| |
1127 do { |
| |
1128 if (isdigit(str.ptr[pos])) { |
| |
1129 factor *= 0.1; |
| |
1130 result = result + factor * (str.ptr[pos] - '0'); |
| |
1131 } else if (strchr(groupsep, str.ptr[pos]) == NULL) { |
| |
1132 break; |
| |
1133 } |
| |
1134 } while (++pos < str.length); |
| |
1135 } |
| |
1136 |
| |
1137 // no exponent? |
| |
1138 if (pos == str.length) { |
| |
1139 *output = result * sign; |
| |
1140 return 0; |
| |
1141 } |
| |
1142 |
| |
1143 // now the next separator MUST be the exponent separator |
| |
1144 // and at least one char must follow |
| |
1145 if ((str.ptr[pos] | 32) != 'e' || str.length <= pos + 1) { |
| |
1146 errno = EINVAL; |
| |
1147 return -1; |
| |
1148 } |
| |
1149 pos++; |
| |
1150 |
| |
1151 // check if we have a sign for the exponent |
| |
1152 double factor = 10.; |
| |
1153 if (str.ptr[pos] == '-') { |
| |
1154 factor = .1; |
| |
1155 pos++; |
| |
1156 } else if (str.ptr[pos] == '+') { |
| |
1157 pos++; |
| |
1158 } |
| |
1159 |
| |
1160 // at least one digit must follow |
| |
1161 if (pos == str.length) { |
| |
1162 errno = EINVAL; |
| |
1163 return -1; |
| |
1164 } |
| |
1165 |
| |
1166 // parse the exponent |
| |
1167 unsigned int exp = 0; |
| |
1168 do { |
| |
1169 if (isdigit(str.ptr[pos])) { |
| |
1170 exp = 10 * exp + (str.ptr[pos] - '0'); |
| |
1171 } else if (strchr(groupsep, str.ptr[pos]) == NULL) { |
| |
1172 errno = EINVAL; |
| |
1173 return -1; |
| |
1174 } |
| |
1175 } while (++pos < str.length); |
| |
1176 |
| |
1177 // apply the exponent by fast exponentiation |
| |
1178 do { |
| |
1179 if (exp & 1) { |
| |
1180 result *= factor; |
| |
1181 } |
| |
1182 factor *= factor; |
| |
1183 } while ((exp >>= 1) > 0); |
| |
1184 |
| |
1185 // store the result and exit |
| |
1186 *output = result * sign; |
| |
1187 return 0; |
| |
1188 } |