diff options
Diffstat (limited to 'strbuf.c')
-rw-r--r-- | strbuf.c | 170 |
1 files changed, 148 insertions, 22 deletions
@@ -1,41 +1,167 @@ #include "cache.h" -#include "strbuf.h" -void strbuf_init(struct strbuf *sb) { - sb->buf = NULL; - sb->eof = sb->alloc = sb->len = 0; +void strbuf_init(struct strbuf *sb, size_t hint) +{ + memset(sb, 0, sizeof(*sb)); + if (hint) + strbuf_grow(sb, hint); } -static void strbuf_begin(struct strbuf *sb) { +void strbuf_release(struct strbuf *sb) +{ free(sb->buf); - strbuf_init(sb); + memset(sb, 0, sizeof(*sb)); } -static void inline strbuf_add(struct strbuf *sb, int ch) { - if (sb->alloc <= sb->len) { - sb->alloc = sb->alloc * 3 / 2 + 16; - sb->buf = xrealloc(sb->buf, sb->alloc); +void strbuf_reset(struct strbuf *sb) +{ + if (sb->len) + strbuf_setlen(sb, 0); +} + +char *strbuf_detach(struct strbuf *sb) +{ + char *res = sb->buf; + strbuf_init(sb, 0); + return res; +} + +void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc) +{ + strbuf_release(sb); + sb->buf = buf; + sb->len = len; + sb->alloc = alloc; + strbuf_grow(sb, 0); + sb->buf[sb->len] = '\0'; +} + +void strbuf_grow(struct strbuf *sb, size_t extra) +{ + if (sb->len + extra + 1 <= sb->len) + die("you want to use way too much memory"); + ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc); +} + +void strbuf_rtrim(struct strbuf *sb) +{ + while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1])) + sb->len--; + sb->buf[sb->len] = '\0'; +} + +void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len) +{ + strbuf_grow(sb, len); + if (pos > sb->len) + die("`pos' is too far after the end of the buffer"); + memmove(sb->buf + pos + len, sb->buf + pos, sb->len - pos); + memcpy(sb->buf + pos, data, len); + strbuf_setlen(sb, sb->len + len); +} + +void strbuf_splice(struct strbuf *sb, size_t pos, size_t len, + const void *data, size_t dlen) +{ + if (pos + len < pos) + die("you want to use way too much memory"); + if (pos > sb->len) + die("`pos' is too far after the end of the buffer"); + if (pos + len > sb->len) + die("`pos + len' is too far after the end of the buffer"); + + if (dlen >= len) + strbuf_grow(sb, dlen - len); + memmove(sb->buf + pos + dlen, + sb->buf + pos + len, + sb->len - pos - len); + memcpy(sb->buf + pos, data, dlen); + strbuf_setlen(sb, sb->len + dlen - len); +} + +void strbuf_add(struct strbuf *sb, const void *data, size_t len) +{ + strbuf_grow(sb, len); + memcpy(sb->buf + sb->len, data, len); + strbuf_setlen(sb, sb->len + len); +} + +void strbuf_addf(struct strbuf *sb, const char *fmt, ...) +{ + int len; + va_list ap; + + va_start(ap, fmt); + len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); + va_end(ap); + if (len < 0) { + len = 0; } - sb->buf[sb->len++] = ch; + if (len > strbuf_avail(sb)) { + strbuf_grow(sb, len); + va_start(ap, fmt); + len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); + va_end(ap); + if (len > strbuf_avail(sb)) { + die("this should not happen, your snprintf is broken"); + } + } + strbuf_setlen(sb, sb->len + len); } -static void strbuf_end(struct strbuf *sb) { - strbuf_add(sb, 0); +size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f) +{ + size_t res; + + strbuf_grow(sb, size); + res = fread(sb->buf + sb->len, 1, size, f); + if (res > 0) { + strbuf_setlen(sb, sb->len + res); + } + return res; } -void read_line(struct strbuf *sb, FILE *fp, int term) { - int ch; - strbuf_begin(sb); - if (feof(fp)) { - sb->eof = 1; - return; +ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint) +{ + size_t oldlen = sb->len; + + strbuf_grow(sb, hint ? hint : 8192); + for (;;) { + ssize_t cnt; + + cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1); + if (cnt < 0) { + strbuf_setlen(sb, oldlen); + return -1; + } + if (!cnt) + break; + sb->len += cnt; + strbuf_grow(sb, 8192); } + + sb->buf[sb->len] = '\0'; + return sb->len - oldlen; +} + +int strbuf_getline(struct strbuf *sb, FILE *fp, int term) +{ + int ch; + + strbuf_grow(sb, 0); + if (feof(fp)) + return EOF; + + strbuf_reset(sb); while ((ch = fgetc(fp)) != EOF) { if (ch == term) break; - strbuf_add(sb, ch); + strbuf_grow(sb, 1); + sb->buf[sb->len++] = ch; } if (ch == EOF && sb->len == 0) - sb->eof = 1; - strbuf_end(sb); + return EOF; + + sb->buf[sb->len] = '\0'; + return 0; } |