jdict

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

Commit: c1bea4cf97eb69e402ba5207a7aea34dda583aa2
Parent: b1f0d632a045db27f4de3c86579b3e6b392894c9
Author: Randy Palamar
Date:   Wed, 16 Oct 2024 06:25:09 -0600

split platform code into seperate file

Diffstat:
Mbuild.sh | 7++++---
Mjdict.c | 185++++++++++++++-----------------------------------------------------------------
Aplatform_posix.c | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 181 insertions(+), 157 deletions(-)

diff --git a/build.sh b/build.sh @@ -1,6 +1,5 @@ #!/bin/sh -cflags="-march=native -O3 -std=c99 -Wall -Wextra" -cflags="${cflags} -D_DEFAULT_SOURCE" +cflags="-march=native -O3 -std=c99 -Wall -Wextra -fno-builtin" #cflags="${cflags} -fproc-stat-report" #cflags="${cflags} -Rpass-missed=.*" ldflags="-static" @@ -8,7 +7,9 @@ ldflags="-static" cc=${CC:-cc} debug=${DEBUG} +src=platform_posix.c + [ $debug ] && cflags="$cflags -O0 -ggdb -D_DEBUG" [ ! $debug ] && ldflags="-s $ldflags" -${cc} $cflags $ldflags jdict.c -o jdict +${cc} $cflags $ldflags $src -o jdict diff --git a/jdict.c b/jdict.c @@ -1,10 +1,4 @@ /* See LICENSE for license details. */ -#include <dirent.h> -#include <fcntl.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <unistd.h> - #include <stdint.h> #include <stddef.h> typedef uint8_t u8; @@ -14,6 +8,7 @@ typedef int32_t i32; typedef uint32_t u32; typedef uint32_t b32; typedef ptrdiff_t size; +typedef ptrdiff_t iptr; #ifdef _DEBUG #define ASSERT(c) do { __asm("int3; nop"); } while (0) @@ -86,10 +81,16 @@ typedef struct { #include "config.h" -#define os_path_sep s8("/") -static b32 os_write(i32, s8); static void __attribute__((noreturn)) os_exit(i32); +static void os_write(iptr, s8); +static s8 os_read_whole_file(char *, Arena *, u32); +static b32 os_read_stdin(u8 *, size); + +static PathStream os_begin_path_stream(char *); +static s8 os_get_valid_file(PathStream *, s8); +static void os_end_path_stream(PathStream *); + static Stream error_stream; static Stream stdout_stream; @@ -150,81 +151,6 @@ die(Stream *s) os_exit(1); } -static void -os_exit(i32 code) -{ - _exit(code); - unreachable(); -} - -static Arena -os_new_arena(size cap) -{ - Arena a; - - size pagesize = sysconf(_SC_PAGESIZE); - if (cap % pagesize != 0) - cap += pagesize - cap % pagesize; - - a.beg = mmap(0, cap, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); - if (a.beg == MAP_FAILED) - return (Arena){0}; - a.end = a.beg + cap; -#ifdef _DEBUG_ARENA - a.min_capacity_remaining = cap; -#endif - return a; -} - -static size -os_file_size(char *file) -{ - struct stat st; - if (stat(file, &st) < 0) { - stream_append_s8(&error_stream, s8("failed to stat: ")); - stream_append_s8(&error_stream, cstr_to_s8(file)); - die(&error_stream); - } - return st.st_size; -} - -static b32 -os_read(i32 fd, size count, u8 *buf) -{ - size rlen = read(fd, buf, count); - return rlen == count; -} - -static s8 -os_read_file(char *file, u8 *buf, size file_size) -{ - i32 fd = open(file, O_RDONLY); - if (fd < 0) { - stream_append_s8(&error_stream, s8("failed to open: ")); - stream_append_s8(&error_stream, cstr_to_s8(file)); - die(&error_stream); - } - - s8 result = {.len = file_size, .s = buf}; - size rlen = read(fd, result.s, result.len); - close(fd); - - if (rlen != result.len) { - stream_append_s8(&error_stream, s8("failed to read whole file: ")); - stream_append_s8(&error_stream, cstr_to_s8(file)); - die(&error_stream); - } - - return result; -} - -static b32 -os_write(i32 file, s8 raw) -{ - b32 result = write(file, raw.s, raw.len) == raw.len; - return result; -} - static void * mem_clear(void *p_, u8 c, size len) { @@ -306,6 +232,15 @@ s8_cmp(s8 a, s8 b) return result; } +static s8 +s8_cut_head(s8 s, size count) +{ + s8 result = s; + result.s += count; + result.len -= count; + return result; +} + /* * trim whitespace from start and end of str * returns a new s8 (same memory) @@ -390,10 +325,7 @@ static void parse_term_bank(Arena *a, struct ht *ht, char *tbank) { Arena start = *a; - - size file_size = os_file_size(tbank); - u8 *file_buf = alloc(a, u8, file_size, ARENA_ALLOC_END|ARENA_NO_CLEAR); - s8 data = os_read_file(tbank, file_buf, file_size); + s8 data = os_read_whole_file(tbank, a, ARENA_ALLOC_END); /* allocate tokens */ size ntoks = (1 << HT_EXP) * YOMI_TOKS_PER_ENT + 1; @@ -480,52 +412,6 @@ cleanup: a->end = start.end; } -static PathStream -begin_path_stream(char *dirname) -{ - DIR *dir; - if (!(dir = opendir(dirname))) { - stream_append_s8(&error_stream, s8("opendir: failed to open: ")); - stream_append_s8(&error_stream, cstr_to_s8(dirname)); - die(&error_stream); - } - return (PathStream){.dirfd = dir}; -} - -static s8 -get_valid_file(PathStream *ps, s8 prefix) -{ - s8 result = {0}; - if (ps->dirfd) { - struct dirent *dent; - while ((dent = readdir(ps->dirfd)) != NULL) { - if (dent->d_type == DT_REG) { - b32 valid = 1; - for (size i = 0; i < prefix.len; i++) { - if (prefix.s[i] != dent->d_name[i]) { - valid = 0; - break; - } - } - if (valid) { - result = cstr_to_s8(dent->d_name); - /* NOTE: include the NUL terminator */ - result.len++; - break; - } - } - } - } - return result; -} - -static void -end_path_stream(PathStream *ps) -{ - closedir(ps->dirfd); - ps->dirfd = 0; -} - static int make_dict(Arena *a, Dict *d) { @@ -538,19 +424,19 @@ make_dict(Arena *a, Dict *d) stream_append_s8(&path, os_path_sep); stream_append_s8(&path, d->rom); stream_append_byte(&path, 0); - PathStream ps = begin_path_stream((char *)path.data); + PathStream ps = os_begin_path_stream((char *)path.data); path.widx -= 1; stream_append_s8(&path, os_path_sep); i32 start_widx = path.widx; s8 fn_pre = s8("term"); - for (s8 fn = get_valid_file(&ps, fn_pre); fn.len; fn = get_valid_file(&ps, fn_pre)) { + for (s8 fn = os_get_valid_file(&ps, fn_pre); fn.len; fn = os_get_valid_file(&ps, fn_pre)) { path.widx = start_widx; stream_append_s8(&path, fn); parse_term_bank(a, &d->ht, (char *)path.data); } - end_path_stream(&ps); + os_end_path_stream(&ps); /* NOTE: clear temporary allocations */ a->end = start.end; @@ -618,7 +504,7 @@ get_stdin_line(Stream *buf) b32 result = 0; for (; buf->widx < buf->cap; buf->widx++) { u8 *c = buf->data + buf->widx; - if (!os_read(STDIN_FILENO, 1, c) || *c == (u8)-1) { + if (!os_read_stdin(c, 1) || *c == (u8)-1) { break; } else if (*c == '\n') { result = 1; @@ -653,21 +539,12 @@ repl(Arena *a, Dict *dicts, size_t ndicts) stream_flush(&stdout_stream); } -int -main(int argc, char *argv[]) +static i32 +jdict(Arena *a, i32 argc, char *argv[]) { - Arena memory = os_new_arena(1024 * MEGABYTE); Dict *dicts = NULL; - size_t ndicts = 0, nterms = 0; - int iflag = 0; - - error_stream.fd = STDERR_FILENO; - error_stream.cap = 4096; - error_stream.data = alloc(&memory, u8, error_stream.cap, ARENA_NO_CLEAR); - - stdout_stream.fd = STDOUT_FILENO; - stdout_stream.cap = 8 * MEGABYTE; - stdout_stream.data = alloc(&memory, u8, error_stream.cap, ARENA_NO_CLEAR); + i32 ndicts = 0, nterms = 0; + i32 iflag = 0; s8 argv0 = cstr_to_s8(argv[0]); for (argv++, argc--; argv[0] && argv[0][0] == '-' && argv[0][1]; argc--, argv++) { @@ -714,7 +591,7 @@ main(int argc, char *argv[]) /* NOTE: remaining argv elements are search terms */ nterms = argc; - s8 *terms = alloc(&memory, s8, nterms, 0); + s8 *terms = alloc(a, s8, nterms, 0); for (i32 i = 0; argc && *argv; argv++, i++, argc--) terms[i] = cstr_to_s8(*argv); @@ -722,10 +599,10 @@ main(int argc, char *argv[]) usage(argv0); if (iflag == 0) - for (size_t i = 0; i < ndicts; i++) - find_and_print_defs(&memory, &dicts[i], terms, nterms); + for (i32 i = 0; i < ndicts; i++) + find_and_print_defs(a, &dicts[i], terms, nterms); else - repl(&memory, dicts, ndicts); + repl(a, dicts, ndicts); #ifdef _DEBUG_ARENA stream_append_s8(&error_stream, s8("min remaining arena capacity: ")); diff --git a/platform_posix.c b/platform_posix.c @@ -0,0 +1,146 @@ +#define _DEFAULT_SOURCE 1 +#include <dirent.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <unistd.h> + +#define os_path_sep s8("/") + +#include "jdict.c" + +static void +os_exit(i32 code) +{ + _exit(code); + unreachable(); +} + +static Arena +os_new_arena(size cap) +{ + Arena a; + + size pagesize = sysconf(_SC_PAGESIZE); + if (cap % pagesize != 0) + cap += pagesize - cap % pagesize; + + a.beg = mmap(0, cap, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + if (a.beg == MAP_FAILED) + return (Arena){0}; + a.end = a.beg + cap; +#ifdef _DEBUG_ARENA + a.min_capacity_remaining = cap; +#endif + return a; +} + +static b32 +os_read_stdin(u8 *buf, size count) +{ + size rlen = read(STDIN_FILENO, buf, count); + return rlen == count; +} + +static s8 +os_read_whole_file(char *file, Arena *a, u32 arena_flags) +{ + + struct stat st; + if (stat(file, &st) < 0) { + stream_append_s8(&error_stream, s8("failed to stat: ")); + stream_append_s8(&error_stream, cstr_to_s8(file)); + die(&error_stream); + } + + i32 fd = open(file, O_RDONLY); + if (fd < 0) { + stream_append_s8(&error_stream, s8("failed to open: ")); + stream_append_s8(&error_stream, cstr_to_s8(file)); + die(&error_stream); + } + + s8 result = {.len = st.st_size, .s = alloc(a, u8, st.st_size, arena_flags|ARENA_NO_CLEAR)}; + size rlen = read(fd, result.s, result.len); + close(fd); + + if (rlen != result.len) { + stream_append_s8(&error_stream, s8("failed to read whole file: ")); + stream_append_s8(&error_stream, cstr_to_s8(file)); + die(&error_stream); + } + + return result; +} + +static void +os_write(iptr file, s8 raw) +{ + while (raw.len) { + size r = write(file, raw.s, raw.len); + if (r < 0) os_exit(1); + raw = s8_cut_head(raw, r); + } +} + +static PathStream +os_begin_path_stream(char *directory) +{ + DIR *dir; + if (!(dir = opendir(directory))) { + stream_append_s8(&error_stream, s8("opendir: failed to open: ")); + stream_append_s8(&error_stream, cstr_to_s8(directory)); + die(&error_stream); + } + return (PathStream){.dirfd = dir}; +} + +static s8 +os_get_valid_file(PathStream *ps, s8 match_prefix) +{ + s8 result = {0}; + if (ps->dirfd) { + struct dirent *dent; + while ((dent = readdir(ps->dirfd)) != NULL) { + if (dent->d_type == DT_REG) { + b32 valid = 1; + for (size i = 0; i < match_prefix.len; i++) { + if (match_prefix.s[i] != dent->d_name[i]) { + valid = 0; + break; + } + } + if (valid) { + result = cstr_to_s8(dent->d_name); + /* NOTE: include the NUL terminator */ + result.len++; + break; + } + } + } + } + return result; +} + +static void +os_end_path_stream(PathStream *ps) +{ + closedir(ps->dirfd); + ps->dirfd = 0; +} + +i32 +main(i32 argc, char *argv[]) +{ + Arena memory = os_new_arena(1024 * MEGABYTE); + + error_stream.fd = STDERR_FILENO; + error_stream.cap = 4096; + error_stream.data = alloc(&memory, u8, error_stream.cap, ARENA_NO_CLEAR); + + stdout_stream.fd = STDOUT_FILENO; + stdout_stream.cap = 8 * MEGABYTE; + stdout_stream.data = alloc(&memory, u8, error_stream.cap, ARENA_NO_CLEAR); + + return jdict(&memory, argc, argv); +}