kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

strbuf.h (2477B)


      1 #ifndef KIT_STRBUF_H
      2 #define KIT_STRBUF_H
      3 
      4 /* Tiny bounded text builder, freestanding-friendly.
      5  *
      6  * Caller owns the backing buffer.  strbuf_init reserves one slot for the
      7  * NUL terminator; appends past `cap-1` characters silently truncate and
      8  * `truncated` flips to 1 so the caller can detect overflow without
      9  * scanning the result.  Every helper keeps the buffer NUL-terminated
     10  * after every append, so the buffer is always a valid C string. */
     11 
     12 #include <stddef.h>
     13 
     14 #include "core/core.h"
     15 #include "core/slice.h"
     16 
     17 typedef struct StrBuf {
     18   char* base; /* start of buffer (caller owned) */
     19   char* p;    /* next write slot */
     20   char* end;  /* one past last writable byte (reserves NUL slot) */
     21   u8 truncated;
     22   u8 pad[7];
     23 } StrBuf;
     24 
     25 static inline void strbuf_init(StrBuf* sb, char* buf, size_t cap) {
     26   sb->base = buf;
     27   sb->p = buf;
     28   sb->end = (cap == 0) ? buf : (buf + cap - 1);
     29   sb->truncated = 0;
     30   if (cap) buf[0] = '\0';
     31 }
     32 
     33 static inline void strbuf_reset(StrBuf* sb) {
     34   sb->p = sb->base;
     35   sb->truncated = 0;
     36   if (sb->base != sb->end || sb->base != NULL) {
     37     if (sb->base) *sb->base = '\0';
     38   }
     39 }
     40 
     41 static inline size_t strbuf_len(const StrBuf* sb) {
     42   return (size_t)(sb->p - sb->base);
     43 }
     44 
     45 static inline const char* strbuf_cstr(const StrBuf* sb) { return sb->base; }
     46 
     47 /* View the accumulated bytes as a Slice. The backing buffer stays
     48  * NUL-terminated, so the slice's `.s` is safe to hand to NUL-requiring
     49  * boundaries while `.len` carries the exact length. */
     50 static inline Slice strbuf_slice(const StrBuf* sb) {
     51   return (Slice){.s = sb->base, .len = strbuf_len(sb)};
     52 }
     53 
     54 static inline void strbuf_putc(StrBuf* sb, char c) {
     55   if (sb->p < sb->end) {
     56     *sb->p++ = c;
     57     *sb->p = '\0';
     58   } else {
     59     sb->truncated = 1;
     60   }
     61 }
     62 
     63 static inline void strbuf_puts(StrBuf* sb, const char* s) {
     64   while (*s) strbuf_putc(sb, *s++);
     65 }
     66 
     67 /* Append `n` bytes verbatim (may contain embedded NULs; the builder still
     68  * appends a trailing NUL byte after them so strbuf_cstr() works for the
     69  * common all-printable case). */
     70 static inline void strbuf_putn(StrBuf* sb, const char* s, size_t n) {
     71   for (size_t i = 0; i < n; ++i) strbuf_putc(sb, s[i]);
     72 }
     73 
     74 /* Append a slice's bytes verbatim (length-explicit, no NUL scan). */
     75 static inline void strbuf_put_slice(StrBuf* sb, Slice s) {
     76   strbuf_putn(sb, s.s, s.len);
     77 }
     78 
     79 void strbuf_put_u64(StrBuf*, u64 v);
     80 void strbuf_put_i64(StrBuf*, i64 v);
     81 void strbuf_put_hex_u64(StrBuf*, u64 v); /* "0x" + hex, no padding */
     82 
     83 #endif