docs/Writerside/topics/printf.h.md

changeset 1210
2ad0cf0f314b
parent 1172
1a6aa0301226
--- 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 <cx/printf.h>
 
 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 `<stdarg.h>`.
+it is called with an argument list as defined by `<stdarg.h>`.
+
+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/printf.h>
 
-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()`,

mercurial