#ifndef JAC_STRINGBUILDER #define JAC_STRINGBUILDER #include #include #include #include #include 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: */