feat(string): complete string.h + strdup/memccpy

This commit is contained in:
2026-09-03 20:05:49 -04:00
parent 20f514d91c
commit 06d2ec7c34
19 changed files with 1860 additions and 2 deletions
+226 -2
View File
@@ -7,8 +7,14 @@
* String and memory functions, gated by the active compatibility profile
* (see include/vlibc/features.h). Levels are cumulative:
*
* Level 1 (onlyposix): ISO C core — memcpy, memmove, memset, strlen, strcmp.
* Level 2 (muslmimic): BSD extensions — strlcpy, strlcat.
* Level 1 (onlyposix): ISO C core + POSIX.1-2008 base — memcpy, memmove,
* memset, memchr, memcmp, strlen, strnlen, strcmp,
* strncmp, strcpy, strncpy, strcat, strncat, strchr,
* strrchr, strspn, strcspn, strpbrk, strstr, strtok,
* strtok_r, strcoll, strxfrm, strdup, strndup,
* strsignal.
* Level 2 (muslmimic): BSD + XSI extensions — strlcpy, strlcat, stpcpy,
* stpncpy, memccpy, strcoll_l, strxfrm_l.
* Level 3 (muslext): GNU extensions — strcasestr.
*
* This header includes <vlibc/features.h> itself, so the gates below always
@@ -33,6 +39,15 @@ extern "C" {
__attribute__((pure)) size_t
strlen(const char *s);
/*
* Return the length of s, excluding the terminating NUL, examining at most
* maxlen bytes; the result is at most maxlen even when s is not a proper
* NUL-terminated string.
* pure: reads memory, no side effects.
*/
__attribute__((pure)) size_t
strnlen(const char *s, size_t maxlen);
/*
* Compare the strings lhs and rhs; return negative, zero, or positive when
* lhs is less than, equal to, or greater than rhs.
@@ -41,6 +56,24 @@ strlen(const char *s);
__attribute__((pure)) int
strcmp(const char *lhs, const char *rhs);
/*
* Compare at most n bytes of lhs and rhs, stopping early at the first
* difference or the first NUL; return negative, zero, or positive when lhs
* is less than, equal to, or greater than rhs.
* pure: reads memory, no side effects.
*/
__attribute__((pure)) int
strncmp(const char *lhs, const char *rhs, size_t n);
/*
* Compare s1 and s2 under the active locale's collating sequence; return
* negative, zero, or positive. Only the "C" locale exists so far (locales
* are owned by a later todo), where collation is identical to strcmp.
* pure: reads memory, no side effects.
*/
__attribute__((pure)) int
strcoll(const char *s1, const char *s2);
/*
* Copy n bytes from src to dst. The regions must not overlap (restrict).
* No intent attribute: it writes memory.
@@ -63,6 +96,157 @@ memmove(void *dst, const void *src, size_t n);
void *
memset(void *dst, int c, size_t n);
/*
* Return a pointer to the first occurrence of c (converted to unsigned
* char) among the first n bytes of s, or NULL when absent.
* pure: reads memory, no side effects.
*/
__attribute__((pure)) void *
memchr(const void *s, int c, size_t n);
/*
* Compare the first n bytes of lhs and rhs as unsigned char; return
* negative, zero, or positive when lhs is less than, equal to, or greater
* than rhs. Unlike strcmp, a NUL byte does not end the comparison.
* pure: reads memory, no side effects.
*/
__attribute__((pure)) int
memcmp(const void *lhs, const void *rhs, size_t n);
/*
* Copy src to dst, including the terminating NUL; return dst. The strings
* must not overlap (restrict).
* No intent attribute: it writes memory.
*/
char *
strcpy(char *restrict dst, const char *restrict src);
/*
* Copy at most n bytes from src to dst. When src is shorter than n the
* remainder of dst is NUL-padded; when src is n bytes or longer the result
* is not NUL-terminated. Return dst.
* No intent attribute: it writes memory.
*/
char *
strncpy(char *restrict dst, const char *restrict src, size_t n);
/*
* Append src (including its NUL) to the end of dst; return dst. The strings
* must not overlap (restrict).
* No intent attribute: it writes memory.
*/
char *
strcat(char *restrict dst, const char *restrict src);
/*
* Append at most n bytes of src to dst and always NUL-terminate; return
* dst.
* No intent attribute: it writes memory.
*/
char *
strncat(char *restrict dst, const char *restrict src, size_t n);
/*
* Return a pointer to the first occurrence of c (converted to char) in s,
* or NULL when absent. The terminating NUL is part of the string, so
* strchr(s, '\0') returns a pointer to it.
* pure: reads memory, no side effects.
*/
__attribute__((pure)) char *
strchr(const char *s, int c);
/*
* Return a pointer to the last occurrence of c (converted to char) in s, or
* NULL when absent. The terminating NUL is part of the string, so
* strrchr(s, '\0') returns a pointer to it.
* pure: reads memory, no side effects.
*/
__attribute__((pure)) char *
strrchr(const char *s, int c);
/*
* Return the length of the initial span of s consisting entirely of bytes
* that occur in accept.
* pure: reads memory, no side effects.
*/
__attribute__((pure)) size_t
strspn(const char *s, const char *accept);
/*
* Return the length of the initial span of s consisting entirely of bytes
* that do NOT occur in reject.
* pure: reads memory, no side effects.
*/
__attribute__((pure)) size_t
strcspn(const char *s, const char *reject);
/*
* Return a pointer to the first byte in s that also occurs in accept, or
* NULL when none occurs.
* pure: reads memory, no side effects.
*/
__attribute__((pure)) char *
strpbrk(const char *s, const char *accept);
/*
* Return a pointer to the first occurrence of needle in haystack, or NULL
* when absent. An empty needle matches haystack itself.
* pure: reads memory, no side effects.
*/
__attribute__((pure)) char *
strstr(const char *haystack, const char *needle);
/*
* Split s into tokens delimited by any byte from sep. On the first call s
* names the string; subsequent calls with NULL continue the same string.
* Leading and consecutive delimiters produce no empty tokens, and the
* delimiter bytes in s are overwritten with NUL. Returns NULL when no token
* remains. strtok keeps its state in private static storage and is not
* thread-safe; strtok_r keeps it in *state and is.
* No intent attribute: strtok mutates private state, strtok_r writes
* through its parameters.
*/
char *
strtok(char *restrict s, const char *restrict sep);
char *
strtok_r(char *restrict s, const char *restrict sep, char **restrict state);
/*
* Transform src under the active locale's collating sequence so that strcmp
* on transformed strings orders them as strcoll would, storing at most n
* bytes of the result in dst (always NUL-terminated when n > 0; nothing is
* written when n == 0). Return the length of the full transformed string,
* excluding the NUL. In the "C" locale the transformation is the identity
* and the return is strlen(src).
* No intent attribute: it writes memory.
*/
size_t
strxfrm(char *restrict dst, const char *restrict src, size_t n);
/*
* Return a heap copy of s (malloc-allocated; release with free), or NULL
* with errno ENOMEM on allocation failure. strndup copies at most n bytes
* and NUL-terminates, so strndup(s, 0) returns the empty string.
* malloc: returns fresh unaliased storage the caller owns.
*/
__attribute__((malloc)) char *
strdup(const char *s);
__attribute__((malloc)) char *
strndup(const char *s, size_t n);
/*
* Return a pointer to a static string describing the signal sig, or a
* formatted "Unknown signal <sig>" string for unrecognized numbers. Never
* returns NULL; distinct known signals yield distinct strings. The text for
* signal 0 is unspecified by POSIX and deliberately not pinned.
*
* No intent attribute: the unknown-signal path writes shared storage.
*/
char *
strsignal(int sig);
#if VLIBC_LEVEL >= 2
/* Level 2 (muslmimic): BSD extensions. */
@@ -83,6 +267,46 @@ size_t
strlcat(char *dst, const char *src, size_t size);
#endif /* VLIBC_LEVEL >= 2 */
#if VLIBC_LEVEL_GE(2)
/* Level 2 (muslmimic): XSI extensions. */
/*
* strcpy/strncpy variants returning a pointer to the terminating NUL of
* dst: stpcpy to the NUL of the copied string, stpncpy to the first NUL
* written (or to dst + n when no NUL was written).
* No intent attribute: they write memory.
*/
char *
stpcpy(char *restrict dst, const char *restrict src);
char *
stpncpy(char *restrict dst, const char *restrict src, size_t n);
/*
* Copy at most n bytes from src to dst, stopping after the first byte equal
* to c (converted to unsigned char); return a pointer to the byte after c
* in dst when found, NULL otherwise. The regions must not overlap
* (restrict).
* No intent attribute: it writes memory.
*/
void *
memccpy(void *restrict dst, const void *restrict src, int c, size_t n);
/*
* Locale-parameterized XSI variants of strcoll/strxfrm. No locale machinery
* exists yet, so the locale argument is accepted and ignored and behavior
* is the "C" locale behavior of the base functions. The locale parameter is
* typed void * for now: locale_t will be an ABI-identical pointer typedef
* defined by <locale.h>, whose todo updates these signatures to the real
* type.
*/
__attribute__((pure)) int
strcoll_l(const char *s1, const char *s2, void *locale);
size_t
strxfrm_l(char *restrict dst, const char *restrict src, size_t n, void *locale);
#endif /* VLIBC_LEVEL_GE(2) */
#if VLIBC_LEVEL >= 3
/* Level 3 (muslext): GNU extensions. */