From 615559a3834044ba4a56e8d896ebead4a3c8fed9 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 21 Oct 2020 17:20:54 +0200 Subject: Fixed missing _Generic types. Renamed c_print to c_printf, added some usage. --- README.md | 75 ++++++++++++++++++++++++++++------------------------ examples/benchmark.c | 18 ++++++------- examples/share_ptr.c | 14 +++++----- stc/cfmt.h | 47 ++++++++++++++++---------------- 4 files changed, 81 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index 3d9f2274..94269e23 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ The usage of the containers is vert similar to the C++ standard containers, so i All containers mentioned above, except cstr_t and cbitset_t, are generic and therefore typesafe (similar to templates in C++). No casting is used. A simple example: ```C #include +#include using_cvec(i, int); @@ -32,8 +33,9 @@ int main(void) { cvec_i vec = cvec_i_init(); cvec_i_push_back(&vec, 1); cvec_i_push_back(&vec, 2); - c_foreach (i, cvec_i, vec) - printf(" %d", *i.val); + + c_foreach (i, cvec_i, vec) + c_printf(0, " {}", *i.val); cvec_i_del(&vec); } ``` @@ -42,14 +44,14 @@ Using containers with complex element types is simple: #include #include -typedef struct { +typedef struct { cstr_t name; // dynamic string int id; } User; void User_del(User* u) { cstr_del(&u->name); } -int User_compare(User* u, User* v) +int User_compare(User* u, User* v) { int c = strcmp(u->name.str, v->name.str); return c != 0 ? c : u->id - v->id; } using_cvec(u, User, User_del, User_compare); @@ -58,8 +60,8 @@ int main(void) { cvec_u vec = cvec_u_init(); cvec_u_push_back(&vec, (User) {cstr_from("admin"), 0}); // cstr_from() allocates string memory cvec_u_push_back(&vec, (User) {cstr_from("usera"), 1}); - c_foreach (i, cvec_u, vec) - printf("%s: %d\n", i.val->name.str, i.val->id); + c_foreach (i, cvec_u, vec) + c_printf(0, "{}: {}\n", i.val->name.str, i.val->id); cvec_u_del(&vec); // free everything } ``` @@ -192,7 +194,7 @@ The examples folder contains further examples. **cvec** of *int64_t*. ```C #include -#include +#include using_cvec(ix, int64_t); // ix is just an example type tag name. @@ -209,7 +211,7 @@ int main() { bignums.data[i] /= i; // make them smaller c_foreach (i, cvec_ix, bignums) - printf(" %d", *i.val); + c_printf(0, " {}", *i.val); cvec_ix_del(&bignums); } // Output: @@ -217,7 +219,7 @@ int main() { ``` **cvec** of *cstr_t*. ```C -#include +#include #include using_cvec_str(); @@ -232,10 +234,10 @@ int main() { cstr_t tmp = cstr_from_fmt("%d elements so far", cvec_str_size(names)); cvec_str_push_back(&names, tmp); // tmp is moved to names, do not del() it. - printf("%s\n", names.data[1].str); // Access the second element + c_printf(0, "{}\n", names.data[1].str); // Access the second element c_foreach (i, cvec_str, names) - printf("item: %s\n", i.val->str); + c_printf(0, "item: {}\n", i.val->str); cvec_str_del(&names); } // Output: @@ -246,28 +248,29 @@ item: 2 elements so far ``` **cstr** string example. ```C -#include +#include int main() { cstr_t s1 = cstr_from("one-nine-three-seven-five"); - printf("%s.\n", s1.str); + c_printf(0, "{}.\n", s1.str); cstr_insert(&s1, 3, "-two"); - printf("%s.\n", s1.str); + c_printf(0, "{}.\n", s1.str); cstr_erase(&s1, 7, 5); // -nine - printf("%s.\n", s1.str); + c_printf(0, "{}.\n", s1.str); cstr_replace(&s1, cstr_find(&s1, "seven"), 5, "four"); - printf("%s.\n", s1.str); + c_printf(stderr, "{}.\n", s1.str); // reassign: cstr_assign(&s1, "one two three four five six seven"); cstr_append(&s1, " eight"); printf("append: %s\n", s1.str); - cstr_t full_path = cstr_from_fmt("%s/%s.%s", "directory", "filename", "ext"); - printf("%s\n", full_path.str); + cstr_t full_path cstr_init; + c_printf(&full_path, "{}/{}.{}", "directory", "filename", "ext"); + c_printf(1, "{}\n", full_path.str); // 1 = stderr c_del(cstr, &s1, &full_path); } @@ -283,7 +286,7 @@ directory/filename.ext ```C #include #include -#include +#include using_cmap(ii, int, int); using_cmap_str(); @@ -294,7 +297,7 @@ int main() { cmap_ii_put(&nums, 8, 64); // similar to insert_or_assign() cmap_ii_emplace(&nums, 11, 121); - printf("%d\n", cmap_ii_find(&nums, 8)->second); + c_printf(0, "{}\n", cmap_ii_find(&nums, 8)->second); cmap_ii_del(&nums); // -- map of str -- @@ -304,9 +307,9 @@ int main() { cmap_str_emplace(&strings, "Sunny", "afternoon"); c_push_items(&strings, cmap_str, { {"Eleven", "XI"}, {"Six", "VI"} }); - printf("size = %zu\n", cmap_str_size(strings)); + c_printf(0, "size = {}\n", cmap_str_size(strings)); c_foreach (i, cmap_str, strings) - printf("%s: %s\n", i.val->first.str, i.val->second.str); + c_printf(0, "{}: {}\n", i.val->first.str, i.val->second.str); cmap_str_del(&strings); // frees all strings and map. } // Output: @@ -320,7 +323,7 @@ Eleven: XI ``` **cset** of *cstr*. ```C -#include +#include #include using_cset_str(); // cstr set. See the discussion above. @@ -335,7 +338,7 @@ int main() { // iterate the set of cstr_t values: c_foreach (i, cset_str, words) - printf("%s ", i.val->str); + c_printf(0, "{} ", i.val->str); cset_str_del(&words); } // Output: @@ -344,6 +347,7 @@ Hello World **clist** of *int64_t*. Similar to c++ *std::forward_list*, but can do both *push_front()* and *push_back()* as well as *pop_front()*. ```C #include +#include #include using_clist(fx, double); @@ -361,13 +365,13 @@ int main() { printf("initial: "); c_foreach (i, clist_fx, list) - printf(" %g", *i.val); + c_printf(0, " {:.16}", *i.val); clist_fx_sort(&list); // mergesort O(n*log n) printf("\nsorted: "); c_foreach (i, clist_fx, list) - printf(" %g", *i.val); + c_printf(0, " {:10f}", *i.val); clist_fx_del(&list); } @@ -378,6 +382,7 @@ sorted: 1 2 3 4 5 6 7 8 9 10 20 30 40 50 60 70 80 90 **cpqueue** priority queue demo: ```C #include +#include #include #include @@ -398,7 +403,7 @@ int main() // Extract and disply the fifty smallest. c_forrange (50) { - printf("%zd ", *cpqueue_i_top(&heap)); + c_printf(0, "{} ", *cpqueue_i_top(&heap)); cpqueue_i_pop(&heap); } cpqueue_i_del(&heap); @@ -409,6 +414,7 @@ int main() **cqueue** adapter container. Uses singly linked list as representation. ```C #include +#include #include using_clist(i, int); @@ -425,7 +431,7 @@ int main() { cqueue_i_pop(&queue); c_foreach (i, cqueue_i, queue) - printf(" %d", *i.val); + c_printf(0, " {}", *i.val); cqueue_i_del(&queue); } @@ -436,6 +442,7 @@ int main() { ```C #include #include +#include using_carray(f, float); @@ -447,9 +454,9 @@ int main() carray1f a1 = carray3f_at2(&a3, 5, 4); // sub-array a3[5][4] (no data copy). carray2f a2 = carray3f_at1(&a3, 5); // sub-array a3[5] - printf("%f\n", *carray1f_at(&a1, 3)); // a1[3] (3.14f) - printf("%f\n", *carray2f_at(&a2, 4, 3)); // a2[4][3] (3.14f) - printf("%f\n", *carray3f_at(&a3, 5, 4, 3)); // a3[5][4][3] (3.14f) + c_printf(stdout, "{}\n", *carray1f_at(&a1, 3)); // a1[3] (3.14f) + c_printf(stdout, "{}\n", *carray2f_at(&a2, 4, 3)); // a2[4][3] (3.14f) + c_printf(stdout, "{}\n", *carray3f_at(&a3, 5, 4, 3)); // a3[5][4][3] (3.14f) // ... carray1f_del(&a1); // does nothing, since it is a sub-array. carray2f_del(&a2); // same. @@ -500,7 +507,7 @@ Code: #include #include #include -#include +#include #include using_cmap(ii, int, int); @@ -564,10 +571,10 @@ void display_hist(cvec_mi hist, int scale, int mean, int stddev) int k = (int) (i.val->second * stddev * scale * 25ull / 10 / n); if (k > 0) { cstr_take(&bar, cstr_with_size(k, '*')); - printf("%4d %s\n", i.val->first, bar.str); + c_printf(0, "{:4} {}\n", i.val->first, bar.str); } } - printf("Normal distribution with mean=%d, stddev=%d. '*' = %.0f samples out of %d.\n", + c_printf(0, "Normal distribution with mean={}, stddev={}. '*' = {:.0f} samples out of {}.\n", mean, stddev, n / (2.5 * stddev * scale), n); cstr_del(&bar); } diff --git a/examples/benchmark.c b/examples/benchmark.c index b9da16f7..9f2467fe 100644 --- a/examples/benchmark.c +++ b/examples/benchmark.c @@ -151,7 +151,7 @@ int rr = RR; erased += M##_ERASE(X, RAND(rr)); \ } \ difference = clock() - before; \ - c_print(0, #M ": time: {:5.02f}, sum: {}, erased {}, size: {}, buckets: {:8}\n", \ + c_printf(0, #M ": time: {:5.02f}, sum: {}, erased {}, size: {}, buckets: {:8}\n", \ (float) difference / CLOCKS_PER_SEC, checksum, erased, (size_t) M##_SIZE(X), (size_t) M##_BUCKETS(X)); \ M##_CLEAR(X); \ } @@ -166,7 +166,7 @@ int rr = RR; for (size_t i = 0; i < N2; ++i) \ erased += M##_ERASE(X, i); \ difference = clock() - before; \ - c_print(0, #M ": time: {:5.02f}, erased {}, size: {}, buckets: {:8}\n", \ + c_printf(0, #M ": time: {:5.02f}, erased {}, size: {}, buckets: {:8}\n", \ (float) difference / CLOCKS_PER_SEC, erased, (size_t) M##_SIZE(X), (size_t) M##_BUCKETS(X)); \ M##_CLEAR(X); \ } @@ -183,7 +183,7 @@ int rr = RR; for (size_t i = 0; i < N3; ++i) \ erased += M##_ERASE(X, RAND(rr)); \ difference = clock() - before; \ - c_print(0, #M ": time: {:5.02f}, erased {}, size: {}, buckets: {:8}\n", \ + c_printf(0, #M ": time: {:5.02f}, erased {}, size: {}, buckets: {:8}\n", \ (float) difference / CLOCKS_PER_SEC, erased, (size_t) M##_SIZE(X), (size_t) M##_BUCKETS(X)); \ M##_CLEAR(X); \ } @@ -199,7 +199,7 @@ int rr = RR; for (int k=0; k<5; k++) M##_FOR (X, i) \ sum += M##_ITEM(X, i); \ difference = clock() - before; \ - c_print(0, #M ": time: {:5.02f}, sum {}, size: {}, buckets: {:8}\n", \ + c_printf(0, #M ": time: {:5.02f}, sum {}, size: {}, buckets: {:8}\n", \ (float) difference / CLOCKS_PER_SEC, sum, (size_t) M##_SIZE(X), (size_t) M##_BUCKETS(X)); \ M##_CLEAR(X); \ } @@ -219,16 +219,16 @@ int main(int argc, char* argv[]) { rr = argc == 2 ? atoi(argv[1]) : RR; seed = time(NULL); - c_print(0, "\nRandom keys are in range [0, 2^%d), seed = %zu:\n", rr, seed); - c_print(0, "\nUnordered maps: %d repeats of Insert random key + try to remove a random key:\n", N1); + c_printf(0, "\nRandom keys are in range [0, 2^{}), seed = {}:\n", rr, seed); + c_printf(0, "\nUnordered maps: {} repeats of Insert random key + try to remove a random key:\n", N1); RUN_TEST(1) - c_print(0, "\nUnordered maps: Insert %d index keys, then remove them in same order:\n", N2); + c_printf(0, "\nUnordered maps: Insert {} index keys, then remove them in same order:\n", N2); RUN_TEST(2) - c_print(0, "\nUnordered maps: Insert %d random keys, then remove them in same order:\n", N3); + c_printf(0, "\nUnordered maps: Insert {} random keys, then remove them in same order:\n", N3); RUN_TEST(3) - c_print(0, "\nUnordered maps: Iterate %d random keys:\n", N4); + c_printf(0, "\nUnordered maps: Iterate {} random keys:\n", N4); RUNX_TEST(4) } diff --git a/examples/share_ptr.c b/examples/share_ptr.c index 5dd52d19..571a80d4 100644 --- a/examples/share_ptr.c +++ b/examples/share_ptr.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include typedef struct { cstr_t name, last; } Person; @@ -11,7 +11,7 @@ Person* Person_make(Person* p, const char* name, const char* last) { return p; } void Person_del(Person* p) { - printf("del: %s\n", p->name.str); + c_printf(0, "del: {}\n", p->name.str); c_del(cstr, &p->name, &p->last); } int Person_compare(const Person* p, const Person* q) { @@ -40,7 +40,7 @@ int main() { cvec_pe_push_back(&vec, csptr_pe_share(p)); // Don't forget to share! } c_foreach (i, clist_pe, queue) - printf(" %s\n", i.val->get->name.str); + c_printf(0, " {}\n", i.val->get->name.str); puts("Sort and pop 3:"); clist_pe_sort(&queue); @@ -52,18 +52,18 @@ int main() { puts("Sorted queue:"); c_foreach (i, clist_pe, queue) - printf(" %s\n", i.val->get->name.str); + c_printf(0, " {}\n", i.val->get->name.str); puts("Sorted vec:"); c_foreach (i, cvec_pe, vec) - printf(" %s\n", i.val->get->name.str); + c_printf(0, " {}\n", i.val->get->name.str); Person lost; Person_make(&lost, "Name 5", "Last 5"); csptr_pe ptmp = {&lost, NULL}; // share pointer without counter - OK. clist_pe_iter_t lit = clist_pe_find(&queue, ptmp); Person_del(&lost); - if (lit.val) printf("Found: %s\n", lit.val->get->name.str); + if (lit.val) c_printf(0, "Found: {}\n", lit.val->get->name.str); - printf("use %ld\n", *joe.use_count); + c_printf(0, "use {}\n", *joe.use_count); csptr_pe_del(&joe); puts("Destroy queue:"); diff --git a/stc/cfmt.h b/stc/cfmt.h index 158ada20..8e13e778 100644 --- a/stc/cfmt.h +++ b/stc/cfmt.h @@ -41,14 +41,13 @@ _cfmt_conv(const char *fmt, ...); cstr_t *: cstr_fmt) #if defined(_MSC_VER) && !defined(__clang__) -# define _cfmt_uschar unsigned char: "hhu" +# define _cfmt_uschar() char: "hhd", unsigned char: "hhu" #else -# define _cfmt_uschar signed char: "hhd", unsigned char: "hhu" +# define _cfmt_uschar() char: "hhd", signed char: "hhd", unsigned char: "hhu" #endif #define _cfmt(x) _Generic ((x), \ - char: "c", \ - _cfmt_uschar, \ + _cfmt_uschar(), \ short: "hd", \ unsigned short: "hu", \ int: "d", \ @@ -61,7 +60,9 @@ _cfmt_conv(const char *fmt, ...); double: "g", \ long double: "Lg", \ char *: "s", \ - void *: "p") + void *: "p", \ + const char *: "s", \ + const void *: "p") #else inline auto _cfmt_fn(FILE*) {return fprintf;} inline auto _cfmt_fn(char*) {return sprintf;} @@ -84,56 +85,56 @@ _cfmt_conv(const char *fmt, ...); inline auto _cfmt(const void *x) {return "p";} #endif -#define c_print(...) c_MACRO_OVERLOAD(c_print, __VA_ARGS__) -#define c_print_2(to, fmt) \ +#define c_printf(...) c_MACRO_OVERLOAD(c_printf, __VA_ARGS__) +#define c_printf_2(to, fmt) \ do { char *_fm = _cfmt_conv(fmt); \ _cfmt_fn(to)(to, _fm); free(_fm); } while (0) -#define c_print_3(to, fmt, c) \ +#define c_printf_3(to, fmt, c) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c)); \ _cfmt_fn(to)(to, _fm, c); free(_fm); } while (0) -#define c_print_4(to, fmt, c, d) \ +#define c_printf_4(to, fmt, c, d) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c), _cfmt(d)); \ _cfmt_fn(to)(to, _fm, c, d); free(_fm); } while (0) -#define c_print_5(to, fmt, c, d, e) \ +#define c_printf_5(to, fmt, c, d, e) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c), _cfmt(d), _cfmt(e)); \ _cfmt_fn(to)(to, _fm, c, d, e); free(_fm); } while (0) -#define c_print_6(to, fmt, c, d, e, f) \ +#define c_printf_6(to, fmt, c, d, e, f) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c), _cfmt(d), _cfmt(e), _cfmt(f)); \ _cfmt_fn(to)(to, _fm, c, d, e, f); free(_fm); } while (0) -#define c_print_7(to, fmt, c, d, e, f, g) \ +#define c_printf_7(to, fmt, c, d, e, f, g) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c), _cfmt(d), _cfmt(e), _cfmt(f), _cfmt(g)); \ _cfmt_fn(to)(to, _fm, c, d, e, f, g); free(_fm); } while (0) -#define c_print_8(to, fmt, c, d, e, f, g, h) \ +#define c_printf_8(to, fmt, c, d, e, f, g, h) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c), _cfmt(d), _cfmt(e), _cfmt(f), _cfmt(g), _cfmt(h)); \ _cfmt_fn(to)(to, _fm, c, d, e, f, g, h); free(_fm); } while (0) -#define c_print_9(to, fmt, c, d, e, f, g, h, i) \ +#define c_printf_9(to, fmt, c, d, e, f, g, h, i) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c), _cfmt(d), _cfmt(e), _cfmt(f), _cfmt(g), _cfmt(h), _cfmt(i)); \ _cfmt_fn(to)(to, _fm, c, d, e, f, g, h, i); free(_fm); } while (0) -#define c_print_10(to, fmt, c, d, e, f, g, h, i, j) \ +#define c_printf_10(to, fmt, c, d, e, f, g, h, i, j) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c), _cfmt(d), _cfmt(e), _cfmt(f), _cfmt(g), _cfmt(h), _cfmt(i), _cfmt(j)); \ _cfmt_fn(to)(to, _fm, c, d, e, f, g, h, i, j); free(_fm); } while (0) -#define c_print_11(to, fmt, c, d, e, f, g, h, i, j, k) \ +#define c_printf_11(to, fmt, c, d, e, f, g, h, i, j, k) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c), _cfmt(d), _cfmt(e), _cfmt(f), _cfmt(g), _cfmt(h), _cfmt(i), _cfmt(j), _cfmt(k)); \ _cfmt_fn(to)(to, _fm, c, d, e, f, g, h, i, j, k); free(_fm); } while (0) -#define c_print_12(to, fmt, c, d, e, f, g, h, i, j, k, m) \ +#define c_printf_12(to, fmt, c, d, e, f, g, h, i, j, k, m) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c), _cfmt(d), _cfmt(e), _cfmt(f), _cfmt(g), _cfmt(h), _cfmt(i), _cfmt(j), _cfmt(k), _cfmt(m)); \ _cfmt_fn(to)(to, _fm, c, d, e, f, g, h, i, j, k, m); free(_fm); } while (0) -#define c_print_13(to, fmt, c, d, e, f, g, h, i, j, k, m, n) \ +#define c_printf_13(to, fmt, c, d, e, f, g, h, i, j, k, m, n) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c), _cfmt(d), _cfmt(e), _cfmt(f), _cfmt(g), _cfmt(h), _cfmt(i), _cfmt(j), _cfmt(k), _cfmt(m), _cfmt(n)); \ _cfmt_fn(to)(to, _fm, c, d, e, f, g, h, i, j, k, m, n); free(_fm); } while (0) -#define c_print_14(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o) \ +#define c_printf_14(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c), _cfmt(d), _cfmt(e), _cfmt(f), _cfmt(g), _cfmt(h), _cfmt(i), _cfmt(j), _cfmt(k), _cfmt(m), _cfmt(n), _cfmt(o)); \ _cfmt_fn(to)(to, _fm, c, d, e, f, g, h, i, j, k, m, n, o); free(_fm); } while (0) -#define c_print_15(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o, p) \ +#define c_printf_15(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o, p) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c), _cfmt(d), _cfmt(e), _cfmt(f), _cfmt(g), _cfmt(h), _cfmt(i), _cfmt(j), _cfmt(k), _cfmt(m), _cfmt(n), _cfmt(o), _cfmt(p)); \ _cfmt_fn(to)(to, _fm, c, d, e, f, g, h, i, j, k, m, n, o, p); free(_fm); } while (0) -#define c_print_16(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o, p, q) \ +#define c_printf_16(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o, p, q) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c), _cfmt(d), _cfmt(e), _cfmt(f), _cfmt(g), _cfmt(h), _cfmt(i), _cfmt(j), _cfmt(k), _cfmt(m), _cfmt(n), _cfmt(o), _cfmt(p), _cfmt(p)); \ _cfmt_fn(to)(to, _fm, c, d, e, f, g, h, i, j, k, m, n, o, p, q); free(_fm); } while (0) -#define c_print_17(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o, p, q, r) \ +#define c_printf_17(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o, p, q, r) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c), _cfmt(d), _cfmt(e), _cfmt(f), _cfmt(g), _cfmt(h), _cfmt(i), _cfmt(j), _cfmt(k), _cfmt(m), _cfmt(n), _cfmt(o), _cfmt(p), _cfmt(p), _cfmt(r)); \ _cfmt_fn(to)(to, _fm, c, d, e, f, g, h, i, j, k, m, n, o, p, q, r); free(_fm); } while (0) -#define c_print_18(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o, p, q, r, s) \ +#define c_printf_18(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o, p, q, r, s) \ do { char *_fm = _cfmt_conv(fmt, _cfmt(c), _cfmt(d), _cfmt(e), _cfmt(f), _cfmt(g), _cfmt(h), _cfmt(i), _cfmt(j), _cfmt(k), _cfmt(m), _cfmt(n), _cfmt(o), _cfmt(p), _cfmt(p), _cfmt(r), _cfmt(s)); \ _cfmt_fn(to)(to, _fm, c, d, e, f, g, h, i, j, k, m, n, o, p, q, r, s); free(_fm); } while (0) -- cgit v1.2.3