#include "str.h" #include #include #include #include #include #define STARTING_SIZE 256 #define READ_CHUNK_SIZE 1024 static void str_ensure_init(str *s) { if (s->data) return; s->capacity = STARTING_SIZE; s->length = 0; s->data = malloc(s->capacity); if (!s->data) abort(); s->data[0] = '\0'; } static void str_ensure_capacity(str *s, size_t extra) { str_ensure_init(s); size_t needed = s->length + extra + 1; // +1 for '\0' if (needed <= s->capacity) return; while (s->capacity < needed) s->capacity *= 2; char *new_data = realloc(s->data, s->capacity); if (!new_data) abort(); s->data = new_data; } void free_str(str *s) { free(s->data); s->data = NULL; s->length = 0; s->capacity = 0; } void str_append(str *s, const char *from) { str_append_len(s, from, strlen(from)); } void str_append_c(str *s, char c) { str_append_len(s, &c, 1); } void str_append_len(str *s, const char *from, size_t len) { str_ensure_capacity(s, len); memcpy(s->data + s->length, from, len); s->length += len; s->data[s->length] = '\0'; } void str_append_read(str *s, int fd) { char buf[READ_CHUNK_SIZE]; ssize_t n; while ((n = read(fd, buf, sizeof(buf))) > 0) { str_append_len(s, buf, (size_t)n); } } void str_append_fread(str *s, FILE *file) { char buf[READ_CHUNK_SIZE]; size_t n; while ((n = fread(buf, 1, sizeof(buf), file)) > 0) { str_append_len(s, buf, n); } } void str_append_fread_len(str *s, size_t size, FILE *file) { char buf[READ_CHUNK_SIZE]; while (size > 0) { size_t chunk = size > sizeof(buf) ? sizeof(buf) : size; size_t n = fread(buf, 1, chunk, file); if (n == 0) break; str_append_len(s, buf, n); size -= n; if (n < chunk) break; } } void str_appendf(str *s, const char *fmt, ...) { va_list args; va_start(args, fmt); va_list copy; va_copy(copy, args); int needed = vsnprintf(NULL, 0, fmt, copy); va_end(copy); if (needed < 0) { va_end(args); return; } str_ensure_capacity(s, (size_t)needed); vsnprintf(s->data + s->length, s->capacity - s->length, fmt, args); s->length += (size_t)needed; va_end(args); }