diff -r 4a72c47226f4 -r 2ad0cf0f314b docs/Writerside/topics/printf.h.md --- a/docs/Writerside/topics/printf.h.md Sat Feb 15 16:36:29 2025 +0100 +++ b/docs/Writerside/topics/printf.h.md Sat Feb 15 17:43:21 2025 +0100 @@ -6,26 +6,36 @@ With the help of these convenience functions, you do not need the libc `snprintf` to print your string to a temporary buffer anymore, plus you do not need to worry about too small buffer sizes, because the functions will automatically allocate enough memory to contain the entire formatted string. +> Although UCX usually uses `size_t` for sizes, the return type of all `printf`-like functions +> (except for the `cx_asprintf()` family of functions) is `int`, consistent with the stdio `printf` return type. +{style="note"} + ## Print to Streams and Buffers ```C #include int cx_fprintf(void *stream, cx_write_func wfc, - const char *fmt, ...); + const char *fmt, ...); int cx_vfprintf(void *stream, cx_write_func wfc, - const char *fmt, va_list ap); + const char *fmt, va_list ap); int cx_bprintf(CxBuffer *buf, const char *fmt, ...); ``` -> TODO: document -{style="warning"} +The `cx_fprintf()` function uses the stdio `snprintf()` to prepare a formatted string +which is then written to the `stream` using the write function `wfc`. +The return value is the number of bytes written or a value less than zero when an error occurred. +If the resulting string is short enough, no additional memory is allocated on the heap. +See the Section about [](#small-buffer-optimization) for more details. The `cx_vfprintf()` function is equivalent to `cx_fprintf()`, except that instead of being called with a variable number of arguments, -they are called with an argument list as defined by ``. +it is called with an argument list as defined by ``. + +The `cx_bprintf()` function is implemented as macro for `cx_fprintf()` with the +`CxBuffer` as `stream` and the `cxBufferWriteFunc` as write function. ## Print to Freshly Allocated Memory @@ -35,16 +45,18 @@ cxmutstr cx_asprintf(const char *fmt, ...); cxmutstr cx_asprintf_a(const CxAllocator *allocator, - const char *fmt, ...); + const char *fmt, ...); cxmutstr cx_vasprintf(const char *fmt, va_list ap); cxmutstr cx_vasprintf_a(const CxAllocator *allocator, - const char *fmt, va_list ap); + const char *fmt, va_list ap); ``` -> TODO: document -{style="warning"} +The `cx_asprintf()` and `cx_asprintf_a()` functions print the formatted output directly to a freshly allocated +string which is then returned from the function. +On platforms (or when using allocators) where allocation can fail, +the returned string may be empty and the `ptr` field set to `NULL`. The `cx_vasprintf()` and `cx_vasprintf_a()` functions are equivalent to `cx_asprintf()` and `cx_asprintf_a()`, except that instead of being called with a variable number of arguments, @@ -55,18 +67,51 @@ ```C #include -cx_sprintf -cx_sprintf_a -cx_sprintf_s -cx_sprintf_sa -cx_vsprintf -cx_vsprintf_a -cx_vsprintf_s -cx_vsprintf_sa +int cx_sprintf(char **str, size_t *len, + const char *fmt, ...); + +int cx_sprintf_a(CxAllocator *alloc, char **str, size_t *len, + const char *fmt, ...); + +int cx_sprintf_s(char *buf, size_t *len, char **str, + const char *fmt, ...); + +int cx_sprintf_sa(CxAllocator *alloc, + char *buf, size_t *len, char **str, + const char *fmt, ...); + +int cx_vsprintf(char **str, size_t *len, + const char *fmt, va_list ap); + +int cx_vsprintf_a(CxAllocator *alloc, char **str, size_t *len, + const char *fmt, va_list ap); + +int cx_vsprintf_s(char *buf, size_t *len, char **str, + const char *fmt, ...); + +int cx_vsprintf_sa(CxAllocator *alloc, + char *buf, size_t *len, char **str, + const char *fmt, va_list ap); ``` -> TODO: document -{style="warning"} +The `cx_sprintf()` and `cx_sprintf_a()` functions take a pointer `str` to a pointer to a pre-allocated buffer, +as well as a pointer `len` to `*str`'s length. +If the formatted output would not fit into this buffer, it is reallocated +and the new pointer to the buffer and the new length are written back to the variables pointed to by `str` and `len`. + +The `cx_sprintf_s()` and `cx_sprintf_sa()` functions differ from the previous function in that they take +the pointer to the pre-allocated buffer in the `buf` argument and not in the `str` argument +(which in this case is only used for storing the resulting pointer), and _always_ allocate an entirely new buffer +when the length is insufficient. +This is particularly useful when you want to print the formatted string to a buffer allocated on the stack, but also +want the option to switch to heap-allocated memory when necessary. + +In other words: when the formatted output fits into the buffer pointed to by `buf`, `buf` will be written to `*str`. +Otherwise, the pointer to the freshly allocated buffer is written to `*str`. + +> When using `cx_sprintf()` or `cx_sprintf_a()` you should always make sure that the string pointed to by `*str` +> was allocated by a matching allocator. +> This restriction does not apply for `cx_sprintf_s()` or `cx_sprintf_sa()` which would allocate a fresh buffer when needed. The `cx_vsprintf()`, `cx_vsprintf_a()`, `cx_vsprintf_s()`, and `cx_vsprintf_sa()` functions are equivalent to `cx_sprintf()`, `cx_sprintf_a()`, `cx_sprintf_s()`, and `cx_sprintf_sa()`,