aboutsummaryrefslogtreecommitdiffstats
path: root/include/stringbuilder.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/stringbuilder.h')
-rw-r--r--include/stringbuilder.h114
1 files changed, 114 insertions, 0 deletions
diff --git a/include/stringbuilder.h b/include/stringbuilder.h
new file mode 100644
index 0000000..e695082
--- /dev/null
+++ b/include/stringbuilder.h
@@ -0,0 +1,114 @@
+#ifndef JAC_STRINGBUILDER
+#define JAC_STRINGBUILDER
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct jac_sb {
+ char *data;
+ size_t size;
+ size_t cap;
+} jac_sb;
+
+jac_sb jac_sb_empty(void);
+jac_sb jac_sb_new(size_t size);
+jac_sb jac_sb_from_buf(const char* buf);
+jac_sb jac_sb_from_buf_n(const char* buf, size_t size);
+
+void jac_sb_append_buf(jac_sb *sb, const char *c);
+void jac_sb_append_buf_n(jac_sb *sb, const char *c, size_t n);
+void jac_sb_putc(jac_sb *sb, char c);
+void jac_sb_snprintf(jac_sb *sb, const char* fmt, ...);
+void jac_sb_vsnprintf(jac_sb *sb, const char* fmt, va_list list);
+
+void jac_sb_free(jac_sb sb);
+
+#define STRINGBUILDER_IMPLEMENTATION
+#ifdef STRINGBUILDER_IMPLEMENTATION
+
+#define __SB_REALLOC(sb, n) \
+do { \
+ if (sb->size + n >= sb->cap) { \
+ size_t rsz = 1UL << \
+ (64 - __builtin_clzl((unsigned long)(sb->size+n))); \
+ sb->data = realloc(sb->data, rsz + 1); \
+ sb->cap = rsz; \
+ } \
+ sb->size += n; \
+} while(0) \
+
+jac_sb jac_sb_empty(void) {
+ return (jac_sb){.data = calloc(1, 1), .size = 0, .cap = 0};
+}
+jac_sb jac_sb_new(size_t size) {
+ return (jac_sb){.data = calloc(size + 1, 1), .size = 0, .cap = size};
+}
+jac_sb jac_sb_from_buf(const char* buf) {
+ size_t ln = strlen(buf);
+ jac_sb ret = {.data = malloc(ln + 1), .size = ln, .cap = ln};
+ memcpy(ret.data, buf, ln);
+ ret.data[ret.size] = '\0';
+ return ret;
+}
+jac_sb jac_sb_from_buf_n(const char* buf, size_t size) {
+ jac_sb ret = {.data = malloc(size + 1), .size = size, .cap = size};
+ memcpy(ret.data, buf, size);
+ ret.data[size] = '\0';
+ return ret;
+}
+
+void jac_sb_append_buf(jac_sb *sb, const char *c) {
+ jac_sb_append_buf_n(sb, c, strlen(c));
+}
+void jac_sb_append_buf_n(jac_sb *sb, const char *c, size_t n) {
+ __SB_REALLOC(sb, n);
+ memcpy(sb->data + sb->size - n, c, n);
+ sb->data[sb->size] = '\0';
+}
+void jac_sb_putc(jac_sb *sb, char c) {
+ if (sb->size + 1 >= sb->cap) {
+ sb->cap <<= 1;
+ sb->data = realloc(sb->data, sb->cap + 1);
+ }
+ sb->data[sb->size++] = c;
+ sb->data[sb->size] = '\0';
+}
+
+void jac_sb_snprintf(jac_sb *sb, const char* fmt, ...) {
+ va_list l;
+ va_start(l, fmt);
+ jac_sb_vsnprintf(sb, fmt, l);
+}
+void jac_sb_vsnprintf(jac_sb *sb, const char* fmt, va_list list) {
+ va_list ls1;
+ size_t ln;
+try_write:
+ /*cap: 4, size: 2
+ * | a | b | \0 | \0 | \0 |
+ */
+ va_copy(ls1, list);
+ ln = vsnprintf(sb->data + sb->size, sb->cap - sb->size + 1, fmt, ls1);
+ va_end(ls1);
+ if (ln >= sb->cap - sb->size + 1) {
+ sb->cap <<= 1;
+ sb->data = realloc(sb->data, sb->cap + 1);
+ goto try_write;
+ }
+ va_end(list);
+ sb->size += ln;
+}
+
+void jac_sb_free(jac_sb sb) {
+ free(sb.data);
+}
+
+
+#undef __SB_REALLOC
+#endif /* STRINGBUILDER_IMPLEMENTATION */
+
+#endif /* JAC_STRINGBUILDER */
+
+/* vim: set ts=8 noet: */