ucx/string.c

changeset 112
c3f2f16fa4b8
parent 108
77254bd6dccb
child 113
dde28a806552
equal deleted inserted replaced
111:81c4f73236a4 112:c3f2f16fa4b8
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 #ifdef MEMRCHR_NEED_GNU
29 #define _GNU_SOURCE
30 #endif
31
28 #include "cx/string.h" 32 #include "cx/string.h"
29 33
30 #include <string.h> 34 #include <string.h>
31 #include <stdarg.h> 35 #include <stdarg.h>
32 #include <assert.h> 36 #include <assert.h>
33 #include <errno.h> 37 #include <errno.h>
34 #include <limits.h> 38 #include <limits.h>
35 #include <float.h> 39 #include <float.h>
40 #include <ctype.h>
36 41
37 #ifdef _WIN32 42 #ifdef _WIN32
38 #define cx_strcasecmp_impl _strnicmp 43 #define cx_strcasecmp_impl _strnicmp
39 #else 44 #else
40 #include <strings.h> 45 #include <strings.h>
41 #define cx_strcasecmp_impl strncasecmp 46 #define cx_strcasecmp_impl strncasecmp
42 #endif 47 #endif
43 48
44 cxmutstr cx_mutstr(char *cstring) { 49 cxmutstr cx_mutstr(char *cstring) {
45 return (cxmutstr) {cstring, strlen(cstring)}; 50 return (cxmutstr) {cstring, cstring == NULL ? 0 : strlen(cstring)};
46 } 51 }
47 52
48 cxmutstr cx_mutstrn( 53 cxmutstr cx_mutstrn(
49 char *cstring, 54 char *cstring,
50 size_t length 55 size_t length
51 ) { 56 ) {
52 return (cxmutstr) {cstring, length}; 57 return (cxmutstr) {cstring, length};
53 } 58 }
54 59
55 cxstring cx_str(const char *cstring) { 60 cxstring cx_str(const char *cstring) {
56 return (cxstring) {cstring, strlen(cstring)}; 61 return (cxstring) {cstring, cstring == NULL ? 0 : strlen(cstring)};
57 } 62 }
58 63
59 cxstring cx_strn( 64 cxstring cx_strn(
60 const char *cstring, 65 const char *cstring,
61 size_t length 66 size_t length
229 cxstring result = cx_strchr(cx_strcast(string), chr); 234 cxstring result = cx_strchr(cx_strcast(string), chr);
230 return (cxmutstr) {(char *) result.ptr, result.length}; 235 return (cxmutstr) {(char *) result.ptr, result.length};
231 } 236 }
232 237
233 cxstring cx_strrchr( 238 cxstring cx_strrchr(
234 cxstring string, 239 cxstring string,
235 int chr 240 int chr
236 ) { 241 ) {
242 #ifdef WITH_MEMRCHR
243 char *ret = memrchr(string.ptr, 0xFF & chr, string.length);
244 if (ret == NULL) return (cxstring) {NULL, 0};
245 return (cxstring) {ret, string.length - (ret - string.ptr)};
246 #else
237 chr = 0xFF & chr; 247 chr = 0xFF & chr;
238 size_t i = string.length; 248 size_t i = string.length;
239 while (i > 0) { 249 while (i > 0) {
240 i--; 250 i--;
241 // TODO: improve by comparing multiple bytes at once
242 if (string.ptr[i] == chr) { 251 if (string.ptr[i] == chr) {
243 return cx_strsubs(string, i); 252 return cx_strsubs(string, i);
244 } 253 }
245 } 254 }
246 return (cxstring) {NULL, 0}; 255 return (cxstring) {NULL, 0};
256 #endif
247 } 257 }
248 258
249 cxmutstr cx_strrchr_m( 259 cxmutstr cx_strrchr_m(
250 cxmutstr string, 260 cxmutstr string,
251 int chr 261 int chr
518 memcpy(result.ptr, string.ptr, string.length); 528 memcpy(result.ptr, string.ptr, string.length);
519 result.ptr[string.length] = '\0'; 529 result.ptr[string.length] = '\0';
520 return result; 530 return result;
521 } 531 }
522 532
523 static bool str_isspace(char c) {
524 // TODO: remove once UCX has public API for this
525 return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\v' || c == '\f';
526 }
527
528 cxstring cx_strtrim(cxstring string) { 533 cxstring cx_strtrim(cxstring string) {
529 cxstring result = string; 534 cxstring result = string;
530 // TODO: optimize by comparing multiple bytes at once 535 while (result.length > 0 && isspace((unsigned char)(result.ptr[0]))) {
531 while (result.length > 0 && str_isspace(*result.ptr)) {
532 result.ptr++; 536 result.ptr++;
533 result.length--; 537 result.length--;
534 } 538 }
535 while (result.length > 0 && str_isspace(result.ptr[result.length - 1])) { 539 while (result.length > 0 && isspace((unsigned char)result.ptr[result.length - 1])) {
536 result.length--; 540 result.length--;
537 } 541 }
538 return result; 542 return result;
539 } 543 }
540 544
955 } 959 }
956 *output = (float) d; 960 *output = (float) d;
957 return 0; 961 return 0;
958 } 962 }
959 963
960 static bool str_isdigit(char c) {
961 // TODO: remove once UCX has public API for this
962 return c >= '0' && c <= '9';
963 }
964
965 int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupsep) { 964 int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupsep) {
966 // TODO: overflow check 965 // TODO: overflow check
967 // TODO: increase precision 966 // TODO: increase precision
968 967
969 // emptiness check 968 // emptiness check
992 } 991 }
993 992
994 // parse all digits until we find the decsep 993 // parse all digits until we find the decsep
995 size_t pos = 0; 994 size_t pos = 0;
996 do { 995 do {
997 if (str_isdigit(str.ptr[pos])) { 996 if (isdigit((unsigned char)str.ptr[pos])) {
998 result = result * 10 + (str.ptr[pos] - '0'); 997 result = result * 10 + (str.ptr[pos] - '0');
999 } else if (strchr(groupsep, str.ptr[pos]) == NULL) { 998 } else if (strchr(groupsep, str.ptr[pos]) == NULL) {
1000 break; 999 break;
1001 } 1000 }
1002 } while (++pos < str.length); 1001 } while (++pos < str.length);
1021 } 1020 }
1022 } 1021 }
1023 // parse everything until exponent or end 1022 // parse everything until exponent or end
1024 double factor = 1.; 1023 double factor = 1.;
1025 do { 1024 do {
1026 if (str_isdigit(str.ptr[pos])) { 1025 if (isdigit((unsigned char)str.ptr[pos])) {
1027 factor *= 0.1; 1026 factor *= 0.1;
1028 result = result + factor * (str.ptr[pos] - '0'); 1027 result = result + factor * (str.ptr[pos] - '0');
1029 } else if (strchr(groupsep, str.ptr[pos]) == NULL) { 1028 } else if (strchr(groupsep, str.ptr[pos]) == NULL) {
1030 break; 1029 break;
1031 } 1030 }
1062 } 1061 }
1063 1062
1064 // parse the exponent 1063 // parse the exponent
1065 unsigned int exp = 0; 1064 unsigned int exp = 0;
1066 do { 1065 do {
1067 if (str_isdigit(str.ptr[pos])) { 1066 if (isdigit((unsigned char)str.ptr[pos])) {
1068 exp = 10 * exp + (str.ptr[pos] - '0'); 1067 exp = 10 * exp + (str.ptr[pos] - '0');
1069 } else if (strchr(groupsep, str.ptr[pos]) == NULL) { 1068 } else if (strchr(groupsep, str.ptr[pos]) == NULL) {
1070 errno = EINVAL; 1069 errno = EINVAL;
1071 return -1; 1070 return -1;
1072 } 1071 }

mercurial