diff --git a/src/driver.c b/src/driver.c index 11a1e26..a3454d1 100644 --- a/src/driver.c +++ b/src/driver.c @@ -49,6 +49,8 @@ int main(void) { catch: perror(intent); finally: + /* fixme: ~scan should be idempotent but it's not on disabling ASLR, which + debug mode is in. */ scan_(&scn); journal_(&jrnl); return intent ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/src/scan.h b/src/scan.h index fe21a19..8a553f2 100644 --- a/src/scan.h +++ b/src/scan.h @@ -14,6 +14,11 @@ struct kvpair { struct pair key, value; }; #define ARRAY_TYPE struct kvpair #define ARRAY_HEAD #include "../src/array.h" +#define TREE_NAME linekvpair +#define TREE_KEY union line64 +#define TREE_VALUE struct kvpair +#define TREE_HEAD +#include "../src/tree.h" /* Place array. */ struct place { struct pair name; double x, y; }; @@ -96,10 +101,6 @@ struct scan { struct pairmap_table map; struct linemap_tree dates; } sources, documents; - struct { - struct kvpair_array array; - struct linemap_tree dates; - } contacts; struct { struct place_array array; struct pairmap_table map; @@ -115,7 +116,7 @@ struct scan { struct pairmap_table map; struct linemap_tree dates; } edits; - //struct kvpair_tree contacts;? + struct linekvpair_tree contacts, books, tvs, movies, ideas; struct glider_tree gliders; struct flight_tree flights; struct kjv_tree kjvs; diff --git a/src/scan.re.c b/src/scan.re.c index e312033..3718401 100644 --- a/src/scan.re.c +++ b/src/scan.re.c @@ -41,6 +41,20 @@ static void kvpair_to_string(const struct kvpair *const s, #define ARRAY_TO_STRING #define ARRAY_BODY #include "../src/array.h" +static void linekvpair_to_string(const union line64 line, + const struct kvpair *const kv, + char (*const a)[12]) { (void)kv; date32_to_string(line.date, a); } +static int linekvpair_compare(const union line64 a, const union line64 b) + { return a.u64 > b.u64; } +#define TREE_NAME linekvpair +#define TREE_KEY union line64 +#define TREE_VALUE struct kvpair +#define TREE_COMPARE +#define TREE_TO_STRING +#define TREE_DEFAULT {{0,0},{0,0}} +#define TREE_BODY +#include "../src/tree.h" + /* Array of places. */ static void place_to_string(const struct place *const p, @@ -124,8 +138,9 @@ static int scan_day(struct scan *const scan, union date32 date, struct score *new_score = 0; struct glider *new_glider = 0; struct flight *new_flight = 0; - enum kjv_book book = Revelation; - uint32_t chapter = 0, verse = 0, verse_end = 0; + struct { + enum kjv_book book; uint32_t chapter, verse, verse_end; + } kjv = { Revelation, 0, 0, 0 }; assert(scan && date.u32 && buffer); YYCURSOR = YYMARKER = yyt1 = buffer; @@ -186,7 +201,12 @@ static int scan_day(struct scan *const scan, union date32 date, /* ^"[" ... */ * { fail = "bracket unrecognized"; goto catch; } "document: " :=> document - "rem: " :=> remark //change to "rem" + "rem: " :=> remark + "contact: " :=> contact + "book: " :=> book + "tv: " :=> tv + "movie: " :=> movie + "idea: " :=> idea * { fail = "document title"; goto catch; } @s0 bralabel @s1 "]" => future { @@ -228,6 +248,86 @@ static int scan_day(struct scan *const scan, union date32 date, continue; } + * { fail = "contact unrecognized"; goto catch; } + @s0 bralabel @s1 "]" => future { + const union line64 key = { { (uint32_t)line, date } }; + struct kvpair *pair; + switch(linekvpair_tree_bulk_assign(&scan->contacts, key, &pair)) { + case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch; + case TREE_ABSENT: break; + } + pair->key.a = s0, pair->key.b = s1; + pair->value.a = pair->value.b = 0; + assert(!future), future = &pair->value; + fprintf(stderr, "%s[%zu]: new contact <<%.*s>>.\n", + datestr, line, (int)(s1 - s0), s0); + continue; + } + + * { fail = "book unrecognized"; goto catch; } + @s0 bralabel @s1 "]" => future { + const union line64 key = { { (uint32_t)line, date } }; + struct kvpair *pair; + switch(linekvpair_tree_bulk_assign(&scan->books, key, &pair)) { + case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch; + case TREE_ABSENT: break; + } + pair->key.a = s0, pair->key.b = s1; + pair->value.a = pair->value.b = 0; + assert(!future), future = &pair->value; + fprintf(stderr, "%s[%zu]: new book <<%.*s>>.\n", + datestr, line, (int)(s1 - s0), s0); + continue; + } + + * { fail = "tv unrecognized"; goto catch; } + @s0 bralabel @s1 "]" => future { + const union line64 key = { { (uint32_t)line, date } }; + struct kvpair *pair; + switch(linekvpair_tree_bulk_assign(&scan->tvs, key, &pair)) { + case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch; + case TREE_ABSENT: break; + } + pair->key.a = s0, pair->key.b = s1; + pair->value.a = pair->value.b = 0; + assert(!future), future = &pair->value; + fprintf(stderr, "%s[%zu]: new tv <<%.*s>>.\n", + datestr, line, (int)(s1 - s0), s0); + continue; + } + + * { fail = "movie unrecognized"; goto catch; } + @s0 bralabel @s1 "]" => future { + const union line64 key = { { (uint32_t)line, date } }; + struct kvpair *pair; + switch(linekvpair_tree_bulk_assign(&scan->contacts, key, &pair)) { + case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch; + case TREE_ABSENT: break; + } + pair->key.a = s0, pair->key.b = s1; + pair->value.a = pair->value.b = 0; + assert(!future), future = &pair->value; + fprintf(stderr, "%s[%zu]: new movie <<%.*s>>.\n", + datestr, line, (int)(s1 - s0), s0); + continue; + } + + * { fail = "idea unrecognized"; goto catch; } + @s0 bralabel @s1 "]" => future { + const union line64 key = { { (uint32_t)line, date } }; + struct kvpair *pair; + switch(linekvpair_tree_bulk_assign(&scan->contacts, key, &pair)) { + case TREE_PRESENT: fail = "duplicate"; case TREE_ERROR: goto catch; + case TREE_ABSENT: break; + } + pair->key.a = s0, pair->key.b = s1; + pair->value.a = pair->value.b = 0; + assert(!future), future = &pair->value; + fprintf(stderr, "%s[%zu]: new idea <<%.*s>>.\n", + datestr, line, (int)(s1 - s0), s0); + continue; + } + * { fail = "place unrecognized"; goto catch; } @s0 parlabel @s1 / "\n" => skip { also_place: { const struct pair keyword = pair(s0, s1); @@ -523,107 +623,95 @@ static int scan_day(struct scan *const scan, union date32 date, /* Books in KJV. */ - "Genesis" / kjvlookat => book { book = Genesis; continue; } - "Exodus" / kjvlookat => book { book = Exodus; continue; } - "Leviticus" / kjvlookat => book { book = Leviticus; continue; } - "Numbers" / kjvlookat => book { book = Numbers; continue; } - "Deuteronomy" / kjvlookat => book - { book = Deuteronomy; continue; } - "Joshua" / kjvlookat => book { book = Joshua; continue; } - "Judges" / kjvlookat => book { book = Judges; continue; } - "Ruth" / kjvlookat => book { book = Ruth; continue; } - first "Samuel" / kjvlookat => book { book = ISamuel; continue; } - second "Samuel" / kjvlookat => book - { book = IISamuel; continue; } - first "Kings" / kjvlookat => book { book = IKings; continue; } - second "Kings" / kjvlookat => book { book = IIKings; continue; } - first "Chronicles" / kjvlookat - => book { book = IChronicles; continue; } - second "Chronicles" / kjvlookat - => book { book = IIChronicles; continue; } - "Ezra" / kjvlookat => book { book = Ezra; continue; } - "Nehemiah" / kjvlookat => book { book = Nehemiah; continue; } - "Esther" / kjvlookat => book { book = Esther; continue; } - "Job" / kjvlookat => book { book = Job; continue; } - "Psalms" / kjvlookat => book { book = Psalms; continue; } - "Proverbs" / kjvlookat => book { book = Proverbs; continue; } - "Ecclesiastes" / kjvlookat - => book { book = Ecclesiastes; continue; } - "Song of Solomon" / kjvlookat - => book { book = Song_of_Solomon; continue; } - "Isaiah" / kjvlookat => book { book = Isaiah; continue; } - "Jeremiah" / kjvlookat => book { book = Jeremiah; continue; } - "Lamentations" / kjvlookat - => book { book = Lamentations; continue; } - "Ezekiel" / kjvlookat => book { book = Ezekiel; continue; } - "Daniel" / kjvlookat => book { book = Daniel; continue; } - "Hosea" / kjvlookat => book { book = Hosea; continue; } - "Joel" / kjvlookat => book { book = Joel; continue; } - "Amos" / kjvlookat => book { book = Amos; continue; } - "Obadiah" / kjvlookat => book { book = Obadiah; continue; } - "Jonah" / kjvlookat => book { book = Jonah; continue; } - "Micah" / kjvlookat => book { book = Micah; continue; } - "Nahum" / kjvlookat => book { book = Nahum; continue; } - "Habakkuk" / kjvlookat => book { book = Habakkuk; continue; } - "Zephaniah" / kjvlookat => book { book = Zephaniah; continue; } - "Haggai" / kjvlookat => book { book = Haggai; continue; } - "Zechariah" / kjvlookat => book { book = Zechariah; continue; } - "Malachi" / kjvlookat => book { book = Malachi; continue; } - "Matthew" / kjvlookat => book { book = Matthew; continue; } - "Mark" / kjvlookat => book { book = Mark; continue; } - "Luke" / kjvlookat => book { book = Luke; continue; } - "John" / kjvlookat => book { book = John; continue; } - "Acts" / kjvlookat => book { book = Acts; continue; } - "Romans" / kjvlookat => book { book = Romans; continue; } - first "Corinthians" / kjvlookat - => book { book = ICorinthians; continue; } - second "Corinthians" / kjvlookat - => book { book = IICorinthians; continue; } - "Galatians" / kjvlookat => book { book = Galatians; continue; } - "Ephesians" / kjvlookat => book { book = Ephesians; continue; } - "Philippians" / kjvlookat => book - { book = Philippians; continue; } - "Colossians" / kjvlookat => book { book = Colossians; continue; } - first "Thessalonians" / kjvlookat - => book { book = IThessalonians; continue; } - second "Thessalonians" / kjvlookat - => book { book = IIThessalonians; continue; } - first "Timothy" / kjvlookat => book - { book = ITimothy; continue; } - second "Timothy" / kjvlookat => book - { book = IITimothy; continue; } - "Titus" / kjvlookat => book { book = Titus; continue; } - "Philemon" / kjvlookat => book { book = Philemon; continue; } - "Hebrews" / kjvlookat => book { book = Hebrews; continue; } - "James" / kjvlookat => book { book = James; continue; } - first "Peter" / kjvlookat => book { book = IPeter; continue; } - second "Peter" / kjvlookat => book { book = IIPeter; continue; } - first "John" / kjvlookat => book { book = IJohn; continue; } - second "John" / kjvlookat => book { book = IIJohn; continue; } - third "John" / kjvlookat => book { book = IIIJohn; continue; } - "Jude" / kjvlookat => book { book = Jude; continue; } - "Revelation" / kjvlookat => book { book = Revelation; continue; } - * { fail = "kjv unrecognized"; goto catch; } + "Genesis" / kjvlookat => kjvbook { kjv.book = Genesis; continue; } + "Exodus" / kjvlookat => kjvbook { kjv.book = Exodus; continue; } + "Leviticus" / kjvlookat => kjvbook { kjv.book = Leviticus; continue; } + "Numbers" / kjvlookat => kjvbook { kjv.book = Numbers; continue; } + "Deuteronomy" / kjvlookat => kjvbook { kjv.book = Deuteronomy; continue; } + "Joshua" / kjvlookat => kjvbook { kjv.book = Joshua; continue; } + "Judges" / kjvlookat => kjvbook { kjv.book = Judges; continue; } + "Ruth" / kjvlookat => kjvbook { kjv.book = Ruth; continue; } + first "Samuel" / kjvlookat => kjvbook { kjv.book = ISamuel; continue; } + second "Samuel" / kjvlookat => kjvbook { kjv.book = IISamuel; continue; } + first "Kings" / kjvlookat => kjvbook { kjv.book = IKings; continue; } + second "Kings" / kjvlookat => kjvbook { kjv.book = IIKings; continue; } + first "Chronicles" / kjvlookat => kjvbook { kjv.book = IChronicles; continue; } + second "Chronicles" / kjvlookat => kjvbook { kjv.book = IIChronicles; continue; } + "Ezra" / kjvlookat => kjvbook { kjv.book = Ezra; continue; } + "Nehemiah" / kjvlookat => kjvbook { kjv.book = Nehemiah; continue; } + "Esther" / kjvlookat => kjvbook { kjv.book = Esther; continue; } + "Job" / kjvlookat => kjvbook { kjv.book = Job; continue; } + "Psalms" / kjvlookat => kjvbook { kjv.book = Psalms; continue; } + "Proverbs" / kjvlookat => kjvbook { kjv.book = Proverbs; continue; } + "Ecclesiastes" / kjvlookat => kjvbook + { kjv.book = Ecclesiastes; continue; } + "Song of Solomon" / kjvlookat => kjvbook + { kjv.book = Song_of_Solomon; continue; } + "Isaiah" / kjvlookat => kjvbook { kjv.book = Isaiah; continue; } + "Jeremiah" / kjvlookat => kjvbook { kjv.book = Jeremiah; continue; } + "Lamentations" / kjvlookat => kjvbook { kjv.book = Lamentations; continue; } + "Ezekiel" / kjvlookat => kjvbook { kjv.book = Ezekiel; continue; } + "Daniel" / kjvlookat => kjvbook { kjv.book = Daniel; continue; } + "Hosea" / kjvlookat => kjvbook { kjv.book = Hosea; continue; } + "Joel" / kjvlookat => kjvbook { kjv.book = Joel; continue; } + "Amos" / kjvlookat => kjvbook { kjv.book = Amos; continue; } + "Obadiah" / kjvlookat => kjvbook { kjv.book = Obadiah; continue; } + "Jonah" / kjvlookat => kjvbook { kjv.book = Jonah; continue; } + "Micah" / kjvlookat => kjvbook { kjv.book = Micah; continue; } + "Nahum" / kjvlookat => kjvbook { kjv.book = Nahum; continue; } + "Habakkuk" / kjvlookat => kjvbook { kjv.book = Habakkuk; continue; } + "Zephaniah" / kjvlookat => kjvbook { kjv.book = Zephaniah; continue; } + "Haggai" / kjvlookat => kjvbook { kjv.book = Haggai; continue; } + "Zechariah" / kjvlookat => kjvbook { kjv.book = Zechariah; continue; } + "Malachi" / kjvlookat => kjvbook { kjv.book = Malachi; continue; } + "Matthew" / kjvlookat => kjvbook { kjv.book = Matthew; continue; } + "Mark" / kjvlookat => kjvbook { kjv.book = Mark; continue; } + "Luke" / kjvlookat => kjvbook { kjv.book = Luke; continue; } + "John" / kjvlookat => kjvbook { kjv.book = John; continue; } + "Acts" / kjvlookat => kjvbook { kjv.book = Acts; continue; } + "Romans" / kjvlookat => kjvbook { kjv.book = Romans; continue; } + first "Corinthians" / kjvlookat => kjvbook { kjv.book = ICorinthians; continue; } + second "Corinthians" / kjvlookat => kjvbook { kjv.book = IICorinthians; continue; } + "Galatians" / kjvlookat => kjvbook { kjv.book = Galatians; continue; } + "Ephesians" / kjvlookat => kjvbook { kjv.book = Ephesians; continue; } + "Philippians" / kjvlookat => kjvbook { kjv.book = Philippians; continue; } + "Colossians" / kjvlookat => kjvbook { kjv.book = Colossians; continue; } + first "Thessalonians" / kjvlookat => kjvbook { kjv.book = IThessalonians; continue; } + second "Thessalonians" / kjvlookat => kjvbook { kjv.book = IIThessalonians; continue; } + first "Timothy" / kjvlookat => kjvbook { kjv.book = ITimothy; continue; } + second "Timothy" / kjvlookat => kjvbook { kjv.book = IITimothy; continue; } + "Titus" / kjvlookat => kjvbook { kjv.book = Titus; continue; } + "Philemon" / kjvlookat => kjvbook { kjv.book = Philemon; continue; } + "Hebrews" / kjvlookat => kjvbook { kjv.book = Hebrews; continue; } + "James" / kjvlookat => kjvbook { kjv.book = James; continue; } + first "Peter" / kjvlookat => kjvbook { kjv.book = IPeter; continue; } + second "Peter" / kjvlookat => kjvbook { kjv.book = IIPeter; continue; } + first "John" / kjvlookat => kjvbook { kjv.book = IJohn; continue; } + second "John" / kjvlookat => kjvbook { kjv.book = IIJohn; continue; } + third "John" / kjvlookat => kjvbook { kjv.book = IIIJohn; continue; } + "Jude" / kjvlookat => kjvbook { kjv.book = Jude; continue; } + "Revelation" / kjvlookat => kjvbook { kjv.book = Revelation; continue; } + * { fail = "kjv unrecognized"; goto catch; } /* 19:15a, just ignore the a. */ - " " @s0 natural @s1 ":" @t0 natural @t1 [ab]? { - if(chapter || verse || verse_end) + " " @s0 natural @s1 ":" @t0 natural @t1 [ab]? { + if(kjv.chapter || kjv.verse || kjv.verse_end) { fail = "kjv reference"; goto catch; } - if(!pair_to_natural(s0, s1, &chapter) - || !pair_to_natural(t0, t1, &verse)) + if(!pair_to_natural(s0, s1, &kjv.chapter) + || !pair_to_natural(t0, t1, &kjv.verse)) { fail = "kjv reference numerical error"; goto catch; } continue; } - "-" @s0 natural @s1 [ab]? { /* Verse range. */ - if(!chapter || !verse || verse_end) + "-" @s0 natural @s1 [ab]? { /* Verse range. */ + if(!kjv.chapter || !kjv.verse || kjv.verse_end) { fail = "kjv range unrecognized"; goto catch; } - if(!pair_to_natural(s0, s1, &verse_end)) + if(!pair_to_natural(s0, s1, &kjv.verse_end)) { fail = "kjv range numerical error"; goto catch; } continue; } - " -- " => skip { - if(!chapter || !verse) + " -- " => skip { + if(!kjv.chapter || !kjv.verse) { fail = "kjv missing information"; goto catch; } - if(verse_end && verse_end <= verse) + if(kjv.verse_end && kjv.verse_end <= kjv.verse) { fail = "kjv interval error"; goto catch; } const union line64 key = {{ (uint32_t)line, date }}; struct kjvrange *value; @@ -631,17 +719,18 @@ static int scan_day(struct scan *const scan, union date32 date, case TREE_PRESENT: fail = "kjv 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; + value->start.book = kjv.book; + value->start.chapter = kjv.chapter; + value->start.verse = kjv.verse; + value->verse_end = kjv.verse_end; break; } - fprintf(stderr, "%s[%zu]: KJV %s %" PRIu32 ":%" PRIu32, - datestr, line, kjv_book_string[book], chapter, verse); - if(verse_end) fprintf(stderr, "-%u", verse_end); + fprintf(stderr, "%s[%zu]: KJV %s %" PRIu32 ":%" PRIu32, datestr, + line, kjv_book_string[kjv.book], kjv.chapter, kjv.verse); + if(kjv.verse_end) fprintf(stderr, "-%u", kjv.verse_end); fprintf(stderr, "\n"); - book = Revelation, chapter = 0, verse = 0, verse_end = 0; + kjv.book = Revelation, kjv.chapter = 0, kjv.verse = 0, + kjv.verse_end = 0; continue; } @@ -688,16 +777,26 @@ static int scan_day(struct scan *const scan, union date32 date, catch: if(!errno) errno = EILSEQ; date32_to_string(date, &datestr); - fprintf(stderr, "%s line %zu: %s" /*" condition %d"*/ ".\n", + fprintf(stderr, "%s line %zu fail: %s" /*" condition %d"*/ ".\n", datestr, line, fail/*, condition*/); return 0; } void scan_(struct scan *const scan) { + fprintf(stderr, "fixme: ~scan should be idempotent <<\n"); // now it is? if(!scan) return; + // printing it made it so? + fprintf(stderr, "~scan kjv %s\n", kjv_tree_to_string(&scan->kjvs)); kjv_tree_(&scan->kjvs); + fprintf(stderr, "~scan finished kjv\n"); flight_tree_(&scan->flights); glider_tree_(&scan->gliders); + linekvpair_tree_(&scan->ideas); + linekvpair_tree_(&scan->movies); + linekvpair_tree_(&scan->tvs); + linekvpair_tree_(&scan->books); + linekvpair_tree_(&scan->contacts); + fprintf(stderr, "~scan finished linekvpair\n"); linemap_tree_(&scan->scores.dates); pair_map_table_(&scan->scores.map); @@ -718,6 +817,7 @@ void scan_(struct scan *const scan) { linemap_tree_(&scan->sources.dates); pair_map_table_(&scan->sources.map); kvpair_array_(&scan->sources.array); + fprintf(stderr, "~scan finish >>\n"); } /** @param[jrnl] Must be constant throughout the use of the returned value. */ @@ -759,14 +859,22 @@ struct scan scan(struct journal *const jrnl) { /* Scans make trees bulk-loaded; fix to real tree. */ if(!linemap_tree_bulk_finish(&scan.sources.dates) + || !linemap_tree_bulk_finish(&scan.documents.dates) || !linemap_tree_bulk_finish(&scan.places.dates) || !linemap_tree_bulk_finish(&scan.scores.dates) + || !linemap_tree_bulk_finish(&scan.edits.dates) + || !linekvpair_tree_bulk_finish(&scan.contacts) + || !linekvpair_tree_bulk_finish(&scan.books) + || !linekvpair_tree_bulk_finish(&scan.tvs) + || !linekvpair_tree_bulk_finish(&scan.movies) + || !linekvpair_tree_bulk_finish(&scan.ideas) || !glider_tree_bulk_finish(&scan.gliders) || !flight_tree_bulk_finish(&scan.flights) || !kjv_tree_bulk_finish(&scan.kjvs)) goto catch; goto finally; catch: + fprintf(stderr, "Scan failed.\n"); scan_(&scan); finally: return scan; diff --git a/src/tree.h b/src/tree.h index 13d8254..6d4c30c 100644 --- a/src/tree.h +++ b/src/tree.h @@ -33,8 +33,8 @@ tree, . The above illustration is 5. @param[TREE_DEFAULT] - Default trait; a name that satisfies `C` naming conventions when mangled and a - value> used in treeget>. + Default trait which must be set to a value>, used in + treeget>. @param[TREE_TO_STRING] To string trait `` contained in . Require @@ -42,7 +42,8 @@ @param[TREE_EXPECT_TRAIT, TREE_TRAIT] Named traits are obtained by including `tree.h` multiple times with - `TREE_EXPECT_TRAIT` and then subsequently including the name in `TREE_TRAIT`. + `TREE_EXPECT_TRAIT` and then subsequently including the name that satisfies + `C` naming conventions when mangled in `TREE_TRAIT`. @param[TREE_HEAD, TREE_BODY] These go together to allow exporting non-static data between compilation units @@ -514,7 +515,8 @@ static void B_(tree_)(struct B_(tree) *const tree) { } /** Clears `tree`, which can be null, idle, empty, or full. If it is empty or - full, it remains active. @order \O(|`tree`|) @allow */ + full, it remains active, (all except one node are freed.) + @order \O(|`tree`|) @allow */ static void B_(tree_clear)(struct B_(tree) *const tree) { PB_(clear)(tree); } /** Private: counts a sub-tree, `tree`. */ @@ -582,12 +584,12 @@ static PB_(key) B_(tree_more_or)(const struct B_(tree) *const tree, } #ifdef TREE_VALUE /*