dlib

Unnamed repository; edit this file 'description' to name the repository.
git clone https://git.deepztream.com/dlib
Log | Files | Refs

dlib.h (12091B)


      1 #ifndef DLIB_H
      2 #define DLIB_H 1
      3 
      4 #include <assert.h>
      5 #include <ctype.h>
      6 #include <fcntl.h>
      7 #include <limits.h>
      8 #include <stdarg.h>
      9 #include <stdio.h>
     10 #include <stdbool.h>
     11 #include <stdint.h>
     12 #include <stdlib.h>
     13 #include <errno.h>
     14 #include <string.h>
     15 #include <unistd.h>
     16 
     17 #define todo_p(msg) \
     18   do { \
     19     fprintf(stderr, "%s:%i:1: Error: TODO: %s\n", __FILE__, __LINE__, (msg)); \
     20     abort(); \
     21   } while (0)
     22 
     23 #define todo(msg) \
     24   do { \
     25     fprintf(stderr, "%s:%i:1: Error: TODO: %s\n", __FILE__, __LINE__, (msg)); \
     26     return false; \
     27   } while (0)
     28 
     29 #define unimplemented() \
     30   do { \
     31     fprintf(stderr, "%s:%i:1: Error: not implemented %s\n", __FILE__, __LINE__, __func__); \
     32     abort(); \
     33   } while (0)
     34 
     35 #define unreachable(msg) \
     36   do { \
     37     fprintf(stderr, "%s:%i:1: Error: Unreachable: %s\n", __FILE__, __LINE__, (msg)); \
     38     abort(); \
     39   } while (0)
     40 
     41 #define pop_arg(argc, argv) ((argc)--, *(argv)++)
     42 
     43 #define da_append(da, new)\
     44   do {\
     45     if ((da)->capacity <= (da)->count) {\
     46       (da)->capacity = (da)->capacity ? (da)->capacity * 2 : 16;\
     47       (da)->items = realloc((da)->items, sizeof(*(da)->items) * (da)->capacity);\
     48     }\
     49     (da)->items[(da)->count++] = (new);\
     50   } while(0)
     51 
     52 #define da_prepend(da, new)\
     53   do {\
     54     if ((da)->capacity <= (da)->count) {\
     55       (da)->capacity = (da)->capacity ? (da)->capacity * 2 : 16;\
     56       (da)->items = realloc((da)->items, sizeof(*(da)->items) * (da)->capacity);\
     57     }\
     58     memmove((da)->items + 1, (da)->items, sizeof(*(da)->items) * ((da)->count++));\
     59     (da)->items[0] = (new);\
     60   } while(0)
     61 
     62 #define da_reserve(da, len)\
     63   do {\
     64     if ((da)->capacity >= (len)) break;\
     65     (da)->capacity = (len);\
     66     (da)->items = realloc((da)->items, sizeof(*(da)->items) * (len));\
     67   } while(0)
     68 
     69 #define da_expand(da, size)\
     70   do {\
     71     if ((da)->count >= (size)) break;\
     72     da_reserve(da, size);\
     73     (da)->count = (size);\
     74   } while(0)
     75 
     76 #define da_delete(da, index)\
     77   do {\
     78     assert(index >= 0 && index < (da)->count);\
     79     (da)->items[index] = (da)->items[--(da)->count];\
     80   } while (0)
     81 
     82 #define da_delete_ordered(da, index)\
     83   do {\
     84     assert(index < (da)->count);\
     85     memmove(&(da)->items[(index)], &(da)->items[(index) + 1], sizeof(*(da)->items) * ((da)->count-- - (index) - 1));\
     86   } while (0)
     87 
     88 typedef struct {
     89   union {
     90     char *items;
     91     const char *data;
     92   };
     93   union {
     94     ssize_t count;
     95     ssize_t length;
     96   };
     97   ssize_t capacity;
     98 } Sb;
     99 #define String_builder Sb
    100 
    101 typedef struct {
    102   union {
    103     const char *items;
    104     const char *data;
    105   };
    106   union {
    107     ssize_t count;
    108     ssize_t length;
    109   };
    110 } Sv;
    111 #define String_view Sv
    112 
    113 typedef struct {
    114   void *base;
    115   void *head;
    116   void *end;
    117 } Temp_allocator;
    118 
    119 #define TA_DEFAULT_SIZE (1024*1024)
    120 
    121 void ta_init(Temp_allocator *ta, size_t size);
    122 void *ta_alloc(Temp_allocator *ta, size_t size);
    123 
    124 #define sb_append_char da_append
    125 int sb_printf(Sb *sb, const char *fmt, ...);
    126 void sb_append_cstr(Sb *sb, const char *cstr);
    127 void sb_append_sv(Sb *sb, Sv sv);
    128 bool sb_append_and_unescape_sv(Sb *sb, Sv sv);
    129 
    130 bool sb_read(Sb *sb, int fd);
    131 bool sb_read_file(Sb *sb, const char *file_name);
    132 void sb_write(int fd, Sb sb);
    133 
    134 void sb_release(Sb *sb);
    135 
    136 #define sv_literal(str) ((Sv){.items = (str), .count = (sizeof (str) - 1)})
    137 
    138 Sv sv_from_sb(Sb sb);
    139 Sv sv_from_cstr(const char *cstr);
    140 const char *sv_to_cstr(Sv sv);
    141 long int sv_to_number(Sv sv, int base);
    142 ssize_t sv_find_char(Sv sv, char c);
    143 
    144 Sv sv_chop(Sv sv, ssize_t count, Sv *rest);
    145 Sv sv_chop_delim(Sv sv, char c, Sv *rest);
    146 
    147 Sv sv_getline(Sv *sv);
    148 
    149 Sv sv_trim_left(Sv sv);
    150 Sv sv_trim_right(Sv sv);
    151 Sv sv_trim(Sv sv);
    152 
    153 Sv sv_substring(Sv sv, ssize_t start, ssize_t req_count);
    154 
    155 int sv_compare(Sv sv1, Sv sv2);
    156 bool sv_equal(Sv sv1, Sv sv2);
    157 bool sv_starts_with_cstr(Sv sv, const char *cstr);
    158 bool sv_starts_with(Sv sv, Sv prefix);
    159 
    160 void sv_write(int fd, Sv sv);
    161 
    162 /* Adding missing libc functions */
    163 int ctoi(int c);
    164 #define isddigit isdigit
    165 int isbdigit(int c);
    166 int isodigit(int c);
    167 
    168 int is_digit_base(int c, int base);
    169 
    170 #ifdef DLIB_IMPLEMENTATION
    171 
    172 void
    173 ta_init(Temp_allocator *ta, size_t size)
    174 {
    175   ta->base = malloc(size);
    176   ta->head = ta->base;
    177   ta->end = ta->base + size;
    178 }
    179 
    180 void *
    181 ta_alloc(Temp_allocator *ta, size_t size)
    182 {
    183   if (!ta->base) {
    184     ta->base = malloc(TA_DEFAULT_SIZE);
    185     ta->head = ta->base;
    186     ta->end = ta->base + TA_DEFAULT_SIZE;
    187   }
    188   void *result = ta->head;
    189   ta->head += (size + 0xF) & ~0xFul;
    190   if (ta->head >= ta->end) {
    191     fprintf(stderr, "Error: Temp allocator out of memory\n");
    192     exit(1);
    193   }
    194   return result;
    195 }
    196 
    197 int
    198 sb_printf(Sb *sb, const char *fmt, ...) {
    199   va_list args, args_copy;
    200   va_start(args, fmt);
    201   va_copy(args_copy, args);
    202   int len = vsnprintf(NULL, 0, fmt, args_copy) + 1;
    203   ssize_t new_size = sb->count + len;
    204   da_reserve(sb, new_size);
    205   va_end(args_copy);
    206   vsnprintf(sb->items + sb->count, len, fmt, args);
    207   va_end(args);
    208   sb->count = new_size - 1;
    209   return len - 1;
    210 }
    211 
    212 void
    213 sb_append_cstr(Sb *sb, const char *cstr)
    214 {
    215   ssize_t len = strlen(cstr);
    216   da_reserve(sb, sb->count + len);
    217   strcpy(sb->items + sb->count, cstr);
    218   sb->count += len;
    219 }
    220 
    221 void
    222 sb_append_sv(Sb *sb, Sv sv)
    223 {
    224   da_reserve(sb, sb->count + sv.count);
    225   memcpy(sb->items + sb->count, sv.items, sv.count);
    226   sb->count += sv.count;
    227 }
    228 
    229 /* Returns `false` if it encounters an invalid escape character */
    230 
    231 bool
    232 sb_append_and_unescape_sv(Sb *sb, Sv sv)
    233 {
    234   bool success = true;
    235   ssize_t i;
    236   char c;
    237   for (i = 0; i < sv.count; i++) {
    238     c = sv.data[i];
    239     if (c == '\\') {
    240       if (++i >= sv.count) {
    241         success = false;
    242       } else {
    243         c = sv.data[i];
    244         if (c == 'n') {
    245           c = '\n';
    246         } else if (c == 't') {
    247           c = '\t';
    248         } else if (c == 'r') {
    249           c = '\r';
    250         } else if (c == '0') {
    251           c = '\0';
    252         } else {
    253           if (c >= 32 && c < 127) {
    254             fprintf(stderr, "Info: escape character '%c' unsupported\n", c);
    255           } else {
    256             fprintf(stderr, "Info: escape character 0x%x02 unsupported\n", c);
    257           }
    258           success = false;
    259         }
    260       }
    261     }
    262     sb_append_char(sb, c);
    263   }
    264   return success;
    265 }
    266 
    267 bool
    268 sb_read(Sb *sb, int fd)
    269 {
    270   ssize_t read_count;
    271   ssize_t buf_size = 4096;
    272   char *buf = malloc(buf_size);
    273   do {
    274     read_count = read(fd, buf, buf_size);
    275     if (read_count < 0) {
    276       if (errno == EINTR) {
    277         continue;
    278       }
    279       perror("sb_read()");
    280       return false;
    281     }
    282     if (read_count == 0) {
    283       break;
    284     }
    285     sb_append_sv(sb, ((Sv) {.items = buf, .length = read_count}));
    286     if (read_count < buf_size) {
    287       break;
    288     }
    289   } while (1);
    290   free(buf);
    291   return true;
    292 }
    293 
    294 bool
    295 sb_read_file(Sb *sb, const char *file_name)
    296 {
    297   int fd = open(file_name, O_RDONLY);
    298   if (fd < 0) {
    299     perror("sb_read()");
    300     return false;
    301   }
    302   ssize_t read_count;
    303   ssize_t buf_size = 4096;
    304   char *buf = malloc(buf_size);
    305   do {
    306     read_count = read(fd, buf, buf_size);
    307     if (read_count < 0) {
    308       if (errno == EINTR) {
    309         continue;
    310       }
    311       perror("sb_read_file()");
    312       return false;
    313     }
    314     if (read_count == 0) {
    315       break;
    316     }
    317     sb_append_sv(sb, ((Sv) {.items = buf, .length = read_count}));
    318   } while (1);
    319   free(buf);
    320   return true;
    321 }
    322 
    323 void
    324 sb_write(int fd, Sb sb)
    325 {
    326   write(fd, sb.items, sb.length);
    327 }
    328 
    329 void
    330 sb_release(Sb *sb)
    331 {
    332   if (sb->capacity) {
    333     free(sb->items);
    334     sb->items = NULL;
    335     sb->count = 0;
    336     sb->capacity = 0;
    337   }
    338 }
    339 
    340 /* String view functions */
    341 
    342 void
    343 sv_write(int fd, Sv sv)
    344 {
    345   write(fd, sv.items, sv.count);
    346 }
    347 
    348 Sv
    349 sv_from_sb(Sb sb)
    350 {
    351   return (Sv) {.items = sb.items, .count = sb.count};
    352 }
    353 
    354 Sv
    355 sv_from_cstr(const char *cstr)
    356 {
    357   return (Sv) {.items = cstr, .count = strlen(cstr)};
    358 }
    359 
    360 const char *
    361 sv_to_cstr(Sv sv)
    362 {
    363   char *cstr = malloc(sv.count + 1);
    364   memcpy(cstr, sv.data, sv.count);
    365   cstr[sv.count] = '\0';
    366   return cstr;
    367 }
    368 
    369 long int
    370 sv_to_number(Sv sv, int base)
    371 {
    372   assert(sv.count > 0 && sv.items);
    373   long int result = 0;
    374   bool negative = false;
    375   if (*sv.items == '-') {
    376     negative = true;
    377     sv.items++;
    378     sv.count--;
    379   }
    380   if (sv_starts_with_cstr(sv, "0b") ||
    381       sv_starts_with_cstr(sv, "0o") ||
    382       sv_starts_with_cstr(sv, "0d") ||
    383       sv_starts_with_cstr(sv, "0x")) {
    384     sv.items += 2;
    385     sv.count -= 2;
    386   }
    387   do {
    388     if (!is_digit_base(*sv.items, base)) {
    389       fprintf(stderr, "Error: sv_to_number: Not a valid base%i digit '%c'\n", base, *sv.items);
    390     }
    391     result *= base;
    392     result += ctoi(*sv.items);
    393     sv.items++;
    394     sv.count--;
    395   } while (sv.count);
    396   return negative ? -result : result;
    397 }
    398 
    399 ssize_t
    400 sv_find_char(Sv sv, char c)
    401 {
    402   ssize_t pos = 0;
    403   while (sv.count > pos && sv.items[pos] != c)
    404     pos++;
    405   for (pos = 0; pos < sv.count && sv.items[pos] != c; pos++);
    406   return pos < sv.count ? pos : -1;
    407 }
    408 
    409 Sv
    410 sv_chop_delim(Sv sv, char c, Sv *rest)
    411 {
    412   ssize_t pos = sv_find_char(sv, c);
    413   Sv res = sv;
    414   if (pos > 0) {
    415     res.count = pos;
    416 
    417     rest->count -= pos + 1;
    418     rest->items += pos + 1;
    419   }
    420   return res;
    421 }
    422 
    423 Sv
    424 sv_chop(Sv sv, ssize_t count, Sv *rest)
    425 {
    426   Sv left = {0};
    427   ssize_t lcount, rcount;
    428   if (count > sv.count) {
    429     lcount = sv.count;
    430     rcount = 0;
    431   } else if (-count > sv.count) {
    432     lcount = 0;
    433     rcount = sv.count;
    434   } else if (count < 0) {
    435     lcount = sv.count + count;
    436     rcount = -count;
    437   } else {
    438     lcount = count;
    439     rcount = sv.count - count;
    440   }
    441   left.items = sv.items;
    442   left.count = lcount;
    443   if (rest) {
    444     rest->items = sv.items + lcount;
    445     rest->count = rcount;
    446   }
    447   return left;
    448 }
    449 
    450 Sv
    451 sv_trim_left(Sv sv)
    452 {
    453   while (sv.count && isspace(sv.items[0])) {
    454     sv.count--;
    455     sv.items++;
    456   }
    457   return sv;
    458 }
    459 
    460 Sv
    461 sv_trim_right(Sv sv)
    462 {
    463   while (sv.count && isspace(sv.items[sv.count - 1])) {
    464     sv.count--;
    465   }
    466   return sv;
    467 }
    468 
    469 Sv
    470 sv_trim(Sv sv)
    471 {
    472   return sv_trim_right(sv_trim_left(sv));
    473 }
    474 
    475 Sv
    476 sv_substring(Sv sv, ssize_t start, ssize_t req_count)
    477 {
    478   Sv ss = {0};
    479   if (start >= sv.count) return ss;
    480   ss.count = (req_count < sv.count - start) ? req_count : sv.count - start;
    481   ss.items = sv.items + start;
    482   return ss;
    483 }
    484 
    485 int
    486 sv_compare(Sv sv1, Sv sv2)
    487 {
    488   if (sv1.items == sv2.items && sv1.count == sv2.count) return 0;
    489   signed char diff;
    490   ssize_t pos;
    491   for (pos = 0; pos < sv1.count; pos++) {
    492     if (pos == sv2.count) return 1;
    493     if ((diff = sv1.items[pos] - sv2.items[pos])) return diff;
    494   }
    495   return pos < sv2.count ? -1 : 0;
    496 }
    497 
    498 bool
    499 sv_equal(Sv sv1, Sv sv2)
    500 {
    501   if (sv1.count != sv2.count) return false;
    502   if (sv1.items == sv2.items) return true;
    503   ssize_t pos;
    504   for (pos = 0; pos < sv1.count && sv1.items[pos] == sv2.items[pos]; pos++);
    505   return pos == sv1.count;
    506 }
    507 
    508 bool
    509 sv_starts_with_cstr(Sv sv, const char *cstr)
    510 {
    511   size_t cstr_len = strlen(cstr);
    512   assert(cstr_len <= SSIZE_MAX);
    513   if (sv.count < (ssize_t) cstr_len) return false;
    514   ssize_t pos;
    515   for (pos = 0; pos < (ssize_t) cstr_len && sv.items[pos] == cstr[pos]; pos++);
    516   return pos == (ssize_t) cstr_len;
    517 }
    518 
    519 bool
    520 sv_starts_with(Sv sv, Sv prefix)
    521 {
    522   if (sv.count < prefix.count) return false;
    523   ssize_t pos;
    524   for (pos = 0; pos < prefix.count && sv.items[pos] == prefix.items[pos]; pos++);
    525   return pos == prefix.count;
    526 }
    527 
    528 Sv
    529 sv_getline(Sv *sv)
    530 {
    531   Sv line = sv_chop_delim(*sv, '\n', sv);
    532   if (line.count && line.items[line.count - 1] == '\r') {
    533     line.count--;
    534   }
    535   return line;
    536 }
    537 
    538 int
    539 isbdigit(int c)
    540 {
    541   if (c > 127) {
    542     todo_p("unicode support");
    543   }
    544   return c == '0' || c == '1';
    545 }
    546 
    547 int
    548 isodigit(int c)
    549 {
    550   if (c > 127) {
    551     todo_p("unicode support");
    552   }
    553   return c == '0' || c == '1' || c == '2' || c == '3' ||
    554          c == '4' || c == '5' || c == '6' || c == '7';
    555 }
    556 
    557 int
    558 is_digit_base(int c, int base)
    559 {
    560   if (base == 2)  return isbdigit(c);
    561   if (base == 8)  return isodigit(c);
    562   if (base == 10) return isddigit(c);
    563   if (base == 16) return isxdigit(c);
    564   fprintf(stderr, "Error: is_digit_base: invalid base %i\n", base);
    565   return 0;
    566 }
    567 
    568 int
    569 ctoi(int c)
    570 {
    571   if (c >= '0' && c <= '9') return c - '0';
    572   if (c >= 'A' && c <= 'Z') return c - 'A' + 10;
    573   if (c >= 'a' && c <= 'z') return c - 'a' + 10;
    574   fprintf(stderr, "Error: ctoi: invalid digit '%c'\n", c);
    575   return 0;
    576 }
    577 
    578 #endif // DLIB_IMPLEMENTATION
    579 
    580 #endif // DLIB_H