commit 17ea5a41be7a78531e1919b84399d09fe36bdfcf
Author: William Djupström <william@deepztream.com>
Date: Sun, 20 Sep 2026 11:07:25 +0200
Initial commit
Diffstat:
| A | dlib.h | | | 580 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 580 insertions(+), 0 deletions(-)
diff --git a/dlib.h b/dlib.h
@@ -0,0 +1,580 @@
+#ifndef DLIB_H
+#define DLIB_H 1
+
+#include <assert.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#define todo_p(msg) \
+ do { \
+ fprintf(stderr, "%s:%i:1: Error: TODO: %s\n", __FILE__, __LINE__, (msg)); \
+ abort(); \
+ } while (0)
+
+#define todo(msg) \
+ do { \
+ fprintf(stderr, "%s:%i:1: Error: TODO: %s\n", __FILE__, __LINE__, (msg)); \
+ return false; \
+ } while (0)
+
+#define unimplemented() \
+ do { \
+ fprintf(stderr, "%s:%i:1: Error: not implemented %s\n", __FILE__, __LINE__, __func__); \
+ abort(); \
+ } while (0)
+
+#define unreachable(msg) \
+ do { \
+ fprintf(stderr, "%s:%i:1: Error: Unreachable: %s\n", __FILE__, __LINE__, (msg)); \
+ abort(); \
+ } while (0)
+
+#define pop_arg(argc, argv) ((argc)--, *(argv)++)
+
+#define da_append(da, new)\
+ do {\
+ if ((da)->capacity <= (da)->count) {\
+ (da)->capacity = (da)->capacity ? (da)->capacity * 2 : 16;\
+ (da)->items = realloc((da)->items, sizeof(*(da)->items) * (da)->capacity);\
+ }\
+ (da)->items[(da)->count++] = (new);\
+ } while(0)
+
+#define da_prepend(da, new)\
+ do {\
+ if ((da)->capacity <= (da)->count) {\
+ (da)->capacity = (da)->capacity ? (da)->capacity * 2 : 16;\
+ (da)->items = realloc((da)->items, sizeof(*(da)->items) * (da)->capacity);\
+ }\
+ memmove((da)->items + 1, (da)->items, sizeof(*(da)->items) * ((da)->count++));\
+ (da)->items[0] = (new);\
+ } while(0)
+
+#define da_reserve(da, len)\
+ do {\
+ if ((da)->capacity >= (len)) break;\
+ (da)->capacity = (len);\
+ (da)->items = realloc((da)->items, sizeof(*(da)->items) * (len));\
+ } while(0)
+
+#define da_expand(da, size)\
+ do {\
+ if ((da)->count >= (size)) break;\
+ da_reserve(da, size);\
+ (da)->count = (size);\
+ } while(0)
+
+#define da_delete(da, index)\
+ do {\
+ assert(index >= 0 && index < (da)->count);\
+ (da)->items[index] = (da)->items[--(da)->count];\
+ } while (0)
+
+#define da_delete_ordered(da, index)\
+ do {\
+ assert(index < (da)->count);\
+ memmove(&(da)->items[(index)], &(da)->items[(index) + 1], sizeof(*(da)->items) * ((da)->count-- - (index) - 1));\
+ } while (0)
+
+typedef struct {
+ union {
+ char *items;
+ const char *data;
+ };
+ union {
+ ssize_t count;
+ ssize_t length;
+ };
+ ssize_t capacity;
+} Sb;
+#define String_builder Sb
+
+typedef struct {
+ union {
+ const char *items;
+ const char *data;
+ };
+ union {
+ ssize_t count;
+ ssize_t length;
+ };
+} Sv;
+#define String_view Sv
+
+typedef struct {
+ void *base;
+ void *head;
+ void *end;
+} Temp_allocator;
+
+#define TA_DEFAULT_SIZE (1024*1024)
+
+void ta_init(Temp_allocator *ta, size_t size);
+void *ta_alloc(Temp_allocator *ta, size_t size);
+
+#define sb_append_char da_append
+int sb_printf(Sb *sb, const char *fmt, ...);
+void sb_append_cstr(Sb *sb, const char *cstr);
+void sb_append_sv(Sb *sb, Sv sv);
+bool sb_append_and_unescape_sv(Sb *sb, Sv sv);
+
+bool sb_read(Sb *sb, int fd);
+bool sb_read_file(Sb *sb, const char *file_name);
+void sb_write(int fd, Sb sb);
+
+void sb_release(Sb *sb);
+
+#define sv_literal(str) ((Sv){.items = (str), .count = (sizeof (str) - 1)})
+
+Sv sv_from_sb(Sb sb);
+Sv sv_from_cstr(const char *cstr);
+const char *sv_to_cstr(Sv sv);
+long int sv_to_number(Sv sv, int base);
+ssize_t sv_find_char(Sv sv, char c);
+
+Sv sv_chop(Sv sv, ssize_t count, Sv *rest);
+Sv sv_chop_delim(Sv sv, char c, Sv *rest);
+
+Sv sv_getline(Sv *sv);
+
+Sv sv_trim_left(Sv sv);
+Sv sv_trim_right(Sv sv);
+Sv sv_trim(Sv sv);
+
+Sv sv_substring(Sv sv, ssize_t start, ssize_t req_count);
+
+int sv_compare(Sv sv1, Sv sv2);
+bool sv_equal(Sv sv1, Sv sv2);
+bool sv_starts_with_cstr(Sv sv, const char *cstr);
+bool sv_starts_with(Sv sv, Sv prefix);
+
+void sv_write(int fd, Sv sv);
+
+/* Adding missing libc functions */
+int ctoi(int c);
+#define isddigit isdigit
+int isbdigit(int c);
+int isodigit(int c);
+
+int is_digit_base(int c, int base);
+
+#ifdef DLIB_IMPLEMENTATION
+
+void
+ta_init(Temp_allocator *ta, size_t size)
+{
+ ta->base = malloc(size);
+ ta->head = ta->base;
+ ta->end = ta->base + size;
+}
+
+void *
+ta_alloc(Temp_allocator *ta, size_t size)
+{
+ if (!ta->base) {
+ ta->base = malloc(TA_DEFAULT_SIZE);
+ ta->head = ta->base;
+ ta->end = ta->base + TA_DEFAULT_SIZE;
+ }
+ void *result = ta->head;
+ ta->head += (size + 0xF) & ~0xFul;
+ if (ta->head >= ta->end) {
+ fprintf(stderr, "Error: Temp allocator out of memory\n");
+ exit(1);
+ }
+ return result;
+}
+
+int
+sb_printf(Sb *sb, const char *fmt, ...) {
+ va_list args, args_copy;
+ va_start(args, fmt);
+ va_copy(args_copy, args);
+ int len = vsnprintf(NULL, 0, fmt, args_copy) + 1;
+ ssize_t new_size = sb->count + len;
+ da_reserve(sb, new_size);
+ va_end(args_copy);
+ vsnprintf(sb->items + sb->count, len, fmt, args);
+ va_end(args);
+ sb->count = new_size - 1;
+ return len - 1;
+}
+
+void
+sb_append_cstr(Sb *sb, const char *cstr)
+{
+ ssize_t len = strlen(cstr);
+ da_reserve(sb, sb->count + len);
+ strcpy(sb->items + sb->count, cstr);
+ sb->count += len;
+}
+
+void
+sb_append_sv(Sb *sb, Sv sv)
+{
+ da_reserve(sb, sb->count + sv.count);
+ memcpy(sb->items + sb->count, sv.items, sv.count);
+ sb->count += sv.count;
+}
+
+/* Returns `false` if it encounters an invalid escape character */
+
+bool
+sb_append_and_unescape_sv(Sb *sb, Sv sv)
+{
+ bool success = true;
+ ssize_t i;
+ char c;
+ for (i = 0; i < sv.count; i++) {
+ c = sv.data[i];
+ if (c == '\\') {
+ if (++i >= sv.count) {
+ success = false;
+ } else {
+ c = sv.data[i];
+ if (c == 'n') {
+ c = '\n';
+ } else if (c == 't') {
+ c = '\t';
+ } else if (c == 'r') {
+ c = '\r';
+ } else if (c == '0') {
+ c = '\0';
+ } else {
+ if (c >= 32 && c < 127) {
+ fprintf(stderr, "Info: escape character '%c' unsupported\n", c);
+ } else {
+ fprintf(stderr, "Info: escape character 0x%x02 unsupported\n", c);
+ }
+ success = false;
+ }
+ }
+ }
+ sb_append_char(sb, c);
+ }
+ return success;
+}
+
+bool
+sb_read(Sb *sb, int fd)
+{
+ ssize_t read_count;
+ ssize_t buf_size = 4096;
+ char *buf = malloc(buf_size);
+ do {
+ read_count = read(fd, buf, buf_size);
+ if (read_count < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ perror("sb_read()");
+ return false;
+ }
+ if (read_count == 0) {
+ break;
+ }
+ sb_append_sv(sb, ((Sv) {.items = buf, .length = read_count}));
+ if (read_count < buf_size) {
+ break;
+ }
+ } while (1);
+ free(buf);
+ return true;
+}
+
+bool
+sb_read_file(Sb *sb, const char *file_name)
+{
+ int fd = open(file_name, O_RDONLY);
+ if (fd < 0) {
+ perror("sb_read()");
+ return false;
+ }
+ ssize_t read_count;
+ ssize_t buf_size = 4096;
+ char *buf = malloc(buf_size);
+ do {
+ read_count = read(fd, buf, buf_size);
+ if (read_count < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ perror("sb_read_file()");
+ return false;
+ }
+ if (read_count == 0) {
+ break;
+ }
+ sb_append_sv(sb, ((Sv) {.items = buf, .length = read_count}));
+ } while (1);
+ free(buf);
+ return true;
+}
+
+void
+sb_write(int fd, Sb sb)
+{
+ write(fd, sb.items, sb.length);
+}
+
+void
+sb_release(Sb *sb)
+{
+ if (sb->capacity) {
+ free(sb->items);
+ sb->items = NULL;
+ sb->count = 0;
+ sb->capacity = 0;
+ }
+}
+
+/* String view functions */
+
+void
+sv_write(int fd, Sv sv)
+{
+ write(fd, sv.items, sv.count);
+}
+
+Sv
+sv_from_sb(Sb sb)
+{
+ return (Sv) {.items = sb.items, .count = sb.count};
+}
+
+Sv
+sv_from_cstr(const char *cstr)
+{
+ return (Sv) {.items = cstr, .count = strlen(cstr)};
+}
+
+const char *
+sv_to_cstr(Sv sv)
+{
+ char *cstr = malloc(sv.count + 1);
+ memcpy(cstr, sv.data, sv.count);
+ cstr[sv.count] = '\0';
+ return cstr;
+}
+
+long int
+sv_to_number(Sv sv, int base)
+{
+ assert(sv.count > 0 && sv.items);
+ long int result = 0;
+ bool negative = false;
+ if (*sv.items == '-') {
+ negative = true;
+ sv.items++;
+ sv.count--;
+ }
+ if (sv_starts_with_cstr(sv, "0b") ||
+ sv_starts_with_cstr(sv, "0o") ||
+ sv_starts_with_cstr(sv, "0d") ||
+ sv_starts_with_cstr(sv, "0x")) {
+ sv.items += 2;
+ sv.count -= 2;
+ }
+ do {
+ if (!is_digit_base(*sv.items, base)) {
+ fprintf(stderr, "Error: sv_to_number: Not a valid base%i digit '%c'\n", base, *sv.items);
+ }
+ result *= base;
+ result += ctoi(*sv.items);
+ sv.items++;
+ sv.count--;
+ } while (sv.count);
+ return negative ? -result : result;
+}
+
+ssize_t
+sv_find_char(Sv sv, char c)
+{
+ ssize_t pos = 0;
+ while (sv.count > pos && sv.items[pos] != c)
+ pos++;
+ for (pos = 0; pos < sv.count && sv.items[pos] != c; pos++);
+ return pos < sv.count ? pos : -1;
+}
+
+Sv
+sv_chop_delim(Sv sv, char c, Sv *rest)
+{
+ ssize_t pos = sv_find_char(sv, c);
+ Sv res = sv;
+ if (pos > 0) {
+ res.count = pos;
+
+ rest->count -= pos + 1;
+ rest->items += pos + 1;
+ }
+ return res;
+}
+
+Sv
+sv_chop(Sv sv, ssize_t count, Sv *rest)
+{
+ Sv left = {0};
+ ssize_t lcount, rcount;
+ if (count > sv.count) {
+ lcount = sv.count;
+ rcount = 0;
+ } else if (-count > sv.count) {
+ lcount = 0;
+ rcount = sv.count;
+ } else if (count < 0) {
+ lcount = sv.count + count;
+ rcount = -count;
+ } else {
+ lcount = count;
+ rcount = sv.count - count;
+ }
+ left.items = sv.items;
+ left.count = lcount;
+ if (rest) {
+ rest->items = sv.items + lcount;
+ rest->count = rcount;
+ }
+ return left;
+}
+
+Sv
+sv_trim_left(Sv sv)
+{
+ while (sv.count && isspace(sv.items[0])) {
+ sv.count--;
+ sv.items++;
+ }
+ return sv;
+}
+
+Sv
+sv_trim_right(Sv sv)
+{
+ while (sv.count && isspace(sv.items[sv.count - 1])) {
+ sv.count--;
+ }
+ return sv;
+}
+
+Sv
+sv_trim(Sv sv)
+{
+ return sv_trim_right(sv_trim_left(sv));
+}
+
+Sv
+sv_substring(Sv sv, ssize_t start, ssize_t req_count)
+{
+ Sv ss = {0};
+ if (start >= sv.count) return ss;
+ ss.count = (req_count < sv.count - start) ? req_count : sv.count - start;
+ ss.items = sv.items + start;
+ return ss;
+}
+
+int
+sv_compare(Sv sv1, Sv sv2)
+{
+ if (sv1.items == sv2.items && sv1.count == sv2.count) return 0;
+ signed char diff;
+ ssize_t pos;
+ for (pos = 0; pos < sv1.count; pos++) {
+ if (pos == sv2.count) return 1;
+ if ((diff = sv1.items[pos] - sv2.items[pos])) return diff;
+ }
+ return pos < sv2.count ? -1 : 0;
+}
+
+bool
+sv_equal(Sv sv1, Sv sv2)
+{
+ if (sv1.count != sv2.count) return false;
+ if (sv1.items == sv2.items) return true;
+ ssize_t pos;
+ for (pos = 0; pos < sv1.count && sv1.items[pos] == sv2.items[pos]; pos++);
+ return pos == sv1.count;
+}
+
+bool
+sv_starts_with_cstr(Sv sv, const char *cstr)
+{
+ size_t cstr_len = strlen(cstr);
+ assert(cstr_len <= SSIZE_MAX);
+ if (sv.count < (ssize_t) cstr_len) return false;
+ ssize_t pos;
+ for (pos = 0; pos < (ssize_t) cstr_len && sv.items[pos] == cstr[pos]; pos++);
+ return pos == (ssize_t) cstr_len;
+}
+
+bool
+sv_starts_with(Sv sv, Sv prefix)
+{
+ if (sv.count < prefix.count) return false;
+ ssize_t pos;
+ for (pos = 0; pos < prefix.count && sv.items[pos] == prefix.items[pos]; pos++);
+ return pos == prefix.count;
+}
+
+Sv
+sv_getline(Sv *sv)
+{
+ Sv line = sv_chop_delim(*sv, '\n', sv);
+ if (line.count && line.items[line.count - 1] == '\r') {
+ line.count--;
+ }
+ return line;
+}
+
+int
+isbdigit(int c)
+{
+ if (c > 127) {
+ todo_p("unicode support");
+ }
+ return c == '0' || c == '1';
+}
+
+int
+isodigit(int c)
+{
+ if (c > 127) {
+ todo_p("unicode support");
+ }
+ return c == '0' || c == '1' || c == '2' || c == '3' ||
+ c == '4' || c == '5' || c == '6' || c == '7';
+}
+
+int
+is_digit_base(int c, int base)
+{
+ if (base == 2) return isbdigit(c);
+ if (base == 8) return isodigit(c);
+ if (base == 10) return isddigit(c);
+ if (base == 16) return isxdigit(c);
+ fprintf(stderr, "Error: is_digit_base: invalid base %i\n", base);
+ return 0;
+}
+
+int
+ctoi(int c)
+{
+ if (c >= '0' && c <= '9') return c - '0';
+ if (c >= 'A' && c <= 'Z') return c - 'A' + 10;
+ if (c >= 'a' && c <= 'z') return c - 'a' + 10;
+ fprintf(stderr, "Error: ctoi: invalid digit '%c'\n", c);
+ return 0;
+}
+
+#endif // DLIB_IMPLEMENTATION
+
+#endif // DLIB_H