#include #include #include #include "str.h" #include "err.h" /* strings */ void str_init(str_t *b, size_t n) { b->buf = calloc(1, n); if (!b->buf) { efatal("str_init"); } b->cap = n; b->sz = 0; } /* does NOT change sz! just makes room */ void str_grow(str_t *b, size_t n) { size_t sz = b->sz + n; size_t c = b->cap; if (sz > c) { while (sz > c) c <<= 1; char *p = realloc(b->buf, c); if (!p) efatal("str_grow"); b->buf = p; b->cap = c; } } void str_cat(str_t *b, strv_t s) { str_grow(b, s.n); memcpy(&b->buf[b->sz], s.s, s.n); b->sz += s.n; } void str_catc(str_t *b, char c) { str_grow(b, 1); b->buf[b->sz++] = c; } void str_free(str_t *b) { free(b->buf); } /* string views */ strv_t strv(const char *s) { return (strv_t) { s, strlen(s) }; } int strv_split(strv_t *src, int chr, strv_t *dest) { char *c = memchr(src->s, chr, src->n); *dest = (strv_t) { src->s, c ? c - src->s : src->n }; src->s = c ? c + 1 : &src->s[src->n]; src->n -= dest->n + !!c; return (src->n + dest->n) > 0; } char strv_next(strv_t *s) { if (s->n > 0) { s->n--; return *(s->s++); } else { return 0; } } void str_fmt(str_t *b, const char *fmt, ...) { va_list ap; char c; b->sz = 0; va_start(ap, fmt); while ((c = *fmt++)) { if (c == '%' && *fmt) { switch ((c = *fmt++)) { case 'c': str_catc(b, va_arg(ap, int)); break; case 's': str_cat(b, va_arg(ap, strv_t)); break; default: str_catc(b, c); } } else { str_catc(b, c); } } va_end(ap); }