From 4db31489c2042002ab5011147547b2b07c6c1eb4 Mon Sep 17 00:00:00 2001 From: Neil Date: Sun, 12 Mar 2023 20:43:27 -0700 Subject: [PATCH] callback is to much steps; have verse tree --- src/journal.h | 2 +- src/journal.re.c | 25 +++++++++++------- src/kjv.h | 2 +- src/kjv.re.c | 9 ++----- src/pair.c | 7 +++-- src/scan_kjv.re.c | 65 ++++++++++++++++++++++++++++++----------------- test/test_kjv.c | 2 +- 7 files changed, 67 insertions(+), 45 deletions(-) diff --git a/src/journal.h b/src/journal.h index dd226d9..0a498b1 100644 --- a/src/journal.h +++ b/src/journal.h @@ -35,7 +35,7 @@ struct journal { struct day_tree days; struct text backing; }; struct journal_iterator { struct day_tree_iterator _; }; struct journal journal(void); void journal_(struct journal *); -/*int journal_is_valid(const struct journal *);*/ +int journal_is_empty(const struct journal *); const char *journal_to_string(const struct journal *); struct journal_iterator journal_iterator(struct journal *const j); int journal_next(struct journal_iterator *, union date32 *, const char **); diff --git a/src/journal.re.c b/src/journal.re.c index cb81538..e67d48e 100644 --- a/src/journal.re.c +++ b/src/journal.re.c @@ -1,4 +1,9 @@ -/** Reading all journal entries in yyyy/mm/dd.txt. +/** @license 2022 Neil Edelman, distributed under the terms of the + [GNU General Public License 3](https://opensource.org/licenses/GPL-3.0). + + Reading all journal entries yyyy-mm-dd in yyyy/mm/dd.txt to a tree. + [re2c](https://re2c.org/) is a convince (and fast) for "looks like" functions, + telling the recursion to go into a directory. @std GNU, C11, assumes reverse order unions. */ #define BASE @@ -13,6 +18,7 @@ #include /* umask (POSIX) */ #include /* opendir readdir closedir */ +/* Day tree-map from date to pointer; is backed by a huge array of text. */ void date32_to_string(const union date32 d, char (*const a)[12]) { sprintf(*a, "%" PRIu32 "-%2.2" PRIu32 "-%2.2" PRIu32, d.year % 10000, d.month % 100, d.day % 100); @@ -24,11 +30,11 @@ static void day_to_string(const union date32 d, const char *const*const entry, #define TREE_NAME day #define TREE_KEY union date32 #define TREE_VALUE const char * -#define TREE_COMPARE -#define TREE_TO_STRING +#define TREE_COMPARE /* custom comparison. */ +#define TREE_TO_STRING /* printing day. */ #include "../src/tree.h" -/* Temporary filename arrangement. */ +/* Temporary filename arrangement in directory. */ #if INT_MAX >= 100000000000 #error int_to_string requires truncation on this compiler. #endif @@ -109,7 +115,8 @@ void journal_(struct journal *const j) { text_(&j->backing); } -/** @return A completed journal out of "journal". */ +/** @return A completed journal out of "journal". Any reading errors and + `errno` will be set, it will be idle. */ struct journal journal(void) { const char *const dir_journal = "journal"; struct journal j = {0}; @@ -221,14 +228,14 @@ recatch: journal_(&j); finally: if(dir) { if(closedir(dir)) { dir = 0; goto recatch; } dir = 0; } - int_array_(&years), int_array_(&months), int_array_(&days); + int_array_(&years), int_array_(&months), int_array_(&days); /* Temporary. */ return j; } /** @return `j` read in some data? */ -/*int journal_is_valid(const struct journal *const j) { - return j && j->days.root.node && j->backing.a.data; -}*/ +int journal_is_empty(const struct journal *const j) { + return !j || !j->days.root.node || !j->backing.a.data; +} /** @return `j` as a string. */ const char *journal_to_string(const struct journal *const j) diff --git a/src/kjv.h b/src/kjv.h index 04f646b..b9ef13b 100644 --- a/src/kjv.h +++ b/src/kjv.h @@ -110,7 +110,7 @@ struct kjv { }; struct kjv kjv(void); void kjv_(struct kjv *); -int kjv_is_valid(const struct kjv *const kjv); +int kjv_is_empty(const struct kjv *const kjv); /* Only used in test. */ int kjv_add(struct kjv *const kjv, const union kjvcite cite); const char *kjv_to_string(const struct kjv *const kjv); diff --git a/src/kjv.re.c b/src/kjv.re.c index e6d9a07..3a558aa 100644 --- a/src/kjv.re.c +++ b/src/kjv.re.c @@ -213,20 +213,15 @@ catch: recatch: kjv_(&kjv); finally: - printf("kjv: %s.\n", kjv_to_string(&kjv)); - printf("kjv: closedir errno %d\n", errno); if(dir) { if(closedir(dir)) { dir = 0; goto recatch; } dir = 0; } - printf("kjv: is_in_kjv errno %d\n", errno); if(is_in_kjv && (is_in_kjv = 0, chdir("..") == -1)) goto recatch; - printf("kjv: ~text(backing) errno %d\n", errno); text_(&backing); - printf("kjv: %p errno %d\n", (void *)&kjv, errno); return kjv; } /** Has loaded properly? Otherwise, probably `errno` is set. */ -int kjv_is_valid(const struct kjv *const kjv) - { return kjv && kjv->verses.buckets; } +int kjv_is_empty(const struct kjv *const kjv) + { return !kjv || !kjv->verses.buckets; } /** Adds `cite` to `kjv` if not present. Only used in test. @return Is the kjv still valid. */ diff --git a/src/pair.c b/src/pair.c index 11c48a4..45165a8 100644 --- a/src/pair.c +++ b/src/pair.c @@ -17,7 +17,7 @@ struct pair pair(const char *const a, const char *const b) { return p; } -/** Doesn't check anything. +/** Doesn't check if the number is actually in [0, 9]. @return Whether it was able to parse unsigned `p` to `n`. */ int pair_to_natural(const char *s, const char *const e, uint32_t *const n) { uint32_t accum = 0; @@ -49,6 +49,7 @@ int pair_hours_to_minutes(const char *h0, const char *const h1, ? (*n = hours * 60 + minutes * 6, 1) : 0; } +/** @return The content of `x` is the same as `y`. */ int pair_is_equal(struct pair x, struct pair y) { assert(x.a <= x.b && y.a <= y.b); if(!x.a) return !y.a; @@ -58,6 +59,8 @@ int pair_is_equal(struct pair x, struct pair y) { return 1; } +/** @return Exact match between a pair `x` (start-end pointers) and a string + `y` (null-terminated). */ int pair_is_string(struct pair x, const char *y) { assert(x.a <= x.b); if(!x.a) return !y; @@ -66,7 +69,7 @@ int pair_is_string(struct pair x, const char *y) { return !*y; } -/** djb2 */ +/** @return A djb2 hash of `p`. */ uint32_t pair_djb2(struct pair p) { uint32_t hash = 5381, c; while(p.a < p.b) { diff --git a/src/scan_kjv.re.c b/src/scan_kjv.re.c index 9690364..d8b653d 100644 --- a/src/scan_kjv.re.c +++ b/src/scan_kjv.re.c @@ -13,16 +13,20 @@ #include #include +/* Callback is stupid; separate into tree with line and verse, and then more + processing. */ +typedef int (*scan_callback)(struct kjv *, union line64, union kjvcite, + uint32_t); + /*!conditions:re2c*/ static int scan(union date32 date, const char *const buffer, - struct kjv *const kj) { + const scan_callback callback, struct kjv *const kj) { const char *YYCURSOR, *YYMARKER, *yyt1, *yyt2, *yyt3, *s0, *s1, *t0, *t1; enum kjv_book book = Revelation; uint32_t chapter = 0, verse = 0, verse_end = 0; enum YYCONDTYPE condition = yycline; size_t line = 1; - char datestr[12] = {0}; const char *why = "unexpected"; assert(buffer && kj); YYCURSOR = YYMARKER = yyt1 = buffer; @@ -150,25 +154,13 @@ static int scan(union date32 date, const char *const buffer, continue; } engage => skip { - char citestr[12]; if(!chapter || !verse) { why = "missing information"; goto catch; } if(verse_end && verse_end <= verse) { why = "interval error"; goto catch; } union kjvcite cite = { .book = book, .chapter = chapter, .verse = verse }; - if(!datestr[0]) date32_to_string(date, &datestr); /* Only once. */ - kjvcite_to_string(cite, &citestr); - for( ; ; verse++, cite.verse++) { - if(!kjv_add(kj, cite)) { why = "add to set"; goto catch; } - if(!verse_end || verse_end <= verse) break; - } - printf("%s\t%zu\t%zu\t%zu\t# ", - datestr, kj->words.verse, kj->words.set, kj->words.cumulative); - if(verse_end) { - printf("%s-%" PRIu32 "\n", citestr, verse_end); - } else { - printf("%s\n", citestr); - } + if(!callback(kj, date, cite, verse_end)) + { why = "add to set"; goto catch; } book = Revelation, chapter = 0, verse = 0, verse_end = 0; continue; } @@ -176,32 +168,56 @@ static int scan(union date32 date, const char *const buffer, assert(0); /* Never gets here. */ catch: if(!errno) errno = EILSEQ; - date32_to_string(date, &datestr); - fprintf(stderr, "%s\n" - "%s line %zu: %s.\n", buffer, datestr, line, why); + { + char datestr[12]; + date32_to_string(date, &datestr); + fprintf(stderr, "%s\n" + "%s line %zu: %s.\n", buffer, datestr, line, why); + } return 0; } +static int add_to_set(struct kjv *const kj, const union line64 line, + union kjvcite cite, const uint32_t verse_end) { + char citestr[12], datestr[12]; + const struct source *src = source_lookup(&s, line); + assert(src); if(!src->name.a) { errno = EDOM; goto catch; } + kjvcite_to_string(cite, &citestr); + for( ; ; cite.verse++) { + if(!kjv_add(kj, cite)) return 0; + if(!verse_end || verse_end <= cite.verse) break; + } + date32_to_string(date, &datestr); + printf("%s\t%zu\t%zu\t%zu\t# ", + datestr, kj->words.verse, kj->words.set, kj->words.cumulative); + if(verse_end) { + printf("%s-%" PRIu32 "\n", citestr, verse_end); + } else { + printf("%s\n", citestr); + } + return 1; +} + int main(void) { int success = EXIT_SUCCESS; + const char *reason = "unknown"; errno = 0; struct journal j; struct journal_iterator it; - printf("1. kjv\n"); struct kjv bible = kjv(); - if(errno) { printf("kjv?\n"); goto catch; } + if(kjv_is_empty(&bible)) { reason = "kjv failed to load"; goto catch; } union date32 k; const char *v; - printf("2. journal\n"); j = journal(); - if(errno) goto catch; + if(journal_is_empty(&j)) { reason = "journal failed to load"; goto catch; } fprintf(stderr, "Journal: %s.\n", journal_to_string(&j)); printf("set term postscript eps enhanced\n" "set output \"kjv.eps\"\n" "$Data <