ucx/string.c

branch
dav-2
changeset 889
42cdbf9bbd49
parent 886
da79af4baec8
equal deleted inserted replaced
887:26541c37b619 889:42cdbf9bbd49
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>
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
449 ) { 459 ) {
450 return cx_strsplit_a(allocator, cx_strcast(string), 460 return cx_strsplit_a(allocator, cx_strcast(string),
451 delim, limit, (cxstring **) output); 461 delim, limit, (cxstring **) output);
452 } 462 }
453 463
454 int cx_strcmp( 464 int cx_strcmp_(
455 cxstring s1, 465 cxstring s1,
456 cxstring s2 466 cxstring s2
457 ) { 467 ) {
458 if (s1.length == s2.length) { 468 if (s1.length == s2.length) {
459 return strncmp(s1.ptr, s2.ptr, s1.length); 469 return strncmp(s1.ptr, s2.ptr, s1.length);
466 if (r != 0) return r; 476 if (r != 0) return r;
467 return -1; 477 return -1;
468 } 478 }
469 } 479 }
470 480
471 int cx_strcasecmp( 481 int cx_strcasecmp_(
472 cxstring s1, 482 cxstring s1,
473 cxstring s2 483 cxstring s2
474 ) { 484 ) {
475 if (s1.length == s2.length) { 485 if (s1.length == s2.length) {
476 return cx_strcasecmp_impl(s1.ptr, s2.ptr, s1.length); 486 return cx_strcasecmp_impl(s1.ptr, s2.ptr, s1.length);
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
541 cxmutstr cx_strtrim_m(cxmutstr string) { 545 cxmutstr cx_strtrim_m(cxmutstr string) {
542 cxstring result = cx_strtrim(cx_strcast(string)); 546 cxstring result = cx_strtrim(cx_strcast(string));
543 return (cxmutstr) {(char *) result.ptr, result.length}; 547 return (cxmutstr) {(char *) result.ptr, result.length};
544 } 548 }
545 549
546 bool cx_strprefix( 550 bool cx_strprefix_(
547 cxstring string, 551 cxstring string,
548 cxstring prefix 552 cxstring prefix
549 ) { 553 ) {
550 if (string.length < prefix.length) return false; 554 if (string.length < prefix.length) return false;
551 return memcmp(string.ptr, prefix.ptr, prefix.length) == 0; 555 return memcmp(string.ptr, prefix.ptr, prefix.length) == 0;
552 } 556 }
553 557
554 bool cx_strsuffix( 558 bool cx_strsuffix_(
555 cxstring string, 559 cxstring string,
556 cxstring suffix 560 cxstring suffix
557 ) { 561 ) {
558 if (string.length < suffix.length) return false; 562 if (string.length < suffix.length) return false;
559 return memcmp(string.ptr + string.length - suffix.length, 563 return memcmp(string.ptr + string.length - suffix.length,
560 suffix.ptr, suffix.length) == 0; 564 suffix.ptr, suffix.length) == 0;
561 } 565 }
562 566
563 bool cx_strcaseprefix( 567 bool cx_strcaseprefix_(
564 cxstring string, 568 cxstring string,
565 cxstring prefix 569 cxstring prefix
566 ) { 570 ) {
567 if (string.length < prefix.length) return false; 571 if (string.length < prefix.length) return false;
568 #ifdef _WIN32 572 #ifdef _WIN32
570 #else 574 #else
571 return strncasecmp(string.ptr, prefix.ptr, prefix.length) == 0; 575 return strncasecmp(string.ptr, prefix.ptr, prefix.length) == 0;
572 #endif 576 #endif
573 } 577 }
574 578
575 bool cx_strcasesuffix( 579 bool cx_strcasesuffix_(
576 cxstring string, 580 cxstring string,
577 cxstring suffix 581 cxstring suffix
578 ) { 582 ) {
579 if (string.length < suffix.length) return false; 583 if (string.length < suffix.length) return false;
580 #ifdef _WIN32 584 #ifdef _WIN32
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