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: 10641ce02c9f5d1d86940bdd92caad157f715071
Parent: cafba69bda40a9a83da5834f8753a7ef45269fd4
Author: Randy Palamar
Date:   Tue, 31 Dec 2024 16:26:00 -0700

remove PathStream abstraction

since we are using openat we can just keep track of the file
descriptor (handle) for the directory and use that to open files
relative to it. Then we don't need to copy the file name out of
the getdents/readdir buffer saving some useless busy work.

Diffstat:
Mjdict.c | 19+++++++------------
Mplatform_linux.c | 27+++++++++++----------------
Mplatform_posix.c | 46+++++++++++++++++++---------------------------
3 files changed, 37 insertions(+), 55 deletions(-)

diff --git a/jdict.c b/jdict.c @@ -52,11 +52,6 @@ typedef struct { #endif } Arena; -typedef struct { - Stream *dir_name; - void *dirfd; -} PathStream; - #include "yomidict.c" #define YOMI_TOKS_PER_ENT 10 @@ -92,9 +87,9 @@ static void __attribute__((noreturn)) os_exit(i32); static b32 os_write(iptr, s8); static b32 os_read_stdin(u8 *, size); -static PathStream os_begin_path_stream(Stream *, Arena *, u32); -static s8 os_get_valid_file(PathStream *, s8, Arena *, u32); -static void os_end_path_stream(PathStream *); +static iptr os_begin_path_stream(Stream *, Arena *, u32); +static s8 os_get_valid_file(iptr, s8, Arena *, u32); +static void os_end_path_stream(iptr); static Stream error_stream; static Stream stdout_stream; @@ -423,18 +418,18 @@ make_dict(Arena *a, Dict *d) stream_append_s8(&path, prefix); stream_append_s8(&path, os_path_sep); stream_append_s8(&path, d->rom); - PathStream ps = os_begin_path_stream(&path, a, ARENA_ALLOC_END); + iptr path_stream = os_begin_path_stream(&path, a, ARENA_ALLOC_END); u8 *arena_end = a->end; s8 fn_pre = s8("term"); - for (s8 filedata = os_get_valid_file(&ps, fn_pre, a, ARENA_ALLOC_END); + for (s8 filedata = os_get_valid_file(path_stream, fn_pre, a, ARENA_ALLOC_END); filedata.len; - filedata = os_get_valid_file(&ps, fn_pre, a, ARENA_ALLOC_END)) + filedata = os_get_valid_file(path_stream, fn_pre, a, ARENA_ALLOC_END)) { parse_term_bank(a, &d->ht, filedata); a->end = arena_end; } - os_end_path_stream(&ps); + os_end_path_stream(path_stream); a->end = starting_arena_end; diff --git a/platform_linux.c b/platform_linux.c @@ -123,7 +123,7 @@ os_new_arena(size requested_size) return result; } -static PathStream +static iptr os_begin_path_stream(Stream *dir_name, Arena *a, u32 arena_flags) { stream_append_byte(dir_name, 0); @@ -131,29 +131,28 @@ os_begin_path_stream(Stream *dir_name, Arena *a, u32 arena_flags) if (fd > -4096UL) { stream_append_s8(&error_stream, s8("os_begin_path_stream: failed to open: ")); - stream_append_s8(&error_stream, (s8){.len = dir_name->widx, .s = dir_name->data}); + stream_append_s8(&error_stream, (s8){.len = dir_name->widx - 1, .s = dir_name->data}); die(&error_stream); } LinuxDirectoryStream *lds = alloc(a, LinuxDirectoryStream, 1, arena_flags); lds->fd = fd; - return (PathStream){.dir_name = dir_name, .dirfd = lds}; + return (iptr)lds; } static void -os_end_path_stream(PathStream *ps) +os_end_path_stream(iptr path_stream) { - LinuxDirectoryStream *lds = ps->dirfd; + LinuxDirectoryStream *lds = (LinuxDirectoryStream *)path_stream; syscall1(SYS_close, (iptr)lds->fd); - ps->dirfd = 0; } static s8 -os_get_valid_file(PathStream *ps, s8 match_prefix, Arena *a, u32 arena_flags) +os_get_valid_file(iptr path_stream, s8 match_prefix, Arena *a, u32 arena_flags) { s8 result = {0}; - LinuxDirectoryStream *lds = ps->dirfd; - if (lds) { + if (path_stream) { + LinuxDirectoryStream *lds = (LinuxDirectoryStream *)path_stream; for (;;) { if (lds->buf_pos >= lds->buf_end) { u64 ret = syscall3(SYS_getdents64, lds->fd, (iptr)lds->buf, @@ -169,22 +168,18 @@ os_get_valid_file(PathStream *ps, s8 match_prefix, Arena *a, u32 arena_flags) } u16 record_len = *(u16 *)(lds->buf + lds->buf_pos + DIRENT_RECLEN_OFF); u8 type = lds->buf[lds->buf_pos + DIRENT_TYPE_OFF]; - /* NOTE: technically this contains extra NULs but it doesn't matter - * for this purpose. We need NUL terminated to call SYS_read */ - s8 name = {.len = record_len - 2 - DIRENT_NAME_OFF, - .s = lds->buf + lds->buf_pos + DIRENT_NAME_OFF}; + char *name = (char *)lds->buf + lds->buf_pos + DIRENT_NAME_OFF; lds->buf_pos += record_len; if (type == DT_REGULAR_FILE) { b32 valid = 1; for (size i = 0; i < match_prefix.len; i++) { - if (match_prefix.s[i] != name.s[i]) { + if (match_prefix.s[i] != name[i]) { valid = 0; break; } } if (valid) { - result = os_read_whole_file_at((char *)name.s, lds->fd, - a, arena_flags); + result = os_read_whole_file_at(name, lds->fd, a, arena_flags); break; } } diff --git a/platform_posix.c b/platform_posix.c @@ -56,19 +56,19 @@ os_read_stdin(u8 *buf, size count) } static s8 -os_read_whole_file(char *file, Arena *a, u32 arena_flags) +os_read_whole_file_at(char *file, iptr dir_fd, Arena *a, u32 arena_flags) { - struct stat st; - if (stat(file, &st) < 0) { - stream_append_s8(&error_stream, s8("failed to stat: ")); + i32 fd = openat(dir_fd, 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); } - i32 fd = open(file, O_RDONLY); - if (fd < 0) { - stream_append_s8(&error_stream, s8("failed to open: ")); + struct stat st; + if (fstat(fd, &st) < 0) { + stream_append_s8(&error_stream, s8("failed to stat: ")); stream_append_s8(&error_stream, cstr_to_s8(file)); die(&error_stream); } @@ -97,47 +97,40 @@ os_write(iptr file, s8 raw) return 1; } -static PathStream +static iptr os_begin_path_stream(Stream *dir_name, Arena *a, u32 arena_flags) { (void)a; (void)arena_flags; stream_append_byte(dir_name, 0); DIR *dir = opendir((char *)dir_name->data); - dir_name->widx--; if (!dir) { stream_append_s8(&error_stream, s8("opendir: failed to open: ")); - stream_append_s8(&error_stream, (s8){.len = dir_name->widx, .s = dir_name->data}); + stream_append_s8(&error_stream, (s8){.len = dir_name->widx - 1, .s = dir_name->data}); die(&error_stream); } - stream_append_byte(dir_name, '/'); - return (PathStream){.dir_name = dir_name, .dirfd = dir}; + return (iptr)dir; } static s8 -os_get_valid_file(PathStream *ps, s8 match_prefix, Arena *a, u32 arena_flags) +os_get_valid_file(iptr path_stream, s8 match_prefix, Arena *a, u32 arena_flags) { s8 result = {0}; - if (ps->dirfd) { + if (path_stream) { + DIR *dir = (DIR *)path_stream; + iptr dir_fd = dirfd(dir); struct dirent *dent; - while ((dent = readdir(ps->dirfd)) != NULL) { + while ((dent = readdir(dir)) != NULL) { if (dent->d_type == DT_REG) { b32 valid = 1; - /* NOTE: technically this contains extra NULs but it doesn't matter - * for this purpose. We need NUL terminated to call read() */ - s8 name = {.len = dent->d_reclen - 2 - offsetof(struct dirent, d_name), - .s = (u8 *)dent->d_name}; for (size i = 0; i < match_prefix.len; i++) { - if (match_prefix.s[i] != name.s[i]) { + if (match_prefix.s[i] != dent->d_name[i]) { valid = 0; break; } } if (valid) { - Stream dir_name = *ps->dir_name; - stream_append_s8(&dir_name, name); - result = os_read_whole_file((char *)dir_name.data, a, - arena_flags); + result = os_read_whole_file_at(dent->d_name, dir_fd, a, arena_flags); break; } } @@ -147,10 +140,9 @@ os_get_valid_file(PathStream *ps, s8 match_prefix, Arena *a, u32 arena_flags) } static void -os_end_path_stream(PathStream *ps) +os_end_path_stream(iptr path_stream) { - closedir(ps->dirfd); - ps->dirfd = 0; + closedir((DIR *)path_stream); } i32