| 527     memcpy(result.ptr, string.ptr, string.length); | 526     memcpy(result.ptr, string.ptr, string.length); | 
| 528     result.ptr[string.length] = '\0'; | 527     result.ptr[string.length] = '\0'; | 
| 529     return result; | 528     return result; | 
| 530 } | 529 } | 
| 531 | 530 | 
|  | 531 static bool str_isspace(char c) { | 
|  | 532     // TODO: remove once UCX has public API for this | 
|  | 533     return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\v' || c == '\f'; | 
|  | 534 } | 
|  | 535 | 
| 532 cxstring cx_strtrim(cxstring string) { | 536 cxstring cx_strtrim(cxstring string) { | 
| 533     cxstring result = string; | 537     cxstring result = string; | 
| 534     // TODO: optimize by comparing multiple bytes at once | 538     // TODO: optimize by comparing multiple bytes at once | 
| 535     while (result.length > 0 && isspace(*result.ptr)) { | 539     while (result.length > 0 && str_isspace(*result.ptr)) { | 
| 536         result.ptr++; | 540         result.ptr++; | 
| 537         result.length--; | 541         result.length--; | 
| 538     } | 542     } | 
| 539     while (result.length > 0 && isspace(result.ptr[result.length - 1])) { | 543     while (result.length > 0 && str_isspace(result.ptr[result.length - 1])) { | 
| 540         result.length--; | 544         result.length--; | 
| 541     } | 545     } | 
| 542     return result; | 546     return result; | 
| 543 } | 547 } | 
| 544 | 548 | 
| 590 #endif | 594 #endif | 
| 591 } | 595 } | 
| 592 | 596 | 
| 593 void cx_strlower(cxmutstr string) { | 597 void cx_strlower(cxmutstr string) { | 
| 594     for (size_t i = 0; i < string.length; i++) { | 598     for (size_t i = 0; i < string.length; i++) { | 
| 595         string.ptr[i] = (char) tolower(string.ptr[i]); | 599         if ((unsigned int) (string.ptr[i] - 'A') < 26u) { | 
|  | 600             string.ptr[i] += 'a' - 'A'; | 
|  | 601         } | 
| 596     } | 602     } | 
| 597 } | 603 } | 
| 598 | 604 | 
| 599 void cx_strupper(cxmutstr string) { | 605 void cx_strupper(cxmutstr string) { | 
| 600     for (size_t i = 0; i < string.length; i++) { | 606     for (size_t i = 0; i < string.length; i++) { | 
| 601         string.ptr[i] = (char) toupper(string.ptr[i]); | 607         if ((unsigned int) (string.ptr[i] - 'a') < 26u) { | 
|  | 608             string.ptr[i] += 'A' - 'a'; | 
|  | 609         } | 
| 602     } | 610     } | 
| 603 } | 611 } | 
| 604 | 612 | 
| 605 #ifndef CX_STRREPLACE_INDEX_BUFFER_SIZE | 613 #ifndef CX_STRREPLACE_INDEX_BUFFER_SIZE | 
| 606 #define CX_STRREPLACE_INDEX_BUFFER_SIZE 64 | 614 #define CX_STRREPLACE_INDEX_BUFFER_SIZE 64 | 
| 1053     } | 1061     } | 
| 1054     *output = (float) d; | 1062     *output = (float) d; | 
| 1055     return 0; | 1063     return 0; | 
| 1056 } | 1064 } | 
| 1057 | 1065 | 
|  | 1066 static bool str_isdigit(char c) { | 
|  | 1067     // TODO: remove once UCX has public API for this | 
|  | 1068     return c >= '0' && c <= '9'; | 
|  | 1069 } | 
|  | 1070 | 
| 1058 int cx_strtod_lc(cxstring str, double *output, char decsep, const char *groupsep) { | 1071 int cx_strtod_lc(cxstring str, double *output, char decsep, const char *groupsep) { | 
| 1059     // TODO: overflow check | 1072     // TODO: overflow check | 
| 1060     // TODO: increase precision | 1073     // TODO: increase precision | 
| 1061 | 1074 | 
| 1062     // trim and check | 1075     // trim and check | 
| 1086     } | 1099     } | 
| 1087 | 1100 | 
| 1088     // parse all digits until we find the decsep | 1101     // parse all digits until we find the decsep | 
| 1089     size_t pos = 0; | 1102     size_t pos = 0; | 
| 1090     do { | 1103     do { | 
| 1091         if (isdigit(str.ptr[pos])) { | 1104         if (str_isdigit(str.ptr[pos])) { | 
| 1092             result = result * 10 + (str.ptr[pos] - '0'); | 1105             result = result * 10 + (str.ptr[pos] - '0'); | 
| 1093         } else if (strchr(groupsep, str.ptr[pos]) == NULL) { | 1106         } else if (strchr(groupsep, str.ptr[pos]) == NULL) { | 
| 1094             break; | 1107             break; | 
| 1095         } | 1108         } | 
| 1096     } while (++pos < str.length); | 1109     } while (++pos < str.length); | 
| 1156     } | 1169     } | 
| 1157 | 1170 | 
| 1158     // parse the exponent | 1171     // parse the exponent | 
| 1159     unsigned int exp = 0; | 1172     unsigned int exp = 0; | 
| 1160     do { | 1173     do { | 
| 1161         if (isdigit(str.ptr[pos])) { | 1174         if (str_isdigit(str.ptr[pos])) { | 
| 1162             exp = 10 * exp + (str.ptr[pos] - '0'); | 1175             exp = 10 * exp + (str.ptr[pos] - '0'); | 
| 1163         } else if (strchr(groupsep, str.ptr[pos]) == NULL) { | 1176         } else if (strchr(groupsep, str.ptr[pos]) == NULL) { | 
| 1164             errno = EINVAL; | 1177             errno = EINVAL; | 
| 1165             return -1; | 1178             return -1; | 
| 1166         } | 1179         } |