Working on refactoring kjv.
This commit is contained in:
parent
ac983acf22
commit
7c8f0a63e9
6
Makefile
6
Makefile
@ -39,8 +39,8 @@ default: $(projects)
|
|||||||
bin/test-text: build/text.o build/test_text.o
|
bin/test-text: build/text.o build/test_text.o
|
||||||
bin/test-journal: build/text.o build/journal.o build/test_journal.o
|
bin/test-journal: build/text.o build/journal.o build/test_journal.o
|
||||||
bin/test-source: build/text.o build/pair.o build/journal.o build/source.o build/test_source.o
|
bin/test-source: build/text.o build/pair.o build/journal.o build/source.o build/test_source.o
|
||||||
bin/test-kjv: build/text.o build/pair.o build/kjvcount.o build/test_kjv.o
|
bin/test-kjv: build/text.o build/pair.o build/kjvcite.o build/test_kjv.o
|
||||||
bin/kjv: build/text.o build/pair.o build/journal.o build/kjvcount.o build/kjv.o build/source.o
|
bin/kjv: build/text.o build/pair.o build/journal.o build/kjvcite.o build/kjv.o build/source.o
|
||||||
bin/flight: build/text.o build/pair.o build/journal.o build/source.o build/flights.o build/flighthours.o
|
bin/flight: build/text.o build/pair.o build/journal.o build/source.o build/flights.o build/flighthours.o
|
||||||
|
|
||||||
bin/%:
|
bin/%:
|
||||||
@ -71,7 +71,7 @@ build/%.c: src/%.re.c
|
|||||||
# # https://github.com/neil-edelman/cdoc documentation
|
# # https://github.com/neil-edelman/cdoc documentation
|
||||||
# -cdoc -o $@ $<
|
# -cdoc -o $@ $<
|
||||||
|
|
||||||
.SECONDARY: build/kjv.c build/journal.c build/source.c build/scan_kjv.c build/flights.c build/kjvcount.c
|
.SECONDARY: build/kjv.c build/journal.c build/source.c build/scan_kjv.c build/flights.c build/kjvcite.c
|
||||||
.PHONY: clean release test
|
.PHONY: clean release test
|
||||||
|
|
||||||
test: $(projects)
|
test: $(projects)
|
||||||
|
10
src/array.h
10
src/array.h
@ -33,10 +33,8 @@
|
|||||||
|
|
||||||
@param[ARRAY_HEAD, ARRAY_BODY]
|
@param[ARRAY_HEAD, ARRAY_BODY]
|
||||||
These go together to allow exporting non-static data between compilation units
|
These go together to allow exporting non-static data between compilation units
|
||||||
by separating the `ARRAY_HEAD`, which is intended to go in the header, with
|
by separating the header head from the code body. `ARRAY_HEAD` needs identical
|
||||||
`ARRAY_NAME` and `ARRAY_TYPE`, and `ARRAY_BODY` functions. [All static
|
`ARRAY_NAME` and `ARRAY_TYPE`.
|
||||||
functions will have `s_` prepended for ease of creating a public thunk
|
|
||||||
functions, which most likely will conflict with static functions.]
|
|
||||||
|
|
||||||
@std C89 */
|
@std C89 */
|
||||||
|
|
||||||
@ -53,8 +51,8 @@
|
|||||||
|| defined(ARRAY_TRAIT) && !defined(ARRAY_HAS_TO_STRING))
|
|| defined(ARRAY_TRAIT) && !defined(ARRAY_HAS_TO_STRING))
|
||||||
#error Test requires to string.
|
#error Test requires to string.
|
||||||
#endif
|
#endif
|
||||||
#if defined ARRAY_HEAD && defined ARRAY_BODY
|
#if defined ARRAY_HEAD && (defined ARRAY_BODY || defined ARRAY_TRAIT)
|
||||||
#error Can not be ARRAY_HEAD and ARRAY_BODY.
|
#error Can not be simultaneously defined.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef ARRAY_H /* <!-- idempotent */
|
#ifndef ARRAY_H /* <!-- idempotent */
|
||||||
|
52
src/kjv.h
52
src/kjv.h
@ -1,4 +1,4 @@
|
|||||||
#include "kjvcount.h"
|
#include "kjvcite.h"
|
||||||
|
|
||||||
#define TREE_NAME kjvline
|
#define TREE_NAME kjvline
|
||||||
#define TREE_KEY union line64
|
#define TREE_KEY union line64
|
||||||
@ -6,20 +6,8 @@
|
|||||||
#define TREE_HEAD
|
#define TREE_HEAD
|
||||||
#include "../src/tree.h"
|
#include "../src/tree.h"
|
||||||
|
|
||||||
|
/* fixme?? */
|
||||||
|
|
||||||
#if defined PROTO \
|
|
||||||
|| !defined BASE && !defined PRIVATE && !defined PROTO /* <!-- proto */
|
|
||||||
#ifdef BASE
|
|
||||||
#error BASE!!!
|
|
||||||
#endif
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
struct kjv {
|
|
||||||
struct kjvline_tree line;
|
|
||||||
struct kjvset_table set;
|
|
||||||
struct count_table count;
|
|
||||||
struct { size_t total, cumulative, set, verse; } words;
|
|
||||||
};
|
|
||||||
void kjv_line_(struct kjvline_tree *);
|
void kjv_line_(struct kjvline_tree *);
|
||||||
struct kjvline_tree kjv_line(struct journal *);
|
struct kjvline_tree kjv_line(struct journal *);
|
||||||
int kjv_line_is_empty(const struct kjvline_tree *);
|
int kjv_line_is_empty(const struct kjvline_tree *);
|
||||||
@ -27,39 +15,3 @@ const char *kjv_line_to_string(const struct kjvline_tree *);
|
|||||||
struct kjvline_tree_iterator kjv_line_iterator(struct kjvline_tree *);
|
struct kjvline_tree_iterator kjv_line_iterator(struct kjvline_tree *);
|
||||||
int kjv_line_next(struct kjvline_tree_iterator *, union line64 *,
|
int kjv_line_next(struct kjvline_tree_iterator *, union line64 *,
|
||||||
const struct kjvrange **);
|
const struct kjvrange **);
|
||||||
|
|
||||||
#if 0
|
|
||||||
const char *kjvline_to_string(const struct kjvline *);
|
|
||||||
struct kjvline_iterator kjvline_iterator(struct kjvline *);
|
|
||||||
int kjvline_next(struct kjvline_iterator *, union line64 *,
|
|
||||||
const struct kjvline **);
|
|
||||||
|
|
||||||
struct flights_iterator { struct flight_tree_iterator _; };
|
|
||||||
struct flights flights(/*const*/ struct journal *);
|
|
||||||
void flights_(struct flights *);
|
|
||||||
const char *flights_to_string(const struct flights *);
|
|
||||||
struct flights_iterator flights_iterator(struct flights *);
|
|
||||||
int flights_next(struct flights_iterator *, union line64 *,
|
|
||||||
const struct flight **);
|
|
||||||
|
|
||||||
|
|
||||||
struct kjv kjv(void);
|
|
||||||
void kjv_(struct 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);
|
|
||||||
const char *kjv_set_to_string(const struct kjv *const kjv);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* proto --> */
|
|
||||||
|
|
||||||
#ifdef BASE
|
|
||||||
#undef BASE
|
|
||||||
#endif
|
|
||||||
#ifdef PRIVATE
|
|
||||||
#undef PRIVATE
|
|
||||||
#endif
|
|
||||||
#ifdef PROTO
|
|
||||||
#undef PROTO
|
|
||||||
#endif
|
|
||||||
|
22
src/kjv.re.c
22
src/kjv.re.c
@ -233,24 +233,19 @@ int kjv_line_next(struct kjvline_tree_iterator *const it, union line64 *const k,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
int success = EXIT_SUCCESS;
|
int success = EXIT_SUCCESS;
|
||||||
const char *reason = 0;
|
const char *reason = 0;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
struct kjvcount count = {0};
|
struct kjvcount_table count = {0};
|
||||||
struct journal jrnl = {0};
|
struct journal jrnl = {0};
|
||||||
struct sources srcs = {0};
|
struct sources srcs = {0};
|
||||||
struct kjvline_tree lines = {0};
|
struct kjvline_tree lines = {0};
|
||||||
|
size_t no_total;
|
||||||
|
|
||||||
count = kjvcount();
|
count = kjv_count(&no_total);
|
||||||
fprintf(stderr, "KJV count: %s.\n", kjvcount_to_string(&count));
|
fprintf(stderr, "KJV count: %s.\n", kjv_count_to_string(&count));
|
||||||
if(kjvcount_is_empty(&count))
|
if(!no_total) { reason = "kjv failed to load"; goto catch; }
|
||||||
{ reason = "kjv failed to load"; goto catch; }
|
|
||||||
|
|
||||||
jrnl = journal();
|
jrnl = journal();
|
||||||
fprintf(stderr, "Journal: %s.\n", journal_to_string(&jrnl));
|
fprintf(stderr, "Journal: %s.\n", journal_to_string(&jrnl));
|
||||||
@ -274,8 +269,7 @@ int main(void) {
|
|||||||
printf("set term postscript eps enhanced\n"
|
printf("set term postscript eps enhanced\n"
|
||||||
"set output \"kjv.eps\"\n"
|
"set output \"kjv.eps\"\n"
|
||||||
"$Data <<EOD\n"
|
"$Data <<EOD\n"
|
||||||
"# date, source, verse, words, set / %zu\n",
|
"# date, source, verse, words, set / %zu\n", no_total);
|
||||||
count.words.total);
|
|
||||||
while(kjv_line_next(&it, &line, &range)) {
|
while(kjv_line_next(&it, &line, &range)) {
|
||||||
char citestr[12], datestr[12];
|
char citestr[12], datestr[12];
|
||||||
const struct source *src = source_lookup(&srcs, line); /* Source. */
|
const struct source *src = source_lookup(&srcs, line); /* Source. */
|
||||||
@ -319,7 +313,7 @@ int main(void) {
|
|||||||
"#set style fill solid 0.1 #pattern 5 (better, but restarts)\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"
|
"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",
|
"$Data using 1:($4)*100/%zu with steps lw 1 title \"cumulative\"\n",
|
||||||
count.words.total, count.words.total);
|
no_total, no_total);
|
||||||
goto finally;
|
goto finally;
|
||||||
catch:
|
catch:
|
||||||
success = EXIT_FAILURE;
|
success = EXIT_FAILURE;
|
||||||
@ -327,7 +321,7 @@ catch:
|
|||||||
if(reason) fprintf(stderr, "Details: %s.\n", reason);
|
if(reason) fprintf(stderr, "Details: %s.\n", reason);
|
||||||
finally:
|
finally:
|
||||||
kjv_line_(&lines);
|
kjv_line_(&lines);
|
||||||
kjvcount_(&count);
|
kjv_count_(&count);
|
||||||
journal_(&jrnl);
|
journal_(&jrnl);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ void kjvcite_to_string(const union kjvcite, char (*)[12]);
|
|||||||
#define TABLE_HEAD
|
#define TABLE_HEAD
|
||||||
#include "../src/table.h"
|
#include "../src/table.h"
|
||||||
|
|
||||||
#define TABLE_NAME count
|
#define TABLE_NAME kjvcount
|
||||||
#define TABLE_KEY union kjvcite
|
#define TABLE_KEY union kjvcite
|
||||||
#define TABLE_UINT uint32_t
|
#define TABLE_UINT uint32_t
|
||||||
#define TABLE_VALUE unsigned
|
#define TABLE_VALUE unsigned
|
||||||
@ -98,19 +98,12 @@ void kjvcite_to_string(const union kjvcite, char (*)[12]);
|
|||||||
#include "../src/table.h"
|
#include "../src/table.h"
|
||||||
|
|
||||||
#include <stddef.h> /* size_t */
|
#include <stddef.h> /* size_t */
|
||||||
struct kjvcount {
|
void kjv_count_(struct kjvcount_table *);
|
||||||
struct count_table verses;
|
struct kjvcount_table kjv_count(size_t *);
|
||||||
struct { size_t total, cumulative, set; } words;
|
size_t kjv_count_get(struct kjvcount_table *, const union kjvcite);
|
||||||
};
|
const char *kjv_count_to_string(const struct kjvcount_table *);
|
||||||
void kjvcount_(struct kjvcount *);
|
|
||||||
struct kjvcount kjvcount(void);
|
|
||||||
int kjvcount_is_empty(const struct kjvcount *);
|
|
||||||
const char *kjvcount_to_string(const struct kjvcount *);
|
|
||||||
|
|
||||||
|
|
||||||
/* FIXME: this should be in something else. */
|
|
||||||
struct kjvset_table kjv_set(void);
|
struct kjvset_table kjv_set(void);
|
||||||
void kjv_set_(struct kjvset_table *);
|
void kjv_set_(struct kjvset_table *);
|
||||||
int kjv_set_add(struct kjvset_table *const set,
|
enum table_result kjv_set_add(struct kjvset_table *, const union kjvcite);
|
||||||
struct kjvcount *const count, const union kjvcite cite);
|
|
||||||
const char *kjv_set_to_string(const struct kjvset_table *);
|
const char *kjv_set_to_string(const struct kjvset_table *);
|
@ -8,7 +8,7 @@
|
|||||||
"All included Bible translations are in the public domain."
|
"All included Bible translations are in the public domain."
|
||||||
@std C11 */
|
@std C11 */
|
||||||
|
|
||||||
#include "../src/kjvcount.h"
|
#include "../src/kjvcite.h"
|
||||||
#include "../src/text.h"
|
#include "../src/text.h"
|
||||||
#include "../src/pair.h"
|
#include "../src/pair.h"
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
@ -60,11 +60,12 @@ static void kjvset_to_string(const union kjvcite x, char (*const a)[12])
|
|||||||
#include "../src/table.h"
|
#include "../src/table.h"
|
||||||
|
|
||||||
/* Derived information on verse word count. */
|
/* Derived information on verse word count. */
|
||||||
static uint32_t count_hash(const union kjvcite x) { return kjvset_hash(x); }
|
static uint32_t kjvcount_hash(const union kjvcite x) { return kjvset_hash(x); }
|
||||||
static union kjvcite count_unhash(const uint32_t x) { return kjvset_unhash(x); }
|
static union kjvcite kjvcount_unhash(const uint32_t x)
|
||||||
static void count_to_string(const union kjvcite x, const unsigned count,
|
{ return kjvset_unhash(x); }
|
||||||
char (*const a)[12]) { (void)count; kjvset_to_string(x, a); }
|
static void kjvcount_to_string(const union kjvcite x, const unsigned count,
|
||||||
#define TABLE_NAME count
|
char (*const a)[12]) { (void)count; kjvcite_to_string(x, a); }
|
||||||
|
#define TABLE_NAME kjvcount
|
||||||
#define TABLE_KEY union kjvcite
|
#define TABLE_KEY union kjvcite
|
||||||
#define TABLE_UINT uint32_t
|
#define TABLE_UINT uint32_t
|
||||||
#define TABLE_VALUE unsigned /* Count words. */
|
#define TABLE_VALUE unsigned /* Count words. */
|
||||||
@ -144,27 +145,26 @@ scan:
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* KJV count -- loaded up on initialization and is static for it's lifetime.
|
||||||
/** Frees `kjv`. */
|
Given the verse citation, how many words does it have? */
|
||||||
void kjvcount_(struct kjvcount *const count) {
|
/** Frees `count`. */
|
||||||
if(!count) return;
|
void kjv_count_(struct kjvcount_table *const count) { kjvcount_table_(count); }
|
||||||
count_table_(&count->verses);
|
/** Loads 66 files from the "kjv/" directory and counts all the words, which
|
||||||
count->words.total = count->words.cumulative = count->words.set = 0;
|
are stored in `total`. `total` is zero if an error occurred, in which case the
|
||||||
}
|
details are sent to `stderr` and `errno` is set. @return On success, a
|
||||||
|
`kjvcount_table` that maps citations to word count. */
|
||||||
/** Loads 66 files from the "kjv/" directory. Prints out something if it
|
struct kjvcount_table kjv_count(size_t *const total) {
|
||||||
doesn't work, but does not call `perror` or reset `errno`. Use
|
|
||||||
<fn:kjvcount_is_empty> to tell. */
|
|
||||||
struct kjvcount kjvcount(void) {
|
|
||||||
const char *const dir_kjv = "kjv";
|
const char *const dir_kjv = "kjv";
|
||||||
struct char_array backing = text();
|
struct char_array backing = text();
|
||||||
struct kjvcount count = {0};
|
struct kjvcount_table count = kjvcount_table();
|
||||||
DIR *dir = 0;
|
DIR *dir = 0;
|
||||||
struct dirent *de = 0;
|
struct dirent *de = 0;
|
||||||
struct { size_t offset; int is; } build[KJV_BOOK_SIZE] = { 0 };
|
struct { size_t offset; int is; } build[KJV_BOOK_SIZE] = { 0 };
|
||||||
enum kjv_book b = 0;
|
enum kjv_book b = 0;
|
||||||
int is_in_kjv = 0;
|
int is_in_kjv = 0;
|
||||||
|
|
||||||
|
assert(total);
|
||||||
|
*total = 0;
|
||||||
/* For all files in directory KJV with <#>*.txt, read into backing. */
|
/* For all files in directory KJV with <#>*.txt, read into backing. */
|
||||||
if(chdir(dir_kjv) == -1 || (is_in_kjv = 1, !(dir = opendir("."))))
|
if(chdir(dir_kjv) == -1 || (is_in_kjv = 1, !(dir = opendir("."))))
|
||||||
goto catch;
|
goto catch;
|
||||||
@ -194,53 +194,39 @@ struct kjvcount kjvcount(void) {
|
|||||||
const union kjvcite cite
|
const union kjvcite cite
|
||||||
= { .book = b, .chapter = x.chapter, .verse = x.verse };
|
= { .book = b, .chapter = x.chapter, .verse = x.verse };
|
||||||
unsigned *words;
|
unsigned *words;
|
||||||
switch(count_table_assign(&count.verses, cite, &words)) {
|
switch(kjvcount_table_assign(&count, cite, &words)) {
|
||||||
case TABLE_PRESENT: fprintf(stderr, "[%u]%s %u:%u duplicated.\n",
|
case TABLE_PRESENT: fprintf(stderr, "[%u]%s %u:%u duplicated.\n",
|
||||||
b + 1, kjv_book_string[b], x.chapter, x.verse); errno = EDOM;
|
b + 1, kjv_book_string[b], x.chapter, x.verse); errno = EDOM;
|
||||||
case TABLE_ERROR: goto catch;
|
case TABLE_ERROR: goto catch;
|
||||||
case TABLE_ABSENT: break;
|
case TABLE_ABSENT: break;
|
||||||
}
|
}
|
||||||
*words = x.words, count.words.total += x.words;
|
*words = x.words, *total += x.words;
|
||||||
}
|
}
|
||||||
if(x.error) { fprintf(stderr, "[%u]%s on line %zu\n",
|
if(x.error) { fprintf(stderr, "[%u]%s on line %zu\n",
|
||||||
b + 1, kjv_book_string[b], x.line); goto catch; }
|
b + 1, kjv_book_string[b], x.line); goto catch; }
|
||||||
}
|
}
|
||||||
goto finally;
|
goto finally;
|
||||||
catch:
|
catch:
|
||||||
|
*total = 0;
|
||||||
if(de) fprintf(stderr, "While reading %s/%s.\n", dir_kjv, de->d_name);
|
if(de) fprintf(stderr, "While reading %s/%s.\n", dir_kjv, de->d_name);
|
||||||
else fprintf(stderr, "In directory %s/.\n", dir_kjv);
|
else fprintf(stderr, "In directory %s/.\n", dir_kjv);
|
||||||
recatch:
|
recatch:
|
||||||
kjvcount_(&count);
|
kjv_count_(&count);
|
||||||
finally:
|
finally:
|
||||||
if(dir) { if(closedir(dir)) { dir = 0; goto recatch; } dir = 0; }
|
if(dir) { if(closedir(dir)) { dir = 0; goto recatch; } dir = 0; }
|
||||||
if(is_in_kjv && (is_in_kjv = 0, chdir("..") == -1)) goto recatch;
|
if(is_in_kjv && (is_in_kjv = 0, chdir("..") == -1)) goto recatch;
|
||||||
text_(&backing);
|
text_(&backing);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
size_t kjv_count_get(struct kjvcount_table *const count,
|
||||||
|
const union kjvcite cite) { return kjvcount_table_get(count, cite); }
|
||||||
|
const char *kjv_count_to_string(const struct kjvcount_table *const count)
|
||||||
|
{ return kjvcount_table_to_string(count); }
|
||||||
|
|
||||||
/** Has loaded properly? Otherwise, probably `errno` is set. */
|
/* KJV set -- keeps track of membership by verse. */
|
||||||
int kjvcount_is_empty(const struct kjvcount *const kjv)
|
|
||||||
{ return !kjv || !kjv->verses.buckets; }
|
|
||||||
|
|
||||||
const char *kjvcount_to_string(const struct kjvcount *const count)
|
|
||||||
{ return count ? count_table_to_string(&count->verses) : ""; }
|
|
||||||
|
|
||||||
struct kjvset_table kjv_set(void) { return kjvset_table(); }
|
struct kjvset_table kjv_set(void) { return kjvset_table(); }
|
||||||
void kjv_set_(struct kjvset_table *const set) { kjvset_table_(set); }
|
void kjv_set_(struct kjvset_table *const set) { kjvset_table_(set); }
|
||||||
|
enum table_result kjv_set_add(struct kjvset_table *const set,
|
||||||
|
const union kjvcite cite) { return kjvset_table_try(set, cite); }
|
||||||
const char *kjv_set_to_string(const struct kjvset_table *const set)
|
const char *kjv_set_to_string(const struct kjvset_table *const set)
|
||||||
{ return set ? kjvset_table_to_string(set) : 0; }
|
{ return set ? kjvset_table_to_string(set) : 0; }
|
||||||
/** Adds `cite` to `kjv` if not present. Only used in test.
|
|
||||||
@return Is the kjv still valid. */
|
|
||||||
int kjv_set_add(struct kjvset_table *const set,
|
|
||||||
struct kjvcount *const count, const union kjvcite cite) {
|
|
||||||
size_t no_verse;
|
|
||||||
if(!set || !count) return 0;
|
|
||||||
no_verse = count_table_get(&count->verses, cite);
|
|
||||||
count->words.cumulative += no_verse;
|
|
||||||
switch(kjvset_table_try(set, cite)) {
|
|
||||||
case TABLE_ERROR: return 0;
|
|
||||||
case TABLE_ABSENT: count->words.set += no_verse; /* Sic. */
|
|
||||||
case TABLE_PRESENT: break;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
14
src/table.h
14
src/table.h
@ -41,14 +41,14 @@
|
|||||||
`TABLE_EXPECT_TRAIT` and then subsequently including the name in
|
`TABLE_EXPECT_TRAIT` and then subsequently including the name in
|
||||||
`TABLE_TRAIT`.
|
`TABLE_TRAIT`.
|
||||||
|
|
||||||
@param[TABLE_HEAD, TABLE_BODY]
|
|
||||||
These go together to allow exporting non-static data between compilation units
|
These go together to allow exporting non-static data between compilation units
|
||||||
by separating the `TABLE_BODY` refers to `TABLE_HEAD`, and identical
|
by separating the `TABLE_BODY` refers to `TABLE_HEAD`, and identical
|
||||||
|
|
||||||
|
@param[TABLE_HEAD, TABLE_BODY]
|
||||||
|
These go together to allow exporting non-static data between compilation units
|
||||||
|
by separating the header head from the code body. `TABLE_HEAD` needs identical
|
||||||
`TABLE_NAME`, `TABLE_KEY`, `TABLE_UNHASH`, `TABLE_VALUE`, and `TABLE_UINT`.
|
`TABLE_NAME`, `TABLE_KEY`, `TABLE_UNHASH`, `TABLE_VALUE`, and `TABLE_UINT`.
|
||||||
|
|
||||||
@fixme Remove entry as public struct, this should be entirely private.
|
|
||||||
@fixme Why not have two `to_string` arguments on map? It's C, after all. This
|
|
||||||
would be useful in some practical cases.
|
|
||||||
@std C89 */
|
@std C89 */
|
||||||
|
|
||||||
#if !defined(TABLE_NAME) || !defined(TABLE_KEY)
|
#if !defined(TABLE_NAME) || !defined(TABLE_KEY)
|
||||||
@ -61,8 +61,8 @@
|
|||||||
|| defined(TABLE_TRAIT) && !defined(TABLE_HAS_TO_STRING))
|
|| defined(TABLE_TRAIT) && !defined(TABLE_HAS_TO_STRING))
|
||||||
#error Test requires to string.
|
#error Test requires to string.
|
||||||
#endif
|
#endif
|
||||||
#if defined TABLE_HEAD && defined TABLE_BODY
|
#if defined TABLE_HEAD && (defined TABLE_BODY || defined TABLE_TRAIT)
|
||||||
#error Can not be TABLE_HEAD and TABLE_BODY.
|
#error Can not be simultaneously defined.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TABLE_H /* <!-- idempotent */
|
#ifndef TABLE_H /* <!-- idempotent */
|
||||||
@ -94,10 +94,12 @@
|
|||||||
![A diagram of the result states.](../doc/table/result.png) */
|
![A diagram of the result states.](../doc/table/result.png) */
|
||||||
enum table_result { TABLE_RESULT };
|
enum table_result { TABLE_RESULT };
|
||||||
#undef X
|
#undef X
|
||||||
|
#ifndef TABLE_HEAD /* <!-- body */
|
||||||
#define X(n) #n
|
#define X(n) #n
|
||||||
/** A static array of strings describing the <tag:table_result>. */
|
/** A static array of strings describing the <tag:table_result>. */
|
||||||
static const char *const table_result_str[] = { TABLE_RESULT };
|
static const char *const table_result_str[] = { TABLE_RESULT };
|
||||||
#undef X
|
#undef X
|
||||||
|
#endif /* body --> */
|
||||||
#undef TABLE_RESULT
|
#undef TABLE_RESULT
|
||||||
#endif /* idempotent --> */
|
#endif /* idempotent --> */
|
||||||
|
|
||||||
|
13
src/text.c
13
src/text.c
@ -1,4 +1,5 @@
|
|||||||
/** Dynamic contiguous string that is used to load files. */
|
/** Dynamic contiguous string that is used to load files into a
|
||||||
|
`struct char_array`. */
|
||||||
|
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -8,14 +9,16 @@
|
|||||||
#define ARRAY_BODY
|
#define ARRAY_BODY
|
||||||
#include "../src/array.h"
|
#include "../src/array.h"
|
||||||
|
|
||||||
|
/** @return Idle. */
|
||||||
struct char_array text(void) { return char_array(); }
|
struct char_array text(void) { return char_array(); }
|
||||||
|
|
||||||
|
/** Destroys `text`. */
|
||||||
void text_(struct char_array *const text) { char_array_(text); }
|
void text_(struct char_array *const text) { char_array_(text); }
|
||||||
|
|
||||||
/** Append a text file, `fn`, to `c`, and add a '\0'.
|
/** Append a text file, `fn`, to `text`, and add a '\0'.
|
||||||
@return The start of the appended file or null on error. A partial read is a
|
@return The start of the appended file or null on error. A partial read is a
|
||||||
failure. @throws[fopen, fread, malloc]
|
failure. @throws[fopen, fread, realloc]
|
||||||
@throws[EISEQ] The text file has embedded nulls.
|
@throws[EISEQ] The text file has embedded nulls. */
|
||||||
@throws[ERANGE] If the standard library does not follow POSIX? */
|
|
||||||
char *text_append_file(struct char_array *text, const char *const fn) {
|
char *text_append_file(struct char_array *text, const char *const fn) {
|
||||||
FILE *fp = 0;
|
FILE *fp = 0;
|
||||||
const size_t granularity = 1024;
|
const size_t granularity = 1024;
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
|
|
||||||
@param[TREE_HEAD, TREE_BODY]
|
@param[TREE_HEAD, TREE_BODY]
|
||||||
These go together to allow exporting non-static data between compilation units
|
These go together to allow exporting non-static data between compilation units
|
||||||
by separating the `TABLE_BODY` refers to `TABLE_HEAD`, and identical
|
by separating the header head from the code body. `TREE_HEAD` needs identical
|
||||||
`TREE_NAME`, `TREE_KEY`, `TREE_VALUE`, and `TREE_ORDER`.
|
`TREE_NAME`, `TREE_KEY`, `TREE_VALUE`, and `TREE_ORDER`.
|
||||||
|
|
||||||
@fixme merge, difference
|
@fixme merge, difference
|
||||||
@ -63,8 +63,8 @@
|
|||||||
|| defined(TREE_TRAIT) && !defined(TREE_HAS_TO_STRING))
|
|| defined(TREE_TRAIT) && !defined(TREE_HAS_TO_STRING))
|
||||||
#error Test requires to string.
|
#error Test requires to string.
|
||||||
#endif
|
#endif
|
||||||
#if defined TREE_HEAD && defined TREE_BODY
|
#if defined TREE_HEAD && (defined TREE_BODY || defined TREE_TRAIT)
|
||||||
#error Can not be TREE_HEAD and TREE_BODY.
|
#error Can not be simultaneously defined.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TREE_H /* <!-- idempotent */
|
#ifndef TREE_H /* <!-- idempotent */
|
||||||
@ -101,10 +101,12 @@
|
|||||||
![A diagram of the result states.](../doc/tree/result.png) */
|
![A diagram of the result states.](../doc/tree/result.png) */
|
||||||
enum tree_result { TREE_RESULT };
|
enum tree_result { TREE_RESULT };
|
||||||
#undef X
|
#undef X
|
||||||
|
#ifndef TREE_HEAD /* <!-- body */
|
||||||
#define X(n) #n
|
#define X(n) #n
|
||||||
/** A static array of strings describing the <tag:tree_result>. */
|
/** A static array of strings describing the <tag:tree_result>. */
|
||||||
static const char *const tree_result_str[] = { TREE_RESULT };
|
static const char *const tree_result_str[] = { TREE_RESULT };
|
||||||
#undef X
|
#undef X
|
||||||
|
#endif /* body --> */
|
||||||
#undef TREE_RESULT
|
#undef TREE_RESULT
|
||||||
struct tree_node_count { size_t branches, leaves; };
|
struct tree_node_count { size_t branches, leaves; };
|
||||||
#endif /* idempotent --> */
|
#endif /* idempotent --> */
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "../src/kjvcount.h"
|
#include "../src/kjvcite.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <inttypes.h> /* C99 */
|
#include <inttypes.h> /* C99 */
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -8,25 +8,38 @@
|
|||||||
int main(void) {
|
int main(void) {
|
||||||
int success = EXIT_SUCCESS;
|
int success = EXIT_SUCCESS;
|
||||||
errno = 0; /* `errno` is not set correctly to 0 in some debug situations. */
|
errno = 0; /* `errno` is not set correctly to 0 in some debug situations. */
|
||||||
struct kjvcount count = kjvcount();
|
size_t no_total, no_set = 0;
|
||||||
|
struct kjvcount_table count = kjv_count(&no_total);
|
||||||
struct kjvset_table set = kjv_set();
|
struct kjvset_table set = kjv_set();
|
||||||
|
union kjvcite verse = { .book = Genesis, .chapter = 1, .verse = 1 };
|
||||||
fprintf(stderr, "%zu total words, %s.\n",
|
fprintf(stderr, "%zu total words, %s.\n",
|
||||||
count.words.total, kjvcount_to_string(&count));
|
no_total, kjv_count_to_string(&count));
|
||||||
if(kjvcount_is_empty(&count)) goto catch;
|
if(!no_total) goto catch;
|
||||||
kjv_set_add(&set, &count,
|
switch(kjv_set_add(&set, verse)) {
|
||||||
(union kjvcite){ .book = Genesis, .chapter = 1, .verse = 1 });
|
case TABLE_ERROR: goto catch;
|
||||||
kjv_set_add(&set, &count,
|
case TABLE_PRESENT: assert(0); break;
|
||||||
(union kjvcite){ .book = Genesis, .chapter = 1, .verse = 2 });
|
case TABLE_ABSENT: no_set += kjv_count_get(&count, verse); break;
|
||||||
kjv_set_add(&set, &count,
|
}
|
||||||
(union kjvcite){ .book = Genesis, .chapter = 1, .verse = 1 });
|
verse.verse = 2;
|
||||||
fprintf(stderr, "%zu of which: %s.\n", count.words.set, kjv_set_to_string(&set));
|
switch(kjv_set_add(&set, verse)) {
|
||||||
assert(count.words.total == 789633);
|
case TABLE_ERROR: goto catch;
|
||||||
assert(count.words.set == 39);
|
case TABLE_PRESENT: assert(0); break;
|
||||||
|
case TABLE_ABSENT: no_set += kjv_count_get(&count, verse); break;
|
||||||
|
}
|
||||||
|
verse.verse = 1;
|
||||||
|
switch(kjv_set_add(&set, verse)) {
|
||||||
|
case TABLE_ERROR: goto catch;
|
||||||
|
case TABLE_PRESENT: break;
|
||||||
|
case TABLE_ABSENT: assert(0); break;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "%zu of which: %s.\n", no_set, kjv_set_to_string(&set));
|
||||||
|
assert(no_total == 789633);
|
||||||
|
assert(no_set == 39);
|
||||||
goto finally;
|
goto finally;
|
||||||
catch:
|
catch:
|
||||||
success = EXIT_FAILURE, perror("kjv");
|
success = EXIT_FAILURE, perror("kjv");
|
||||||
finally:
|
finally:
|
||||||
kjv_set_(&set);
|
kjv_set_(&set);
|
||||||
kjvcount_(&count);
|
kjv_count_(&count);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user