callback is to much steps; have verse tree
This commit is contained in:
parent
d137919d13
commit
4db31489c2
@ -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 **);
|
||||
|
@ -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 <sys/stat.h> /* umask (POSIX) */
|
||||
#include <dirent.h> /* 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 /* <fn:day_compare> custom comparison. */
|
||||
#define TREE_TO_STRING /* <fn:day_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)
|
||||
|
@ -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);
|
||||
|
@ -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. */
|
||||
|
@ -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 <http://www.cse.yorku.ca/~oz/hash.html> */
|
||||
/** @return A djb2 <http://www.cse.yorku.ca/~oz/hash.html> hash of `p`. */
|
||||
uint32_t pair_djb2(struct pair p) {
|
||||
uint32_t hash = 5381, c;
|
||||
while(p.a < p.b) {
|
||||
|
@ -13,16 +13,20 @@
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* 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;
|
||||
}
|
||||
<book> 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 <<EOD\n"
|
||||
"# date\tverse\tset\tcumulative / %zu\n", bible.words.total);
|
||||
it = journal_iterator(&j);
|
||||
while(journal_next(&it, &k, &v)) if(!scan(k, v, &bible)) goto catch;
|
||||
while(journal_next(&it, &k, &v))
|
||||
if(!scan(k, v, &add_to_set, &bible)) goto catch;
|
||||
printf("EOD\n"
|
||||
"set monochrome\n"
|
||||
"set xdata time\n"
|
||||
@ -220,6 +236,7 @@ int main(void) {
|
||||
catch:
|
||||
success = EXIT_FAILURE;
|
||||
perror("journal");
|
||||
fprintf(stderr, "Details: %s.\n", reason);
|
||||
finally:
|
||||
kjv_(&bible);
|
||||
journal_(&j);
|
||||
|
@ -10,7 +10,7 @@ int main(void) {
|
||||
errno = 0; /* `errno` is not set correctly to 0 in some debug situations. */
|
||||
struct kjv k = kjv();
|
||||
fprintf(stderr, "%zu total words, %s.\n", k.words.total, kjv_to_string(&k));
|
||||
if(!kjv_is_valid(&k)) goto catch;
|
||||
if(kjv_is_empty(&k)) goto catch;
|
||||
kjv_add(&k, (union kjvcite){ .book = Genesis, .chapter = 1, .verse = 1 });
|
||||
kjv_add(&k, (union kjvcite){ .book = Genesis, .chapter = 1, .verse = 2 });
|
||||
kjv_add(&k, (union kjvcite){ .book = Genesis, .chapter = 1, .verse = 1 });
|
||||
|
Loading…
Reference in New Issue
Block a user