dlib.h (7041B)
1 #ifndef DLIB_H 2 #define DLIB_H 1 3 4 #include <assert.h> 5 #include <ctype.h> 6 #include <stdarg.h> 7 #include <stdio.h> 8 #include <stdbool.h> 9 #include <stdint.h> 10 #include <stdlib.h> 11 #include <errno.h> 12 #include <string.h> 13 #include <unistd.h> 14 15 #define da_append(da, new)\ 16 do {\ 17 if ((da)->capacity <= (da)->count) {\ 18 (da)->capacity = (da)->capacity ? (da)->capacity * 2 : 16;\ 19 (da)->items = realloc((da)->items, sizeof(*(da)->items) * (da)->capacity);\ 20 }\ 21 (da)->items[(da)->count++] = (new);\ 22 } while(0) 23 24 #define da_prepend(da, new)\ 25 do {\ 26 if ((da)->capacity <= (da)->count) {\ 27 (da)->capacity = (da)->capacity ? (da)->capacity * 2 : 16;\ 28 (da)->items = realloc((da)->items, sizeof(*(da)->items) * (da)->capacity);\ 29 }\ 30 memmove((da)->items + 1, (da)->items, sizeof(*(da)->items) * ((da)->count++));\ 31 (da)->items[0] = (new);\ 32 } while(0) 33 34 #define da_reserve(da, len)\ 35 do {\ 36 if ((da)->capacity >= (len)) break;\ 37 (da)->capacity = (len);\ 38 (da)->items = realloc((da)->items, sizeof(*(da)->items) * (len));\ 39 } while(0) 40 41 #define da_delete(da, index)\ 42 do {\ 43 assert(index >= 0 && index < (da)->count);\ 44 (da)->items[index] = (da)->items[--(da)->count];\ 45 } while (0) 46 47 typedef struct { 48 union { 49 char *items; 50 const char *data; 51 }; 52 union { 53 ssize_t count; 54 ssize_t length; 55 }; 56 ssize_t capacity; 57 } string_builder; 58 59 typedef struct { 60 union { 61 const char *items; 62 const char *data; 63 }; 64 union { 65 ssize_t count; 66 ssize_t length; 67 }; 68 } string_view; 69 70 #define sb_append_char da_append 71 void sb_printf(string_builder *sb, const char *fmt, ...); 72 void sb_append_cstr(string_builder *sb, const char *cstr); 73 void sb_append_sv(string_builder *sb, string_view sv); 74 75 void sb_read(string_builder *sb, int fd); 76 void sb_read_file(string_builder *sb, int fd); 77 void sb_write(int fd, string_builder sb); 78 79 void sv_write(int fd, string_view sv); 80 81 #define sv_literal(str) ((string_view){.data = (str), .count = (sizeof (str) - 1)}) 82 83 string_view sv_from_sb(string_builder sb); 84 ssize_t sv_find_char(string_view sv, char c); 85 86 string_view sv_chop(string_view sv, ssize_t count, string_view *rest); 87 string_view sv_chop_delim(string_view sv, char c, string_view *rest); 88 89 string_view sv_getline(string_view *sv); 90 91 string_view sv_trim_left(string_view sv); 92 string_view sv_trim_right(string_view sv); 93 string_view sv_trim(string_view sv); 94 95 string_view sv_substring(string_view sv, ssize_t start, ssize_t req_count); 96 97 int sv_compare(string_view sv1, string_view sv2); 98 bool sv_equal(string_view sv1, string_view sv2); 99 100 101 #ifdef DLIB_IMPLEMENTATION 102 103 void 104 sb_printf(string_builder *sb, const char *fmt, ...) { 105 va_list args, args_copy; 106 va_start(args, fmt); 107 va_copy(args_copy, args); 108 int len = vsnprintf(NULL, 0, fmt, args_copy) + 1; 109 ssize_t new_size = sb->count + len; 110 da_reserve(sb, new_size); 111 va_end(args_copy); 112 vsnprintf(sb->items + sb->count, len, fmt, args); 113 va_end(args); 114 sb->count = new_size - 1; 115 } 116 117 void 118 sb_append_cstr(string_builder *sb, const char *cstr) 119 { 120 ssize_t len = strlen(cstr); 121 da_reserve(sb, sb->count + len); 122 strcpy(sb->items + sb->count, cstr); 123 sb->count += len; 124 } 125 126 void 127 sb_append_sv(string_builder *sb, string_view sv) 128 { 129 da_reserve(sb, sb->count + sv.count); 130 memcpy(sb->items + sb->count, sv.data, sv.count); 131 sb->count += sv.count; 132 } 133 134 void 135 sb_read(string_builder *sb, int fd) 136 { 137 ssize_t read_count; 138 ssize_t buf_size = 4096; 139 char *buf = malloc(buf_size); 140 do { 141 read_count = read(fd, buf, buf_size); 142 if (read_count < 0) { 143 if (errno == EINTR) { 144 continue; 145 } 146 perror(NULL); 147 exit(1); 148 } 149 if (read_count == 0) { 150 break; 151 } 152 sb_append_sv(sb, ((string_view) {.data = buf, .length = read_count})); 153 if (read_count < buf_size) { 154 break; 155 } 156 } while (1); 157 free(buf); 158 } 159 160 void 161 sb_read_file(string_builder *sb, int fd) 162 { 163 ssize_t read_count; 164 ssize_t buf_size = 4096; 165 char *buf = malloc(buf_size); 166 do { 167 read_count = read(fd, buf, buf_size); 168 if (read_count < 0) { 169 if (errno == EINTR) { 170 continue; 171 } 172 perror(NULL); 173 exit(1); 174 } 175 if (read_count == 0) { 176 break; 177 } 178 sb_append_sv(sb, ((string_view) {.data = buf, .length = read_count})); 179 } while (1); 180 free(buf); 181 } 182 183 void 184 sb_write(int fd, string_builder sb) 185 { 186 write(fd, sb.data, sb.length); 187 } 188 189 /* String view functions */ 190 191 void 192 sv_write(int fd, string_view sv) 193 { 194 write(fd, sv.data, sv.count); 195 } 196 197 string_view 198 sv_from_sb(string_builder sb) 199 { 200 return (string_view) {.data = sb.items, .count = sb.count}; 201 } 202 203 ssize_t 204 sv_find_char(string_view sv, char c) 205 { 206 ssize_t pos = 0; 207 while (sv.count > pos && sv.data[pos] != c) 208 pos++; 209 for (pos = 0; pos < sv.count && sv.data[pos] != c; pos++); 210 return pos < sv.count ? pos : -1; 211 } 212 213 string_view 214 sv_chop_delim(string_view sv, char c, string_view *rest) 215 { 216 ssize_t pos = sv_find_char(sv, c); 217 string_view res = sv; 218 if (pos > 0) { 219 res.count = pos; 220 221 rest->count -= pos + 1; 222 rest->data += pos + 1; 223 } 224 return res; 225 } 226 227 string_view 228 sv_chop(string_view sv, ssize_t count, string_view *rest) 229 { 230 string_view left = {0}; 231 ssize_t lcount, rcount; 232 if (count > sv.count) { 233 lcount = sv.count; 234 rcount = 0; 235 } else if (-count > sv.count) { 236 lcount = 0; 237 rcount = sv.count; 238 } else if (count < 0) { 239 lcount = sv.count + count; 240 rcount = -count; 241 } else { 242 lcount = count; 243 rcount = sv.count - count; 244 } 245 left.data = sv.data; 246 left.count = lcount; 247 if (rest) { 248 rest->data = sv.data + lcount; 249 rest->count = rcount; 250 } 251 return left; 252 } 253 254 string_view 255 sv_trim_left(string_view sv) 256 { 257 while (sv.count && isspace(sv.data[0])) { 258 sv.count--; 259 sv.data++; 260 } 261 return sv; 262 } 263 264 string_view 265 sv_trim_right(string_view sv) 266 { 267 while (sv.count && isspace(sv.data[sv.count - 1])) { 268 sv.count--; 269 } 270 return sv; 271 } 272 273 string_view 274 sv_trim(string_view sv) 275 { 276 return sv_trim_right(sv_trim_left(sv)); 277 } 278 279 string_view 280 sv_substring(string_view sv, ssize_t start, ssize_t req_count) 281 { 282 string_view ss = {0}; 283 if (start >= sv.count) return ss; 284 ss.count = (req_count < sv.count - start) ? req_count : sv.count - start; 285 ss.data = sv.data + start; 286 return ss; 287 } 288 289 int 290 sv_compare(string_view sv1, string_view sv2) 291 { 292 if (sv1.data == sv2.data && sv1.count == sv2.count) return 0; 293 signed char diff; 294 ssize_t pos; 295 for (pos = 0; pos < sv1.count; pos++) { 296 if (pos == sv2.count) return 1; 297 if ((diff = sv1.data[pos] - sv2.data[pos])) return diff; 298 } 299 return pos < sv2.count ? -1 : 0; 300 } 301 302 bool 303 sv_equal(string_view sv1, string_view sv2) 304 { 305 if (sv1.count != sv2.count) return false; 306 if (sv1.data == sv2.data) return true; 307 ssize_t pos; 308 for (pos = 0; pos < sv1.count && sv1.data[pos] == sv2.data[pos]; pos++); 309 return pos == sv1.count; 310 } 311 312 string_view 313 sv_getline(string_view *sv) 314 { 315 string_view line = sv_chop_delim(*sv, '\n', sv); 316 if (line.count && line.data[line.count - 1] == '\r') { 317 line.count--; 318 } 319 return line; 320 } 321 322 #endif // DLIB_IMPLEMENTATION 323 324 #endif // DLIB_H