#include #include "mrk/buf.h" mrk_err mrk_buf_init(mrk_buf *buf) { MRK_MALLOC(&buf->s, 2); // 2 ^ 0 buf->cap = 1; buf->len = 0; buf->s[buf->len] = '\0'; return mrk_err_ok; } mrk_err mrk_buf_expand(mrk_buf *buf, size_t required) { size_t new_cap = buf->cap; while (buf->len + required >= new_cap) { // Grow buffer size in powers of two new_cap <<= 1; } // No need to reallocate if there's already enough space if (new_cap == buf->cap) { return mrk_err_ok; } char *new_buf = realloc(buf->s, new_cap + 1); if (new_buf == NULL) { return mrk_err_failed_alloc; } buf->s = new_buf; buf->cap = new_cap; return mrk_err_ok; } mrk_err mrk_buf_compact(mrk_buf *buf) { char *new_buf = realloc(buf->s, buf->len + 1); if (new_buf == NULL) { return mrk_err_failed_alloc; } buf->s = new_buf; buf->cap = buf->len; return mrk_err_ok; } mrk_err mrk_buf_append(mrk_buf *buf, const char *s) { size_t len = strlen(s); return mrk_buf_append_n(buf, s, len); } mrk_err mrk_buf_append_n(mrk_buf *buf, const char *s, size_t len) { MRK_RES(mrk_buf_expand(buf, len)); memcpy(&buf->s[buf->len], s, len); buf->len += len; // Keep the buffer nul-terminated buf->s[buf->len] = '\0'; return mrk_err_ok; }