/* * strbuf.c — safe growable printf buffer */ #include "strbuf.h" #include "mem.h" #include #include #include #define STRBUF_MIN_CAP 16 void strbuf_init(struct strbuf *sb, size_t initial_cap) { if (initial_cap < STRBUF_MIN_CAP) initial_cap = STRBUF_MIN_CAP; sb->buf = u_malloc(initial_cap); if (sb->buf) { sb->buf[0] = '\0'; sb->cap = initial_cap; } else { sb->cap = 0; } sb->len = 0; } void strbuf_free(struct strbuf *sb) { if (sb->buf) { u_free(sb->buf); sb->buf = NULL; } sb->cap = 0; sb->len = 0; } char *strbuf_detach(struct strbuf *sb) { char *ret = sb->buf; sb->buf = NULL; sb->cap = 0; sb->len = 0; return ret; } void strbuf_reset(struct strbuf *sb) { if (sb->buf) sb->buf[0] = '\0'; sb->len = 0; } static int strbuf_grow(struct strbuf *sb, size_t need) { size_t nc = sb->cap ? sb->cap : STRBUF_MIN_CAP; while (nc < need) { nc *= 2; if (nc < STRBUF_MIN_CAP) return -1; } char *n = u_realloc(sb->buf, nc); if (!n) return -1; sb->buf = n; sb->cap = nc; return 0; } int strbuf_addf(struct strbuf *sb, const char *fmt, ...) { va_list ap; /* measure */ va_start(ap, fmt); int need = vsnprintf(NULL, 0, fmt, ap); va_end(ap); if (need < 0) { return -1; } /* grow */ size_t want = sb->len + (size_t)need + 1; /* +1 for '\0' */ if (want > sb->cap && strbuf_grow(sb, want) < 0) return -1; /* write */ va_start(ap, fmt); int w = vsnprintf(sb->buf + sb->len, sb->cap - sb->len, fmt, ap); va_end(ap); if (w > 0) sb->len += (size_t)w; return w; } void strbuf_addc(struct strbuf *sb, char c) { if (sb->len + 2 > sb->cap && strbuf_grow(sb, sb->len + 2) < 0) return; sb->buf[sb->len++] = c; sb->buf[sb->len] = '\0'; } void strbuf_adds(struct strbuf *sb, const char *s) { if (!s) return; size_t slen = strlen(s); if (sb->len + slen + 1 > sb->cap && strbuf_grow(sb, sb->len + slen + 1) < 0) return; memcpy(sb->buf + sb->len, s, slen); sb->len += slen; sb->buf[sb->len] = '\0'; }