From 7c57f4fb7edf33d030975a04160f183f71c48ecd Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 6 Jun 2023 18:13:18 +0200 Subject: Fixed some logic in coroutines. Changed API in c11/print.h (not officially part of STC as it is C11). --- include/c11/print.h | 87 ++++++++++++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 44 deletions(-) (limited to 'include/c11/print.h') diff --git a/include/c11/print.h b/include/c11/print.h index 7c155875..ee0d8151 100644 --- a/include/c11/print.h +++ b/include/c11/print.h @@ -1,7 +1,7 @@ #ifndef FMT_H_INCLUDED #define FMT_H_INCLUDED /* -VER 2.1: NEW API: +VER 2.2: NEW API: void print(fmt, ...); void println(fmt, ...); void printd(dest, fmt, ...); @@ -9,28 +9,31 @@ void printd(dest, fmt, ...); void fmt_print(fmt, ...); void fmt_println(fmt, ...); void fmt_printd(dest, fmt, ...); -void fmt_destroy(fmt_buffer* buf); +void fmt_close(fmt_stream* ss); dest - destination, one of: FILE* fp Write to a file char* strbuf Write to a pre-allocated string buffer - fmt_buffer* buf Auto realloc the needed memory (safe). - Set buf->stream=1 for stream-mode. - Call fmt_destroy(buf) after usage. + fmt_stream* ss Write to a string-stream (auto allocated). + Set ss->overwrite=1 for overwrite-mode. + Call fmt_close(ss) after usage. fmt - format string {} Auto-detected format. If :MOD is not specified, float will use ".8g" format, and double ".16g". - {:MOD} Format modifiers: < left align (replaces -), default for char*, char. - > right align, default for numbers. - Other than that MOD can be normal printf format modifiers. - {{, }} Print chars {, and }. (note: a single % prints %). + {:MODS} Format modifiers: '<' left align (replaces '-'). Default for char* and char. + '>' right align. Default for numbers. + Other than that MODS can be regular printf() format modifiers. + {{ }} % Print the '{', '}', and '%' characters. * C11 or higher required. * MAX 255 chars fmt string by default. MAX 12 arguments after fmt string. -* Static linking by default, shared symbols by defining FMT_HEADER / FMT_IMPLEMENT. +* Define FMT_IMPLEMENT or i_implement prior to #include in one translation unit. +* Define FMT_SHORTS to define print(), println() and printd() macros, without fmt_ prefix. * (c) operamint, 2022, MIT License. ----------------------------------------------------------------------------------- +#define FMT_IMPLEMENT +#define FMT_SHORTS #include "c11/print.h" int main() { @@ -50,15 +53,15 @@ int main() { printd(stdout, "{:10} {:10} {:10}\n", "Hello", "Mad", "World"); printd(stderr, "100%: {:<20} {:.*} {}\n", string, 4, pi, x); printd(buffer, "Precision: {} {:.10} {}", string, pi, x); - println("{}", buffer); - println("Vector: ({}, {}, {})", 3.2, 3.3, pi); + fmt_println("{}", buffer); + fmt_println("Vector: ({}, {}, {})", 3.2, 3.3, pi); - fmt_buffer out[1] = {{.stream=1}}; - printd(out, "{} {}", "Pi is:", pi); - print("{}, len={}, cap={}\n", out->data, out->len, out->cap); - printd(out, "{} {}", ", Pi squared is:", pi*pi); - print("{}, len={}, cap={}\n", out->data, out->len, out->cap); - fmt_destroy(out); + fmt_stream ss[1] = {0}; + printd(ss, "{} {}", "Pi is:", pi); + print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap); + printd(ss, "{} {}", ", Pi squared is:", pi*pi); + print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap); + fmt_close(ss); } */ #include @@ -77,11 +80,6 @@ int main() { #define _fmt_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \ _14, _15, _16, N, ...) N -#if defined FMT_HEADER || defined FMT_IMPLEMENT -# define FMT_API -#else -# define FMT_API static inline -#endif #if defined FMT_NDEBUG || defined NDEBUG # define fmt_OK(exp) (void)(exp) #else @@ -91,25 +89,25 @@ int main() { typedef struct { char* data; intptr_t cap, len; - _Bool stream; -} fmt_buffer; + _Bool overwrite; +} fmt_stream; -FMT_API void fmt_destroy(fmt_buffer* buf); -FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...); -FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...); +void fmt_close(fmt_stream* ss); +int _fmt_parse(char* p, int nargs, const char *fmt, ...); +void _fmt_bprint(fmt_stream*, const char* fmt, ...); #ifndef FMT_MAX #define FMT_MAX 256 #endif -#ifndef FMT_NOSHORTS +#ifdef FMT_SHORTS #define print(...) fmt_printd(stdout, __VA_ARGS__) -#define println(...) fmt_printd((fmt_buffer*)0, __VA_ARGS__) +#define println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__) #define printd fmt_printd #endif #define fmt_print(...) fmt_printd(stdout, __VA_ARGS__) -#define fmt_println(...) fmt_printd((fmt_buffer*)0, __VA_ARGS__) +#define fmt_println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__) #define fmt_printd(...) fmt_OVERLOAD(fmt_printd, __VA_ARGS__) /* Primary function. */ @@ -161,7 +159,7 @@ FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...); #define _fmt_fn(x) _Generic ((x), \ FILE*: fprintf, \ char*: sprintf, \ - fmt_buffer*: _fmt_bprint) + fmt_stream*: _fmt_bprint) #if defined(_MSC_VER) && !defined(__clang__) # define _signed_char_hhd @@ -192,38 +190,38 @@ FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...); const wchar_t*: "ls", \ const void*: "p") -#if defined FMT_IMPLEMENT || !(defined FMT_HEADER || defined FMT_IMPLEMENT) +#if defined FMT_IMPLEMENT || defined i_implement #include #include #include -FMT_API void fmt_destroy(fmt_buffer* buf) { - free(buf->data); +void fmt_close(fmt_stream* ss) { + free(ss->data); } -FMT_API void _fmt_bprint(fmt_buffer* buf, const char* fmt, ...) { +void _fmt_bprint(fmt_stream* ss, const char* fmt, ...) { va_list args, args2; va_start(args, fmt); - if (buf == NULL) { + if (ss == NULL) { vprintf(fmt, args); putchar('\n'); goto done1; } va_copy(args2, args); const int n = vsnprintf(NULL, 0U, fmt, args); if (n < 0) goto done2; - const intptr_t pos = buf->stream ? buf->len : 0; - buf->len = pos + n; - if (buf->len > buf->cap) { - buf->cap = buf->len + buf->cap/2; - buf->data = (char*)realloc(buf->data, (size_t)buf->cap + 1U); + const intptr_t pos = ss->overwrite ? 0 : ss->len; + ss->len = pos + n; + if (ss->len > ss->cap) { + ss->cap = ss->len + ss->cap/2; + ss->data = (char*)realloc(ss->data, (size_t)ss->cap + 1U); } - vsprintf(buf->data + pos, fmt, args2); + vsprintf(ss->data + pos, fmt, args2); done2: va_end(args2); done1: va_end(args); } -FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...) { +int _fmt_parse(char* p, int nargs, const char *fmt, ...) { char *arg, *p0, ch; int n = 0, empty; va_list args; @@ -273,3 +271,4 @@ FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...) { } #endif #endif +#undef i_implement \ No newline at end of file -- cgit v1.2.3 From d6ddb811365d5dd2cbc9c485f43ed4215d8e0148 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 7 Jun 2023 21:10:32 +0200 Subject: Updated and renamed c11/print.h to c11/fmt.h. Added fmt_tm() to print time/date from a struct tm. --- docs/cspan_api.md | 2 +- include/c11/fmt.h | 287 ++++++++++++++++++++++++++++++++++++++++++++++++++++ include/c11/print.h | 274 ------------------------------------------------- src/singleupdate.sh | 2 +- 4 files changed, 289 insertions(+), 276 deletions(-) create mode 100644 include/c11/fmt.h delete mode 100644 include/c11/print.h (limited to 'include/c11/print.h') diff --git a/docs/cspan_api.md b/docs/cspan_api.md index f0c6babd..3a811ebf 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -137,7 +137,7 @@ int main() { Slicing cspan without and with reducing the rank: ```c #define i_implement -#include +#include #include using_cspan3(Span, int); // Shorthand to define Span, Span2, and Span3 diff --git a/include/c11/fmt.h b/include/c11/fmt.h new file mode 100644 index 00000000..6c1388af --- /dev/null +++ b/include/c11/fmt.h @@ -0,0 +1,287 @@ +#ifndef FMT_H_INCLUDED +#define FMT_H_INCLUDED +/* +VER 2.2: NEW API: +void fmt_print(fmt, ...); +void fmt_println(fmt, ...); +void fmt_printd(dest, fmt, ...); +const char* fmt_tm(fmt, struct tm* tp); +void fmt_close(fmt_stream* ss); + + dest - destination, one of: + FILE* fp Write to a file + char* strbuf Write to a pre-allocated string buffer + fmt_stream* ss Write to a string-stream (auto allocated). + Set ss->overwrite=1 for overwrite-mode. + Call fmt_close(ss) after usage. + + fmt - format string (const char*) + {} Auto-detected format. If :MOD is not specified, + float will use ".8g" format, and double ".16g". + {:MODS} Format modifiers: '<' left align (replaces '-'). Default for char* and char. + '>' right align. Default for numbers. + Other than that MODS can be regular printf() format modifiers. + {{ }} % Print the '{', '}', and '%' characters. + +* C11 or higher required. +* MAX 255 chars fmt string by default. MAX 12 arguments after fmt string. +* Define FMT_IMPLEMENT or i_implement prior to #include in one translation unit. +* Define FMT_SHORTS to add print(), println() and printd() macros, without fmt_ prefix. +* (c) operamint, 2022, MIT License. +----------------------------------------------------------------------------------- +#define FMT_IMPLEMENT +#define FMT_SHORTS +#include "c11/fmt.h" + +int main() { + const double pi = 3.141592653589793; + const size_t x = 1234567890; + const char* string = "Hello world"; + const wchar_t* wstr = L"The whole"; + const char z = 'z'; + _Bool flag = 1; + unsigned char r = 123, g = 214, b = 90, w = 110; + char buffer[64]; + + print("Color: ({} {} {}), {}\n", r, g, b, flag); + println("Wide: {}, {}", wstr, L"wide world"); + println("{:10} {:10} {:10.2f}", 42ull, 43, pi); + println("{:>10} {:>10} {:>10}", z, z, w); + printd(stdout, "{:10} {:10} {:10}\n", "Hello", "Mad", "World"); + printd(stderr, "100%: {:<20} {:.*} {}\n", string, 4, pi, x); + printd(buffer, "Precision: {} {:.10} {}", string, pi, x); + fmt_println("{}", buffer); + fmt_println("Vector: ({}, {}, {})", 3.2, 3.3, pi); + + fmt_stream ss[1] = {0}; + printd(ss, "{} {}", "Pi is:", pi); + print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap); + printd(ss, "{} {}", ", Pi squared is:", pi*pi); + print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap); + fmt_close(ss); + + time_t now = time(NULL); + struct tm t1 = *localtime(&now), t2 = t1; + t2.tm_year += 2; + fmt_print(1, "Dates:\n {}\n {}\n", fmt_tm("%Y-%m-%d %X %Z", &t1), + fmt_tm("%Y-%m-%d %X %Z", &t2)); +} +*/ +#include +#include +#include + +#define fmt_OVERLOAD(name, ...) \ + fmt_JOIN(name, fmt_NUMARGS(__VA_ARGS__))(__VA_ARGS__) +#define fmt_CONCAT(a, b) a ## b +#define fmt_JOIN(a, b) fmt_CONCAT(a, b) +#define fmt_EXPAND(...) __VA_ARGS__ +#define fmt_NUMARGS(...) _fmt_APPLY_ARG_N((__VA_ARGS__, _fmt_RSEQ_N)) + +#define _fmt_APPLY_ARG_N(args) fmt_EXPAND(_fmt_ARG_N args) +#define _fmt_RSEQ_N 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +#define _fmt_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \ + _14, _15, _16, N, ...) N + +#if defined FMT_NDEBUG || defined NDEBUG +# define fmt_OK(exp) (void)(exp) +#else +# define fmt_OK(exp) assert(exp) +#endif + +typedef struct { + char* data; + intptr_t cap, len; + _Bool overwrite; +} fmt_stream; + +#define fmt_tm(fmt, tmptr) _fmt_strftime(fmt, tmptr) /* Max 2 usages. Buffer = 64 chars. */ +void fmt_close(fmt_stream* ss); +int _fmt_parse(char* p, int nargs, const char *fmt, ...); +void _fmt_bprint(fmt_stream*, const char* fmt, ...); +struct tm; const char* _fmt_strftime(const char *fmt, const struct tm *tp); + +#ifndef FMT_MAX +#define FMT_MAX 128 +#endif + +#ifdef FMT_SHORTS +#define print(...) fmt_printd(stdout, __VA_ARGS__) +#define println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__) +#define printd fmt_printd +#endif + +#define fmt_print(...) fmt_printd(stdout, __VA_ARGS__) +#define fmt_println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__) +#define fmt_printd(...) fmt_OVERLOAD(fmt_printd, __VA_ARGS__) + +/* Primary function. */ +#define fmt_printd2(to, fmt) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 0, fmt); \ + fmt_OK(_n == 0); _fmt_fn(to)(to, fmt); } while (0) +#define fmt_printd3(to, fmt, c) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 1, fmt, _fc(c)); \ + fmt_OK(_n == 1); _fmt_fn(to)(to, _fs, c); } while (0) +#define fmt_printd4(to, fmt, c, d) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 2, fmt, _fc(c), _fc(d)); \ + fmt_OK(_n == 2); _fmt_fn(to)(to, _fs, c, d); } while (0) +#define fmt_printd5(to, fmt, c, d, e) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 3, fmt, _fc(c), _fc(d), _fc(e)); \ + fmt_OK(_n == 3); _fmt_fn(to)(to, _fs, c, d, e); } while (0) +#define fmt_printd6(to, fmt, c, d, e, f) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 4, fmt, _fc(c), _fc(d), _fc(e), _fc(f)); \ + fmt_OK(_n == 4); _fmt_fn(to)(to, _fs, c, d, e, f); } while (0) +#define fmt_printd7(to, fmt, c, d, e, f, g) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 5, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g)); \ + fmt_OK(_n == 5); _fmt_fn(to)(to, _fs, c, d, e, f, g); } while (0) +#define fmt_printd8(to, fmt, c, d, e, f, g, h) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 6, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h)); \ + fmt_OK(_n == 6); _fmt_fn(to)(to, _fs, c, d, e, f, g, h); } while (0) +#define fmt_printd9(to, fmt, c, d, e, f, g, h, i) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 7, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), _fc(i)); \ + fmt_OK(_n == 7); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i); } while (0) +#define fmt_printd10(to, fmt, c, d, e, f, g, h, i, j) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 8, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ + _fc(i), _fc(j)); \ + fmt_OK(_n == 8); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j); } while (0) +#define fmt_printd11(to, fmt, c, d, e, f, g, h, i, j, k) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 9, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ + _fc(i), _fc(j), _fc(k)); \ + fmt_OK(_n == 9); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k); } while (0) +#define fmt_printd12(to, fmt, c, d, e, f, g, h, i, j, k, m) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 10, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ + _fc(i), _fc(j), _fc(k), _fc(m)); \ + fmt_OK(_n == 10); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m); } while (0) +#define fmt_printd13(to, fmt, c, d, e, f, g, h, i, j, k, m, n) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 11, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ + _fc(i), _fc(j), _fc(k), _fc(m), _fc(n)); \ + fmt_OK(_n == 11); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n); } while (0) +#define fmt_printd14(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 12, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ + _fc(i), _fc(j), _fc(k), _fc(m), _fc(n), _fc(o)); \ + fmt_OK(_n == 12); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n, o); } while (0) + +#define _fmt_fn(x) _Generic ((x), \ + FILE*: fprintf, \ + char*: sprintf, \ + fmt_stream*: _fmt_bprint) + +#if defined(_MSC_VER) && !defined(__clang__) +# define _signed_char_hhd +#else +# define _signed_char_hhd signed char: "hhd", +#endif + +#define _fc(x) _Generic (x, \ + _Bool: "d", \ + unsigned char: "hhu", \ + _signed_char_hhd \ + char: "c", \ + short: "hd", \ + unsigned short: "hu", \ + int: "d", \ + unsigned: "u", \ + long: "ld", \ + unsigned long: "lu", \ + long long: "lld", \ + unsigned long long: "llu", \ + float: "g", \ + double: "@g", \ + long double: "@Lg", \ + char*: "s", \ + wchar_t*: "ls", \ + void*: "p", \ + const char*: "s", \ + const wchar_t*: "ls", \ + const void*: "p") + +#if defined FMT_IMPLEMENT || defined i_implement + +#include +#include +#include +#include + +void fmt_close(fmt_stream* ss) { + free(ss->data); +} + +const char* _fmt_strftime(const char *fmt, const struct tm *tp) { + static char buf[2][64], i = 0; + i = !i; + strftime(buf[i], 64, fmt, tp); + return buf[i]; +} + +void _fmt_bprint(fmt_stream* ss, const char* fmt, ...) { + va_list args, args2; + va_start(args, fmt); + if (ss == NULL) { + vprintf(fmt, args); putchar('\n'); + goto done1; + } + va_copy(args2, args); + const int n = vsnprintf(NULL, 0U, fmt, args); + if (n < 0) goto done2; + const intptr_t pos = ss->overwrite ? 0 : ss->len; + ss->len = pos + n; + if (ss->len > ss->cap) { + ss->cap = ss->len + ss->cap/2; + ss->data = (char*)realloc(ss->data, (size_t)ss->cap + 1U); + } + vsprintf(ss->data + pos, fmt, args2); + done2: va_end(args2); + done1: va_end(args); +} + +int _fmt_parse(char* p, int nargs, const char *fmt, ...) { + char *arg, *p0, ch; + int n = 0, empty; + va_list args; + va_start(args, fmt); + do { + switch ((ch = *fmt)) { + case '%': + *p++ = '%'; + break; + case '}': + if (*++fmt == '}') break; /* ok */ + n = 99; + continue; + case '{': + if (*++fmt == '{') break; /* ok */ + if (++n > nargs) continue; + if (*fmt != ':' && *fmt != '}') n = 99; + fmt += (*fmt == ':'); + empty = *fmt == '}'; + arg = va_arg(args, char *); + *p++ = '%', p0 = p; + while (1) switch (*fmt) { + case '\0': n = 99; /* nobreak */ + case '}': goto done; + case '<': *p++ = '-', ++fmt; break; + case '>': p0 = NULL; /* nobreak */ + case '-': ++fmt; break; + case '*': if (++n <= nargs) arg = va_arg(args, char *); /* nobreak */ + default: *p++ = *fmt++; + } + done: + switch (*arg) { + case 'g': if (empty) memcpy(p, ".8", 2), p += 2; break; + case '@': ++arg; if (empty) memcpy(p, ".16", 3), p += 3; break; + } + if (!strchr("csdioxXufFeEaAgGnp", fmt[-1])) + while (*arg) *p++ = *arg++; + if (p0 && (p[-1] == 's' || p[-1] == 'c')) /* left-align str */ + memmove(p0 + 1, p0, (size_t)(p++ - p0)), *p0 = '-'; + fmt += *fmt == '}'; + continue; + } + *p++ = *fmt++; + } while (ch); + va_end(args); + return n; +} +#endif +#endif +#undef i_implement diff --git a/include/c11/print.h b/include/c11/print.h deleted file mode 100644 index ee0d8151..00000000 --- a/include/c11/print.h +++ /dev/null @@ -1,274 +0,0 @@ -#ifndef FMT_H_INCLUDED -#define FMT_H_INCLUDED -/* -VER 2.2: NEW API: -void print(fmt, ...); -void println(fmt, ...); -void printd(dest, fmt, ...); - -void fmt_print(fmt, ...); -void fmt_println(fmt, ...); -void fmt_printd(dest, fmt, ...); -void fmt_close(fmt_stream* ss); - - dest - destination, one of: - FILE* fp Write to a file - char* strbuf Write to a pre-allocated string buffer - fmt_stream* ss Write to a string-stream (auto allocated). - Set ss->overwrite=1 for overwrite-mode. - Call fmt_close(ss) after usage. - - fmt - format string - {} Auto-detected format. If :MOD is not specified, - float will use ".8g" format, and double ".16g". - {:MODS} Format modifiers: '<' left align (replaces '-'). Default for char* and char. - '>' right align. Default for numbers. - Other than that MODS can be regular printf() format modifiers. - {{ }} % Print the '{', '}', and '%' characters. - -* C11 or higher required. -* MAX 255 chars fmt string by default. MAX 12 arguments after fmt string. -* Define FMT_IMPLEMENT or i_implement prior to #include in one translation unit. -* Define FMT_SHORTS to define print(), println() and printd() macros, without fmt_ prefix. -* (c) operamint, 2022, MIT License. ------------------------------------------------------------------------------------ -#define FMT_IMPLEMENT -#define FMT_SHORTS -#include "c11/print.h" - -int main() { - const double pi = 3.141592653589793; - const size_t x = 1234567890; - const char* string = "Hello world"; - const wchar_t* wstr = L"The whole"; - const char z = 'z'; - _Bool flag = 1; - unsigned char r = 123, g = 214, b = 90, w = 110; - char buffer[64]; - - print("Color: ({} {} {}), {}\n", r, g, b, flag); - println("Wide: {}, {}", wstr, L"wide world"); - println("{:10} {:10} {:10.2f}", 42ull, 43, pi); - println("{:>10} {:>10} {:>10}", z, z, w); - printd(stdout, "{:10} {:10} {:10}\n", "Hello", "Mad", "World"); - printd(stderr, "100%: {:<20} {:.*} {}\n", string, 4, pi, x); - printd(buffer, "Precision: {} {:.10} {}", string, pi, x); - fmt_println("{}", buffer); - fmt_println("Vector: ({}, {}, {})", 3.2, 3.3, pi); - - fmt_stream ss[1] = {0}; - printd(ss, "{} {}", "Pi is:", pi); - print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap); - printd(ss, "{} {}", ", Pi squared is:", pi*pi); - print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap); - fmt_close(ss); -} -*/ -#include -#include -#include - -#define fmt_OVERLOAD(name, ...) \ - fmt_JOIN(name, fmt_NUMARGS(__VA_ARGS__))(__VA_ARGS__) -#define fmt_CONCAT(a, b) a ## b -#define fmt_JOIN(a, b) fmt_CONCAT(a, b) -#define fmt_EXPAND(...) __VA_ARGS__ -#define fmt_NUMARGS(...) _fmt_APPLY_ARG_N((__VA_ARGS__, _fmt_RSEQ_N)) - -#define _fmt_APPLY_ARG_N(args) fmt_EXPAND(_fmt_ARG_N args) -#define _fmt_RSEQ_N 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 -#define _fmt_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \ - _14, _15, _16, N, ...) N - -#if defined FMT_NDEBUG || defined NDEBUG -# define fmt_OK(exp) (void)(exp) -#else -# define fmt_OK(exp) assert(exp) -#endif - -typedef struct { - char* data; - intptr_t cap, len; - _Bool overwrite; -} fmt_stream; - -void fmt_close(fmt_stream* ss); -int _fmt_parse(char* p, int nargs, const char *fmt, ...); -void _fmt_bprint(fmt_stream*, const char* fmt, ...); - -#ifndef FMT_MAX -#define FMT_MAX 256 -#endif - -#ifdef FMT_SHORTS -#define print(...) fmt_printd(stdout, __VA_ARGS__) -#define println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__) -#define printd fmt_printd -#endif - -#define fmt_print(...) fmt_printd(stdout, __VA_ARGS__) -#define fmt_println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__) -#define fmt_printd(...) fmt_OVERLOAD(fmt_printd, __VA_ARGS__) - -/* Primary function. */ -#define fmt_printd2(to, fmt) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 0, fmt); \ - fmt_OK(_n == 0); _fmt_fn(to)(to, fmt); } while (0) -#define fmt_printd3(to, fmt, c) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 1, fmt, _fc(c)); \ - fmt_OK(_n == 1); _fmt_fn(to)(to, _fs, c); } while (0) -#define fmt_printd4(to, fmt, c, d) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 2, fmt, _fc(c), _fc(d)); \ - fmt_OK(_n == 2); _fmt_fn(to)(to, _fs, c, d); } while (0) -#define fmt_printd5(to, fmt, c, d, e) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 3, fmt, _fc(c), _fc(d), _fc(e)); \ - fmt_OK(_n == 3); _fmt_fn(to)(to, _fs, c, d, e); } while (0) -#define fmt_printd6(to, fmt, c, d, e, f) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 4, fmt, _fc(c), _fc(d), _fc(e), _fc(f)); \ - fmt_OK(_n == 4); _fmt_fn(to)(to, _fs, c, d, e, f); } while (0) -#define fmt_printd7(to, fmt, c, d, e, f, g) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 5, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g)); \ - fmt_OK(_n == 5); _fmt_fn(to)(to, _fs, c, d, e, f, g); } while (0) -#define fmt_printd8(to, fmt, c, d, e, f, g, h) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 6, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h)); \ - fmt_OK(_n == 6); _fmt_fn(to)(to, _fs, c, d, e, f, g, h); } while (0) -#define fmt_printd9(to, fmt, c, d, e, f, g, h, i) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 7, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), _fc(i)); \ - fmt_OK(_n == 7); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i); } while (0) -#define fmt_printd10(to, fmt, c, d, e, f, g, h, i, j) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 8, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j)); \ - fmt_OK(_n == 8); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j); } while (0) -#define fmt_printd11(to, fmt, c, d, e, f, g, h, i, j, k) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 9, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j), _fc(k)); \ - fmt_OK(_n == 9); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k); } while (0) -#define fmt_printd12(to, fmt, c, d, e, f, g, h, i, j, k, m) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 10, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j), _fc(k), _fc(m)); \ - fmt_OK(_n == 10); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m); } while (0) -#define fmt_printd13(to, fmt, c, d, e, f, g, h, i, j, k, m, n) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 11, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j), _fc(k), _fc(m), _fc(n)); \ - fmt_OK(_n == 11); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n); } while (0) -#define fmt_printd14(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 12, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j), _fc(k), _fc(m), _fc(n), _fc(o)); \ - fmt_OK(_n == 12); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n, o); } while (0) - -#define _fmt_fn(x) _Generic ((x), \ - FILE*: fprintf, \ - char*: sprintf, \ - fmt_stream*: _fmt_bprint) - -#if defined(_MSC_VER) && !defined(__clang__) -# define _signed_char_hhd -#else -# define _signed_char_hhd signed char: "hhd", -#endif - -#define _fc(x) _Generic (x, \ - _Bool: "d", \ - unsigned char: "hhu", \ - _signed_char_hhd \ - char: "c", \ - short: "hd", \ - unsigned short: "hu", \ - int: "d", \ - unsigned: "u", \ - long: "ld", \ - unsigned long: "lu", \ - long long: "lld", \ - unsigned long long: "llu", \ - float: "g", \ - double: "@g", \ - long double: "@Lg", \ - char*: "s", \ - wchar_t*: "ls", \ - void*: "p", \ - const char*: "s", \ - const wchar_t*: "ls", \ - const void*: "p") - -#if defined FMT_IMPLEMENT || defined i_implement - -#include -#include -#include - -void fmt_close(fmt_stream* ss) { - free(ss->data); -} - -void _fmt_bprint(fmt_stream* ss, const char* fmt, ...) { - va_list args, args2; - va_start(args, fmt); - if (ss == NULL) { - vprintf(fmt, args); putchar('\n'); - goto done1; - } - va_copy(args2, args); - const int n = vsnprintf(NULL, 0U, fmt, args); - if (n < 0) goto done2; - const intptr_t pos = ss->overwrite ? 0 : ss->len; - ss->len = pos + n; - if (ss->len > ss->cap) { - ss->cap = ss->len + ss->cap/2; - ss->data = (char*)realloc(ss->data, (size_t)ss->cap + 1U); - } - vsprintf(ss->data + pos, fmt, args2); - done2: va_end(args2); - done1: va_end(args); -} - -int _fmt_parse(char* p, int nargs, const char *fmt, ...) { - char *arg, *p0, ch; - int n = 0, empty; - va_list args; - va_start(args, fmt); - do { - switch ((ch = *fmt)) { - case '%': - *p++ = '%'; - break; - case '}': - if (*++fmt == '}') break; /* ok */ - n = 99; - continue; - case '{': - if (*++fmt == '{') break; /* ok */ - if (++n > nargs) continue; - if (*fmt != ':' && *fmt != '}') n = 99; - fmt += (*fmt == ':'); - empty = *fmt == '}'; - arg = va_arg(args, char *); - *p++ = '%', p0 = p; - while (1) switch (*fmt) { - case '\0': n = 99; /* nobreak */ - case '}': goto done; - case '<': *p++ = '-', ++fmt; break; - case '>': p0 = NULL; /* nobreak */ - case '-': ++fmt; break; - case '*': if (++n <= nargs) arg = va_arg(args, char *); /* nobreak */ - default: *p++ = *fmt++; - } - done: - switch (*arg) { - case 'g': if (empty) memcpy(p, ".8", 2), p += 2; break; - case '@': ++arg; if (empty) memcpy(p, ".16", 3), p += 3; break; - } - if (!strchr("csdioxXufFeEaAgGnp", fmt[-1])) - while (*arg) *p++ = *arg++; - if (p0 && (p[-1] == 's' || p[-1] == 'c')) /* left-align str */ - memmove(p0 + 1, p0, (size_t)(p++ - p0)), *p0 = '-'; - fmt += *fmt == '}'; - continue; - } - *p++ = *fmt++; - } while (ch); - va_end(args); - return n; -} -#endif -#endif -#undef i_implement \ No newline at end of file diff --git a/src/singleupdate.sh b/src/singleupdate.sh index 9b1d37a0..8a621e57 100644 --- a/src/singleupdate.sh +++ b/src/singleupdate.sh @@ -1,6 +1,6 @@ d=$(git rev-parse --show-toplevel) mkdir -p $d/../stcsingle/c11 $d/../stcsingle/stc -python singleheader.py $d/include/c11/print.h > $d/../stcsingle/c11/print.h +python singleheader.py $d/include/c11/fmt.h > $d/../stcsingle/c11/fmt.h python singleheader.py $d/include/stc/calgo.h > $d/../stcsingle/stc/calgo.h python singleheader.py $d/include/stc/carc.h > $d/../stcsingle/stc/carc.h python singleheader.py $d/include/stc/cbits.h > $d/../stcsingle/stc/cbits.h -- cgit v1.2.3