* using STRBUF_DESTROY before returning from the function. Failure to call
* STRBUF_DESTROY will leak the memory allocated to (strbuf_t).ptr. */
#define STRBUF_CREATE \
- &(strbuf_t) { .ptr = NULL }
+ (strbuf_t) { .ptr = NULL }
-/* STRBUF_CREATE_STATIC allocates a new strbuf_t on the stack, using the fixed
- * sized buffer "b". You may optionally call STRBUF_DESTROY with a fixed-sized
- * buffer. */
+/* STRBUF_CREATE_FIXED allocates a new strbuf_t on the stack, using the buffer
+ * "b" of fixed size "sz". The buffer is freed automatically when it goes out
+ * of scope. */
+#define STRBUF_CREATE_FIXED(b, sz) \
+ (strbuf_t) { .ptr = b, .size = sz, .fixed = 1 }
+
+/* STRBUF_CREATE_STATIC allocates a new strbuf_t on the stack, using the static
+ * buffer "b". This macro assumes that is can use `sizeof(b)` to determine the
+ * size of "b". If that is not the case, use STRBUF_CREATE_FIXED instead. */
#define STRBUF_CREATE_STATIC(b) \
- &(strbuf_t) { .ptr = b, .size = sizeof(b), .fixed = 1 }
+ (strbuf_t) { .ptr = b, .size = sizeof(b), .fixed = 1 }
/* STRBUF_DESTROY frees the memory allocated inside the buffer. The buffer
- * itself is assumed to be allocated on the stack and is not freed. */
+ * itself is assumed to be allocated on the stack and is not freed. Calling
+ * STRBUF_DESTROY with a buffer that was allocated with STRBUF_CREATE_FIXED or
+ * STRBUF_CREATE_STATIC is a no-op. */
#define STRBUF_DESTROY(buf) \
do { \
- if (!buf->fixed) { \
- free(buf->ptr); \
+ if (buf.fixed) { \
+ break; \
} \
- *buf = (strbuf_t){.ptr = NULL}; \
+ free(buf.ptr); \
+ buf.ptr = NULL; \
} while (0)
/* strbuf_create allocates a new strbuf_t on the heap, which must be freed
* using strbuf_destroy. */
strbuf_t *strbuf_create(void);
-/* strbuf_create_static allocates a new strbuf_t on the stack, using the fixed
+/* strbuf_create_fixed allocates a new strbuf_t on the stack, using the fixed
* sized buffer "buffer". The returned strbuf_t* must be freed using
* strbuf_destroy. */
-strbuf_t *strbuf_create_static(void *buffer, size_t buffer_size);
+strbuf_t *strbuf_create_fixed(void *buffer, size_t buffer_size);
/* strbuf_destroy frees a strbuf_t* allocated on the heap. */
void strbuf_destroy(strbuf_t *buf);
#include <errno.h>
#include <stdbool.h>
-#define STATIC_BUFFER_SIZE 8
+#define STATIC_BUFFER_SIZE 9
int test_buffer(strbuf_t *buf, bool is_static) {
CHECK_ZERO(strbuf_print(buf, "foo"));
EXPECT_EQ_STR("foobar", buf->ptr);
CHECK_ZERO(strbuf_printf(buf, "%d\n", 9000));
- char const *want = is_static ? "foobar9" : "foobar9000\n";
+ char const *want = is_static ? "foobar90" : "foobar9000\n";
EXPECT_EQ_STR(want, buf->ptr);
if (is_static) {
EXPECT_EQ_INT(ENOSPC, strbuf_print(buf, "buffer already filled"));
- EXPECT_EQ_STR("foobar9", buf->ptr);
+ EXPECT_EQ_STR("foobar90", buf->ptr);
}
strbuf_reset(buf);
CHECK_ZERO(strlen(buf->ptr));
CHECK_ZERO(strbuf_print(buf, "new content"));
- want = is_static ? "new con" : "new content";
+ want = is_static ? "new cont" : "new content";
EXPECT_EQ_STR(want, buf->ptr);
return 0;
return status;
}
-DEF_TEST(static_heap) {
- char mem[8];
+DEF_TEST(fixed_heap) {
+ char mem[STATIC_BUFFER_SIZE];
strbuf_t *buf;
- CHECK_NOT_NULL(buf = strbuf_create_static(mem, sizeof(mem)));
+ CHECK_NOT_NULL(buf = strbuf_create_fixed(mem, sizeof(mem)));
int status = test_buffer(buf, true);
}
DEF_TEST(dynamic_stack) {
- strbuf_t *buf;
- CHECK_NOT_NULL(buf = STRBUF_CREATE);
+ strbuf_t buf = {0};
+ buf = STRBUF_CREATE;
- int status = test_buffer(buf, false);
+ int status = test_buffer(&buf, false);
+
+ STRBUF_DESTROY(buf);
+ return status;
+}
+
+DEF_TEST(fixed_stack) {
+ /* This somewhat unusual syntax ensures that `sizeof(b)` will return a wrong
+ * number (size of the pointer, not the buffer; usually 4 or 8, depending on
+ * architecture), failing the test. */
+ char *b = (char[STATIC_BUFFER_SIZE]){0};
+ size_t sz = STATIC_BUFFER_SIZE;
+ strbuf_t buf = {0};
+ buf = STRBUF_CREATE_FIXED(b, sz);
+
+ int status = test_buffer(&buf, true);
STRBUF_DESTROY(buf);
return status;
}
DEF_TEST(static_stack) {
- char mem[8];
- strbuf_t *buf;
- CHECK_NOT_NULL(buf = STRBUF_CREATE_STATIC(mem));
+ char b[STATIC_BUFFER_SIZE];
+ strbuf_t buf = {0};
+ buf = STRBUF_CREATE_STATIC(b);
- int status = test_buffer(buf, true);
+ int status = test_buffer(&buf, true);
STRBUF_DESTROY(buf);
return status;
int main(int argc, char **argv) /* {{{ */
{
RUN_TEST(dynamic_heap);
- RUN_TEST(static_heap);
+ RUN_TEST(fixed_heap);
RUN_TEST(dynamic_stack);
+ RUN_TEST(fixed_stack);
RUN_TEST(static_stack);
END_TEST;