--- a/ucx/cx/string.h Sun Jan 05 17:41:39 2025 +0100 +++ b/ucx/cx/string.h Sun Jan 05 22:00:39 2025 +0100 @@ -26,11 +26,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ /** - * \file string.h - * \brief Strings that know their length. - * \author Mike Becker - * \author Olaf Wintermann - * \copyright 2-Clause BSD License + * @file string.h + * @brief Strings that know their length. + * @author Mike Becker + * @author Olaf Wintermann + * @copyright 2-Clause BSD License */ #ifndef UCX_STRING_H @@ -42,7 +42,7 @@ /** * The maximum length of the "needle" in cx_strstr() that can use SBO. */ -extern unsigned const cx_strstr_sbo_size; +extern const unsigned cx_strstr_sbo_size; /** * The UCX string structure. @@ -50,7 +50,7 @@ struct cx_mutstr_s { /** * A pointer to the string. - * \note The string is not necessarily \c NULL terminated. + * @note The string is not necessarily @c NULL terminated. * Always use the length. */ char *ptr; @@ -69,7 +69,7 @@ struct cx_string_s { /** * A pointer to the immutable string. - * \note The string is not necessarily \c NULL terminated. + * @note The string is not necessarily @c NULL terminated. * Always use the length. */ const char *ptr; @@ -148,7 +148,7 @@ /** * A literal initializer for an UCX string structure. * - * The argument MUST be a string (const char*) \em literal. + * The argument MUST be a string (const char*) @em literal. * * @param literal the string literal */ @@ -160,9 +160,9 @@ /** * Wraps a mutable string that must be zero-terminated. * - * The length is implicitly inferred by using a call to \c strlen(). + * The length is implicitly inferred by using a call to @c strlen(). * - * \note the wrapped string will share the specified pointer to the string. + * @note the wrapped string will share the specified pointer to the string. * If you do want a copy, use cx_strdup() on the return value of this function. * * If you need to wrap a constant string, use cx_str(). @@ -172,26 +172,29 @@ * * @see cx_mutstrn() */ -__attribute__((__warn_unused_result__, __nonnull__)) +cx_attr_nonnull +cx_attr_nodiscard +cx_attr_cstr_arg(1) cxmutstr cx_mutstr(char *cstring); /** * Wraps a string that does not need to be zero-terminated. * - * The argument may be \c NULL if the length is zero. + * The argument may be @c NULL if the length is zero. * - * \note the wrapped string will share the specified pointer to the string. + * @note the wrapped string will share the specified pointer to the string. * If you do want a copy, use cx_strdup() on the return value of this function. * * If you need to wrap a constant string, use cx_strn(). * - * @param cstring the string to wrap (or \c NULL, only if the length is zero) + * @param cstring the string to wrap (or @c NULL, only if the length is zero) * @param length the length of the string * @return the wrapped string * * @see cx_mutstr() */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard +cx_attr_access_rw(1, 2) cxmutstr cx_mutstrn( char *cstring, size_t length @@ -200,9 +203,9 @@ /** * Wraps a string that must be zero-terminated. * - * The length is implicitly inferred by using a call to \c strlen(). + * The length is implicitly inferred by using a call to @c strlen(). * - * \note the wrapped string will share the specified pointer to the string. + * @note the wrapped string will share the specified pointer to the string. * If you do want a copy, use cx_strdup() on the return value of this function. * * If you need to wrap a non-constant string, use cx_mutstr(). @@ -212,72 +215,112 @@ * * @see cx_strn() */ -__attribute__((__warn_unused_result__, __nonnull__)) +cx_attr_nonnull +cx_attr_nodiscard +cx_attr_cstr_arg(1) cxstring cx_str(const char *cstring); /** * Wraps a string that does not need to be zero-terminated. * - * The argument may be \c NULL if the length is zero. + * The argument may be @c NULL if the length is zero. * - * \note the wrapped string will share the specified pointer to the string. + * @note the wrapped string will share the specified pointer to the string. * If you do want a copy, use cx_strdup() on the return value of this function. * * If you need to wrap a non-constant string, use cx_mutstrn(). * - * @param cstring the string to wrap (or \c NULL, only if the length is zero) + * @param cstring the string to wrap (or @c NULL, only if the length is zero) * @param length the length of the string * @return the wrapped string * * @see cx_str() */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard +cx_attr_access_r(1, 2) cxstring cx_strn( const char *cstring, size_t length ); +#ifdef __cplusplus +} // extern "C" +cx_attr_nodiscard +static inline cxstring cx_strcast(cxmutstr str) { + return cx_strn(str.ptr, str.length); +} +cx_attr_nodiscard +static inline cxstring cx_strcast(cxstring str) { + return str; +} +extern "C" { +#else +/** + * Internal function, do not use. + * @param str + * @return + * @see cx_strcast() + */ +cx_attr_nodiscard +static inline cxstring cx_strcast_m(cxmutstr str) { + return (cxstring) {str.ptr, str.length}; +} +/** + * Internal function, do not use. + * @param str + * @return + * @see cx_strcast() + */ +cx_attr_nodiscard +static inline cxstring cx_strcast_c(cxstring str) { + return str; +} + /** * Casts a mutable string to an immutable string. * -* \note This is not seriously a cast. Instead you get a copy +* Does nothing for already immutable strings. +* +* @note This is not seriously a cast. Instead, you get a copy * of the struct with the desired pointer type. Both structs still * point to the same location, though! * -* @param str the mutable string to cast -* @return an immutable copy of the string pointer +* @param str (@c cxstring or @c cxmutstr) the string to cast +* @return (@c cxstring) an immutable copy of the string pointer */ -__attribute__((__warn_unused_result__)) -cxstring cx_strcast(cxmutstr str); +#define cx_strcast(str) _Generic((str), \ + cxmutstr: cx_strcast_m, \ + cxstring: cx_strcast_c) \ + (str) +#endif /** - * Passes the pointer in this string to \c free(). + * Passes the pointer in this string to @c free(). * - * The pointer in the struct is set to \c NULL and the length is set to zero. + * The pointer in the struct is set to @c NULL and the length is set to zero. * - * \note There is no implementation for cxstring, because it is unlikely that + * @note There is no implementation for cxstring, because it is unlikely that * you ever have a <code>const char*</code> you are really supposed to free. * If you encounter such situation, you should double-check your code. * * @param str the string to free */ -__attribute__((__nonnull__)) void cx_strfree(cxmutstr *str); /** * Passes the pointer in this string to the allocators free function. * - * The pointer in the struct is set to \c NULL and the length is set to zero. + * The pointer in the struct is set to @c NULL and the length is set to zero. * - * \note There is no implementation for cxstring, because it is unlikely that + * @note There is no implementation for cxstring, because it is unlikely that * you ever have a <code>const char*</code> you are really supposed to free. * If you encounter such situation, you should double-check your code. * * @param alloc the allocator * @param str the string to free */ -__attribute__((__nonnull__)) +cx_attr_nonnull_arg(1) void cx_strfree_a( const CxAllocator *alloc, cxmutstr *str @@ -285,15 +328,17 @@ /** * Returns the accumulated length of all specified strings. + * + * If this sum overflows, errno is set to EOVERFLOW. * - * \attention if the count argument is larger than the number of the + * @attention if the count argument is larger than the number of the * specified strings, the behavior is undefined. * * @param count the total number of specified strings * @param ... all strings * @return the accumulated length of all strings */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard size_t cx_strlen( size_t count, ... @@ -303,21 +348,26 @@ * Concatenates strings. * * The resulting string will be allocated by the specified allocator. - * So developers \em must pass the return value to cx_strfree_a() eventually. + * So developers @em must pass the return value to cx_strfree_a() eventually. * - * If \p str already contains a string, the memory will be reallocated and + * If @p str already contains a string, the memory will be reallocated and * the other strings are appended. Otherwise, new memory is allocated. * - * \note It is guaranteed that there is only one allocation. + * 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 the allocator to use * @param str the string the other strings shall be concatenated to * @param count the number of the other following strings to concatenate - * @param ... all other strings + * @param ... all other UCX strings * @return the concatenated string */ -__attribute__((__warn_unused_result__, __nonnull__)) +cx_attr_nodiscard +cx_attr_nonnull cxmutstr cx_strcat_ma( const CxAllocator *alloc, cxmutstr str, @@ -329,15 +379,19 @@ * 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. + * So developers @em must pass the return value to cx_strfree_a() eventually. * - * \note It is guaranteed that there is only one allocation. +* 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 the allocator to use - * @param count the number of the other following strings to concatenate - * @param ... all other strings - * @return the concatenated string + * @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__) @@ -345,15 +399,19 @@ /** * Concatenates strings and returns a new string. * - * The resulting string will be allocated by standard \c malloc(). - * So developers \em must pass the return value to cx_strfree() eventually. + * The resulting string will be allocated by standard @c malloc(). + * So developers @em must pass the return value to cx_strfree() eventually. * - * \note It is guaranteed that there is only one allocation. +* 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 count the number of the other following strings to concatenate - * @param ... all other strings - * @return the concatenated string + * @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(count, ...) \ cx_strcat_ma(cxDefaultAllocator, cx_mutstrn(NULL, 0), count, __VA_ARGS__) @@ -361,19 +419,23 @@ /** * Concatenates strings. * - * The resulting string will be allocated by standard \c malloc(). - * So developers \em must pass the return value to cx_strfree() eventually. + * The resulting string will be allocated by standard @c malloc(). + * 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 + * If @p str already contains a string, the memory will be reallocated and * the other strings are appended. Otherwise, new memory is allocated. * - * \note It is guaranteed that there is only one allocation. +* 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 the string the other strings shall be concatenated to - * @param count the number of the other following strings to concatenate - * @param ... all other strings - * @return the concatenated string + * @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 */ #define cx_strcat_m(str, count, ...) \ cx_strcat_ma(cxDefaultAllocator, str, count, __VA_ARGS__) @@ -381,19 +443,19 @@ /** * 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. + * @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 + * @return a substring of @p string starting at @p start * * @see cx_strsubsl() * @see cx_strsubs_m() * @see cx_strsubsl_m() */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard cxstring cx_strsubs( cxstring string, size_t start @@ -402,23 +464,23 @@ /** * 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. + * 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. + * @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 + * @return a substring of @p string starting at @p start * * @see cx_strsubs() * @see cx_strsubs_m() * @see cx_strsubsl_m() */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard cxstring cx_strsubsl( cxstring string, size_t start, @@ -428,19 +490,19 @@ /** * 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. + * @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 + * @return a substring of @p string starting at @p start * * @see cx_strsubsl_m() * @see cx_strsubs() * @see cx_strsubsl() */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard cxmutstr cx_strsubs_m( cxmutstr string, size_t start @@ -449,23 +511,23 @@ /** * 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. + * 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. + * @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 + * @return a substring of @p string starting at @p start * * @see cx_strsubs_m() * @see cx_strsubs() * @see cx_strsubsl() */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard cxmutstr cx_strsubsl_m( cxmutstr string, size_t start, @@ -480,11 +542,11 @@ * * @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 + * @return a substring starting at the first location of @p chr * * @see cx_strchr_m() */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard cxstring cx_strchr( cxstring string, int chr @@ -498,11 +560,11 @@ * * @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 + * @return a substring starting at the first location of @p chr * * @see cx_strchr() */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard cxmutstr cx_strchr_m( cxmutstr string, int chr @@ -516,11 +578,11 @@ * * @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 + * @return a substring starting at the last location of @p chr * * @see cx_strrchr_m() */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard cxstring cx_strrchr( cxstring string, int chr @@ -534,11 +596,11 @@ * * @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 + * @return a substring starting at the last location of @p chr * * @see cx_strrchr() */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard cxmutstr cx_strrchr_m( cxmutstr string, int chr @@ -548,19 +610,19 @@ * Returns a substring starting at the location of the first occurrence of the * specified string. * - * If \p haystack does not contain \p needle, an empty string is returned. + * If @p haystack does not contain @p needle, an empty string is returned. * - * If \p needle is an empty string, the complete \p haystack is + * If @p needle is an empty string, the complete @p haystack is * 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 + * @p needle, or an empty string, if the sequence is not * contained * @see cx_strstr_m() */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard cxstring cx_strstr( cxstring haystack, cxstring needle @@ -570,19 +632,19 @@ * Returns a substring starting at the location of the first occurrence of the * specified string. * - * If \p haystack does not contain \p needle, an empty string is returned. + * If @p haystack does not contain @p needle, an empty string is returned. * - * If \p needle is an empty string, the complete \p haystack is + * If @p needle is an empty string, the complete @p haystack is * 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 + * @p needle, or an empty string, if the sequence is not * contained * @see cx_strstr() */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard cxmutstr cx_strstr_m( cxmutstr haystack, cxstring needle @@ -591,16 +653,18 @@ /** * 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. + * @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 pre-allocated array of at least \p limit length + * @param output a pre-allocated array of at least @p limit length * @return the actual number of split items */ -__attribute__((__warn_unused_result__, __nonnull__)) +cx_attr_nodiscard +cx_attr_nonnull +cx_attr_access_w(4, 3) size_t cx_strsplit( cxstring string, cxstring delim, @@ -611,13 +675,13 @@ /** * Splits a given string using a delimiter string. * - * The array pointed to by \p output will be allocated by \p allocator. + * 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. + * @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. + * @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 @@ -627,7 +691,9 @@ * written to * @return the actual number of split items */ -__attribute__((__warn_unused_result__, __nonnull__)) +cx_attr_nodiscard +cx_attr_nonnull +cx_attr_access_w(5) size_t cx_strsplit_a( const CxAllocator *allocator, cxstring string, @@ -640,16 +706,18 @@ /** * 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. + * @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 pre-allocated array of at least \p limit length + * @param output a pre-allocated array of at least @p limit length * @return the actual number of split items */ -__attribute__((__warn_unused_result__, __nonnull__)) +cx_attr_nodiscard +cx_attr_nonnull +cx_attr_access_w(4, 3) size_t cx_strsplit_m( cxmutstr string, cxstring delim, @@ -660,13 +728,13 @@ /** * Splits a given string using a delimiter string. * - * The array pointed to by \p output will be allocated by \p allocator. + * 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. + * @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. + * @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 @@ -676,7 +744,9 @@ * written to * @return the actual number of split items */ -__attribute__((__warn_unused_result__, __nonnull__)) +cx_attr_nodiscard +cx_attr_nonnull +cx_attr_access_w(5) size_t cx_strsplit_ma( const CxAllocator *allocator, cxmutstr string, @@ -690,10 +760,10 @@ * * @param s1 the first string * @param s2 the second string - * @return negative if \p s1 is smaller than \p s2, positive if \p s1 is larger - * than \p s2, zero if both strings equal + * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger + * than @p s2, zero if both strings equal */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard int cx_strcmp( cxstring s1, cxstring s2 @@ -704,10 +774,10 @@ * * @param s1 the first string * @param s2 the second string - * @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 + * @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 */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard int cx_strcasecmp( cxstring s1, cxstring s2 @@ -720,10 +790,11 @@ * * @param s1 the first string * @param s2 the second string - * @return negative if \p s1 is smaller than \p s2, positive if \p s1 is larger - * than \p s2, zero if both strings equal + * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger + * than @p s2, zero if both strings equal */ -__attribute__((__warn_unused_result__, __nonnull__)) +cx_attr_nodiscard +cx_attr_nonnull int cx_strcmp_p( const void *s1, const void *s2 @@ -736,10 +807,11 @@ * * @param s1 the first string * @param s2 the second string - * @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 + * @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 */ -__attribute__((__warn_unused_result__, __nonnull__)) +cx_attr_nodiscard +cx_attr_nonnull int cx_strcasecmp_p( const void *s1, const void *s2 @@ -749,16 +821,17 @@ /** * Creates a duplicate of the specified string. * - * The new string will contain a copy allocated by \p allocator. + * The new string will contain a copy allocated by @p allocator. * - * \note The returned string is guaranteed to be zero-terminated. + * @note The returned string is guaranteed to be zero-terminated. * * @param allocator the allocator to use * @param string the string to duplicate * @return a duplicate of the string * @see cx_strdup() */ -__attribute__((__warn_unused_result__, __nonnull__)) +cx_attr_nodiscard +cx_attr_nonnull cxmutstr cx_strdup_a( const CxAllocator *allocator, cxstring string @@ -768,12 +841,12 @@ * Creates a duplicate of the specified string. * * The new string will contain a copy allocated by standard - * \c malloc(). So developers \em must pass the return value to cx_strfree(). + * @c malloc(). So developers @em must pass the return value to cx_strfree(). * - * \note The returned string is guaranteed to be zero-terminated. + * @note The returned string is guaranteed to be zero-terminated. * - * @param string the string to duplicate - * @return a duplicate of the string + * @param string (@c cxstring) the string to duplicate + * @return (@c cxmutstr) a duplicate of the string * @see cx_strdup_a() */ #define cx_strdup(string) cx_strdup_a(cxDefaultAllocator, string) @@ -782,13 +855,13 @@ /** * Creates a duplicate of the specified string. * - * The new string will contain a copy allocated by \p allocator. + * The new string will contain a copy allocated by @p allocator. * - * \note The returned string is guaranteed to be zero-terminated. + * @note The returned string is guaranteed to be zero-terminated. * - * @param allocator the allocator to use - * @param string the string to duplicate - * @return a duplicate of the string + * @param allocator (@c CxAllocator*) the allocator to use + * @param string (@c cxmutstr) the string to duplicate + * @return (@c cxmutstr) a duplicate of the string * @see cx_strdup_m() */ #define cx_strdup_ma(allocator, string) cx_strdup_a(allocator, cx_strcast(string)) @@ -797,12 +870,12 @@ * Creates a duplicate of the specified string. * * The new string will contain a copy allocated by standard - * \c malloc(). So developers \em must pass the return value to cx_strfree(). + * @c malloc(). So developers @em must pass the return value to cx_strfree(). * - * \note The returned string is guaranteed to be zero-terminated. + * @note The returned string is guaranteed to be zero-terminated. * - * @param string the string to duplicate - * @return a duplicate of the string + * @param string (@c cxmutstr) the string to duplicate + * @return (@c cxmutstr) a duplicate of the string * @see cx_strdup_ma() */ #define cx_strdup_m(string) cx_strdup_a(cxDefaultAllocator, cx_strcast(string)) @@ -810,25 +883,25 @@ /** * Omits leading and trailing spaces. * - * \note the returned string references the same memory, thus you - * must \em not free the returned memory. + * @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 */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard cxstring cx_strtrim(cxstring string); /** * Omits leading and trailing spaces. * - * \note the returned string references the same memory, thus you - * must \em not free the returned memory. + * @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 */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard cxmutstr cx_strtrim_m(cxmutstr string); /** @@ -836,10 +909,10 @@ * * @param string the string to check * @param prefix the prefix the string should have - * @return \c true, if and only if the string has the specified prefix, - * \c false otherwise + * @return @c true, if and only if the string has the specified prefix, + * @c false otherwise */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard bool cx_strprefix( cxstring string, cxstring prefix @@ -850,10 +923,10 @@ * * @param string the string to check * @param suffix the suffix the string should have - * @return \c true, if and only if the string has the specified suffix, - * \c false otherwise + * @return @c true, if and only if the string has the specified suffix, + * @c false otherwise */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard bool cx_strsuffix( cxstring string, cxstring suffix @@ -864,10 +937,10 @@ * * @param string the string to check * @param prefix the prefix the string should have - * @return \c true, if and only if the string has the specified prefix, - * \c false otherwise + * @return @c true, if and only if the string has the specified prefix, + * @c false otherwise */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard bool cx_strcaseprefix( cxstring string, cxstring prefix @@ -878,10 +951,10 @@ * * @param string the string to check * @param suffix the suffix the string should have - * @return \c true, if and only if the string has the specified suffix, - * \c false otherwise + * @return @c true, if and only if the string has the specified suffix, + * @c false otherwise */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard bool cx_strcasesuffix( cxstring string, cxstring suffix @@ -911,9 +984,9 @@ * Replaces a pattern in a string with another string. * * The pattern is taken literally and is no regular expression. - * Replaces at most \p replmax occurrences. + * Replaces at most @p replmax occurrences. * - * The returned string will be allocated by \p allocator and is guaranteed + * The returned string will be allocated by @p allocator and is guaranteed * to be zero-terminated. * * If allocation fails, or the input string is empty, @@ -926,7 +999,8 @@ * @param replmax maximum number of replacements * @return the resulting string after applying the replacements */ -__attribute__((__warn_unused_result__, __nonnull__)) +cx_attr_nodiscard +cx_attr_nonnull cxmutstr cx_strreplacen_a( const CxAllocator *allocator, cxstring str, @@ -939,19 +1013,19 @@ * Replaces a pattern in a string with another string. * * The pattern is taken literally and is no regular expression. - * Replaces at most \p replmax occurrences. + * Replaces at most @p replmax occurrences. * - * The returned string will be allocated by \c malloc() and is guaranteed + * The returned string will be allocated by @c malloc() and is guaranteed * to be zero-terminated. * * If allocation fails, or the input string is empty, * the returned string will be empty. * - * @param str the string where replacements should be applied - * @param pattern the pattern to search for - * @param replacement the replacement string - * @param replmax maximum number of replacements - * @return the resulting string after applying the replacements + * @param str (@c cxstring) the string where replacements should be applied + * @param pattern (@c cxstring) the pattern to search for + * @param replacement (@c cxstring) the replacement string + * @param replmax (@c size_t) maximum number of replacements + * @return (@c cxmutstr) the resulting string after applying the replacements */ #define cx_strreplacen(str, pattern, replacement, replmax) \ cx_strreplacen_a(cxDefaultAllocator, str, pattern, replacement, replmax) @@ -961,17 +1035,17 @@ * * The pattern is taken literally and is no regular expression. * - * The returned string will be allocated by \p allocator and is guaranteed + * The returned string will be allocated by @p allocator and is guaranteed * to be zero-terminated. * * If allocation fails, or the input string is empty, * the returned string will be empty. * - * @param allocator the allocator to use - * @param str the string where replacements should be applied - * @param pattern the pattern to search for - * @param replacement the replacement string - * @return the resulting string after applying the replacements + * @param allocator (@c CxAllocator*) the allocator to use + * @param str (@c cxstring) the string where replacements should be applied + * @param pattern (@c cxstring) the pattern to search for + * @param replacement (@c cxstring) the replacement string + * @return (@c cxmutstr) the resulting string after applying the replacements */ #define cx_strreplace_a(allocator, str, pattern, replacement) \ cx_strreplacen_a(allocator, str, pattern, replacement, SIZE_MAX) @@ -980,18 +1054,18 @@ * Replaces a pattern in a string with another string. * * The pattern is taken literally and is no regular expression. - * Replaces at most \p replmax occurrences. + * Replaces at most @p replmax occurrences. * - * The returned string will be allocated by \c malloc() and is guaranteed + * The returned string will be allocated by @c malloc() and is guaranteed * to be zero-terminated. * * If allocation fails, or the input string is empty, * the returned string will be empty. * - * @param str the string where replacements should be applied - * @param pattern the pattern to search for - * @param replacement the replacement string - * @return the resulting string after applying the replacements + * @param str (@c cxstring) the string where replacements should be applied + * @param pattern (@c cxstring) the pattern to search for + * @param replacement (@c cxstring) the replacement string + * @return (@c cxmutstr) the resulting string after applying the replacements */ #define cx_strreplace(str, pattern, replacement) \ cx_strreplacen_a(cxDefaultAllocator, str, pattern, replacement, SIZE_MAX) @@ -1004,7 +1078,7 @@ * @param limit the maximum number of tokens that shall be returned * @return a new string tokenization context */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard CxStrtokCtx cx_strtok( cxstring str, cxstring delim, @@ -1019,7 +1093,7 @@ * @param limit the maximum number of tokens that shall be returned * @return a new string tokenization context */ -__attribute__((__warn_unused_result__)) +cx_attr_nodiscard CxStrtokCtx cx_strtok_m( cxmutstr str, cxstring delim, @@ -1036,7 +1110,9 @@ * @return true if successful, false if the limit or the end of the string * has been reached */ -__attribute__((__warn_unused_result__, __nonnull__)) +cx_attr_nonnull +cx_attr_nodiscard +cx_attr_access_w(2) bool cx_strtok_next( CxStrtokCtx *ctx, cxstring *token @@ -1054,7 +1130,9 @@ * @return true if successful, false if the limit or the end of the string * has been reached */ -__attribute__((__warn_unused_result__, __nonnull__)) +cx_attr_nonnull +cx_attr_nodiscard +cx_attr_access_w(2) bool cx_strtok_next_m( CxStrtokCtx *ctx, cxmutstr *token @@ -1067,13 +1145,407 @@ * @param delim array of more delimiters * @param count number of elements in the array */ -__attribute__((__nonnull__)) +cx_attr_nonnull +cx_attr_access_r(2, 3) void cx_strtok_delim( CxStrtokCtx *ctx, const cxstring *delim, size_t count ); +/* ------------------------------------------------------------------------- * + * string to number conversion functions * + * ------------------------------------------------------------------------- */ + +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtos_lc(cxstring str, short *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtoi_lc(cxstring str, int *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtol_lc(cxstring str, long *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtoll_lc(cxstring str, long long *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtoi8_lc(cxstring str, int8_t *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtoi16_lc(cxstring str, int16_t *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtoi32_lc(cxstring str, int32_t *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtoi64_lc(cxstring str, int64_t *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtoz_lc(cxstring str, ssize_t *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtous_lc(cxstring str, unsigned short *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtou_lc(cxstring str, unsigned int *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtoul_lc(cxstring str, unsigned long *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtoull_lc(cxstring str, unsigned long long *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtou8_lc(cxstring str, uint8_t *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtou16_lc(cxstring str, uint16_t *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtou32_lc(cxstring str, uint32_t *output, int base, const char *groupsep); +/** + * @copydoc cx_strtouz_lc() + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtou64_lc(cxstring str, uint64_t *output, int base, const char *groupsep); + +/** + * Converts a string to a number. + * + * The function returns non-zero when conversion is not possible. + * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base. + * It sets errno to ERANGE when the target datatype is too small. + * + * @param str the string to convert + * @param output a pointer to the integer variable where the result shall be stored + * @param base 2, 8, 10, or 16 + * @param groupsep each character in this string is treated as group separator and ignored during conversion + * @retval zero success + * @retval non-zero conversion was not possible + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtouz_lc(cxstring str, size_t *output, int base, const char *groupsep); + +/** + * Converts a string to a single precision floating point number. + * + * The function returns non-zero when conversion is not possible. + * In that case the function sets errno to EINVAL when the reason is an invalid character. + * It sets errno to ERANGE when the necessary representation would exceed the limits defined in libc's float.h. + * + * The decimal separator is assumed to be a dot character. + * The comma character is treated as group separator and ignored during parsing. + * If you want to choose a different format, use cx_strtof_lc(). + * + * @param str the string to convert + * @param output a pointer to the float variable where the result shall be stored + * @param decsep the decimal separator + * @param groupsep each character in this string is treated as group separator and ignored during conversion + * @retval zero success + * @retval non-zero conversion was not possible + */ +cx_attr_access_w(2) cx_attr_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. + * + * The function returns non-zero when conversion is not possible. + * In that case the function sets errno to EINVAL when the reason is an invalid character. + * It sets errno to ERANGE when the necessary representation would exceed the limits defined in libc's float.h. + * + * The decimal separator is assumed to be a dot character. + * The comma character is treated as group separator and ignored during parsing. + * If you want to choose a different format, use cx_strtof_lc(). + * + * @param str the string to convert + * @param output a pointer to the float variable where the result shall be stored + * @param decsep the decimal separator + * @param groupsep each character in this string is treated as group separator and ignored during conversion + * @retval zero success + * @retval non-zero conversion was not possible + */ +cx_attr_access_w(2) cx_attr_nonnull_arg(2) +int cx_strtod_lc(cxstring str, double *output, char decsep, const char *groupsep); + +#ifndef CX_STR_IMPLEMENTATION +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtos_lc(str, output, base, groupsep) cx_strtos_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtoi_lc(str, output, base, groupsep) cx_strtoi_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtol_lc(str, output, base, groupsep) cx_strtol_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtoll_lc(str, output, base, groupsep) cx_strtoll_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtoi8_lc(str, output, base, groupsep) cx_strtoi8_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtoi16_lc(str, output, base, groupsep) cx_strtoi16_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtoi32_lc(str, output, base, groupsep) cx_strtoi32_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtoi64_lc(str, output, base, groupsep) cx_strtoi64_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtoz_lc(str, output, base, groupsep) cx_strtoz_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtous_lc(str, output, base, groupsep) cx_strtous_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtou_lc(str, output, base, groupsep) cx_strtou_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtoul_lc(str, output, base, groupsep) cx_strtoul_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtoull_lc(str, output, base, groupsep) cx_strtoull_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtou8_lc(str, output, base, groupsep) cx_strtou8_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtou16_lc(str, output, base, groupsep) cx_strtou16_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtou32_lc(str, output, base, groupsep) cx_strtou32_lc(cx_strcast(str), output, base, groupsep) +/** + * @copydoc cx_strtouz_lc() + */ +#define cx_strtou64_lc(str, output, base, groupsep) cx_strtou64_lc(cx_strcast(str), output, base, groupsep) +/** + * Converts a string to a number. + * + * The function returns non-zero when conversion is not possible. + * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base. + * It sets errno to ERANGE when the target datatype is too small. + * + * @param str the string to convert + * @param output a pointer to the integer variable where the result shall be stored + * @param base 2, 8, 10, or 16 + * @param groupsep each character in this string is treated as group separator and ignored during conversion + * @retval zero success + * @retval non-zero conversion was not possible + */ +#define cx_strtouz_lc(str, output, base, groupsep) cx_strtouz_lc(cx_strcast(str), output, base, groupsep) + +/** + * @copydoc cx_strtouz() + */ +#define cx_strtos(str, output, base) cx_strtos_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtoi(str, output, base) cx_strtoi_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtol(str, output, base) cx_strtol_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtoll(str, output, base) cx_strtoll_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtoi8(str, output, base) cx_strtoi8_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtoi16(str, output, base) cx_strtoi16_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtoi32(str, output, base) cx_strtoi32_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtoi64(str, output, base) cx_strtoi64_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtoz(str, output, base) cx_strtoz_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtous(str, output, base) cx_strtous_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtou(str, output, base) cx_strtou_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtoul(str, output, base) cx_strtoul_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtoull(str, output, base) cx_strtoull_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtou8(str, output, base) cx_strtou8_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtou16(str, output, base) cx_strtou16_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtou32(str, output, base) cx_strtou32_lc(str, output, base, ",") +/** + * @copydoc cx_strtouz() + */ +#define cx_strtou64(str, output, base) cx_strtou64_lc(str, output, base, ",") +/** + * Converts a string to a number. + * + * The function returns non-zero when conversion is not possible. + * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base. + * It sets errno to ERANGE when the target datatype is too small. + * + * The comma character is treated as group separator and ignored during parsing. + * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtouz_lc()). + * + * @param str the string to convert + * @param output a pointer to the integer variable where the result shall be stored + * @param base 2, 8, 10, or 16 + * @retval zero success + * @retval non-zero conversion was not possible + */ +#define cx_strtouz(str, output, base) cx_strtouz_lc(str, output, base, ",") + +/** + * Converts a string to a single precision floating point number. + * + * The function returns non-zero when conversion is not possible. + * In that case the function sets errno to EINVAL when the reason is an invalid character. + * It sets errno to ERANGE when the necessary representation would exceed the limits defined in libc's float.h. + * + * The decimal separator is assumed to be a dot character. + * The comma character is treated as group separator and ignored during parsing. + * If you want to choose a different format, use cx_strtof_lc(). + * + * @param str the string to convert + * @param output a pointer to the float variable where the result shall be stored + * @param decsep the decimal separator + * @param groupsep each character in this string is treated as group separator and ignored during conversion + * @retval zero success + * @retval non-zero conversion was not possible + */ +#define cx_strtof_lc(str, output, decsep, groupsep) cx_strtof_lc(cx_strcast(str), output, decsep, groupsep) +/** + * Converts a string to a double precision floating point number. + * + * The function returns non-zero when conversion is not possible. + * In that case the function sets errno to EINVAL when the reason is an invalid character. + * + * The decimal separator is assumed to be a dot character. + * The comma character is treated as group separator and ignored during parsing. + * If you want to choose a different format, use cx_strtof_lc(). + * + * @param str the string to convert + * @param output a pointer to the double variable where the result shall be stored + * @param decsep the decimal separator + * @param groupsep each character in this string is treated as group separator and ignored during conversion + * @retval zero success + * @retval non-zero conversion was not possible + */ +#define cx_strtod_lc(str, output, decsep, groupsep) cx_strtod_lc(cx_strcast(str), output, decsep, groupsep) + +/** + * Converts a string to a single precision floating point number. + * + * The function returns non-zero when conversion is not possible. + * In that case the function sets errno to EINVAL when the reason is an invalid character. + * It sets errno to ERANGE when the necessary representation would exceed the limits defined in libc's float.h. + * + * The decimal separator is assumed to be a dot character. + * The comma character is treated as group separator and ignored during parsing. + * If you want to choose a different format, use cx_strtof_lc(). + * + * @param str the string to convert + * @param output a pointer to the float variable where the result shall be stored + * @retval zero success + * @retval non-zero conversion was not possible + */ +#define cx_strtof(str, output) cx_strtof_lc(str, output, '.', ",") +/** + * Converts a string to a double precision floating point number. + * + * The function returns non-zero when conversion is not possible. + * In that case the function sets errno to EINVAL when the reason is an invalid character. + * + * The decimal separator is assumed to be a dot character. + * The comma character is treated as group separator and ignored during parsing. + * If you want to choose a different format, use cx_strtof_lc(). + * + * @param str the string to convert + * @param output a pointer to the double variable where the result shall be stored + * @retval zero success + * @retval non-zero conversion was not possible + */ +#define cx_strtod(str, output) cx_strtod_lc(str, output, '.', ",") + +#endif #ifdef __cplusplus } // extern "C"