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: 1d547467bd0d7e8f90db844d60ec9dea98b94fb8
Parent: 420ff9fcd22a6b803ec6ae2ee8182f3953f509f7
Author: Randy Palamar
Date:   Thu, 17 Oct 2024 07:40:36 -0600

make stream flush implicit when the stream is full

also delay some flushing since it usually doesn't need to happen immediately.

Diffstat:
Mjdict.c | 95++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mplatform_linux.c | 8++++----
Mplatform_posix.c | 5+++--
3 files changed, 57 insertions(+), 51 deletions(-)

diff --git a/jdict.c b/jdict.c @@ -84,9 +84,9 @@ typedef struct { 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 b32 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(Stream *, Arena *, u32); static s8 os_get_valid_file(PathStream *, s8, Arena *, u32); @@ -96,9 +96,21 @@ static Stream error_stream; static Stream stdout_stream; static void +stream_flush(Stream *s) +{ + if (s->fd <= 0) { + s->errors = 1; + } else if (s->widx) { + s->errors = !os_write(s->fd, (s8){.len = s->widx, .s = s->data}); + if (!s->errors) s->widx = 0; + } +} + +static void stream_append_byte(Stream *s, u8 b) { - s->errors |= s->widx + 1 > s->cap; + if (s->widx + 1 > s->cap) + stream_flush(s); if (!s->errors) s->data[s->widx++] = b; } @@ -106,6 +118,8 @@ stream_append_byte(Stream *s, u8 b) static void stream_append_s8(Stream *s, s8 str) { + if (str.len > s->cap - s->widx) + stream_flush(s); s->errors |= (s->cap - s->widx) < str.len; if (!s->errors) { for (size i = 0; i < str.len; i++) @@ -113,6 +127,13 @@ stream_append_s8(Stream *s, s8 str) } } +static void +stream_ensure_newline(Stream *s) +{ + if (s->widx && s->data[s->widx - 1] != '\n') + stream_append_byte(s, '\n'); +} + #ifdef _DEBUG_ARENA static void stream_append_u64(Stream *s, u64 n) @@ -125,16 +146,6 @@ stream_append_u64(Stream *s, u64 n) } #endif -static void -stream_flush(Stream *s) -{ - if (s->widx) { - os_write(s->fd, (s8){.len = s->widx, .s = s->data}); - s->widx = 0; - s->errors = 0; - } -} - static s8 cstr_to_s8(char *cstr) { @@ -146,8 +157,7 @@ cstr_to_s8(char *cstr) static void __attribute__((noreturn)) die(Stream *s) { - if (s->data[s->widx - 1] != '\n') - stream_append_byte(s, '\n'); + stream_ensure_newline(s); stream_flush(s); os_exit(1); } @@ -206,16 +216,9 @@ usage(s8 argv0) } static s8 -s8_alloc(Arena *a, size len) -{ - s8 result = {.len = len, .s = alloc(a, u8, len, ARENA_NO_CLEAR)}; - return result; -} - -static s8 s8_dup(Arena *a, s8 old) { - s8 result = s8_alloc(a, old.len); + s8 result = {.len = old.len, .s = alloc(a, u8, old.len, ARENA_NO_CLEAR)}; for (size i = 0; i < old.len; i++) result.s[i] = old.s[i]; return result; @@ -309,7 +312,6 @@ intern(struct ht *t, s8 key) if ((u32)t->len + 1 == (u32)1<<(HT_EXP - 1)) { stream_append_s8(&error_stream, s8("intern: ht exceeded 0.5 fill factor\n")); - stream_flush(&error_stream); } #endif t->len++; @@ -369,11 +371,9 @@ parse_term_bank(Arena *a, struct ht *ht, s8 data) /* check if entry was valid */ if (tdefs == NULL || tstr == NULL) { - stream_append_s8(&error_stream, s8("parse_term_bank: ")); - if (!tdefs) - stream_append_s8(&error_stream, s8("tdefs")); - else - stream_append_s8(&error_stream, s8("tstr")); + stream_append_s8(&error_stream, s8("parse_term_bank: invalid entry: got ")); + if (!tdefs) stream_append_s8(&error_stream, s8("tdefs")); + else stream_append_s8(&error_stream, s8("tstr")); stream_append_s8(&error_stream, s8(" == NULL\n")); break; } @@ -391,7 +391,6 @@ parse_term_bank(Arena *a, struct ht *ht, s8 data) stream_append_byte(&error_stream, '\t'); stream_append_s8(&error_stream, (*n)->term); stream_append_byte(&error_stream, '\n'); - stream_flush(&error_stream); } } @@ -405,7 +404,7 @@ parse_term_bank(Arena *a, struct ht *ht, s8 data) } cleanup: - stream_flush(&error_stream); + stream_ensure_newline(&error_stream); } static int @@ -444,7 +443,7 @@ make_dicts(Arena *a, Dict *dicts, size_t ndicts) if (!make_dict(a, &dicts[i])) { stream_append_s8(&error_stream, s8("make_dict failed for: ")); stream_append_s8(&error_stream, dicts[i].rom); - die(&error_stream); + stream_append_byte(&error_stream, '\n'); } } } @@ -465,15 +464,21 @@ find_and_print(s8 term, Dict *d) if (!ent || s8_cmp(term, ent->term)) return; + b32 new_line_sep = !s8_cmp(fsep, s8("\n")); for (DictDef *def = ent->def; def; def = def->next) { - if (!s8_cmp(fsep, s8("\n"))) + if (new_line_sep) def->text = unescape(def->text); - stream_append_s8(&stdout_stream, d->name); - stream_append_s8(&stdout_stream, fsep); - stream_append_s8(&stdout_stream, def->text); - stream_append_byte(&stdout_stream, '\n'); - stream_flush(&stdout_stream); + /* NOTE: some dictionaries are "hand-made" by idiots and have definitions + * with only white space in them */ + def->text = s8trim(def->text); + if (def->text.len) { + stream_append_s8(&stdout_stream, d->name); + stream_append_s8(&stdout_stream, fsep); + stream_append_s8(&stdout_stream, def->text); + stream_append_byte(&stdout_stream, '\n'); + } } + stream_flush(&stdout_stream); } static void @@ -483,7 +488,6 @@ find_and_print_defs(Arena *a, Dict *dict, s8 *terms, size_t nterms) stream_append_s8(&error_stream, s8("failed to allocate dict: ")); stream_append_s8(&error_stream, dict->rom); stream_append_byte(&stdout_stream, '\n'); - stream_flush(&error_stream); return; } @@ -527,9 +531,6 @@ repl(Arena *a, Dict *dicts, size_t ndicts) buf.widx = 0; } stream_append_s8(&stdout_stream, repl_quit); - if (repl_quit.s[repl_quit.len - 1] != '\n') - stream_append_byte(&stdout_stream, '\n'); - stream_flush(&stdout_stream); } static i32 @@ -602,9 +603,13 @@ jdict(Arena *a, i32 argc, char *argv[]) stream_append_u64(&error_stream, memory.min_capacity_remaining); stream_append_s8(&error_stream, s8("\nremaining arena capacity: ")); stream_append_u64(&error_stream, memory.end - memory.beg); - stream_append_byte(&error_stream, '\n'); - stream_flush(&error_stream); #endif + stream_ensure_newline(&error_stream); + stream_flush(&error_stream); + + stream_ensure_newline(&stdout_stream); + stream_flush(&stdout_stream); + return 0; } diff --git a/platform_linux.c b/platform_linux.c @@ -39,14 +39,15 @@ os_exit(i32 code) __builtin_unreachable(); } -static void +static b32 os_write(iptr fd, s8 raw) { while (raw.len) { size r = syscall3(SYS_write, fd, (i64)raw.s, raw.len); - if (r < 0) os_exit(1); + if (r < 0) return 0; raw = s8_cut_head(raw, r); } + return 1; } static b32 @@ -146,8 +147,7 @@ os_get_valid_file(PathStream *ps, s8 match_prefix, Arena *a, u32 arena_flags) if (lds) { for (;;) { if (lds->buf_pos >= lds->buf_end) { - u64 ret = syscall3(SYS_getdents, lds->fd, (iptr)lds->buf, - sizeof(lds->buf)); + u64 ret = syscall3(SYS_getdents, lds->fd, (iptr)lds->buf, sizeof(lds->buf)); if (ret > -4096UL) { stream_append_s8(&error_stream, s8("os_get_valid_file: SYS_getdents")); die(&error_stream); diff --git a/platform_posix.c b/platform_posix.c @@ -73,14 +73,15 @@ os_read_whole_file(char *file, Arena *a, u32 arena_flags) return result; } -static void +static b32 os_write(iptr file, s8 raw) { while (raw.len) { size r = write(file, raw.s, raw.len); - if (r < 0) os_exit(1); + if (r < 0) return 0; raw = s8_cut_head(raw, r); } + return 1; } static PathStream