diff -r 38800d479cd4 -r e86049631677 ucx/cx/string.h --- a/ucx/cx/string.h Tue Dec 30 21:39:38 2025 +0100 +++ b/ucx/cx/string.h Wed Dec 31 16:41:16 2025 +0100 @@ -41,6 +41,9 @@ #include +/** Convenience macro for creating a null string */ +#define CX_NULLSTR cx_mutstr(NULL) + /** Expands a UCX string as printf arguments. */ #define CX_SFMT(s) (int) (s).length, (s).ptr @@ -156,7 +159,7 @@ * * @see cx_mutstrn() */ -cx_attr_nodiscard cx_attr_cstr_arg(1) +CX_NODISCARD CX_CSTR_ARG(1) CX_INLINE cxmutstr cx_mutstr(char *cstring) { cxmutstr str; str.ptr = cstring; @@ -180,7 +183,7 @@ * * @see cx_mutstr() */ -cx_attr_nodiscard cx_attr_access_rw(1, 2) +CX_NODISCARD CX_ACCESS_RW(1, 2) CX_INLINE cxmutstr cx_mutstrn(char *cstring, size_t length) { cxmutstr str; str.ptr = cstring; @@ -205,7 +208,7 @@ * * @see cx_strn() */ -cx_attr_nodiscard cx_attr_cstr_arg(1) +CX_NODISCARD CX_CSTR_ARG(1) CX_INLINE cxstring cx_str(const char *cstring) { cxstring str; str.ptr = cstring; @@ -230,7 +233,7 @@ * * @see cx_str() */ -cx_attr_nodiscard cx_attr_access_r(1, 2) +CX_NODISCARD CX_ACCESS_R(1, 2) CX_INLINE cxstring cx_strn(const char *cstring, size_t length) { cxstring str; str.ptr = cstring; @@ -239,42 +242,60 @@ } #ifdef __cplusplus -cx_attr_nodiscard -CX_CPPDECL cxstring cx_strcast(cxmutstr str) { - return cx_strn(str.ptr, str.length); +CX_NODISCARD +CX_CPPDECL cxmutstr cx_strcast_m(cxmutstr str) { + return str; } -cx_attr_nodiscard -CX_CPPDECL cxstring cx_strcast(cxstring str) { +CX_NODISCARD +CX_CPPDECL cxstring cx_strcast_m(cxstring str) { return str; } -cx_attr_nodiscard -CX_CPPDECL cxstring cx_strcast(const char *str) { +CX_NODISCARD +CX_CPPDECL cxmutstr cx_strcast_m(char *str) { + return cx_mutstr(str); +} +CX_NODISCARD +CX_CPPDECL cxmutstr cx_strcast_m(unsigned char *str) { + return cx_mutstr(reinterpret_cast(str)); +} +CX_NODISCARD +CX_CPPDECL cxstring cx_strcast_m(const char *str) { return cx_str(str); } -cx_attr_nodiscard -CX_CPPDECL cxstring cx_strcast(const unsigned char *str) { +CX_NODISCARD +CX_CPPDECL cxstring cx_strcast_m(const unsigned char *str) { return cx_str(reinterpret_cast(str)); } -extern "C" { +CX_NODISCARD +CX_CPPDECL cxstring cx_strcast_(cxmutstr str) { + return cx_strn(str.ptr, str.length); +} +CX_NODISCARD +CX_CPPDECL cxstring cx_strcast_(cxstring str) { + return str; +} +#define cx_strcast(s) cx_strcast_(cx_strcast_m(s)) #else /** * Internal function, do not use. * @param str * @return + * @see cx_strcast_m() * @see cx_strcast() */ -cx_attr_nodiscard -CX_INLINE cxstring cx_strcast_m(cxmutstr str) { - return (cxstring) {str.ptr, str.length}; +CX_NODISCARD +CX_INLINE cxmutstr cx_strcast_cxms(cxmutstr str) { + return str; } /** * Internal function, do not use. * @param str * @return + * @see cx_strcast_m() * @see cx_strcast() */ -cx_attr_nodiscard -CX_INLINE cxstring cx_strcast_c(cxstring str) { +CX_NODISCARD +CX_INLINE cxstring cx_strcast_cxs(cxstring str) { return str; } @@ -282,10 +303,35 @@ * Internal function, do not use. * @param str * @return + * @see cx_strcast_m() + * @see cx_strcast() + */ +CX_NODISCARD +CX_INLINE cxmutstr cx_strcast_uc(unsigned char *str) { + return cx_mutstr((char*)str); +} + +/** + * Internal function, do not use. + * @param str + * @return + * @see cx_strcast_m() * @see cx_strcast() */ -cx_attr_nodiscard -CX_INLINE cxstring cx_strcast_u(const unsigned char *str) { +CX_NODISCARD +CX_INLINE cxmutstr cx_strcast_c(char *str) { + return cx_mutstr(str); +} + +/** + * Internal function, do not use. + * @param str + * @return + * @see cx_strcast_m() + * @see cx_strcast() + */ +CX_NODISCARD +CX_INLINE cxstring cx_strcast_ucc(const unsigned char *str) { return cx_str((const char*)str); } @@ -293,10 +339,11 @@ * Internal function, do not use. * @param str * @return + * @see cx_strcast_m() * @see cx_strcast() */ -cx_attr_nodiscard -CX_INLINE cxstring cx_strcast_z(const char *str) { +CX_NODISCARD +CX_INLINE cxstring cx_strcast_cc(const char *str) { return cx_str(str); } @@ -304,18 +351,62 @@ * Wraps any string into an UCX string. * * @param str (any supported string type) the string to cast - * @return (@c cxstring) the string wrapped as UCX string + * @return (@c cxstring) or (@c cxmutstr) the string wrapped as UCX string + */ +#define cx_strcast_m(str) _Generic((str), \ + cxstring: cx_strcast_cxs, \ + cxmutstr: cx_strcast_cxms, \ + const unsigned char*: cx_strcast_ucc, \ + unsigned char *: cx_strcast_uc, \ + const char*: cx_strcast_cc, \ + char *: cx_strcast_c) (str) + +/** + * Internal function, do not use. + * @param str + * @return + */ +CX_INLINE cxstring cx_strcast_1(cxmutstr str) { + return (cxstring){str.ptr, str.length}; +} + +/** + * Internal function, do not use. + * @param str + * @return */ -#define cx_strcast(str) _Generic((str), \ - cxmutstr: cx_strcast_m, \ - cxstring: cx_strcast_c, \ - const unsigned char*: cx_strcast_u, \ - unsigned char *: cx_strcast_u, \ - const char*: cx_strcast_z, \ - char *: cx_strcast_z) (str) +CX_INLINE cxstring cx_strcast_2(cxstring str) { + return str; +} + +/** internal conversion macro */ +#define cx_strcast_(str) _Generic((str), \ + cxmutstr: cx_strcast_1, \ + cxstring: cx_strcast_2)(str) + +/** + * Converts any string to a cxstring. + * + * @param str (any supported string type) the string to cast + * @return he string converted to a (@c cxstring) + */ +#define cx_strcast(str) cx_strcast_(cx_strcast_m(str)) #endif /** + * Casts away constness and converts a cxstring to a cxmutstr. + * For internal use only! + * @param str + * @return + */ +CX_INLINE cxmutstr cx_mutstrcast(cxstring str) { + cxmutstr s; + s.ptr = (char*)str.ptr; + s.length = str.length; + return s; +} + +/** * Passes the pointer in this string to the cxDefaultAllocator's @c free() function. * * The pointer in the struct is set to @c NULL, and the length is set to zero, @@ -327,7 +418,8 @@ * * @param str the string to free */ -CX_EXPORT void cx_strfree(cxmutstr *str); +CX_EXTERN +void cx_strfree(cxmutstr *str); /** * Passes the pointer in this string to the allocator's free function. @@ -342,8 +434,24 @@ * @param alloc the allocator * @param str the string to free */ -cx_attr_nonnull_arg(1) -CX_EXPORT void cx_strfree_a(const CxAllocator *alloc, cxmutstr *str); +CX_EXTERN CX_NONNULL_ARG(1) +void cx_strfree_a(const CxAllocator *alloc, cxmutstr *str); + +/** + * Copies a string. + * + * Internal function - do not use. + * + * @param alloc the allocator + * @param dest a pointer to the structure where to copy the contents to + * @param src the source string + * + * @retval zero success + * @retval non-zero if re-allocation failed + * @see cx_strcpy_a() + */ +CX_EXTERN CX_NONNULL_ARG(1) +int cx_strcpy_a_(const CxAllocator *alloc, cxmutstr *dest, cxstring src); /** * Copies a string. @@ -353,16 +461,13 @@ * * The string in @p dest is guaranteed to be zero-terminated, regardless of whether @p src is. * - * @param alloc the allocator - * @param dest a pointer to the structure where to copy the contents to + * @param alloc (@c CxAllocator*) the allocator + * @param dest (@c cxmutstr*) a pointer to the structure where to copy the contents to * @param src the source string - * * @retval zero success * @retval non-zero if re-allocation failed */ -cx_attr_nonnull_arg(1) -CX_EXPORT int cx_strcpy_a(const CxAllocator *alloc, cxmutstr *dest, cxstring src); - +#define cx_strcpy_a(alloc, dest, src) cx_strcpy_a_(alloc, dest, cx_strcast(src)) /** * Copies a string. @@ -373,8 +478,7 @@ * The string in @p dest is guaranteed to be zero-terminated, regardless of whether @p src is. * * @param dest (@c cxmutstr*) a pointer to the structure where to copy the contents to - * @param src (@c cxstring) the source string - * + * @param src the source string * @retval zero success * @retval non-zero if re-allocation failed */ @@ -392,8 +496,8 @@ * @param ... all strings * @return the accumulated length of all strings */ -cx_attr_nodiscard -CX_EXPORT size_t cx_strlen(size_t count, ...); +CX_EXTERN CX_NODISCARD +size_t cx_strlen(size_t count, ...); /** * Concatenates strings. @@ -404,12 +508,10 @@ * If @p str already contains a string, the memory will be reallocated and * the other strings are appended. Otherwise, new memory is allocated. * - * If memory allocation fails, the pointer in the returned string will - * be @c NULL. Depending on the allocator, @c errno might be set. - * * @note It is guaranteed that there is only one allocation for the * resulting string. * It is also guaranteed that the returned string is zero-terminated. + * If allocation fails, the @c ptr in the returned string will be @c NULL. * * @param alloc the allocator to use * @param str the string the other strings shall be concatenated to @@ -417,92 +519,111 @@ * @param ... all other UCX strings * @return the concatenated string */ -cx_attr_nodiscard cx_attr_nonnull -CX_EXPORT cxmutstr cx_strcat_ma(const CxAllocator *alloc, +CX_EXTERN CX_NONNULL +cxmutstr cx_strcat_a(const CxAllocator *alloc, cxmutstr str, size_t count, ...); /** * Concatenates strings and returns a new string. * - * The resulting string will be allocated by the specified allocator. - * So developers @em must pass the return value to cx_strfree_a() eventually. - * -* If memory allocation fails, the pointer in the returned string will - * be @c NULL. Depending on the allocator, @c errno might be set. - * - * @note It is guaranteed that there is only one allocation for the - * resulting string. - * It is also guaranteed that the returned string is zero-terminated. - * - * @param alloc (@c CxAllocator*) the allocator to use - * @param count (@c size_t) the number of the other following strings to concatenate - * @param ... all other UCX strings - * @return (@c cxmutstr) the concatenated string - */ -#define cx_strcat_a(alloc, count, ...) \ - cx_strcat_ma(alloc, cx_mutstrn(NULL, 0), count, __VA_ARGS__) - -/** - * Concatenates strings and returns a new string. - * * The resulting string will be allocated by the cxDefaultAllocator. * So developers @em must pass the return value to cx_strfree() eventually. * -* If memory allocation fails, the pointer in the returned string will - * be @c NULL and @c errno might be set. - * * @note It is guaranteed that there is only one allocation for the * resulting string. * It is also guaranteed that the returned string is zero-terminated. + * If allocation fails, the @c ptr in the returned string will be @c NULL. * + * @param str (@c cxmutstr*) the string the other strings shall be concatenated to * @param count (@c size_t) the number of the other following strings to concatenate * @param ... all other UCX strings - * @return (@c cxmutstr) the concatenated string + * @return the concatenated string + */ +#define cx_strcat(str, count, ...) \ + cx_strcat_a(cxDefaultAllocator, str, count, __VA_ARGS__) + +/** + * Returns a substring. + * + * Internal function - do not use. + * + * @param string input string + * @param start start location of the substring + * @param length the maximum length of the returned string + * @return a substring of @p string starting at @p start + * @see cx_strsubsl() */ -#define cx_strcat(count, ...) \ - cx_strcat_ma(cxDefaultAllocator, cx_mutstrn(NULL, 0), count, __VA_ARGS__) +CX_EXTERN CX_NODISCARD +cxstring cx_strsubsl_(cxstring string, size_t start, size_t length); + +/** + * Returns a substring. + * + * Internal function - do not use. + * + * @param string input string + * @param start start location of the substring + * @return a substring of @p string starting at @p start + * @see cx_strsubs() + */ +CX_EXTERN CX_NODISCARD +cxstring cx_strsubs_(cxstring string, size_t start); /** - * Concatenates strings. - * - * The resulting string will be allocated by the cxDefaultAllocator. - * So developers @em must pass the return value to cx_strfree() eventually. - * - * If @p str already contains a string, the memory will be reallocated and - * the other strings are appended. Otherwise, new memory is allocated. - * -* If memory allocation fails, the pointer in the returned string will - * be @c NULL and @c errno might be set. - * - * @note It is guaranteed that there is only one allocation for the - * resulting string. - * It is also guaranteed that the returned string is zero-terminated. - * - * @param str (@c cxmutstr) the string the other strings shall be concatenated to - * @param count (@c size_t) the number of the other following strings to concatenate - * @param ... all other strings - * @return (@c cxmutstr) the concatenated string + * Internal conversion function - do not use. + * @param string + * @param start + * @return + */ +CX_INLINE +cxmutstr cx_strsubs_m_(cxmutstr string, size_t start) { + return cx_mutstrcast(cx_strsubs_(cx_strcast(string), start)); +} + +/** + * Internal conversion function - do not use. + * @param string + * @param start + * @param length + * @return */ -#define cx_strcat_m(str, count, ...) \ - cx_strcat_ma(cxDefaultAllocator, str, count, __VA_ARGS__) +CX_INLINE +cxmutstr cx_strsubsl_m_(cxmutstr string, size_t start, size_t length) { + return cx_mutstrcast(cx_strsubsl_(cx_strcast(string), start, length)); +} +#ifdef __cplusplus +CX_CPPDECL cxstring cx_strsubs_cpp_(cxstring string, size_t start) { + return cx_strsubs_(string, start); +} +CX_CPPDECL cxstring cx_strsubsl_cpp_(cxstring string, size_t start, size_t length) { + return cx_strsubsl_(string, start, length); +} +CX_CPPDECL cxmutstr cx_strsubs_cpp_(cxmutstr string, size_t start) { + return cx_strsubs_m_(string, start); +} +CX_CPPDECL cxmutstr cx_strsubsl_cpp_(cxmutstr string, size_t start, size_t length) { + return cx_strsubsl_m_(string, start, length); +} +#define cx_strsubs(string, start) cx_strsubs_cpp_(cx_strcast_m(string), start) +#define cx_strsubsl(string, start, length) cx_strsubsl_cpp_(cx_strcast_m(string), start, length) +#else /** * Returns a substring starting at the specified location. * * @attention the new string references the same memory area as the - * input string and is usually @em not zero-terminated. + * input string and is @em not zero-terminated. * Use cx_strdup() to get a copy. * * @param string input string - * @param start start location of the substring - * @return a substring of @p string starting at @p start + * @param start (@c size_t) start location of the substring + * @return (@c cxstring or @c cxmutstr) a substring of @p string starting at @p start * * @see cx_strsubsl() - * @see cx_strsubs_m() - * @see cx_strsubsl_m() */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strsubs(cxstring string, size_t start); +#define cx_strsubs(string, start) _Generic(cx_strcast_m(string), \ + cxstring: cx_strsubs_, \ + cxmutstr: cx_strsubs_m_)(cx_strcast_m(string), start) /** * Returns a substring starting at the specified location. @@ -520,51 +641,107 @@ * @return a substring of @p string starting at @p start * * @see cx_strsubs() - * @see cx_strsubs_m() - * @see cx_strsubsl_m() + */ +#define cx_strsubsl(string, start, length) _Generic(cx_strcast_m(string), \ + cxstring: cx_strsubsl_, \ + cxmutstr: cx_strsubsl_m_)(cx_strcast_m(string), start, length) +#endif + +/** + * Returns the character at the specified index offset. + * + * Internal function - do not use. + * + * @param str the string + * @param index the index offset + * @return the character at the index + * @see cx_strat() */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strsubsl(cxstring string, size_t start, size_t length); +CX_INLINE +char cx_strat_(cxstring str, off_t index) { + size_t i; + if (index >= 0) { + i = index; + } else { + i = (size_t) (str.length + index); + } + if (i >= str.length) { + return '\0'; + } + return str.ptr[i]; +} + +/** + * Returns the character at the specified index offset. + * + * When the @p index is negative, the character is counted from the end of the + * string where -1 denotes the last character in the string. + * + * When the @p index is out of bounds, the function returns zero. + * + * @param str the string + * @param index the index offset + * @return the character at the index + * @see cx_strat() + */ +#define cx_strat(str, index) cx_strat_(cx_strcast(str), index) /** - * Returns a substring starting at the specified location. - * - * @attention the new string references the same memory area as the - * input string and is usually @em not zero-terminated. - * Use cx_strdup() to get a copy. - * - * @param string input string - * @param start start location of the substring - * @return a substring of @p string starting at @p start - * - * @see cx_strsubsl_m() - * @see cx_strsubs() - * @see cx_strsubsl() + * Searches for a character in a string. + * Internal function - do not use. + * @param string + * @param chr + * @return + * @see cx_strchr() */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strsubs_m(cxmutstr string, size_t start); +CX_EXTERN CX_NODISCARD +cxstring cx_strchr_(cxstring string, int chr); /** - * Returns a substring starting at the specified location. - * - * The returned string will be limited to @p length bytes or the number - * of bytes available in @p string, whichever is smaller. - * - * @attention the new string references the same memory area as the - * input string and is usually @em not zero-terminated. - * Use cx_strdup() to get a copy. - * - * @param string input string - * @param start start location of the substring - * @param length the maximum length of the returned string - * @return a substring of @p string starting at @p start - * - * @see cx_strsubs_m() - * @see cx_strsubs() - * @see cx_strsubsl() + * Searches for a character in a string. + * Internal function - do not use. + * @param string + * @param chr + * @return + * @see cx_strrchr() */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strsubsl_m(cxmutstr string, size_t start, size_t length); +CX_EXTERN CX_NODISCARD +cxstring cx_strrchr_(cxstring string, int chr); + +#ifdef __cplusplus +CX_CPPDECL cxstring cx_strchr_cpp_(cxstring string, int chr) { + return cx_strchr_(string, chr); +} +CX_CPPDECL cxmutstr cx_strchr_cpp_(cxmutstr string, int chr) { + return cx_mutstrcast(cx_strchr_(cx_strcast(string), chr)); +} +#define cx_strchr(s, chr) cx_strchr_cpp_(cx_strcast_m(s), chr) +CX_CPPDECL cxstring cx_strrchr_cpp_(cxstring string, int chr) { + return cx_strrchr_(string, chr); +} +CX_CPPDECL cxmutstr cx_strrchr_cpp_(cxmutstr string, int chr) { + return cx_mutstrcast(cx_strrchr_(cx_strcast(string), chr)); +} +#define cx_strrchr(s, chr) cx_strrchr_cpp_(cx_strcast_m(s), chr) +#else +/** + * Internal conversion function - do not use. + * @param string + * @param chr + * @return + */ +CX_INLINE cxmutstr cx_strchr_m_(cxmutstr string, int chr) { + return cx_mutstrcast(cx_strchr_(cx_strcast(string), chr)); +} +/** + * Internal conversion function - do not use. + * @param string + * @param chr + * @return + */ +CX_INLINE cxmutstr cx_strrchr_m_(cxmutstr string, int chr) { + return cx_mutstrcast(cx_strrchr_(cx_strcast(string), chr)); +} /** * Returns a substring starting at the location of the first occurrence of the @@ -573,28 +750,13 @@ * If the string does not contain the character, an empty string is returned. * * @param string the string where to locate the character - * @param chr the character to locate - * @return a substring starting at the first location of @p chr - * - * @see cx_strchr_m() + * @param chr (@c int) the character to locate + * @return (@c cxstring or @c cxmutstr) a substring starting at the first + * location of @p chr */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strchr(cxstring string, int chr); - -/** - * Returns a substring starting at the location of the first occurrence of the - * specified character. - * - * If the string does not contain the character, an empty string is returned. - * - * @param string the string where to locate the character - * @param chr the character to locate - * @return a substring starting at the first location of @p chr - * - * @see cx_strchr() - */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strchr_m(cxmutstr string, int chr); +#define cx_strchr(string, chr) _Generic(cx_strcast_m(string), \ + cxstring: cx_strchr_, \ + cxmutstr: cx_strchr_m_)(cx_strcast_m(string), chr) /** * Returns a substring starting at the location of the last occurrence of the @@ -603,28 +765,47 @@ * If the string does not contain the character, an empty string is returned. * * @param string the string where to locate the character - * @param chr the character to locate - * @return a substring starting at the last location of @p chr - * - * @see cx_strrchr_m() + * @param chr (@c int) the character to locate + * @return (@c cxstring or @c cxmutstr) a substring starting at the last + * location of @p chr */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strrchr(cxstring string, int chr); +#define cx_strrchr(string, chr) _Generic(cx_strcast_m(string), \ + cxstring: cx_strrchr_, \ + cxmutstr: cx_strrchr_m_)(cx_strcast_m(string), chr) +#endif /** - * Returns a substring starting at the location of the last occurrence of the - * specified character. + * Searches for a specific substring. * - * If the string does not contain the character, an empty string is returned. + * Internal function - do not use. * - * @param string the string where to locate the character - * @param chr the character to locate - * @return a substring starting at the last location of @p chr - * - * @see cx_strrchr() + * @param haystack the string to be scanned + * @param needle string containing the sequence of characters to match + * @return a substring starting at the first occurrence of @p needle, + * or an empty string, if the sequence is not contained + * @see cx_strstr() */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strrchr_m(cxmutstr string, int chr); +CX_EXTERN CX_NODISCARD +cxstring cx_strstr_(cxstring haystack, cxstring needle); + +#ifdef __cplusplus +CX_CPPDECL cxstring cx_strstr_cpp_(cxstring haystack, cxstring needle) { + return cx_strstr_(haystack, needle); +} +CX_CPPDECL cxmutstr cx_strstr_cpp_(cxmutstr haystack, cxstring needle) { + return cx_mutstrcast(cx_strstr_(cx_strcast(haystack), needle)); +} +#define cx_strstr(h,n) cx_strstr_cpp_(cx_strcast_m(h), cx_strcast(n)) +#else +/** + * Internal conversion - do not use. + * @param haystack + * @param needle + * @return + */ +CX_INLINE cxmutstr cx_strstr_m_(cxmutstr haystack, cxstring needle) { + return cx_mutstrcast(cx_strstr_(cx_strcast(haystack), needle)); +} /** * Returns a substring starting at the location of the first occurrence of the @@ -636,34 +817,106 @@ * returned. * * @param haystack the string to be scanned - * @param needle string containing the sequence of characters to match - * @return a substring starting at the first occurrence of - * @p needle, or an empty string, if the sequence is not - * contained - * @see cx_strstr_m() + * @param needle string containing the sequence of characters to match + * @return (@c cxstring or @c cxmutstr) a substring starting at the first + * occurrence of @p needle, or an empty string, if the sequence is not contained + */ +#define cx_strstr(haystack, needle) _Generic(cx_strcast_m(haystack), \ + cxstring: cx_strstr_,\ + cxmutstr: cx_strstr_m_)(cx_strcast_m(haystack), cx_strcast(needle)) +#endif + +/** + * Splits a given string using a delimiter string. + * + * Internal function - do not use. + * + * @param string the string to split + * @param delim the delimiter + * @param limit the maximum number of split items + * @param output the output array + * @return the actual number of split items + * @see cx_strsplit() */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strstr(cxstring haystack, cxstring needle); +CX_EXTERN CX_NODISCARD CX_NONNULL CX_ACCESS_W(4, 3) +size_t cx_strsplit_(cxstring string, cxstring delim, + size_t limit, cxstring *output); + +/** + * Splits a given string using a delimiter string. + * + * Internal function - do not use. + * + * @param allocator the allocator to use for allocating the resulting array + * @param string the string to split + * @param delim the delimiter + * @param limit the maximum number of split items + * @param output the output array + * @return the actual number of split items + * @see cx_strsplit_a() + */ +CX_EXTERN CX_NODISCARD CX_NONNULL CX_ACCESS_W(5) +size_t cx_strsplit_a_(const CxAllocator *allocator, + cxstring string, cxstring delim, + size_t limit, cxstring **output); + /** - * Returns a substring starting at the location of the first occurrence of the - * specified string. + * Splits a given string using a delimiter string. + * + * Internal function - do not use. * - * If @p haystack does not contain @p needle, an empty string is returned. + * @param string the string to split + * @param delim the delimiter + * @param limit the maximum number of split items + * @param output the output array + * @return the actual number of split items + * @see cx_strsplit_m() + */ +CX_EXTERN CX_NODISCARD CX_NONNULL CX_ACCESS_W(4, 3) +size_t cx_strsplit_m_(cxmutstr string, cxstring delim, + size_t limit, cxmutstr *output); + +/** + * Splits a given string using a delimiter string. * - * If @p needle is an empty string, the complete @p haystack is - * returned. + * Internal function - do not use. * - * @param haystack the string to be scanned - * @param needle string containing the sequence of characters to match - * @return a substring starting at the first occurrence of - * @p needle, or an empty string, if the sequence is not - * contained - * @see cx_strstr() + * @param allocator the allocator to use for allocating the resulting array + * @param string the string to split + * @param delim the delimiter + * @param limit the maximum number of split items + * @param output the output array + * @return the actual number of split items + * @see cx_strsplit_ma() */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strstr_m(cxmutstr haystack, cxstring needle); +CX_EXTERN CX_NODISCARD CX_NONNULL CX_ACCESS_W(5) +size_t cx_strsplit_ma_(const CxAllocator *allocator, + cxmutstr string, cxstring delim, size_t limit, + cxmutstr **output); +#ifdef __cplusplus +CX_CPPDECL size_t cx_strsplit_cpp_(cxstring string, cxstring delim, + size_t limit, cxstring *output) { + return cx_strsplit_(string, delim, limit, output); +} +CX_CPPDECL size_t cx_strsplit_cpp_(cxmutstr string, cxstring delim, + size_t limit, cxmutstr *output) { + return cx_strsplit_m_(string, delim, limit, output); +} +CX_CPPDECL size_t cx_strsplit_a_cpp_(const CxAllocator *allocator, + cxstring string, cxstring delim, size_t limit, cxstring **output) { + return cx_strsplit_a_(allocator, string, delim, limit, output); +} +CX_CPPDECL size_t cx_strsplit_a_cpp_(const CxAllocator *allocator, + cxmutstr string, cxstring delim, size_t limit, cxmutstr **output) { + return cx_strsplit_ma_(allocator, string, delim, limit, output); +} +#define cx_strsplit(string, delim, limit, output) \ + cx_strsplit_cpp_(cx_strcast_m(string), cx_strcast(delim), limit, output) +#define cx_strsplit_a(allocator, string, delim, limit, output) \ + cx_strsplit_a_cpp_(allocator, cx_strcast_m(string), cx_strcast(delim), limit, output) +#else /** * Splits a given string using a delimiter string. * @@ -671,14 +924,17 @@ * @p string. Use cx_strdup() to get copies. * * @param string the string to split - * @param delim the delimiter - * @param limit the maximum number of split items - * @param output a preallocated array of at least @p limit length + * @param delim the delimiter + * @param limit (@c size_t) the maximum number of split items + * @param output (@c cxstring* or @c cxmutstr*) a preallocated array of at + * least @p limit length * @return the actual number of split items */ -cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(4, 3) -CX_EXPORT size_t cx_strsplit(cxstring string, cxstring delim, - size_t limit, cxstring *output); +#define cx_strsplit(string, delim, limit, output) \ + _Generic(cx_strcast_m(string), \ + cxstring: cx_strsplit_, \ + cxmutstr: cx_strsplit_m_)\ + (cx_strcast_m(string), cx_strcast(delim), limit, output) /** * Splits a given string using a delimiter string. @@ -691,59 +947,20 @@ * @attention If allocation fails, the @c NULL pointer will be written to * @p output and the number returned will be zero. * - * @param allocator the allocator to use for allocating the resulting array + * @param allocator (@c CxAllocator*) the allocator to use for allocating the resulting array * @param string the string to split * @param delim the delimiter - * @param limit the maximum number of split items - * @param output a pointer where the address of the allocated array shall be - * written to - * @return the actual number of split items - */ -cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(5) -CX_EXPORT size_t cx_strsplit_a(const CxAllocator *allocator, - cxstring string, cxstring delim, - size_t limit, cxstring **output); - - -/** - * Splits a given string using a delimiter string. - * - * @note The resulting array contains strings that point to the source - * @p string. Use cx_strdup() to get copies. - * - * @param string the string to split - * @param delim the delimiter - * @param limit the maximum number of split items - * @param output a preallocated array of at least @p limit length + * @param limit (@c size_t) the maximum number of split items + * @param output (@c cxstring** or @c cxmutstr**) a pointer where the address + * of the allocated array shall be written to * @return the actual number of split items */ -cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(4, 3) -CX_EXPORT size_t cx_strsplit_m(cxmutstr string, cxstring delim, - size_t limit, cxmutstr *output); - -/** - * Splits a given string using a delimiter string. - * - * The array pointed to by @p output will be allocated by @p allocator. - * - * @note The resulting array contains strings that point to the source - * @p string. Use cx_strdup() to get copies. - * - * @attention If allocation fails, the @c NULL pointer will be written to - * @p output and the number returned will be zero. - * - * @param allocator the allocator to use for allocating the resulting array - * @param string the string to split - * @param delim the delimiter - * @param limit the maximum number of split items - * @param output a pointer where the address of the allocated array shall be - * written to - * @return the actual number of split items - */ -cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(5) -CX_EXPORT size_t cx_strsplit_ma(const CxAllocator *allocator, - cxmutstr string, cxstring delim, size_t limit, - cxmutstr **output); +#define cx_strsplit_a(allocator, string, delim, limit, output) \ + _Generic(cx_strcast_m(string), \ + cxstring: cx_strsplit_a_, \ + cxmutstr: cx_strsplit_ma_)\ + (allocator, cx_strcast_m(string), cx_strcast(delim), limit, output) +#endif /** * Compares two strings. @@ -753,8 +970,8 @@ * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger * than @p s2, zero if both strings equal */ -cx_attr_nodiscard -CX_EXPORT int cx_strcmp_(cxstring s1, cxstring s2); +CX_EXTERN CX_NODISCARD +int cx_strcmp_(cxstring s1, cxstring s2); /** * Compares two strings. @@ -774,8 +991,8 @@ * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger * than @p s2, zero if both strings equal ignoring case */ -cx_attr_nodiscard -CX_EXPORT int cx_strcasecmp_(cxstring s1, cxstring s2); +CX_EXTERN CX_NODISCARD +int cx_strcasecmp_(cxstring s1, cxstring s2); /** * Compares two strings ignoring case. @@ -800,8 +1017,8 @@ * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger * than @p s2, zero if both strings equal */ -cx_attr_nodiscard cx_attr_nonnull -CX_EXPORT int cx_strcmp_p(const void *s1, const void *s2); +CX_EXTERN CX_NODISCARD CX_NONNULL +int cx_strcmp_p(const void *s1, const void *s2); /** * Compares two strings ignoring case. @@ -813,9 +1030,8 @@ * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger * than @p s2, zero if both strings equal ignoring case */ -cx_attr_nodiscard cx_attr_nonnull -CX_EXPORT int cx_strcasecmp_p(const void *s1, const void *s2); - +CX_EXTERN CX_NODISCARD CX_NONNULL +int cx_strcasecmp_p(const void *s1, const void *s2); /** * Creates a duplicate of the specified string. @@ -829,8 +1045,8 @@ * @return a duplicate of the string * @see cx_strdup() */ -cx_attr_nodiscard cx_attr_nonnull -CX_EXPORT cxmutstr cx_strdup_a_(const CxAllocator *allocator, cxstring string); +CX_EXTERN CX_NODISCARD CX_NONNULL +cxmutstr cx_strdup_a_(const CxAllocator *allocator, cxstring string); /** * Creates a duplicate of the specified string. @@ -863,16 +1079,31 @@ #define cx_strdup(string) cx_strdup_a(cxDefaultAllocator, string) /** - * Omits leading and trailing spaces. - * - * @note the returned string references the same memory, thus you - * must @em not free the returned memory. - * - * @param string the string that shall be trimmed - * @return the trimmed string + * Trims a string. + * Internal function - do not use. + * @param string + * @return */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strtrim(cxstring string); +CX_EXTERN CX_NODISCARD +cxstring cx_strtrim_(cxstring string); + +#ifdef __cplusplus +CX_CPPDECL cxstring cx_strtrim_cpp_(cxstring string) { + return cx_strtrim_(string); +} +CX_CPPDECL cxmutstr cx_strtrim_cpp_(cxmutstr string) { + return cx_mutstrcast(cx_strtrim_(cx_strcast(string))); +} +#define cx_strtrim(string) cx_strtrim_cpp_(cx_strcast_m(string)) +#else +/** + * Internal conversion function. + * @param string + * @return + */ +CX_INLINE cxmutstr cx_strtrim_m_(cxmutstr string) { + return cx_mutstrcast(cx_strtrim_(cx_strcast(string))); +} /** * Omits leading and trailing spaces. @@ -881,10 +1112,12 @@ * must @em not free the returned memory. * * @param string the string that shall be trimmed - * @return the trimmed string + * @return (@c cxstring or @c cxmutstr) the trimmed string */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strtrim_m(cxmutstr string); +#define cx_strtrim(string) _Generic(cx_strcast_m(string), \ + cxstring: cx_strtrim_, \ + cxmutstr: cx_strtrim_m_)(cx_strcast_m(string)) +#endif /** * Checks if a string has a specific prefix. @@ -894,8 +1127,8 @@ * @return @c true, if and only if the string has the specified prefix, * @c false otherwise */ -cx_attr_nodiscard -CX_EXPORT bool cx_strprefix_(cxstring string, cxstring prefix); +CX_EXTERN CX_NODISCARD +bool cx_strprefix_(cxstring string, cxstring prefix); /** * Checks if a string has a specific prefix. @@ -915,8 +1148,8 @@ * @return @c true, if and only if the string has the specified suffix, * @c false otherwise */ -cx_attr_nodiscard -CX_EXPORT bool cx_strsuffix_(cxstring string, cxstring suffix); +CX_EXTERN CX_NODISCARD +bool cx_strsuffix_(cxstring string, cxstring suffix); /** * Checks if a string has a specific suffix. @@ -936,8 +1169,8 @@ * @return @c true, if and only if the string has the specified prefix, * @c false otherwise */ -cx_attr_nodiscard -CX_EXPORT bool cx_strcaseprefix_(cxstring string, cxstring prefix); +CX_EXTERN CX_NODISCARD +bool cx_strcaseprefix_(cxstring string, cxstring prefix); /** * Checks if a string has a specific prefix, ignoring the case. @@ -957,8 +1190,8 @@ * @return @c true, if and only if the string has the specified suffix, * @c false otherwise */ -cx_attr_nodiscard -CX_EXPORT bool cx_strcasesuffix_(cxstring string, cxstring suffix); +CX_EXTERN CX_NODISCARD +bool cx_strcasesuffix_(cxstring string, cxstring suffix); /** * Checks, if a string has a specific suffix, ignoring the case. @@ -973,6 +1206,26 @@ /** * Replaces a string with another string. * + * Internal function - do not use. + * + * @param allocator + * @param str + * @param search + * @param replacement + * @param replmax + * @return + * @see cx_strreplace_a() + * @see cx_strreplace() + * @see cx_strreplacen_a() + * @see cx_strreplacen() + */ +CX_EXTERN CX_NODISCARD CX_NONNULL +cxmutstr cx_strreplace_(const CxAllocator *allocator, + cxstring str, cxstring search, cxstring replacement, size_t replmax); + +/** + * Replaces a string with another string. + * * The function replaces at most @p replmax occurrences. * * The returned string will be allocated by @p allocator and is guaranteed @@ -981,16 +1234,15 @@ * If allocation fails, or the input string is empty, * the returned string will be empty. * - * @param allocator the allocator to use + * @param allocator (@c CxAllocator*) the allocator to use * @param str the string where replacements should be applied * @param search the string to search for * @param replacement the replacement string - * @param replmax maximum number of replacements - * @return the resulting string after applying the replacements + * @param replmax (@c size_t) maximum number of replacements + * @return (@c cxmutstr) the resulting string after applying the replacements */ -cx_attr_nodiscard cx_attr_nonnull -CX_EXPORT cxmutstr cx_strreplacen_a(const CxAllocator *allocator, - cxstring str, cxstring search, cxstring replacement, size_t replmax); +#define cx_strreplacen_a(allocator, str, search, replacement, replmax) \ + cx_strreplace_(allocator, cx_strcast(str), cx_strcast(search), cx_strcast(replacement), replmax) /** * Replaces a string with another string. @@ -1003,9 +1255,9 @@ * If allocation fails, or the input string is empty, * the returned string will be empty. * - * @param str (@c cxstring) the string where replacements should be applied - * @param search (@c cxstring) the string to search for - * @param replacement (@c cxstring) the replacement string + * @param str the string where replacements should be applied + * @param search the string to search for + * @param replacement the replacement string * @param replmax (@c size_t) maximum number of replacements * @return (@c cxmutstr) the resulting string after applying the replacements */ @@ -1022,9 +1274,9 @@ * the returned string will be empty. * * @param allocator (@c CxAllocator*) the allocator to use - * @param str (@c cxstring) the string where replacements should be applied - * @param search (@c cxstring) the string to search for - * @param replacement (@c cxstring) the replacement string + * @param str the string where replacements should be applied + * @param search the string to search for + * @param replacement the replacement string * @return (@c cxmutstr) the resulting string after applying the replacements */ #define cx_strreplace_a(allocator, str, search, replacement) \ @@ -1039,9 +1291,9 @@ * If allocation fails, or the input string is empty, * the returned string will be empty. * - * @param str (@c cxstring) the string where replacements should be applied - * @param search (@c cxstring) the string to search for - * @param replacement (@c cxstring) the replacement string + * @param str the string where replacements should be applied + * @param search the string to search for + * @param replacement the replacement string * @return (@c cxmutstr) the resulting string after applying the replacements */ #define cx_strreplace(str, search, replacement) \ @@ -1055,8 +1307,8 @@ * @param limit the maximum number of tokens that shall be returned * @return a new string tokenization context */ -cx_attr_nodiscard -CX_EXPORT CxStrtokCtx cx_strtok_(cxstring str, cxstring delim, size_t limit); +CX_EXTERN CX_NODISCARD +CxStrtokCtx cx_strtok_(cxstring str, cxstring delim, size_t limit); /** * Creates a string tokenization context. @@ -1079,25 +1331,34 @@ * @return true if successful, false if the limit or the end of the string * has been reached */ -cx_attr_nonnull cx_attr_nodiscard cx_attr_access_w(2) -CX_EXPORT bool cx_strtok_next(CxStrtokCtx *ctx, cxstring *token); +CX_EXTERN CX_NONNULL CX_NODISCARD CX_ACCESS_W(2) +bool cx_strtok_next_(CxStrtokCtx *ctx, cxstring *token); +#ifdef __cplusplus +CX_CPPDECL cx_strtok_next(CxStrtokCtx *ctx, cxstring *token) { + return cx_strtok_next_(ctx, token); +} +CX_CPPDECL cx_strtok_next(CxStrtokCtx *ctx, cxmutstr *token) { + // Note: this is actually UB - fixed with start_lifetime_as() in C++23 + // but it works on all supported platforms + return cx_strtok_next_(ctx, reinterpret_cast(token)); +} +#else // ! __cplusplus /** - * Returns the next token of a mutable string. + * Returns the next token. * * The token will point to the source string. * - * @attention - * If the context was not initialized over a mutable string, modifying - * the data of the returned token is undefined behavior. - * - * @param ctx the tokenization context - * @param token a pointer to memory where the next token shall be stored + * @param ctx (@c CxStrtokCtx*) the tokenization context + * @param token a pointer to either a @c cxstring or @c cxmutstr + * where the next token shall be stored * @return true if successful, false if the limit or the end of the string * has been reached */ -cx_attr_nonnull cx_attr_nodiscard cx_attr_access_w(2) -CX_EXPORT bool cx_strtok_next_m(CxStrtokCtx *ctx, cxmutstr *token); +#define cx_strtok_next(ctx, token) _Generic((token), \ + cxstring*: cx_strtok_next_, \ + cxmutstr*: cx_strtok_next_)(ctx, (cxstring*)token) +#endif /** * Defines an array of more delimiters for the specified tokenization context. @@ -1106,8 +1367,8 @@ * @param delim array of more delimiters * @param count number of elements in the array */ -cx_attr_nonnull cx_attr_access_r(2, 3) -CX_EXPORT void cx_strtok_delim(CxStrtokCtx *ctx, const cxstring *delim, size_t count); +CX_EXTERN CX_NONNULL CX_ACCESS_R(2, 3) +void cx_strtok_delim(CxStrtokCtx *ctx, const cxstring *delim, size_t count); /* ------------------------------------------------------------------------- * * string to number conversion functions * @@ -1127,8 +1388,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtos_lc_(cxstring str, short *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtos_lc_(cxstring str, short *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1144,8 +1405,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoi_lc_(cxstring str, int *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoi_lc_(cxstring str, int *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1161,8 +1422,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtol_lc_(cxstring str, long *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtol_lc_(cxstring str, long *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1178,8 +1439,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoll_lc_(cxstring str, long long *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoll_lc_(cxstring str, long long *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1195,8 +1456,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoi8_lc_(cxstring str, int8_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoi8_lc_(cxstring str, int8_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1212,8 +1473,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoi16_lc_(cxstring str, int16_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoi16_lc_(cxstring str, int16_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1229,8 +1490,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoi32_lc_(cxstring str, int32_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoi32_lc_(cxstring str, int32_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1246,8 +1507,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoi64_lc_(cxstring str, int64_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoi64_lc_(cxstring str, int64_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1263,8 +1524,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtous_lc_(cxstring str, unsigned short *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtous_lc_(cxstring str, unsigned short *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1280,8 +1541,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtou_lc_(cxstring str, unsigned int *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtou_lc_(cxstring str, unsigned int *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1297,8 +1558,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoul_lc_(cxstring str, unsigned long *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoul_lc_(cxstring str, unsigned long *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1314,8 +1575,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoull_lc_(cxstring str, unsigned long long *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoull_lc_(cxstring str, unsigned long long *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1331,8 +1592,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtou8_lc_(cxstring str, uint8_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtou8_lc_(cxstring str, uint8_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1348,8 +1609,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtou16_lc_(cxstring str, uint16_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtou16_lc_(cxstring str, uint16_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1365,8 +1626,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtou32_lc_(cxstring str, uint32_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtou32_lc_(cxstring str, uint32_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1382,8 +1643,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtou64_lc_(cxstring str, uint64_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtou64_lc_(cxstring str, uint64_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1399,8 +1660,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoz_lc_(cxstring str, size_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoz_lc_(cxstring str, size_t *output, int base, const char *groupsep); /** * Converts a string to a single precision floating-point number. @@ -1416,8 +1677,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtof_lc_(cxstring str, float *output, char decsep, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtof_lc_(cxstring str, float *output, char decsep, const char *groupsep); /** * Converts a string to a double precision floating-point number. @@ -1433,8 +1694,8 @@ * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupsep); /** * Converts a string to a number. @@ -2080,8 +2341,4 @@ */ #define cx_strtod(str, output) cx_strtod_lc_(cx_strcast(str), output, '.', ",") -#ifdef __cplusplus -} // extern "C" -#endif - #endif //UCX_STRING_H