jrk

my own c stdlib to keep myself sane
git clone git://git.jakekoroman.com/jrk
Log | Files | Refs

jrk.h (25155B)


      1 /*
      2  * TODO:
      3  *   - look at at the jrk_sv_chop_delim_loop stuff. there must
      4  *     must be a better way of handling things.
      5  *
      6  * NOTES:
      7  *   To avoid the application from crashing when calling the die macros
      8  *   you can define JRK_NO_EXIT_ON_DIE. This will convert all die macros
      9  *   to log calls. It is now up to the caller to handle the errors properly.
     10  *   Most functions that can fail will return a bool and will log themselves,
     11  *   which should make error handling easy. Be aware that some will return a
     12  *   negative int to indicate failure. These are normally functions that call
     13  *   into POSIX and return sizes as to be conformant to those POSIX syscalls.
     14  */
     15 
     16 #include <stdbool.h>
     17 #include <stdint.h>
     18 
     19 #ifdef JRK_IMPLEMENTATION_WITH_SHORTNAMES
     20   #define JRK_IMPLEMENTATION
     21   #define JRK_SHORTNAMES
     22 #endif // JRK_IMPLEMENTATION_WITH_SHORTNAMES
     23 
     24 typedef int8_t i8;
     25 typedef int16_t i16;
     26 typedef int32_t i32;
     27 typedef int64_t i64;
     28 
     29 typedef uint8_t u8;
     30 typedef uint16_t u16;
     31 typedef uint32_t u32;
     32 typedef uint64_t u64;
     33 
     34 typedef float f32;
     35 typedef double f64;
     36 
     37 #define JRK_UNUSED(x) (void)x
     38 #define JRK_ARRLENGTH(arr) (sizeof(arr) / sizeof(arr[0]))
     39 
     40 #define jrk_return_defer(value) \
     41     do { result = value; goto defer; } while(0)
     42 
     43 #define JRK_KILOBYTES(x) ((u64)x*1024)
     44 #define JRK_MEGABYTES(x) ((u64)JRK_KILOBYTES((u64)x*1024))
     45 #define JRK_GIGABYTES(x) ((u64)JRK_MEGABYTES((u64)x*1024))
     46 #define JRK_TERABYTES(x) ((u64)JRK_GIGABYTES((u64)x*1024))
     47 
     48 #define JRK_TMPSTRINGS_ARR_CAPACITY 4
     49 #define JRK_TMPSTRINGS_STR_CAPACITY JRK_KILOBYTES(1)
     50 
     51 typedef struct {
     52     u8 *data;
     53     u64 offset;
     54     u64 prev_offset;
     55     u64 capacity;
     56 } jrk_Arena;
     57 
     58 typedef struct {
     59     char *items;
     60     u64 count;
     61     u64 capacity;
     62 } jrk_StringBuilder;
     63 
     64 typedef struct {
     65     char *data;
     66     u64 count;
     67 } jrk_StringView;
     68 
     69 void *jrk_ecalloc(u64, u64);
     70 void *jrk_erealloc(void*, u64);
     71 
     72 jrk_Arena jrk_arena_create(u8*, u64);
     73 void *jrk_arena_push(jrk_Arena*, u64);
     74 char *jrk_arena_push_strf(jrk_Arena*, char*, ...);
     75 void jrk_arena_reset(jrk_Arena*);
     76 void *jrk_arena_resize(jrk_Arena*, void*, u64, u64);
     77 
     78 i32 jrk_arena_sb_appendf(jrk_Arena*, jrk_StringBuilder*, const char*, ...);
     79 void jrk_arena_sb_append_buf_at(jrk_Arena*, jrk_StringBuilder*, char*, u64, u64);
     80 
     81 i32 jrk_rand_num(i32);
     82 i32 jrk_rand_num_range(i32, i32);
     83 
     84 i32 jrk_fd_open_read(char*);
     85 i32 jrk_fd_open_write(char*);
     86 i32 jrk_fd_open_write_append(char*);
     87 u64 jrk_fd_size(i32);
     88 void jrk_fd_close(i32);
     89 
     90 i32 jrk_sb_appendf(jrk_StringBuilder*, const char*, ...);
     91 bool jrk_sb_fd_read_all(jrk_StringBuilder*, i32);
     92 i64 jrk_sb_fd_write_all(jrk_StringBuilder*, i32);
     93 bool jrk_sb_write_file(jrk_StringBuilder*, char*);
     94 bool jrk_sb_read_entire_file(jrk_StringBuilder*, char*);
     95 void jrk_sb_append_buf_at(jrk_StringBuilder*, char*, u64, u64);
     96 
     97 jrk_StringView jrk_sv_from_parts(char*, u64);
     98 jrk_StringView jrk_sv_trim_right(jrk_StringView);
     99 jrk_StringView jrk_sv_trim_left(jrk_StringView);
    100 jrk_StringView jrk_sv_trim(jrk_StringView);
    101 jrk_StringView jrk_sv_from_cstr(char*);
    102 jrk_StringView jrk_sv_chop_delim(jrk_StringView*, char delim);
    103 
    104 char *jrk_tmpstrings_push(char*);
    105 char *jrk_tmpstrings_pushf(char*, ...);
    106 
    107 /* XXX: im not thrilled with this api, the memory can get messy real fast */
    108 #define jrk_sv_chop_delim_loop(sv, it, delim) \
    109     for (jrk_StringView it = jrk_sv_chop_delim(sv, delim); it.count != 0; it = jrk_sv_chop_delim(sv, delim))
    110 
    111 #ifndef jrk_die
    112   #define jrk_die(x)                                                   \
    113       do {                                                             \
    114           fprintf(stderr, "%s:%d: error: "x" \n", __FILE__, __LINE__); \
    115           exit(69);                                                    \
    116       } while (0)
    117 #endif
    118 
    119 #ifndef jrk_diev
    120   #define jrk_diev(x, ...)                                                         \
    121       do {                                                                         \
    122           fprintf(stderr, "%s:%d: error: "x"\n", __FILE__, __LINE__, __VA_ARGS__); \
    123           exit(69);                                                                \
    124       } while (0)
    125 #endif
    126 
    127 #define jrk_edie(x) jrk_diev(x": %s", strerror(errno))
    128 #define jrk_ediev(x, ...) jrk_diev(x": %s", __VA_ARGS__, strerror(errno))
    129 
    130 #ifndef jrk_log
    131   #define jrk_log(x)                    \
    132     do {                                \
    133         fprintf(stderr, "info: "x"\n"); \
    134     } while (0)
    135 #endif
    136 
    137 #ifndef jrk_logv
    138   #define jrk_logv(x, ...)                            \
    139     do {                                              \
    140         fprintf(stderr, "info: "x"\n",  __VA_ARGS__); \
    141     } while (0)
    142 #endif
    143 
    144 #ifndef jrk_elog
    145   #define jrk_elog(x) jrk_log(x": %s", strerror(errno))
    146 #endif
    147 
    148 #ifndef jrk_elogv
    149   #define jrk_elogv(x, ...) jrk_logv(x": %s", __VA_ARGS__, strerror(errno))
    150 #endif
    151 
    152 #define jrk_eelog(x) jrk_elog(x": %s", strerror(errno))
    153 #define jrk_eelogv(x, ...) jrk_elogv(x": %s", __VA_ARGS__, strerror(errno))
    154 
    155 #ifdef JRK_NO_EXIT_ON_DIE
    156   #undef jrk_edie
    157   #define jrk_edie jrk_eelog
    158 
    159   #undef jrk_ediev
    160   #define jrk_ediev jrk_eelogv
    161 
    162   #undef jrk_die
    163   #define jrk_die jrk_elog
    164 
    165   #undef jrk_diev
    166   #define jrk_diev jrk_elogv
    167 #endif
    168 
    169 /* NOTE: no shortname as 'assert' is just too generic */
    170 #define jrk_assert(c, msg)                                              \
    171   do {                                                                  \
    172       if (!(c)) {                                                       \
    173           fprintf(stderr, "%s:%d: error: "msg"\n", __FILE__, __LINE__); \
    174           exit(69);                                                     \
    175       }                                                                 \
    176   } while(0)
    177 
    178 #define jrk_assertv(c, msg, ...)                                                     \
    179   do {                                                                               \
    180       if (!(c)) {                                                                    \
    181           fprintf(stderr, "%s:%d: error: "msg"\n", __FILE__, __LINE__, __VA_ARGS__); \
    182           exit(69);                                                                  \
    183       }                                                                              \
    184   } while(0)
    185 
    186 #define jrk_shift(x, n) ((n)--, *(x)++)
    187 #define jrk_shift_loop(x, n, it) for (char *it = jrk_shift(x, n); n >= 0; it = jrk_shift(x, n))
    188 
    189 #define jrk_emalloc(n) jrk_ecalloc(1, n)
    190 
    191 #define jrk_sb_to_sv(sb) jrk_sv_from_parts((sb).items, (sb).count)
    192 
    193 #define JRK_DA_DEFAULT_INIT_CAPACITY 16
    194 #define jrk_da_reserve(da, expected_capacity)                                                              \
    195     do {                                                                                                   \
    196         if ((expected_capacity) > (da)->capacity) {                                                        \
    197             if ((da)->capacity == 0) {                                                                     \
    198                 (da)->capacity = (expected_capacity) ? (expected_capacity) : JRK_DA_DEFAULT_INIT_CAPACITY; \
    199             }                                                                                              \
    200             while ((expected_capacity) > (da)->capacity) {                                                 \
    201                 (da)->capacity *= 2;                                                                       \
    202             }                                                                                              \
    203             (da)->items = jrk_erealloc((da)->items, (da)->capacity * sizeof(*(da)->items));                \
    204         }                                                                                                  \
    205     } while (0)
    206 
    207 #define jrk_arena_da_reserve(arena, da, expected_capacity)                                             \
    208     do {                                                                                               \
    209         if ((da)->capacity == 0) {                                                                     \
    210             (da)->capacity = (expected_capacity) ? (expected_capacity) : JRK_DA_DEFAULT_INIT_CAPACITY; \
    211             (da)->items = jrk_arena_push(arena, (da)->capacity * sizeof(*(da)->items));                \
    212             break;                                                                                     \
    213         }                                                                                              \
    214         if ((expected_capacity) > (da)->capacity) {                                                    \
    215             u64 old_cap = (da)->capacity;                                                              \
    216             while ((expected_capacity) > (da)->capacity) {                                             \
    217                 (da)->capacity *= 2;                                                                   \
    218             }                                                                                          \
    219             u64 old_size = old_cap * sizeof(*(da)->items);                                             \
    220             u64 new_size = (da)->capacity * sizeof(*(da)->items);                                      \
    221             (da)->items = jrk_arena_resize((arena), (da)->items, old_size, new_size);                  \
    222         }                                                                                              \
    223     } while (0)
    224 
    225 #define jrk_arena_da_append(arena, da, item)                  \
    226     do {                                                      \
    227         jrk_arena_da_reserve((arena), (da), (da)->count + 1); \
    228         (da)->items[(da)->count++] = (item);                  \
    229     } while (0)
    230 
    231 #define jrk_arena_da_append_many(arena, da, new_items, new_items_count)                         \
    232     do {                                                                                        \
    233         jrk_arena_da_reserve((arena), (da), (da)->count + (new_items_count));                   \
    234         memcpy((da)->items + (da)->count, (new_items), (new_items_count)*sizeof(*(da)->items)); \
    235         (da)->count += (new_items_count);                                                       \
    236     } while (0)
    237 
    238 #define jrk_da_append(da, item)                \
    239     do {                                       \
    240         jrk_da_reserve((da), (da)->count + 1); \
    241         (da)->items[(da)->count++] = (item);   \
    242     } while (0);
    243 
    244 #define jrk_da_append_many(da, new_items, new_items_count)                                      \
    245     do {                                                                                        \
    246         jrk_da_reserve((da), (da)->count + (new_items_count));                                  \
    247         memcpy((da)->items + (da)->count, (new_items), (new_items_count)*sizeof(*(da)->items)); \
    248         (da)->count += (new_items_count);                                                       \
    249     } while (0)
    250 
    251 #define jrk_da_create(name, type) \
    252     struct name {                 \
    253         type *items;              \
    254         u64 count;                \
    255         u64 capacity;             \
    256     };                            \
    257     typedef struct name name
    258 
    259 #define jrk_da_free(da)       \
    260     do {                      \
    261         if ((da).items)       \
    262             free((da).items); \
    263     } while (0)
    264 
    265 #define jrk_da_foreach(type,it,da) for (type *it = (da)->items; it < (da)->items + (da)->count; ++it)
    266 
    267 #define jrk_sb_append_null(sb) jrk_da_append((sb), '\0')
    268 #define jrk_sb_free(sb) jrk_da_free((sb))
    269 
    270 #define jrk_arena_sb_append_null(arena, sb) jrk_arena_da_append((arena), (sb), '\0')
    271 
    272 #define jrk_arena_sb_append_cstr(arena, sb, cstr)      \
    273     do {                                               \
    274         const char *s = (cstr);                        \
    275         i64 n = strlen((cstr));                        \
    276         jrk_arena_da_append_many((arena), (sb), s, n); \
    277     } while (0)
    278 
    279 #define jrk_sb_append_cstr(sb, cstr)    \
    280     do {                                \
    281         const char *s = (cstr);         \
    282         i64 n = strlen((cstr));         \
    283         jrk_da_append_many((sb), s, n); \
    284     } while (0)
    285 
    286 
    287 #define jrk_arena_sb_append_buf(arena, sb, buf, size) jrk_arena_da_append_many((arena), (sb), (buf), (size))
    288 
    289 #define jrk_sb_append_buf(sb, buf, size) jrk_da_append_many((sb), (buf), (size))
    290 
    291 #ifdef JRK_SHORTNAMES
    292   #define UNUSED                 JRK_UNUSED
    293   #define ARRLENGTH              JRK_ARRLENGTH
    294   #define KILOBYTES              JRK_KILOBYTES
    295   #define MEGABYTES              JRK_MEGABYTES
    296   #define GIGABYTES              JRK_GIGABYTES
    297   #define TERABYTES              JRK_TERABYTES
    298 
    299   #define return_defer           jrk_return_defer
    300   #define die                    jrk_die
    301   #define diev                   jrk_diev
    302   #define edie                   jrk_edie
    303   #define ediev                  jrk_ediev
    304   #define log                    jrk_log
    305   #define logv                   jrk_logv
    306 
    307   #define Arena                  jrk_Arena
    308   #define StringBuilder          jrk_StringBuilder
    309   #define StringView             jrk_StringView
    310 
    311   #define tmpstrings_push        jrk_tmpstrings_push
    312   #define tmpstrings_pushf       jrk_tmpstrings_pushf
    313 
    314   #define sb_appendf             jrk_sb_appendf
    315   #define sb_append_null         jrk_sb_append_null
    316   #define sb_append_buf          jrk_sb_append_buf
    317   #define sb_append_buf_at       jrk_sb_append_buf_at
    318   #define sb_append_cstr         jrk_sb_append_cstr
    319   #define sb_free                jrk_sb_free
    320   #define sb_fd_read_all         jrk_sb_fd_read_all
    321   #define sb_fd_write_all        jrk_sb_fd_write_all
    322   #define sb_to_sv               jrk_sb_to_sv
    323   #define sb_write_file          jrk_sb_write_file
    324   #define sb_read_entire_file    jrk_sb_read_entire_file
    325 
    326   #define sv_trim_left           jrk_sv_trim_left
    327   #define sv_trim_right          jrk_sv_trim_right
    328   #define sv_trim                jrk_sv_trim
    329   #define sv_from_cstr           jrk_sv_from_cstr
    330   #define sv_from_parts          jrk_sv_from_parts
    331   #define sv_chop_delim          jrk_sv_chop_delim
    332 
    333   #define ecalloc                jrk_ecalloc
    334   #define erealloc               jrk_erealloc
    335   #define emalloc                jrk_emalloc
    336 
    337   #define da_reserve             jrk_da_reserve
    338   #define da_append              jrk_da_append
    339   #define da_append_many         jrk_da_append_many
    340   #define da_foreach             jrk_da_foreach
    341   #define da_create              jrk_da_create
    342   #define da_free                jrk_da_free
    343 
    344   #define arena_create           jrk_arena_create
    345   #define arena_push             jrk_arena_push
    346   #define arena_push_strf        jrk_arena_push_strf
    347   #define arena_resize           jrk_arena_resize
    348   #define arena_reset            jrk_arena_reset
    349 
    350   #define arena_da_reserve       jrk_arena_da_reserve
    351   #define arena_da_append        jrk_arena_da_append
    352   #define arena_da_append_many   jrk_arena_da_append_many
    353 
    354   #define arena_sb_appendf       jrk_arena_sb_appendf
    355   #define arena_sb_append_buf_at jrk_arena_sb_append_buf_at
    356   #define arena_sb_append_buf    jrk_arena_sb_append_buf
    357   #define arena_sb_append_cstr   jrk_arena_sb_append_cstr
    358   #define arena_sb_append_null   jrk_arena_sb_append_null
    359 
    360   #define rand_num               jrk_rand_num
    361   #define rand_num_range         jrk_rand_num_range
    362 
    363   #define fd_close               jrk_fd_close
    364   #define fd_open_read           jrk_fd_open_read
    365   #define fd_open_write          jrk_fd_open_write
    366   #define fd_open_write_append   jrk_fd_open_write_append
    367 
    368   #define shift                  jrk_shift
    369   #define shift_loop             jrk_shift_loop
    370 #endif // JRK_SHORTNAMES
    371 
    372 #ifdef JRK_IMPLEMENTATION
    373 #include <ctype.h>
    374 #include <errno.h>
    375 #include <fcntl.h>
    376 #include <stdarg.h>
    377 #include <stdio.h>
    378 #include <stdlib.h>
    379 #include <string.h>
    380 #include <sys/stat.h>
    381 #include <unistd.h>
    382 
    383 void *
    384 jrk_ecalloc(u64 nmemb, u64 size)
    385 {
    386     void *p;
    387 
    388     if (!(p = calloc(nmemb, size)))
    389         jrk_ediev("jrk_ecalloc(%ld, %ld)", nmemb, size);
    390     return p;
    391 }
    392 
    393 void *
    394 jrk_erealloc(void *ptr, u64 size)
    395 {
    396     void *p;
    397 
    398     if (!(p = realloc(ptr, size)))
    399         jrk_ediev("jrk_erealloc(%p, %ld)", ptr, size);
    400     return p;
    401 }
    402 
    403 // NOTE: only allocate space for translation units with JRK_IMPLEMENTATION
    404 static char jrk__tmpstrings[JRK_TMPSTRINGS_ARR_CAPACITY][JRK_TMPSTRINGS_STR_CAPACITY];
    405 static u32 jrk__tmpstrings_idx = 0;
    406 
    407 char *
    408 jrk_tmpstrings_push(char *str)
    409 {
    410     char *result;
    411     result = jrk_tmpstrings_pushf(str);
    412     return result;
    413 }
    414 
    415 char *
    416 jrk_tmpstrings_pushf(char *fmt, ...)
    417 {
    418     char *result = jrk__tmpstrings[jrk__tmpstrings_idx];
    419 
    420     va_list args;
    421     va_start(args, fmt);
    422     vsnprintf(result, JRK_TMPSTRINGS_STR_CAPACITY, fmt, args);
    423     va_end(args);
    424 
    425     if (++jrk__tmpstrings_idx >= JRK_TMPSTRINGS_ARR_CAPACITY)
    426         jrk__tmpstrings_idx = 0;
    427 
    428     return result;
    429 }
    430 
    431 jrk_Arena
    432 jrk_arena_create(u8 *buffer, u64 buffer_count)
    433 {
    434     jrk_Arena result = {0};
    435     result.data = buffer;
    436     result.capacity = buffer_count;
    437     result.offset = 0;
    438     result.prev_offset = 0;
    439     return result;
    440 }
    441 
    442 void *
    443 jrk_arena_push(jrk_Arena *arena, u64 n)
    444 {
    445     jrk_assertv(arena->offset + n <= arena->capacity,
    446                 "jrk_arena_push(%p, %ld): arena push requires %ld bytes but has a capacity of %ld bytes",
    447                 (void *) arena, n, arena->offset + n, arena->capacity);
    448 
    449     void *result = &arena->data[arena->offset];
    450     arena->prev_offset = arena->offset;
    451     arena->offset += n;
    452     memset(result, 0, n);
    453 
    454 #ifdef JRK_ARENA_DIAGNOSTICS
    455     printf("pushed(%p, %ld)\n  offset: %ld\n  prev_offset: %ld\n", arena, n, arena->offset, arena->prev_offset);
    456 #endif
    457 
    458     return result;
    459 }
    460 
    461 char *
    462 jrk_arena_push_strf(jrk_Arena *arena, char *fmt, ...)
    463 {
    464     char *result = NULL;
    465 
    466     va_list args;
    467     va_start(args, fmt);
    468     i32 n = vsnprintf(NULL, 0, fmt, args);
    469     va_end(args);
    470 
    471     result = jrk_arena_push(arena, (u64) n + 1);
    472 
    473     va_start(args, fmt);
    474     vsnprintf(result, n + 1, fmt, args);
    475     va_end(args);
    476 
    477     return result;
    478 }
    479 
    480 void *
    481 jrk_arena_resize(jrk_Arena *arena, void *old, u64 old_size, u64 new_size)
    482 {
    483     jrk_assertv(new_size > old_size,
    484                 "jrk_arena_resize(%p, %p, %ld, %ld): new_size is smaller than the old_size",
    485                 (void *) arena, old, old_size, new_size);
    486 
    487     jrk_assertv(arena->offset + (new_size - old_size) <= arena->capacity,
    488                 "jrk_arena_resize(%p, %p, %ld, %ld): arena resize requires %ld bytes but has a capacity of %ld bytes",
    489                 (void *) arena, old, old_size, new_size, arena->offset + (new_size - old_size), arena->capacity);
    490 
    491     u8 *result = NULL;
    492 
    493 #ifdef JRK_ARENA_DIAGNOSTICS
    494     printf("resize(%p, %p, %ld, %ld): resizing\n",
    495            arena, old, old_size, new_size);
    496 #endif
    497 
    498     if (old == &arena->data[arena->prev_offset]) {
    499         result = old;
    500         arena->offset = new_size;
    501     } else {
    502         result = &arena->data[arena->offset];
    503         arena->prev_offset = arena->offset;
    504         arena->offset += new_size;
    505         memmove(result, old, old_size);
    506         memset(result + old_size, 0, new_size - old_size);
    507     }
    508 
    509     return (void *) result;
    510 }
    511 
    512 void
    513 jrk_arena_reset(jrk_Arena *arena)
    514 {
    515     arena->offset = 0;
    516     arena->prev_offset = 0;
    517     memset(arena->data, 0, arena->capacity);
    518 }
    519 
    520 i32
    521 jrk_arena_sb_appendf(jrk_Arena *arena, jrk_StringBuilder *sb, const char *fmt, ...)
    522 {
    523     i32 result = -1;
    524 
    525     va_list args;
    526     va_start(args, fmt);
    527     result = vsnprintf(NULL, 0, fmt, args);
    528     va_end(args);
    529 
    530     jrk_arena_da_reserve(arena, sb, sb->count + result + 1);
    531 
    532     va_start(args, fmt);
    533     vsnprintf(sb->items + sb->count, result + 1, fmt, args);
    534     va_end(args);
    535     sb->count += result;
    536 
    537     return result;
    538 }
    539 
    540 i32
    541 jrk_sb_appendf(jrk_StringBuilder *sb, const char *fmt, ...)
    542 {
    543     i32 result = -1;
    544 
    545     va_list args;
    546     va_start(args, fmt);
    547     result = vsnprintf(NULL, 0, fmt, args);
    548     va_end(args);
    549 
    550     jrk_da_reserve(sb, sb->count + result + 1);
    551 
    552     va_start(args, fmt);
    553     vsnprintf(sb->items + sb->count, result + 1, fmt, args);
    554     va_end(args);
    555     sb->count += result;
    556 
    557     return result;
    558 }
    559 
    560 void
    561 jrk_arena_sb_append_buf_at(jrk_Arena *arena, jrk_StringBuilder *sb, char *buf, u64 size, u64 idx)
    562 {
    563     jrk_assertv(idx < sb->count, "jrk_arena_sb_append_buf_at(%p, %p, %p, %ld, %ld): idx is greater than sb->count",
    564                 (void *) arena, (void *) sb, buf, size, idx);
    565 
    566     u64 new_size = sb->count + size;
    567     char *old_items = sb->items;
    568 
    569     jrk_arena_da_reserve(arena, sb, new_size);
    570 
    571     if (old_items == sb->items) { // didn't move
    572         jrk_StringBuilder temp_builder = {0};
    573         temp_builder.items = jrk_emalloc(sb->capacity);
    574         temp_builder.count = sb->count;
    575         temp_builder.capacity = sb->capacity;
    576         memcpy(temp_builder.items, sb->items, sb->count);
    577 
    578         memcpy(sb->items, temp_builder.items, idx);
    579         memcpy(sb->items + idx, buf, size);
    580         memcpy(sb->items + idx + size, temp_builder.items + idx, temp_builder.count - idx);
    581 
    582         jrk_sb_free(temp_builder);
    583     } else { // did move
    584         memcpy(sb->items, old_items, idx);
    585         memcpy(sb->items + idx, buf, size);
    586         memcpy(sb->items + idx + size, old_items + idx, sb->count - idx);
    587     }
    588 
    589     sb->count = new_size;
    590 }
    591 
    592 void
    593 jrk_sb_append_buf_at(jrk_StringBuilder *sb, char *buf, u64 size, u64 idx)
    594 {
    595     jrk_assertv(idx < sb->count, "jrk_sb_append_buf_at(%p, %p, %ld, %ld): idx is greater than sb->count (%ld > %ld)",
    596                 (void *) sb, buf, size, idx, idx, sb->count);
    597 
    598     u64 new_size = sb->count + size;
    599     char *temp = jrk_emalloc(new_size);
    600 
    601     memcpy(temp, sb->items, idx);
    602     memcpy(temp + idx, buf, size);
    603     memcpy(temp + idx + size, sb->items + idx, sb->count - idx);
    604 
    605     free(sb->items);
    606     sb->items = temp;
    607     sb->count = new_size;
    608 
    609     // NOTE: maybe keep it a proper ^2?
    610     sb->capacity = new_size;
    611 }
    612 
    613 u64
    614 jrk_fd_size(i32 fd)
    615 {
    616     struct stat statbuf = {0};
    617     if (fstat(fd, &statbuf) < 0)
    618         jrk_ediev("jrk_fd_size(%d)", fd);
    619 
    620     return statbuf.st_size;
    621 }
    622 
    623 bool
    624 jrk_sb_fd_read_all(jrk_StringBuilder *sb, i32 fd)
    625 {
    626     u64 sz = jrk_fd_size(fd);
    627     jrk_da_reserve(sb, sz);
    628     if (read(fd, sb->items, sz) < 0) {
    629         jrk_ediev("jrk_sb_fd_read_all(%p, %d)", (void *)sb, fd);
    630         return false;
    631     }
    632 
    633     sb->count = sz;
    634     return true;
    635 }
    636 
    637 i64
    638 jrk_sb_fd_write_all(jrk_StringBuilder *sb, i32 fd)
    639 {
    640     i64 result;
    641     result = write(fd, (void *) sb->items, sb->count);
    642     if (result < 0) {
    643         jrk_ediev("jrk_sb_fd_write_all(%p, %d)", (void *)sb, fd);
    644         return -1;
    645     }
    646 
    647     return result;
    648 }
    649 
    650 void
    651 jrk_fd_close(i32 fd)
    652 {
    653     close(fd);
    654 }
    655 
    656 bool
    657 jrk_sb_write_file(jrk_StringBuilder *sb, char *path)
    658 {
    659     i32 fd = jrk_fd_open_write(path);
    660     if (fd < 0) return false;
    661     if (jrk_sb_fd_write_all(sb, fd) < 0) return false;
    662     jrk_fd_close(fd);
    663     return true;
    664 }
    665 
    666 bool
    667 jrk_sb_read_entire_file(jrk_StringBuilder *sb, char *path)
    668 {
    669     i32 fd = jrk_fd_open_read(path);
    670     if (fd < 0) return false;
    671     if (!jrk_sb_fd_read_all(sb, fd)) return false;
    672     jrk_fd_close(fd);
    673 
    674     return true;
    675 }
    676 
    677 i32
    678 jrk_fd_open_read(char *path)
    679 {
    680     i32 result = open(path, O_RDONLY);
    681 
    682     if (result < 0) {
    683         jrk_ediev("jrk_fd_open_read(%s)", path);
    684         return -1;
    685     }
    686 
    687     return result;
    688 }
    689 
    690 i32
    691 jrk_fd_open_write(char *path)
    692 {
    693     i32 result = open(path,
    694                      O_WRONLY | O_CREAT | O_TRUNC,
    695                      S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    696 
    697     if (result < 0) {
    698         jrk_ediev("jrk_fd_open_write(%s)", path);
    699         return -1;
    700     }
    701 
    702     return result;
    703 }
    704 
    705 i32
    706 jrk_fd_open_write_append(char *path)
    707 {
    708     i32 result = open(path,
    709                      O_WRONLY | O_CREAT | O_APPEND,
    710                      S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    711 
    712     if (result < 0) {
    713         jrk_ediev("jrk_fd_open_write_append(%s)", path);
    714         return -1;
    715     }
    716 
    717     return result;
    718 }
    719 
    720 jrk_StringView
    721 jrk_sv_from_parts(char *data, u64 count)
    722 {
    723     jrk_StringView result = {0};
    724     result.data = data;
    725     result.count = count;
    726     return result;
    727 }
    728 
    729 jrk_StringView
    730 jrk_sv_from_cstr(char *data)
    731 {
    732     jrk_StringView result = {0};
    733     result.data = data;
    734     result.count = strlen(data);
    735     return result;
    736 }
    737 
    738 jrk_StringView
    739 jrk_sv_trim_right(jrk_StringView sv)
    740 {
    741     u64 i = 0;
    742     for (; i < sv.count && isspace(sv.data[sv.count - 1 - i]); ++i);
    743     return jrk_sv_from_parts(sv.data, sv.count - i);
    744 }
    745 
    746 jrk_StringView
    747 jrk_sv_trim_left(jrk_StringView sv)
    748 {
    749     u64 i = 0;
    750     for (; i < sv.count && isspace(sv.data[i]); ++i);
    751     return jrk_sv_from_parts(sv.data + i, sv.count - i);
    752 }
    753 
    754 jrk_StringView
    755 jrk_sv_trim(jrk_StringView sv)
    756 {
    757     return jrk_sv_trim_right(jrk_sv_trim_left(sv));
    758 }
    759 
    760 jrk_StringView
    761 jrk_sv_chop_delim(jrk_StringView *sv, char delim)
    762 {
    763     u64 i = 0;
    764     while (i < sv->count && sv->data[i] != delim)
    765         ++i;
    766 
    767     jrk_StringView result = jrk_sv_from_parts(sv->data, i);
    768 
    769     if (i < sv->count) {
    770         sv->data += i + 1;
    771         sv->count -= i + 1;
    772     } else {
    773         sv->data += i;
    774         sv->count -= i;
    775     }
    776 
    777     return result;
    778 }
    779 
    780 i32
    781 jrk_rand_num(i32 upbound)
    782 {
    783     return rand() % upbound + 1;
    784 }
    785 
    786 i32
    787 jrk_rand_num_range(i32 min, i32 max)
    788 {
    789     return rand() % (max - min + 1) + min;
    790 }
    791 
    792 #endif // JRK_IMPLEMENTATION