jdict

command line tool for looking up terms in yomidict dictionaries
git clone anongit@rnpnr.xyz:jdict.git
Log | Files | Refs | Feed | README | LICENSE

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 }