From: git Date: Fri, 17 Apr 2026 11:32:47 +0000 (-0400) Subject: initial public commit X-Git-Url: https://git.datadissipation.net/?a=commitdiff_plain;h=5512033073932aaa28f2b7c2cdcf6d7190e7d5d0;p=single-header-libcext.git initial public commit --- 5512033073932aaa28f2b7c2cdcf6d7190e7d5d0 diff --git a/README.md b/README.md new file mode 100644 index 0000000..59cf6d6 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +A (WIP) collection of portable, strict C99, single-header implementations of common libc extensions. + +### How to + +Include the header in every file needed as usual: + +``` +#include "" +``` + +In the file chosen for the function implementation: + +``` +#define _IMPLEMENTATION_ +#include "" +``` + +By default, the header won't have any includes, change that with: + +``` +#define _INCLUDE_LIBC_ +``` + +Or disable function override with: + +``` +#define HAVE_ +``` diff --git a/asprintf.h b/asprintf.h new file mode 100644 index 0000000..8664796 --- /dev/null +++ b/asprintf.h @@ -0,0 +1,92 @@ +/* https://git.datadissipation.net */ +#ifndef ASPRINTF_H_ + #define ASPRINTF_H_ + + #ifdef ASPRINTF_INCLUDE_LIBC_ + #include + #include + #include + #endif + + #ifndef HAVE_ASPRINTF + int vasprintf_(char **strp, const char *fmt, va_list ap); + int asprintf_(char **strp, const char *fmt, ...); + /* + * Credit for a big part of the macro madness: + * Jens Gudstedt + * https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ + */ + #define vasprintf(s, f, a) vasprintf_(s, f, a) + #define I_COND_COMMA_(...) , + #define I_PICK_ARG_(_1, _2, ARG, ...) ARG + #define I_HAS_COMMA_(...) I_PICK_ARG_(__VA_ARGS__, 1, 0) + + #define I_ISEMPTY_(...) \ + II_ISEMPTY_( \ + /* test if there is just one argument, eventually an empty \ + one */ \ + I_HAS_COMMA_(__VA_ARGS__), \ + /* test if I_COND_COMMA_ together with the argument \ + adds a comma */ \ + I_HAS_COMMA_(I_COND_COMMA_ __VA_ARGS__), \ + /* test if the argument together with a parenthesis \ + adds a comma */ \ + I_HAS_COMMA_(__VA_ARGS__ (/*empty*/)), \ + /* test if placing it between I_COND_COMMA_ and the \ + parenthesis adds a comma */ \ + I_HAS_COMMA_(I_COND_COMMA_ __VA_ARGS__ (/*empty*/)) \ + ) + + #define I_PASTE5_(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4 + #define II_ISEMPTY_(_0, _1, _2, _3)\ + I_HAS_COMMA_(I_PASTE5_(I_IS_EMPTY_CASE_, _0, _1, _2, _3)) + #define I_IS_EMPTY_CASE_0001 , + + #define II_PASTE_(a) I_EMPTY_##a + #define I_PASTE_(a) II_PASTE_(a) + + #define I_GET_ARG_(...) I_PICK_ARG_(__VA_ARGS__) + #define asprintf(s, f, ...)\ + asprintf_(s, f I_PASTE_(I_ISEMPTY_(I_GET_ARG_(, , __VA_ARGS__))) __VA_ARGS__) + #define I_EMPTY_1 + #define I_EMPTY_0 I_COND_COMMA_() + #endif + + #ifdef ASPRINTF_IMPLEMENTATION_ + int vasprintf_(char **strp, const char *fmt, va_list ap) { + int size, ret; + va_list tp; + + va_copy(tp, ap); + size = vsnprintf(NULL, 0, fmt, tp); + va_end(tp); + + if (size < 0) { + return -1; + } + *strp = malloc(size + 1); + if (*strp == NULL) { + return -1; + } + + ret = vsnprintf(*strp, size + 1, fmt, ap); + if (ret < 0) { + free(*strp); + return -1; + } + + return ret; + } + + int asprintf_(char **strp, const char *fmt, ...) { + int ret; + va_list ap; + + va_start(ap, fmt); + ret = vasprintf(strp, fmt, ap); + va_end(ap); + + return ret; + } + #endif +#endif