diff options
Diffstat (limited to 'strio.h')
-rw-r--r-- | strio.h | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/strio.h b/strio.h new file mode 100644 index 0000000..c8bb21f --- /dev/null +++ b/strio.h @@ -0,0 +1,217 @@ +#ifndef STRIO_H +#define STRIO_H + +#include "str.h" +#include "arena.h" + +int read_all(FILE *f, Str *buf, Arena *a); +int next_line(Str *src, Str *line); +void str_putf(Str s, FILE *f); +void str_put(Str s); + +int str_to_u64(Str s, uint64_t *out); +void str_cat_i64(Str *out, int64_t c, char pad_char, int min_width, Arena *a); +void str_cat_u64(Str *out, uint64_t c, char pad_char, int min_width, Arena *a); +void str_cat_fmtv(Str *out, Arena *arena, const char *fmt, va_list ap); +void str_cat_fmt(Str *out, Arena *arena, const char *fmt, ...); +Str str_fmtv(Arena *arena, const char *fmt, va_list ap); +Str str_fmt(Arena *arena, const char *fmt, ...); +const char *cstr_fmt(Arena *arena, const char *fmt, ...); + +#ifdef STRIO_IMPL + +#include <stdio.h> +#include <stdint.h> + +static inline long read_all_file_size(FILE *f) { + fseek(f, 0, SEEK_END); + long t = ftell(f); + fseek(f, 0, SEEK_SET); + return t > 0 ? t : -1; +} + +int read_all(FILE *f, Str *buf, Arena *a) { + if (!f) return -1; + long sz = read_all_file_size(f); + if (sz < 1) { + ptrdiff_t cap = 4096; + buf->s = new_arr(a, char, cap); + buf->n = 0; + while (!feof(f)) { + size_t n = fread(&buf->s[buf->n], 1, cap - buf->n, f); + if (n < 1) break; + buf->n += n; + if (buf->n >= cap) { + size_t c = cap; + while (buf->n >= cap) cap <<= 1; + buf->s = resize(a, buf->s, c, cap); + } + } + } else { + buf->n = sz; + buf->s = new_arr(a, char, sz); + size_t sz = fread(buf->s, 1, buf->n, f); + if (sz < (size_t)buf->n) return -1; + } + return ferror(f) ? -1 : 0; +} + +int next_line(Str *src, Str *line) { + if (src->n < 1) return 0; + line->s = src->s; + char *newln = memchr(src->s, '\n', src->n); + line->n = newln ? newln - src->s : src->n; + src->s += line->n + 1; + src->n -= line->n + 1; + if (line->n > 0 && line->s[line->n-1] == '\r') line->n--; + return 1; +} + +void str_putf(Str s, FILE *f) { + fwrite(s.s, 1, s.n, f); +} + +void str_put(Str s) { + str_putf(s, stdout); +} + +/* formatted conversion */ + +int str_to_u64(Str s, uint64_t *out) { + if (s.n < 1) return -1; + uint64_t acc = 0; + for (int i = 0; i < s.n; i++) { + char c = s.s[i]; + if (!(c >= '0' && c <= '9')) return -1; + acc = (acc * 10) + (c - '0'); + } + *out = acc; + return 0; +} + +static void str_cat_u64_(char buf[32], int *n, uint64_t c) { + int i = 0; + buf[31] = '\0'; + do { + buf[32 - ++i] = (c % 10) + '0'; + c /= 10; + } while (c); + *n = i; +} + +void str_cat_u64(Str *out, uint64_t c, char pad_char, int min_width, Arena *a) { + int n; + /* more than enough for the largest 64-bit number + * log_10(1 << 64) ~= 19.3 digits max */ + char buf[32]; + str_cat_u64_(buf, &n, c); + while (n < min_width && ++n < 32) buf[32-n] = pad_char; + str_cat(out, (Str) { &buf[sizeof(buf) - n], n }, a); +} + +void str_cat_i64(Str *out, int64_t c, char pad_char, int min_width, Arena *a) { + /* more than enough for the largest 64-bit number + * log_10(1 << 64) ~= 19.3 digits max */ + int n, neg = 0; + char buf[32]; + if (c < 0) neg = 1, c = -c; + str_cat_u64_(buf, &n, c); + if (neg) buf[sizeof(buf) - ++n] = '-'; + while (n < min_width && ++n < 32) buf[32-n] = pad_char; + str_cat(out, (Str) { &buf[sizeof(buf) - n], n }, a); +} + +/* IMPORTANT: this is not and will not be printf() compatible + * + * %s - c string + * %S - Str + * %i - int32 + * %I - int64 + * %u - uint32 + * %U - uin64 + * + **/ +void str_cat_fmtv(Str *out, Arena *arena, const char *fmt, va_list ap) { + size_t n = strlen(fmt); + for (size_t i = 0; i < n; i++) { + const char *mch = memchr(&fmt[i], '%', n - i); + if (!mch) { + str_cat(out, (Str) { (char*)&fmt[i], n - i }, arena); + break; + } + size_t skip = mch - &fmt[i]; + if (mch != &fmt[i]) { + str_cat(out, (Str) { (char*)&fmt[i], skip }, arena); + i += skip; + } + if (i + 1 < n) { + int zero_pad = 0, min_width = 0; + i++; + if (fmt[i] == '0') { + zero_pad = 1; + i++; + } + while (i < n && fmt[i] >= '0' && fmt[i] <= '9') { + min_width = min_width * 10 + (fmt[i] - '0'); + i++; + } + if (i >= n) break; + switch (fmt[i]) { + case 's': + str_cat(out, str_from_cstr(va_arg(ap, const char *)), arena); + break; + case 'S': + str_cat(out, va_arg(ap, Str), arena); + break; + case 'i': + str_cat_i64(out, va_arg(ap, int32_t), zero_pad?'0':' ', min_width, arena); + break; + case 'I': + str_cat_i64(out, va_arg(ap, int64_t), zero_pad?'0':' ', min_width, arena); + break; + case 'u': + str_cat_u64(out, va_arg(ap, uint32_t), zero_pad?'0':' ', min_width, arena); + break; + case 'U': + str_cat_u64(out, va_arg(ap, uint64_t), zero_pad?'0':' ', min_width, arena); + break; + default: + str_catc(out, fmt[i], arena); + break; + } + } + } +} + +void str_cat_fmt(Str *out, Arena *arena, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + str_cat_fmtv(out, arena, fmt, ap); + va_end(ap); +} + +Str str_fmtv(Arena *arena, const char *fmt, va_list ap) { + Str s = { 0 }; + str_cat_fmtv(&s, arena, fmt, ap); + return s; +} + +Str str_fmt(Arena *arena, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + Str r = str_fmtv(arena, fmt, ap); + va_end(ap); + return r; +} + +const char *cstr_fmt(Arena *arena, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + Str r = str_fmtv(arena, fmt, ap); + str_catc(&r, '\0', arena); + va_end(ap); + return r.s; +} + +#endif +#endif |