/* * strbuf.h — safe growable printf buffer * * Replaces snprintf(buf+off, sizeof(buf)-off, ...) chains that crash * on overflow (snprintf returns un-truncated size, offset exceeds buffer, * next call gets negative size → FORTIFY abort on Bionic/Android). * * Usage: * struct strbuf sb = strbuf_new(); * strbuf_addf(&sb, "{\"ver\":\"%d\"", ver); * strbuf_addf(&sb, ",\"name\":\"%s\"", name); * strbuf_addf(&sb, "}"); * // use strbuf_str(&sb) or strbuf_detach(&sb) * strbuf_free(&sb); */ #ifndef STRBUF_H #define STRBUF_H #include #include struct strbuf { char *buf; /* allocated buffer, always null-terminated */ size_t cap; /* total capacity (including '\0') */ size_t len; /* current length (excluding '\0') */ }; /* zero-init on stack: struct strbuf sb = {0}; */ #define strbuf_new() ((struct strbuf){NULL, 0, 0}) void strbuf_init(struct strbuf *sb, size_t initial_cap); void strbuf_free(struct strbuf *sb); /* returns buf and detaches — caller must u_free(). sb is reset to empty */ char *strbuf_detach(struct strbuf *sb); /* reset len=0, keep allocation */ void strbuf_reset(struct strbuf *sb); /* printf-like append. auto-grows. returns written bytes or -1 on OOM */ int strbuf_addf(struct strbuf *sb, const char *fmt, ...) __attribute__((format(printf, 2, 3))); void strbuf_addc(struct strbuf *sb, char c); void strbuf_adds(struct strbuf *sb, const char *s); /* safe accessor — never returns NULL */ #define strbuf_str(sb) ((sb)->buf ? (sb)->buf : "") #endif /* STRBUF_H */