2022-12-21 08:29:33 +00:00
|
|
|
#include <limits.h>
|
2024-11-02 11:31:51 +00:00
|
|
|
#include <mango/libc/string.h>
|
2022-12-21 08:29:33 +00:00
|
|
|
|
|
|
|
|
#define ALIGN (sizeof(size_t))
|
|
|
|
|
#define ONES ((size_t)-1 / UCHAR_MAX)
|
|
|
|
|
#define HIGHS (ONES * (UCHAR_MAX / 2 + 1))
|
|
|
|
|
#define HASZERO(X) (((X)-ONES) & ~(X)&HIGHS)
|
|
|
|
|
#define BITOP(A, B, OP) \
|
|
|
|
|
((A)[(size_t)(B) / (8 * sizeof *(A))] OP(size_t) 1 \
|
|
|
|
|
<< ((size_t)(B) % (8 * sizeof *(A))))
|
|
|
|
|
|
|
|
|
|
char *strchrnul(const char *s, int c) {
|
|
|
|
|
size_t *w;
|
|
|
|
|
size_t k;
|
|
|
|
|
|
|
|
|
|
c = (unsigned char)c;
|
|
|
|
|
if (!c) {
|
|
|
|
|
return (char *)s + strlen(s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (; (uintptr_t)s % ALIGN; s++) {
|
|
|
|
|
if (!*s || *(unsigned char *)s == c) {
|
|
|
|
|
return (char *)s;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
k = ONES * c;
|
|
|
|
|
for (w = (void *)s; !HASZERO(*w) && !HASZERO(*w ^ k); w++)
|
|
|
|
|
;
|
|
|
|
|
for (s = (void *)w; *s && *(unsigned char *)s != c; s++)
|
|
|
|
|
;
|
|
|
|
|
return (char *)s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *strchr(const char *s, int c) {
|
|
|
|
|
char *r = strchrnul(s, c);
|
|
|
|
|
return *(unsigned char *)r == (unsigned char)c ? r : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t lfind(const char *str, const char accept) {
|
|
|
|
|
return (size_t)strchr(str, accept);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t strspn(const char *s, const char *c) {
|
|
|
|
|
const char *a = s;
|
|
|
|
|
size_t byteset[32 / sizeof(size_t)] = {0};
|
|
|
|
|
|
|
|
|
|
if (!c[0]) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!c[1]) {
|
|
|
|
|
for (; *s == *c; s++) {
|
|
|
|
|
return s - a;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++)
|
|
|
|
|
;
|
|
|
|
|
for (; *s && BITOP(byteset, *(unsigned char *)s, &); s++)
|
|
|
|
|
;
|
|
|
|
|
return s - a;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t strcspn(const char *s, const char *c) {
|
|
|
|
|
const char *a = s;
|
|
|
|
|
|
|
|
|
|
if (c[0] && c[1]) {
|
|
|
|
|
size_t byteset[32 / sizeof(size_t)] = {0};
|
|
|
|
|
for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++)
|
|
|
|
|
;
|
|
|
|
|
for (; *s && !BITOP(byteset, *(unsigned char *)s, &); s++)
|
|
|
|
|
;
|
|
|
|
|
return s - a;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return strchrnul(s, *c) - a;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *strpbrk(const char *s, const char *b) {
|
|
|
|
|
s += strcspn(s, b);
|
|
|
|
|
return *s ? (char *)s : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *strtok_r(char *str, const char *delim, char **sp) {
|
|
|
|
|
int i = 0;
|
|
|
|
|
int len = strlen(delim);
|
|
|
|
|
|
|
|
|
|
/* Were we given any delimiters? */
|
|
|
|
|
if (len == 0) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we weren't given a string, and save pointer is NULL, return. */
|
|
|
|
|
if (!str && !sp) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we were given a string, initialise sp for subsequent calls. */
|
|
|
|
|
if (str) {
|
|
|
|
|
*sp = str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Go to the start of the substring, skipping any delimiters. */
|
|
|
|
|
char *p_start = *sp;
|
|
|
|
|
while (1) {
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
if (*p_start == delim[i]) {
|
|
|
|
|
p_start++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i == len) {
|
|
|
|
|
*sp = p_start;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Are we at the end of the string? */
|
|
|
|
|
if (**sp == '\0') {
|
|
|
|
|
*sp = NULL;
|
|
|
|
|
return *sp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find the end of the substring, and
|
|
|
|
|
replace the delimiter with null */
|
|
|
|
|
while (**sp != '\0') {
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
if (**sp == delim[i]) {
|
|
|
|
|
**sp = '\0';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(*sp)++;
|
|
|
|
|
if (i < len) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return p_start;
|
|
|
|
|
}
|
|
|
|
|
|