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