2023-03-15 01:02:22 -04:00
|
|
|
/** @license 2022 Neil Edelman, distributed under the terms of the
|
|
|
|
[MIT License](https://opensource.org/licenses/MIT).
|
2022-12-27 02:31:08 -05:00
|
|
|
|
2023-03-15 01:02:22 -04:00
|
|
|
Scan journal entries for kjv references. */
|
|
|
|
|
2023-03-19 00:30:13 -04:00
|
|
|
#include "../src/source.h"
|
2023-03-15 01:02:22 -04:00
|
|
|
#include "../src/kjv.h"
|
2023-02-03 14:50:10 -05:00
|
|
|
#include "../src/pair.h"
|
2023-03-15 01:02:22 -04:00
|
|
|
#include <inttypes.h> /* C99 */
|
2022-12-27 15:28:04 -05:00
|
|
|
#include <stdlib.h>
|
2023-03-15 01:02:22 -04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
2022-12-27 15:28:04 -05:00
|
|
|
#include <assert.h>
|
2023-03-15 01:02:22 -04:00
|
|
|
#include <limits.h>
|
2022-12-27 15:28:04 -05:00
|
|
|
|
2023-03-15 01:02:22 -04:00
|
|
|
|
|
|
|
static void kjvline_to_string(const union line64 line, const struct kjvrange *u,
|
|
|
|
char (*const a)[12]) { (void)u; date32_to_string(line.date, a); }
|
|
|
|
static int kjvline_compare(const union line64 a, const union line64 b)
|
|
|
|
{ return a.u64 > b.u64; }
|
|
|
|
#define TREE_NAME kjvline
|
|
|
|
#define TREE_KEY union line64
|
|
|
|
#define TREE_VALUE struct kjvrange
|
|
|
|
#define TREE_COMPARE
|
|
|
|
#define TREE_TO_STRING
|
2023-03-19 00:30:13 -04:00
|
|
|
#define TREE_BODY
|
2023-03-15 01:02:22 -04:00
|
|
|
#include "../src/tree.h"
|
|
|
|
|
|
|
|
|
2022-12-13 00:25:28 -05:00
|
|
|
/*!conditions:re2c*/
|
2023-03-15 01:02:22 -04:00
|
|
|
|
|
|
|
static int scan(union date32 date, const char *const buffer,
|
|
|
|
struct kjvline_tree *const lines) {
|
|
|
|
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;
|
2022-12-13 03:31:56 -05:00
|
|
|
enum YYCONDTYPE condition = yycline;
|
2023-03-15 01:02:22 -04:00
|
|
|
size_t line = 1;
|
|
|
|
const char *why = "unexpected";
|
|
|
|
assert(buffer && lines);
|
|
|
|
YYCURSOR = YYMARKER = yyt1 = buffer;
|
2022-12-13 00:25:28 -05:00
|
|
|
/*!re2c /**/
|
2023-03-15 01:02:22 -04:00
|
|
|
re2c:define:YYCTYPE = char;
|
|
|
|
re2c:yyfill:enable = 0;
|
2022-12-13 03:31:56 -05:00
|
|
|
re2c:define:YYGETCONDITION = "condition";
|
|
|
|
re2c:define:YYSETCONDITION = "condition = @@;";
|
|
|
|
re2c:define:YYGETCONDITION:naked = 1;
|
2023-03-15 01:02:22 -04:00
|
|
|
re2c:define:YYSETCONDITION:naked = 1;
|
2022-12-13 17:37:50 -05:00
|
|
|
|
2023-03-15 01:02:22 -04:00
|
|
|
unix_control = [\x01-\x08\x0b-\x1f\x7f];
|
|
|
|
ws = [ \t];
|
|
|
|
glyph = [^] \ ("\x00" | "\n" | unix_control | ws);
|
|
|
|
natural = [1-9][0-9]*;
|
|
|
|
engage = ws+ "--" ws+;
|
|
|
|
/* (natural ":")? Don't use for memorizing and use for reading, I think? */
|
|
|
|
/*("``"|"\"") This is not in the next book. */
|
|
|
|
lookat = ws* natural ":" natural [ab]? ("-" natural [ab]?)? engage;
|
|
|
|
first = ("I" | "1") " "?;
|
|
|
|
second = ("II" | "2") " "?;
|
|
|
|
third = ("III" | "3") " "?;
|
|
|
|
*/
|
|
|
|
for( ; ; ) { /*!re2c /**/
|
|
|
|
/* Default ignore. */
|
|
|
|
<skip> [^\n\x00] { continue; }
|
|
|
|
<skip> "\x00" { why = "no newline at end of file"; goto catch; }
|
|
|
|
<line> "\x00" { return 1; }
|
|
|
|
<line, skip> "\n" => line { line++; continue; }
|
|
|
|
<line> * :=> skip
|
2022-12-14 00:05:29 -05:00
|
|
|
|
2023-03-15 01:02:22 -04:00
|
|
|
/* Books. */
|
|
|
|
<line> "Genesis" / lookat => book { book = Genesis; continue; }
|
|
|
|
<line> "Exodus" / lookat => book { book = Exodus; continue; }
|
|
|
|
<line> "Leviticus" / lookat => book { book = Leviticus; continue; }
|
|
|
|
<line> "Numbers" / lookat => book { book = Numbers; continue; }
|
|
|
|
<line> "Deuteronomy" / lookat => book { book = Deuteronomy; continue; }
|
|
|
|
<line> "Joshua" / lookat => book { book = Joshua; continue; }
|
|
|
|
<line> "Judges" / lookat => book { book = Judges; continue; }
|
|
|
|
<line> "Ruth" / lookat => book { book = Ruth; continue; }
|
|
|
|
<line> first "Samuel" / lookat => book { book = ISamuel; continue; }
|
|
|
|
<line> second "Samuel" / lookat => book { book = IISamuel; continue; }
|
|
|
|
<line> first "Kings" / lookat => book { book = IKings; continue; }
|
|
|
|
<line> second "Kings" / lookat => book { book = IIKings; continue; }
|
|
|
|
<line> first "Chronicles" / lookat
|
|
|
|
=> book { book = IChronicles; continue; }
|
|
|
|
<line> second "Chronicles" / lookat
|
|
|
|
=> book { book = IIChronicles; continue; }
|
|
|
|
<line> "Ezra" / lookat => book { book = Ezra; continue; }
|
|
|
|
<line> "Nehemiah" / lookat => book { book = Nehemiah; continue; }
|
|
|
|
<line> "Esther" / lookat => book { book = Esther; continue; }
|
|
|
|
<line> "Job" / lookat => book { book = Job; continue; }
|
|
|
|
<line> "Psalms" / lookat => book { book = Psalms; continue; }
|
|
|
|
<line> "Proverbs" / lookat => book { book = Proverbs; continue; }
|
|
|
|
<line> "Ecclesiastes" / lookat
|
|
|
|
=> book { book = Ecclesiastes; continue; }
|
|
|
|
<line> "Song of Solomon" / lookat
|
|
|
|
=> book { book = Song_of_Solomon; continue; }
|
|
|
|
<line> "Isaiah" / lookat => book { book = Isaiah; continue; }
|
|
|
|
<line> "Jeremiah" / lookat => book { book = Jeremiah; continue; }
|
|
|
|
<line> "Lamentations" / lookat
|
|
|
|
=> book { book = Lamentations; continue; }
|
|
|
|
<line> "Ezekiel" / lookat => book { book = Ezekiel; continue; }
|
|
|
|
<line> "Daniel" / lookat => book { book = Daniel; continue; }
|
|
|
|
<line> "Hosea" / lookat => book { book = Hosea; continue; }
|
|
|
|
<line> "Joel" / lookat => book { book = Joel; continue; }
|
|
|
|
<line> "Amos" / lookat => book { book = Amos; continue; }
|
|
|
|
<line> "Obadiah" / lookat => book { book = Obadiah; continue; }
|
|
|
|
<line> "Jonah" / lookat => book { book = Jonah; continue; }
|
|
|
|
<line> "Micah" / lookat => book { book = Micah; continue; }
|
|
|
|
<line> "Nahum" / lookat => book { book = Nahum; continue; }
|
|
|
|
<line> "Habakkuk" / lookat => book { book = Habakkuk; continue; }
|
|
|
|
<line> "Zephaniah" / lookat => book { book = Zephaniah; continue; }
|
|
|
|
<line> "Haggai" / lookat => book { book = Haggai; continue; }
|
|
|
|
<line> "Zechariah" / lookat => book { book = Zechariah; continue; }
|
|
|
|
<line> "Malachi" / lookat => book { book = Malachi; continue; }
|
|
|
|
<line> "Matthew" / lookat => book { book = Matthew; continue; }
|
|
|
|
<line> "Mark" / lookat => book { book = Mark; continue; }
|
|
|
|
<line> "Luke" / lookat => book { book = Luke; continue; }
|
|
|
|
<line> "John" / lookat => book { book = John; continue; }
|
|
|
|
<line> "Acts" / lookat => book { book = Acts; continue; }
|
|
|
|
<line> "Romans" / lookat => book { book = Romans; continue; }
|
|
|
|
<line> first "Corinthians" / lookat
|
|
|
|
=> book { book = ICorinthians; continue; }
|
|
|
|
<line> second "Corinthians" / lookat
|
|
|
|
=> book { book = IICorinthians; continue; }
|
|
|
|
<line> "Galatians" / lookat => book { book = Galatians; continue; }
|
|
|
|
<line> "Ephesians" / lookat => book { book = Ephesians; continue; }
|
|
|
|
<line> "Philippians" / lookat => book { book = Philippians; continue; }
|
|
|
|
<line> "Colossians" / lookat => book { book = Colossians; continue; }
|
|
|
|
<line> first "Thessalonians" / lookat
|
|
|
|
=> book { book = IThessalonians; continue; }
|
|
|
|
<line> second "Thessalonians" / lookat
|
|
|
|
=> book { book = IIThessalonians; continue; }
|
|
|
|
<line> first "Timothy" / lookat => book { book = ITimothy; continue; }
|
|
|
|
<line> second "Timothy" / lookat => book { book = IITimothy; continue; }
|
|
|
|
<line> "Titus" / lookat => book { book = Titus; continue; }
|
|
|
|
<line> "Philemon" / lookat => book { book = Philemon; continue; }
|
|
|
|
<line> "Hebrews" / lookat => book { book = Hebrews; continue; }
|
|
|
|
<line> "James" / lookat => book { book = James; continue; }
|
|
|
|
<line> first "Peter" / lookat => book { book = IPeter; continue; }
|
|
|
|
<line> second "Peter" / lookat => book { book = IIPeter; continue; }
|
|
|
|
<line> first "John" / lookat => book { book = IJohn; continue; }
|
|
|
|
<line> second "John" / lookat => book { book = IIJohn; continue; }
|
|
|
|
<line> third "John" / lookat => book { book = IIIJohn; continue; }
|
|
|
|
<line> "Jude" / lookat => book { book = Jude; continue; }
|
|
|
|
<line> "Revelation" / lookat => book { book = Revelation; continue; }
|
2022-12-27 02:31:08 -05:00
|
|
|
|
2023-03-15 01:02:22 -04:00
|
|
|
/* Extract further information. */
|
|
|
|
<book> * { why = "default unrecognized"; goto catch; }
|
|
|
|
/* 19:15a, just ignore the a. */
|
|
|
|
<book> ws+ @s0 natural @s1 ":" @t0 natural @t1 [ab]? {
|
|
|
|
if(chapter || verse || verse_end)
|
|
|
|
{ why = "reference unrecognized"; goto catch; }
|
|
|
|
if(!pair_to_natural(s0, s1, &chapter)
|
|
|
|
|| !pair_to_natural(t0, t1, &verse))
|
|
|
|
{ why = "reference numerical error"; goto catch; }
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
<book> "-" @s0 natural @s1 [ab]? { /* Verse range. */
|
|
|
|
if(!chapter || !verse || verse_end)
|
|
|
|
{ why = "range unrecognized"; goto catch; }
|
|
|
|
if(!pair_to_natural(s0, s1, &verse_end))
|
|
|
|
{ why = "range numerical error"; goto catch; }
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
<book> engage => skip {
|
|
|
|
if(!chapter || !verse) { why = "missing information"; goto catch; }
|
|
|
|
if(verse_end && verse_end <= verse)
|
|
|
|
{ why = "interval error"; goto catch; } /* 0 or valid. */
|
|
|
|
const union line64 key
|
|
|
|
= {{ (uint32_t)line, {{ date.day, date.month, date.year }} }};
|
|
|
|
struct kjvrange *value;
|
|
|
|
switch(kjvline_tree_try(lines, key, &value)) {
|
|
|
|
case TREE_PRESENT: why = "duplicate key";
|
|
|
|
case TREE_ERROR: goto catch;
|
|
|
|
case TREE_ABSENT:
|
|
|
|
value->start.book = book;
|
|
|
|
value->start.chapter = chapter;
|
|
|
|
value->start.verse = verse;
|
|
|
|
value->verse_end = verse_end;
|
|
|
|
break;
|
2022-12-14 00:05:29 -05:00
|
|
|
}
|
2023-03-15 01:02:22 -04:00
|
|
|
book = Revelation, chapter = 0, verse = 0, verse_end = 0;
|
|
|
|
continue;
|
2022-12-14 00:05:29 -05:00
|
|
|
}
|
2023-03-15 01:02:22 -04:00
|
|
|
*/ }
|
|
|
|
assert(0); /* Never gets here. */
|
|
|
|
catch:
|
|
|
|
if(!errno) errno = EILSEQ;
|
|
|
|
{
|
|
|
|
char datestr[12];
|
|
|
|
date32_to_string(date, &datestr);
|
2023-03-15 23:10:12 -04:00
|
|
|
fprintf(stderr, "KJV lines: %s.\n"
|
|
|
|
"%s line %zu: %s.\n",
|
|
|
|
kjvline_tree_to_string(lines), datestr, line, why);
|
2022-12-13 03:31:56 -05:00
|
|
|
}
|
2023-03-15 01:02:22 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void kjv_line_(struct kjvline_tree *const f) { kjvline_tree_(f); }
|
|
|
|
|
|
|
|
struct kjvline_tree kjv_line(struct journal *const j) {
|
|
|
|
struct kjvline_tree lines;
|
|
|
|
struct journal_iterator it;
|
|
|
|
union date32 date;
|
|
|
|
const char *text;
|
|
|
|
assert(j);
|
|
|
|
lines = kjvline_tree();
|
|
|
|
it = journal_iterator(j);
|
|
|
|
while(journal_next(&it, &date, &text))
|
|
|
|
if(!scan(date, text, &lines)) goto catch;
|
2022-12-13 03:31:56 -05:00
|
|
|
goto finally;
|
|
|
|
catch:
|
2023-03-15 01:02:22 -04:00
|
|
|
kjv_line_(&lines);
|
2022-12-13 03:31:56 -05:00
|
|
|
finally:
|
2023-03-15 01:02:22 -04:00
|
|
|
return lines;
|
2022-12-13 03:31:56 -05:00
|
|
|
}
|
2022-12-27 15:28:04 -05:00
|
|
|
|
2023-03-15 01:02:22 -04:00
|
|
|
int kjv_line_is_empty(const struct kjvline_tree *const lines)
|
|
|
|
{ return !lines || !lines->root.node; }
|
|
|
|
|
2023-03-15 23:10:12 -04:00
|
|
|
const char *kjv_line_to_string(const struct kjvline_tree *const lines)
|
|
|
|
{ return kjvline_tree_to_string(lines); }
|
2023-03-15 01:02:22 -04:00
|
|
|
|
2023-03-15 23:10:12 -04:00
|
|
|
struct kjvline_tree_iterator kjv_line_iterator(struct kjvline_tree *const lines)
|
|
|
|
{ return kjvline_tree_iterator(lines); }
|
2023-03-15 01:02:22 -04:00
|
|
|
|
|
|
|
int kjv_line_next(struct kjvline_tree_iterator *const it, union line64 *const k,
|
|
|
|
const struct kjvrange **const v) {
|
|
|
|
assert(it && k && v);
|
|
|
|
if(!kjvline_tree_next(it)) return 0;
|
|
|
|
*k = kjvline_tree_key(it);
|
|
|
|
*v = kjvline_tree_value(it);
|
2022-12-27 16:01:51 -05:00
|
|
|
return 1;
|
2022-12-27 15:28:04 -05:00
|
|
|
}
|
|
|
|
|
2022-12-27 16:01:51 -05:00
|
|
|
|
2023-03-15 01:02:22 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main(void) {
|
|
|
|
int success = EXIT_SUCCESS;
|
2023-03-15 23:10:12 -04:00
|
|
|
const char *reason = 0;
|
2023-03-15 01:02:22 -04:00
|
|
|
errno = 0;
|
2023-03-16 22:26:09 -04:00
|
|
|
struct kjvcount count = {0};
|
|
|
|
struct journal jrnl = {0};
|
|
|
|
struct sources srcs = {0};
|
|
|
|
struct kjvline_tree lines = {0};
|
2023-03-15 01:02:22 -04:00
|
|
|
|
2023-03-16 22:26:09 -04:00
|
|
|
count = kjvcount();
|
2023-03-15 23:10:12 -04:00
|
|
|
fprintf(stderr, "KJV count: %s.\n", kjvcount_to_string(&count));
|
|
|
|
if(kjvcount_is_empty(&count))
|
|
|
|
{ reason = "kjv failed to load"; goto catch; }
|
2023-03-15 01:02:22 -04:00
|
|
|
|
2023-03-16 22:26:09 -04:00
|
|
|
jrnl = journal();
|
2023-03-15 23:10:12 -04:00
|
|
|
fprintf(stderr, "Journal: %s.\n", journal_to_string(&jrnl));
|
|
|
|
if(journal_is_empty(&jrnl))
|
|
|
|
{ reason = "journal failed to load"; goto catch; }
|
2023-03-15 01:02:22 -04:00
|
|
|
|
2023-03-16 22:26:09 -04:00
|
|
|
srcs = sources(&jrnl);
|
2023-03-15 23:10:12 -04:00
|
|
|
//fprintf(stderr, "Sources: %s.\n", sources_to_string(&srcs));
|
|
|
|
if(sources_is_empty(&srcs))
|
|
|
|
{ reason = "sources failed to parse"; goto catch; }
|
2023-03-15 01:02:22 -04:00
|
|
|
|
2023-03-16 22:26:09 -04:00
|
|
|
lines = kjv_line(&jrnl);
|
2023-03-15 23:10:12 -04:00
|
|
|
fprintf(stderr, "KJV lines: %s.\n", kjv_line_to_string(&lines));
|
|
|
|
if(kjv_line_is_empty(&lines))
|
|
|
|
{ reason = "KJV lines parsing failed"; goto catch; }
|
|
|
|
|
|
|
|
struct kjvline_tree_iterator it = kjv_line_iterator(&lines);
|
|
|
|
union line64 line;
|
|
|
|
const struct kjvrange *range;
|
2023-03-15 01:02:22 -04:00
|
|
|
|
|
|
|
printf("set term postscript eps enhanced\n"
|
|
|
|
"set output \"kjv.eps\"\n"
|
|
|
|
"$Data <<EOD\n"
|
2023-03-16 23:08:36 -04:00
|
|
|
"# date, source, verse, words, set / %zu\n",
|
|
|
|
count.words.total);
|
2023-03-15 23:10:12 -04:00
|
|
|
while(kjv_line_next(&it, &line, &range)) {
|
|
|
|
char citestr[12], datestr[12];
|
2023-03-16 23:08:36 -04:00
|
|
|
const struct source *src = source_lookup(&srcs, line); /* Source. */
|
2023-03-15 23:10:12 -04:00
|
|
|
if(!src || !src->name.a) { errno = EDOM; goto catch; }
|
2023-03-16 23:08:36 -04:00
|
|
|
date32_to_string(line.date, &datestr); /* Date. */
|
|
|
|
kjvcite_to_string(range->start, &citestr); /* KJV cite. */
|
|
|
|
for(uint32_t c = range->start.verse; ; c++) {
|
|
|
|
//if(!kjv_add(kj, cite)) return 0;
|
|
|
|
if(!range->verse_end || range->verse_end <= c) break;
|
|
|
|
}
|
|
|
|
printf("%s, %.*s, %s", datestr,
|
|
|
|
(int)(src->name.b - src->name.a), src->name.a, citestr);
|
2023-03-16 22:26:09 -04:00
|
|
|
if(range->verse_end) printf("-%" PRIu32, range->verse_end);
|
2023-03-16 23:08:36 -04:00
|
|
|
printf(", \n");
|
2023-03-15 23:10:12 -04:00
|
|
|
#if 0
|
|
|
|
//fixme
|
|
|
|
for( ; ; cite.verse++) {
|
|
|
|
if(!kjv_add(kj, cite)) return 0;
|
|
|
|
if(!verse_end || verse_end <= cite.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);
|
|
|
|
}
|
|
|
|
printf("%d-%.2d-%.2d:%u-%u %s\n");
|
|
|
|
#endif
|
|
|
|
}
|
2023-03-15 01:02:22 -04:00
|
|
|
printf("EOD\n"
|
|
|
|
"set monochrome\n"
|
|
|
|
"set xdata time\n"
|
|
|
|
"set timefmt \"%%Y-%%m-%%d\"\n"
|
|
|
|
"set xtics format \"%%Y-%%m-%%d\" rotate by -30\n"
|
|
|
|
"set ylabel \"words in KJV\"\n"
|
|
|
|
"set format y \"%%g%%%%\"\n"
|
|
|
|
"set key top left\n"
|
|
|
|
"set grid\n"
|
|
|
|
"unset border\n"
|
|
|
|
"#set style fill solid 0.1 #pattern 5 (better, but restarts)\n"
|
|
|
|
"plot $Data using 1:($3)*100/%zu with fillsteps lw 2 title \"set\", \\\n"
|
|
|
|
"$Data using 1:($4)*100/%zu with steps lw 1 title \"cumulative\"\n",
|
|
|
|
count.words.total, count.words.total);
|
|
|
|
goto finally;
|
|
|
|
catch:
|
|
|
|
success = EXIT_FAILURE;
|
|
|
|
perror("journal");
|
2023-03-15 23:10:12 -04:00
|
|
|
if(reason) fprintf(stderr, "Details: %s.\n", reason);
|
2023-03-15 01:02:22 -04:00
|
|
|
finally:
|
|
|
|
kjv_line_(&lines);
|
|
|
|
kjvcount_(&count);
|
2023-03-15 23:10:12 -04:00
|
|
|
journal_(&jrnl);
|
2023-03-15 01:02:22 -04:00
|
|
|
return success;
|
|
|
|
}
|