platform_posix.c (3485B)
1 #define _DEFAULT_SOURCE 1 2 #include <dirent.h> 3 #include <fcntl.h> 4 #include <sys/mman.h> 5 #include <sys/stat.h> 6 #include <unistd.h> 7 8 #include <stdint.h> 9 #include <stddef.h> 10 typedef uint8_t u8; 11 typedef int64_t i64; 12 typedef uint64_t u64; 13 typedef int32_t i32; 14 typedef uint32_t u32; 15 typedef uint32_t b32; 16 typedef uint16_t u16; 17 typedef ptrdiff_t size; 18 typedef size_t usize; 19 typedef ptrdiff_t iptr; 20 21 #define os_path_sep s8("/") 22 23 #include "jdict.c" 24 25 static void 26 os_exit(i32 code) 27 { 28 _exit(code); 29 unreachable(); 30 } 31 32 static Arena 33 os_new_arena(size cap) 34 { 35 Arena a; 36 37 size pagesize = sysconf(_SC_PAGESIZE); 38 if (cap % pagesize != 0) 39 cap += pagesize - cap % pagesize; 40 41 a.beg = mmap(0, cap, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 42 if (a.beg == MAP_FAILED) 43 return (Arena){0}; 44 a.end = a.beg + cap; 45 #ifdef _DEBUG_ARENA 46 a.min_capacity_remaining = cap; 47 #endif 48 return a; 49 } 50 51 static b32 52 os_read_stdin(u8 *buf, size count) 53 { 54 size rlen = read(STDIN_FILENO, buf, count); 55 return rlen == count; 56 } 57 58 static s8 59 os_read_whole_file_at(char *file, iptr dir_fd, Arena *a, u32 arena_flags) 60 { 61 62 i32 fd = openat(dir_fd, file, O_RDONLY); 63 if (fd < 0) { 64 stream_append_s8(&error_stream, s8("failed to open: ")); 65 stream_append_s8(&error_stream, cstr_to_s8(file)); 66 die(&error_stream); 67 } 68 69 struct stat st; 70 if (fstat(fd, &st) < 0) { 71 stream_append_s8(&error_stream, s8("failed to stat: ")); 72 stream_append_s8(&error_stream, cstr_to_s8(file)); 73 die(&error_stream); 74 } 75 76 s8 result = {.len = st.st_size, .s = alloc(a, u8, st.st_size, arena_flags|ARENA_NO_CLEAR)}; 77 size rlen = read(fd, result.s, result.len); 78 close(fd); 79 80 if (rlen != result.len) { 81 stream_append_s8(&error_stream, s8("failed to read whole file: ")); 82 stream_append_s8(&error_stream, cstr_to_s8(file)); 83 die(&error_stream); 84 } 85 86 return result; 87 } 88 89 static b32 90 os_write(iptr file, s8 raw) 91 { 92 while (raw.len) { 93 size r = write(file, raw.s, raw.len); 94 if (r < 0) return 0; 95 raw = s8_cut_head(raw, r); 96 } 97 return 1; 98 } 99 100 static iptr 101 os_begin_path_stream(Stream *dir_name, Arena *a, u32 arena_flags) 102 { 103 (void)a; (void)arena_flags; 104 105 stream_append_byte(dir_name, 0); 106 DIR *dir = opendir((char *)dir_name->data); 107 if (!dir) { 108 stream_append_s8(&error_stream, s8("opendir: failed to open: ")); 109 stream_append_s8(&error_stream, (s8){.len = dir_name->widx - 1, .s = dir_name->data}); 110 die(&error_stream); 111 } 112 return (iptr)dir; 113 } 114 115 static s8 116 os_get_valid_file(iptr path_stream, s8 match_prefix, Arena *a, u32 arena_flags) 117 { 118 s8 result = {0}; 119 if (path_stream) { 120 DIR *dir = (DIR *)path_stream; 121 iptr dir_fd = dirfd(dir); 122 struct dirent *dent; 123 while ((dent = readdir(dir)) != NULL) { 124 if (dent->d_type == DT_REG) { 125 b32 valid = 1; 126 for (size i = 0; i < match_prefix.len; i++) { 127 if (match_prefix.s[i] != dent->d_name[i]) { 128 valid = 0; 129 break; 130 } 131 } 132 if (valid) { 133 result = os_read_whole_file_at(dent->d_name, dir_fd, a, arena_flags); 134 break; 135 } 136 } 137 } 138 } 139 return result; 140 } 141 142 static void 143 os_end_path_stream(iptr path_stream) 144 { 145 closedir((DIR *)path_stream); 146 } 147 148 i32 149 main(i32 argc, char *argv[]) 150 { 151 Arena memory = os_new_arena(1024 * MEGABYTE); 152 153 error_stream.fd = STDERR_FILENO; 154 error_stream.cap = 4096; 155 error_stream.data = alloc(&memory, u8, error_stream.cap, ARENA_NO_CLEAR); 156 157 stdout_stream.fd = STDOUT_FILENO; 158 stdout_stream.cap = 8 * MEGABYTE; 159 stdout_stream.data = alloc(&memory, u8, error_stream.cap, ARENA_NO_CLEAR); 160 161 return jdict(&memory, argc, argv); 162 }