/* * TODO(jake): * - variadic die macros to show params of 'dying' functions * - application shouldn't be dying on all failures, have a way * to configure that ... just die without calling exit() */ #include #ifdef JRK_IMPLEMENTATION_WITH_SHORTNAMES #define JRK_IMPLEMENTATION #define JRK_SHORTNAMES #endif // JRK_IMPLEMENTATION_WITH_SHORTNAMES typedef int8_t i8; typedef int16_t i16; typedef int32_t i32; typedef int64_t i64; typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; typedef float f32; typedef double f64; typedef struct { u8 *data; u64 length; u64 capacity; } jrk_Arena; typedef struct { char *items; u64 count; u64 capacity; } jrk_StringBuilder; typedef struct { char *data; u64 count; } jrk_StringView; void *jrk_ecalloc(u64, u64); void *jrk_erealloc(void*, u64); jrk_Arena jrk_arena_create(u64); void *jrk__arena_push(jrk_Arena*, u64); void jrk_arena_expand(jrk_Arena*, u64); i32 jrk_rand_num(i32); i32 jrk_rand_num_range(i32, i32); i32 jrk_fd_open_read(char*); i32 jrk_fd_open_write(char*); i32 jrk_fd_open_write_append(char*); u64 jrk_fd_size(i32); void jrk_fd_close(i32); i32 jrk_sb_appendf(jrk_StringBuilder*, const char*, ...); void jrk_sb_fd_read_all(jrk_StringBuilder*, i32); u64 jrk_sb_fd_write_all(jrk_StringBuilder*, i32); void jrk_sb_write_file(jrk_StringBuilder*, char*); jrk_StringView jrk_sv_from_parts(char*, u64); jrk_StringView jrk_sv_trim_right(jrk_StringView); jrk_StringView jrk_sv_trim_left(jrk_StringView); jrk_StringView jrk_sv_trim(jrk_StringView); jrk_StringView jrk_sv_from_cstr(char*); /* NOTE(jake): no shortname as 'assert' is just too generic */ #define jrk_assert(c, msg) do { if (!(c)) jrk_die("jrk_assert: "msg); } while(0) #define jrk_emalloc(n) jrk_ecalloc(1, n) #define jrk_arena_destroy(arena) ((arena.data) ? free(arena.data) : (void) 0) #define jrk_arena_push_array(arena, type, n) (type *) jrk__arena_push(arena, sizeof(type) * n) #define jrk_arena_push_struct(arena, type) (type *) jrk__arena_push(arena, sizeof(type)) #define jrk_sb_to_sv(sb) jrk_sv_from_parts((sb).items, (sb).count) #define jrk_da_reserve(da, expected_capacity) \ do { \ if ((expected_capacity) > (da)->capacity) { \ if ((da)->capacity == 0) { \ (da)->capacity = 4; \ } \ while ((expected_capacity) > (da)->capacity) { \ (da)->capacity *= 2; \ } \ (da)->items = jrk_erealloc((da)->items, (da)->capacity * sizeof(*(da)->items)); \ } \ } while (0) #define jrk_da_append(da, item) \ do { \ jrk_da_reserve((da), (da)->count + 1); \ (da)->items[(da)->count++] = (item); \ } while (0); #define jrk_da_append_many(da, new_items, new_items_count) \ do { \ jrk_da_reserve((da), (da)->count + (new_items_count)); \ memcpy((da)->items + (da)->count, (new_items), (new_items_count)*sizeof(*(da)->items)); \ (da)->count += (new_items_count); \ } while (0) #define jrk_da_create(name, type) \ struct name { \ type *items; \ u64 count; \ u64 capacity; \ }; \ typedef struct name name #define jrk_da_free(da) \ do { \ jrk_assert((da).items, "bad free: jrk_da_free da.items is NULL"); \ free((da).items); \ } while (0) #define jrk_da_foreach(type,it,da) for (type *it = (da)->items; it < (da)->items + (da)->count; ++it) #define jrk_sb_append_null(sb) jrk_da_append(sb, '\0') #define jrk_sb_free(sb) jrk_da_free(sb) #define jrk_sb_append_cstr(sb, cstr) \ do { \ const char *s = (cstr); \ i64 n = strlen(cstr); \ jrk_da_append_many(sb, s, n); \ } while (0) #define jrk_sb_append_buf(sb, buf, size) jrk_da_append_many(sb, buf, size) #ifdef JRK_SHORTNAMES #define Arena jrk_Arena #define StringBuilder jrk_StringBuilder #define StringView jrk_StringView #define sb_appendf jrk_sb_appendf #define sb_append_null jrk_sb_append_null #define sb_append_buf jrk_sb_append_buf #define sb_append_cstr jrk_sb_append_cstr #define sb_free jrk_sb_free #define sb_fd_read_all jrk_sb_fd_read_all #define sb_fd_write_all jrk_sb_fd_write_all #define sb_to_sv jrk_sb_to_sv #define sb_write_file jrk_sb_write_file #define sv_trim_left jrk_sv_trim_left #define sv_trim_right jrk_sv_trim_right #define sv_trim jrk_sv_trim #define sv_from_cstr jrk_sv_from_cstr #define sv_from_parts jrk_sv_from_parts #define ecalloc jrk_ecalloc #define erealloc jrk_erealloc #define emalloc jrk_emalloc #define da_reserve jrk_da_reserve #define da_append jrk_da_append #define da_append_many jrk_da_append_many #define da_foreach jrk_da_foreach #define da_create jrk_da_create #define da_free jrk_da_free #define arena_create jrk_arena_create #define arena_destroy jrk_arena_destroy #define arena_push_struct jrk_arena_push_struct #define arena_push_array jrk_arena_push_array #define arena_expand jrk_arena_expand #define rand_num jrk_rand_num #define rand_num_range jrk_rand_num_range #define fd_close jrk_fd_close #define fd_open_read jrk_fd_open_read #define fd_open_write jrk_fd_open_write #define fd_open_write_append jrk_fd_open_write_append #endif // JRK_SHORTNAMES #ifdef JRK_IMPLEMENTATION #include #include #include #include #include #include #include #include #include #define jrk_die(x) do { fprintf(stderr, "%s:%d: error: "x"\n", __FILE__, __LINE__); exit(69); } while(0) #define jrk_edie(x) do { fprintf(stderr, "%s:%d: error: "x": %s\n", __FILE__, __LINE__, strerror(errno)); exit(69); } while(0) #ifdef JRK_SHORTNAMES #define die jrk_die #define edie jrk_edie #endif // JRK_SHORTNAMES void * jrk_ecalloc(u64 nmemb, u64 size) { void *p; if (!(p = calloc(nmemb, size))) jrk_edie("jrk_ecalloc"); return p; } void * jrk_erealloc(void *ptr, u64 size) { void *p; if (!(p = realloc(ptr, size))) jrk_edie("jrk_erealloc"); return p; } jrk_Arena jrk_arena_create(u64 n) { jrk_Arena result; result.length = 0; result.capacity = n; result.data = jrk_ecalloc(result.capacity, 1); return result; } void * jrk__arena_push(jrk_Arena *arena, u64 n) { while (arena->length + n >= arena->capacity) jrk_arena_expand(arena, arena->capacity * 2); void *result = &arena->data[arena->length]; arena->length += n; return result; } void jrk_arena_expand(jrk_Arena *arena, u64 new_capacity) { u8 *tmp = jrk_erealloc(arena->data, new_capacity); arena->capacity = new_capacity; arena->data = tmp; } i32 jrk_sb_appendf(jrk_StringBuilder *sb, const char *fmt, ...) { va_list args; va_start(args, fmt); i32 n = vsnprintf(NULL, 0, fmt, args); va_end(args); jrk_da_reserve(sb, sb->count + n + 1); va_start(args, fmt); vsnprintf(sb->items + sb->count, n + 1, fmt, args); va_end(args); sb->count += n; return n; } u64 jrk_fd_size(i32 fd) { struct stat statbuf = {0}; if (fstat(fd, &statbuf) < 0) jrk_edie("jrk_fd_size"); return statbuf.st_size; } void jrk_sb_fd_read_all(jrk_StringBuilder *sb, i32 fd) { u64 sz = jrk_fd_size(fd); jrk_da_reserve(sb, sz); if (read(fd, sb->items, sz) < 0) jrk_edie("jrk_sb_fd_read_all"); sb->count = sz; } u64 jrk_sb_fd_write_all(jrk_StringBuilder *sb, i32 fd) { i64 result; result = write(fd, (void *) sb->items, sb->count); if (result < 0) jrk_edie("jrk_sb_fd_write_all"); return result; } void jrk_fd_close(i32 fd) { close(fd); } void jrk_sb_write_file(jrk_StringBuilder *sb, char *path) { i32 fd = jrk_fd_open_write(path); jrk_sb_fd_write_all(sb, fd); jrk_fd_close(fd); } i32 jrk_fd_open_read(char *path) { i32 result = open(path, O_RDONLY); if (result < 0) jrk_edie("jrk_fd_open_read"); return result; } i32 jrk_fd_open_write(char *path) { i32 result = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (result < 0) jrk_edie("jrk_fd_open_read"); return result; } i32 jrk_fd_open_write_append(char *path) { i32 result = open(path, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (result < 0) jrk_edie("jrk_fd_open_read"); return result; } jrk_StringView jrk_sv_from_parts(char *data, u64 count) { jrk_StringView result = {0}; result.data = data; if (data[count] == '\0') result.count = count-1; else result.count = count; return result; } jrk_StringView jrk_sv_from_cstr(char *data) { jrk_StringView result = {0}; result.data = data; result.count = strlen(data); return result; } jrk_StringView jrk_sv_trim_right(jrk_StringView sv) { u64 i = 0; for (; i < sv.count && isspace(sv.data[sv.count - 1 - i]); ++i); return jrk_sv_from_parts(sv.data, sv.count - i); } jrk_StringView jrk_sv_trim_left(jrk_StringView sv) { u64 i = 0; for (; i < sv.count && isspace(sv.data[i]); ++i); return jrk_sv_from_parts(sv.data + i, sv.count - i); } jrk_StringView jrk_sv_trim(jrk_StringView sv) { return jrk_sv_trim_right(jrk_sv_trim_left(sv)); } i32 jrk_rand_num(i32 upbound) { return rand() % upbound + 1; } i32 jrk_rand_num_range(i32 min, i32 max) { return rand() % (max - min + 1) + min; } #endif // JRK_IMPLEMENTATION