platform_posix.c (3859B)
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(char *file, Arena *a, u32 arena_flags) 60 { 61 62 struct stat st; 63 if (stat(file, &st) < 0) { 64 stream_append_s8(&error_stream, s8("failed to stat: ")); 65 stream_append_s8(&error_stream, cstr_to_s8(file)); 66 die(&error_stream); 67 } 68 69 i32 fd = open(file, O_RDONLY); 70 if (fd < 0) { 71 stream_append_s8(&error_stream, s8("failed to open: ")); 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 PathStream 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 dir_name->widx--; 108 if (!dir) { 109 stream_append_s8(&error_stream, s8("opendir: failed to open: ")); 110 stream_append_s8(&error_stream, (s8){.len = dir_name->widx, .s = dir_name->data}); 111 die(&error_stream); 112 } 113 stream_append_byte(dir_name, '/'); 114 return (PathStream){.dir_name = dir_name, .dirfd = dir}; 115 } 116 117 static s8 118 os_get_valid_file(PathStream *ps, s8 match_prefix, Arena *a, u32 arena_flags) 119 { 120 s8 result = {0}; 121 if (ps->dirfd) { 122 struct dirent *dent; 123 while ((dent = readdir(ps->dirfd)) != NULL) { 124 if (dent->d_type == DT_REG) { 125 b32 valid = 1; 126 /* NOTE: technically this contains extra NULs but it doesn't matter 127 * for this purpose. We need NUL terminated to call read() */ 128 s8 name = {.len = dent->d_reclen - 2 - offsetof(struct dirent, d_name), 129 .s = (u8 *)dent->d_name}; 130 for (size i = 0; i < match_prefix.len; i++) { 131 if (match_prefix.s[i] != name.s[i]) { 132 valid = 0; 133 break; 134 } 135 } 136 if (valid) { 137 Stream dir_name = *ps->dir_name; 138 stream_append_s8(&dir_name, name); 139 result = os_read_whole_file((char *)dir_name.data, a, 140 arena_flags); 141 break; 142 } 143 } 144 } 145 } 146 return result; 147 } 148 149 static void 150 os_end_path_stream(PathStream *ps) 151 { 152 closedir(ps->dirfd); 153 ps->dirfd = 0; 154 } 155 156 i32 157 main(i32 argc, char *argv[]) 158 { 159 Arena memory = os_new_arena(1024 * MEGABYTE); 160 161 error_stream.fd = STDERR_FILENO; 162 error_stream.cap = 4096; 163 error_stream.data = alloc(&memory, u8, error_stream.cap, ARENA_NO_CLEAR); 164 165 stdout_stream.fd = STDOUT_FILENO; 166 stdout_stream.cap = 8 * MEGABYTE; 167 stdout_stream.data = alloc(&memory, u8, error_stream.cap, ARENA_NO_CLEAR); 168 169 return jdict(&memory, argc, argv); 170 }