--- /dev/null 2007-07-12 03:40:41.165212167 +0300 +++ str.h 2007-08-31 07:35:04.000000000 +0300 @@ -0,0 +1,33 @@ +#ifndef STR_H +#define STR_H + +struct string { + char *buf; + + unsigned int alloc_size; + unsigned int len; + + unsigned int malloced:1; + unsigned int overflowed:1; +}; + +#define STR_STATIC(name, size) \ + struct { \ + struct string str; \ + char string_buf[(size) + 1]; \ + } name = { { (name).string_buf, sizeof((name).string_buf), 0, } } + +extern struct string *str_alloc(unsigned int initial_size); +extern void str_free(struct string **str); + +extern void str_append_n(struct string *str, const char *cstr, + unsigned int len); +extern void str_printfa(struct string *str, const char *fmt, ...) + __attribute__((format (printf, 2, 3))); +extern void str_truncate(struct string *str, unsigned int len); + +#define str_append(str, cstr) str_append_n(str, cstr, strlen(cstr)) +#define str_c(str) ((str)->buf) +#define str_len(str) ((str)->len) + +#endif --- /dev/null 2007-07-12 03:40:41.165212167 +0300 +++ str.c 2007-08-31 07:36:56.000000000 +0300 @@ -0,0 +1,85 @@ +#include "str.h" +#include "git-compat-util.h" + +struct string *str_alloc(unsigned int initial_size) +{ + struct string *str; + + str = xcalloc(sizeof(*str), 1); + str->alloc_size = initial_size + 1; + str->buf = xmalloc(str->alloc_size); + str->buf[0] = '\0'; + return str; +} + +void str_free(struct string **_str) +{ + struct string *str = *_str; + + if (str->malloced) + free(str->buf); + str->buf = NULL; + free(str); + + *_str = NULL; +} + +static void str_grow_if_needed(struct string *str, unsigned int *len) +{ + unsigned int avail = str->alloc_size - str->len; + + if (*len >= avail) { + if (!str->malloced) { + /* static buffer size */ + *len = avail; + str->overflowed = 1; + } else { + str->alloc_size = (str->len + *len) * 2; + str->buf = xrealloc(str->buf, str->alloc_size); + } + } +} + +void str_append_n(struct string *str, const char *cstr, unsigned int len) +{ + str_grow_if_needed(str, &len); + memcpy(str->buf + str->len, cstr, len); + str->len += len; + str->buf[str->len] = '\0'; +} + +void str_printfa(struct string *str, const char *fmt, ...) +{ + unsigned int len, avail = str->alloc_size - str->len; + va_list va, va2; + int ret; + + va_start(va, fmt); + va_copy(va2, va); + ret = vsnprintf(str->buf + str->len, avail, fmt, va); + assert(ret >= 0); + + if ((unsigned int)ret >= avail) { + if (!str->malloced) { + str->overflowed = 1; + ret = avail == 0 ? 0 : avail-1; + } else { + len = ret; + str_grow_if_needed(str, &len); + avail = str->alloc_size - str->len; + + ret = vsnprintf(str->buf + str->len, avail, fmt, va2); + assert(ret >= 0 && (unsigned int)ret < avail); + } + } + str->len += ret; + va_end(va); +} + +void str_truncate(struct string *str, unsigned int len) +{ + if (len >= str->alloc_size) + len = str->alloc_size - 1; + str->len = len; + str->buf[len] = '\0'; +}