diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-05-18 08:57:29 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-05-30 14:07:17 -0600 |
commit | 222ee4838251a88bf23779b5c2b405a4c7dc619c (patch) | |
tree | 990a89da658a4196da122bd2a64ff20531fb97fa | |
parent | 691d3fe7ff920e8113d174c2ce6c3126000a2f82 (diff) |
libmisc: fmt.h: Add fmt_print2() and fmt_asprint()
-rw-r--r-- | libmisc/include/libmisc/fmt.h | 31 | ||||
-rw-r--r-- | libmisc/tests/test_fmt.c | 9 |
2 files changed, 32 insertions, 8 deletions
diff --git a/libmisc/include/libmisc/fmt.h b/libmisc/include/libmisc/fmt.h index c0743ff..6c04d99 100644 --- a/libmisc/include/libmisc/fmt.h +++ b/libmisc/include/libmisc/fmt.h @@ -9,6 +9,7 @@ #include <stddef.h> /* for size_t */ #include <stdint.h> /* for (u)int{n}_t */ +#include <stdlib.h> /* for realloc() */ #include <libmisc/macro.h> #include <libmisc/obj.h> @@ -99,6 +100,11 @@ void fmt_print_bool(lo_interface fmt_dest w, bool b); const char * : fmt_print_str , \ bool : fmt_print_bool )(w, val) +/** Same as fmt_print(), but usable from inside of fmt_print(). */ +#define fmt_print2(w, ...) do { LM_FOREACH_PARAM2_(_fmt_param2, (w), __VA_ARGS__) } while (0) +#define _fmt_param2(...) _LM_DEFER2(_fmt_param_indirect)()(__VA_ARGS__) +#define _fmt_param_indirect() _fmt_param + /* print-to-memory ************************************************************/ struct fmt_buf { @@ -116,16 +122,25 @@ LO_IMPLEMENTATION_H(fmt_dest, struct fmt_buf, fmt_buf); _w.len; \ }) -/* justify ********************************************************************/ +#define fmt_asprint(...) ({ \ + struct fmt_buf _w = {}; \ + lo_interface fmt_dest w = lo_box_fmt_buf_as_fmt_dest(&_w); \ + fmt_print(w, __VA_ARGS__); \ + while (_w.cap <= _w.len) { \ + _w.cap = _w.len + 1; \ + _w.len = 0; \ + _w.dat = realloc(_w.dat, _w.cap); \ + fmt_print(w, __VA_ARGS__); \ + } \ + ((char *)_w.dat)[_w.len] = '\0'; \ + _w.dat; \ +}) -/* *grubles about not being allowed to nest things* */ -#define _fmt_param_indirect() _fmt_param -#define _fmt_print2(w, ...) do { LM_FOREACH_PARAM2_(_fmt_param2, (w), __VA_ARGS__) } while (0) -#define _fmt_param2(...) _LM_DEFER2(_fmt_param_indirect)()(__VA_ARGS__) +/* justify ********************************************************************/ #define fmt_print_ljust(w, width, fillchar, ...) do { \ size_t beg = LO_CALL(w, tell); \ - _fmt_print2(w, __VA_ARGS__); \ + fmt_print2(w, __VA_ARGS__); \ while ((LO_CALL(w, tell) - beg) < width) \ fmt_print_byte(w, fillchar); \ } while (0) @@ -133,10 +148,10 @@ LO_IMPLEMENTATION_H(fmt_dest, struct fmt_buf, fmt_buf); #define fmt_print_rjust(w, width, fillchar, ...) do { \ struct fmt_buf _discard = {}; \ lo_interface fmt_dest discard = lo_box_fmt_buf_as_fmt_dest(&_discard); \ - _fmt_print2(discard, __VA_ARGS__); \ + fmt_print2(discard, __VA_ARGS__); \ while (_discard.len++ < width) \ fmt_print_byte(w, fillchar); \ - _fmt_print2(w, __VA_ARGS__); \ + fmt_print2(w, __VA_ARGS__); \ } while (0) void fmt_print_base16_u8_(lo_interface fmt_dest w, uint8_t x); diff --git a/libmisc/tests/test_fmt.c b/libmisc/tests/test_fmt.c index a9157d6..64b3b8a 100644 --- a/libmisc/tests/test_fmt.c +++ b/libmisc/tests/test_fmt.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ +#include <stdlib.h> /* for free() */ #include <string.h> /* for strcmp(), memcmp(), memset() */ #include <libmisc/fmt.h> @@ -230,5 +231,13 @@ int main() { test_assert(strcmp(str, "{0x68,0x65,0x6C,0x6C,0x6F,0x00}") == 0); memset(str, 0, sizeof(str)); + char *astr = fmt_asprint(""); + test_assert(astr != NULL && astr[0] == '\0'); + free(astr); + + astr = fmt_asprint("hello ", (base2, 9), (qstr, " world!\n")); + test_assert(strcmp(astr, "hello 1001\" world!\\n\"") == 0); + free(astr); + return 0; } |