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 (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 }