45 Commits

Author SHA1 Message Date
9ea7416ba6 -8 required 2025-09-22 13:32:31 -07:00
b38c6d3155 s0 -> *s0 2025-09-22 12:03:12 -07:00
d277afc48c Got it almost working in theory with utf-8? 2025-09-21 20:25:29 -07:00
b9cb570691 Don't know that this will give that much more information, but the changes have been sitting in the staging area for years. 2025-01-27 12:02:00 -08:00
1f6f226943 Added a labs.csv. 2023-09-06 09:12:35 -07:00
7f8937db55 Stub for lab graph. 2023-09-05 22:23:14 -07:00
81fc10966d Added "lab" in for medical [sti] tests. 2023-09-05 21:49:53 -07:00
5d111433c3 Changed the way we get the input; now interpret file in cwd. 2023-08-23 15:33:21 -07:00
af512793b0 "[verse]" changed to ":verse". Journal implicit, but I don't like that because it ties the input/output directories together. Added total to score. 2023-08-04 01:11:22 -07:00
ea4cf06785 Tried to simplify reading by making it the surrent directory. 2023-07-27 02:10:54 -07:00
8b4e83e2ea Scan score graph changed. 2023-06-27 11:56:12 -07:00
45ea09d7ae 2009schmool 2023-05-31 16:42:57 -07:00
a9c04a1924 Julian days. 2023-05-25 23:28:10 -07:00
e33dcbea67 plan -> from 2023-05-22 01:26:58 -07:00
66a3c1752f couch 2023-05-19 03:08:29 -07:00
cb6e0ebab4 Locations in score. 2023-05-14 23:18:59 -07:00
7f8c7710e0 Force. 2023-05-12 22:28:16 -07:00
d46b5b4d4d Last, next month. Blue. 2023-05-12 22:25:58 -07:00
45c667cdda This will not work; dates are not packed. 2023-05-12 14:57:56 -07:00
311316ef88 Dreams entered. 2023-05-09 23:49:34 -07:00
4b905ccefa Improved output. 2023-05-09 23:05:11 -07:00
d08047d4db income, fixed up journal {book:} to [book:] 2023-05-09 16:08:10 -07:00
e87f25c9ee text is working both ways 2023-05-09 14:06:20 -07:00
98c8f8dfc7 Hmmm, not really that great with newlines. 2023-05-09 01:21:13 -07:00
828c2b6595 Hmmm, text is what? 2023-05-09 00:52:32 -07:00
caf6924d0a Whatsapp 2023-05-08 20:41:40 -07:00
b670e7f822 Fixed tree iterating idle. 2023-05-08 20:25:17 -07:00
3e5acec91a currency started 2023-05-08 15:43:16 -07:00
2d11f84bd9 updated tv, movie, rem, book, etc 2023-05-07 21:44:14 -07:00
54dde7c057 source -> kvpair 2023-05-07 00:22:58 -07:00
e6a5242e73 source -> kvpair 2023-05-07 00:06:36 -07:00
04c87cbfa6 line breaks 2023-05-06 23:36:23 -07:00
ecf33b18df ed: changed to rem: 2023-05-06 23:06:30 -07:00
c0228d87bc Correct behaviour on 64-byte ints? 2023-05-06 23:00:49 -07:00
5cb731c9cc Limited loading files to INT_MAX. 2023-05-06 22:48:13 -07:00
31f41f6ced fixmes generated 2023-05-06 22:36:59 -07:00
f31a7a9810 future 2023-05-06 18:42:10 -07:00
c096fbf605 Works with text. 2023-05-06 18:11:23 -07:00
9c2edcb9eb working on polymorphic <<>> 2023-05-05 22:15:15 -07:00
72385093bd Works with ->? 2023-04-30 15:31:10 -07:00
fd2b3afc70 scan place in progress 2023-04-30 13:27:47 -07:00
bfd8d797f9 factored out date32_to_string 2023-04-30 11:06:27 -07:00
a07c9c5811 place_table is not enough; need tree 2023-04-30 02:28:15 -07:00
6866fab753 kjvline -> kjv 2023-04-30 01:49:05 -07:00
dd7ebd4075 Entered "->" into parser, but does not have a data-structure. 2023-04-30 01:15:04 -07:00
84 changed files with 1197 additions and 349 deletions

View File

@@ -30,7 +30,7 @@ else
CF += -g CF += -g
endif endif
projects := bin/test-text bin/test-journal bin/test-source bin/test-kjv bin/kjv bin/flight bin/score bin/scan projects := bin/test-text bin/test-journal bin/test-source bin/test-kjv bin/scan
#docs := $(patsubst test/test_%.c, doc/%.md, $(wildcard test/test_*.c)) #docs := $(patsubst test/test_%.c, doc/%.md, $(wildcard test/test_*.c))
default: $(projects) default: $(projects)
@@ -64,13 +64,13 @@ build/%.o: build/%.c #src/%.h
build/%.c: src/%.re.c build/%.c: src/%.re.c
@echo "\033[0;34mhttps://re2c.org/ generate $@\033[0m" @echo "\033[0;34mhttps://re2c.org/ generate $@\033[0m"
@mkdir -p build @mkdir -p build
re2c -W --tags --conditions -o $@ $< re2c -W -8 --tags --conditions -o $@ $<
#doc/%.md: src/%.h #doc/%.md: src/%.h
# # 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/kjvcite.c build/scores.c build/scan.c .SECONDARY: build/kjv.c build/journal.c build/scan.c
.PHONY: clean release test .PHONY: clean release test
test: $(projects) test: $(projects)

3
derived/.gitignore vendored
View File

@@ -1,2 +1,5 @@
* *
!.gitignore !.gitignore
!interpret
!kjv/
!kjv/*

1
derived/interpret Normal file
View File

@@ -0,0 +1 @@
../../../Documents/journal/

View File

@@ -10,46 +10,105 @@
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#include <assert.h> #include <assert.h>
#include <unistd.h> /* getcwd, chdir */
int main(void) { int main(void) {
const char *intent = "start"; const char *intent = "start";
struct journal jrnl = {0}; struct journal jrnl = {0};
struct scan scn = {0}; struct scan scn = {0};
int showhelp = 1;
FILE *fpwhere = 0;
char cwd[PATH_MAX], jdir[PATH_MAX];
errno = 0; errno = 0;
intent = "../journal"; intent = "current directory";
jrnl = journal(intent); if(!getcwd(cwd, sizeof(cwd))) goto catch;
intent = "interpret";
if(!(fpwhere = fopen(intent, "r"))) goto catch;
if(!fgets(jdir, sizeof jdir, fpwhere)) {
if(!errno) errno = EDOM;
fprintf(stderr, "first line error\n");
goto catch;
}
if(fgetc(fpwhere) != EOF) {
fprintf(stderr, "expected eof\n");
errno = EDOM; goto catch;
}
/* Could be something other than EOF. */
if(errno || (fclose(fpwhere) == EOF && (fpwhere = 0, 1))) goto catch;
fpwhere = 0;
jdir[strcspn(jdir, "\n")] = '\0'; /* Strip. */
if(chdir(jdir)) {
fprintf(stderr, "while switching to directory: %s\n", jdir);
goto catch;
}
showhelp = 0;
intent = "interesting";
perror("errno");
if(errno) goto catch;
intent = "journal";
jrnl = journal();
fprintf(stderr, "Journal: %s.\n", journal_to_string(&jrnl)); fprintf(stderr, "Journal: %s.\n", journal_to_string(&jrnl));
if(errno) goto catch; if(errno) goto catch;
intent = cwd;
if(chdir(cwd)) goto catch;
intent = "parse"; intent = "parse";
scn = scan(&jrnl); scn = scan(&jrnl);
//fprintf(stderr, "Scan: %s.\n", scan_to_string(&scrs)); //fprintf(stderr, "Scan: %s.\n", scan_to_string(&scrs));
// <- Not sure what that would do. // <- Not sure what that would do.
if(errno) goto catch; if(errno) goto catch;
intent = "derived/score.gnu"; intent = "score.gnu";
if(!freopen(intent, "w", stdout)) goto catch; if(!freopen(intent, "w", stdout)) goto catch;
scan_score_graph(&scn); scan_score_graph(&scn);
intent = "derived/glider.gnu"; intent = "labs.csv";
if(!freopen(intent, "w", stdout)) goto catch;
scan_labs_graph(&scn);
intent = "glider.gnu";
if(!freopen(intent, "w", stdout)) goto catch; if(!freopen(intent, "w", stdout)) goto catch;
scan_glider_graph(&scn); scan_glider_graph(&scn);
intent = "derived/flight.gnu"; intent = "flight.gnu";
if(!freopen(intent, "w", stdout)) goto catch; if(!freopen(intent, "w", stdout)) goto catch;
scan_flight_graph(&scn); scan_flight_graph(&scn);
intent = "derived/kjv.gnu"; intent = "kjv.gnu";
if(!freopen(intent, "w", stdout)) goto catch; if(!freopen(intent, "w", stdout)) goto catch;
scan_kjv_graph(&scn); scan_kjv_graph(&scn);
intent = "dream.gnu";
if(!freopen(intent, "w", stdout)) goto catch;
scan_dream_graph(&scn);
intent = 0; intent = 0;
goto finally; goto finally;
catch: catch:
perror(intent); perror(intent);
/* Don't know if that will give real insight into the problem… */
if(freopen("error.txt", "w", stdout)) {
printf("Journal: %s.\n", journal_to_string(&jrnl));
}
finally: finally:
/* fixme: ~scan should be idempotent but it's not on disabling ASLR, which
debug mode is in. */
if(fpwhere && fclose(fpwhere) == EOF)
intent = "interpret", perror(intent);
scan_(&scn); scan_(&scn);
journal_(&jrnl); journal_(&jrnl);
if(intent && showhelp)
fprintf(stderr, "\nMeant to be run in a directory with a file called "
"\"interpret\".\n"
"The contents of that file shall be a directory wherein\n"
"<year>/<month>/<day>.txt, eg 2000/12/01.txt.\n"
"Loads all journal entries and parses them, outputting to the "
"current directory.\n\n");
return intent ? EXIT_FAILURE : EXIT_SUCCESS; return intent ? EXIT_FAILURE : EXIT_SUCCESS;
} }

View File

@@ -20,10 +20,12 @@ union line64 {
#define TREE_HEAD #define TREE_HEAD
#include "../src/tree.h" #include "../src/tree.h"
union date32 date32_last_month(union date32 d);
union date32 date32_next_month(union date32 d);
#include "text.h" #include "text.h"
struct journal { struct day_tree days; struct char_array backing; }; struct journal { struct day_tree days; struct char_array backing; };
struct journal_iterator { struct day_tree_iterator _; }; struct journal_iterator { struct day_tree_iterator _; };
struct journal journal(const char *); struct journal journal(void);
void journal_(struct journal *); void journal_(struct journal *);
int journal_is_empty(const struct journal *); int journal_is_empty(const struct journal *);
const char *journal_to_string(const struct journal *); const char *journal_to_string(const struct journal *);

View File

@@ -17,6 +17,16 @@
#include <sys/stat.h> /* umask (POSIX) */ #include <sys/stat.h> /* umask (POSIX) */
#include <dirent.h> /* opendir readdir closedir */ #include <dirent.h> /* opendir readdir closedir */
union date32 date32_last_month(union date32 d) {
if(d.month <= 1) d.month = 12, d.year--;
else d.month--;
return d;
}
union date32 date32_next_month(union date32 d) {
if(d.month >= 12) d.month = 1, d.year++;
else d.month++;
return d;
}
/* Day tree-map from date to pointer; is backed by a huge array of text. */ /* 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]) { void date32_to_string(const union date32 d, char (*const a)[12]) {
sprintf(*a, "%" PRIu32 "-%2.2" PRIu32 "-%2.2" PRIu32, sprintf(*a, "%" PRIu32 "-%2.2" PRIu32 "-%2.2" PRIu32,
@@ -114,9 +124,9 @@ void journal_(struct journal *const j) {
text_(&j->backing); text_(&j->backing);
} }
/** @return A completed journal out of `dir_journal`. Any reading errors and /** @return A completed journal. Any reading errors and `errno` will be set,
`errno` will be set, it will be idle. */ and will return will be idle. */
struct journal journal(const char *const dir_journal) { struct journal journal(void/*const char *const dir_journal*/) {
struct journal j = {0}; struct journal j = {0};
char *intent = 0; char *intent = 0;
DIR *dir = 0; DIR *dir = 0;
@@ -126,12 +136,10 @@ struct journal journal(const char *const dir_journal) {
int *y = 0, *y_end, *m = 0, *m_end, *d = 0, *d_end; int *y = 0, *y_end, *m = 0, *m_end, *d = 0, *d_end;
struct day_tree_iterator it; struct day_tree_iterator it;
union { const char **text; uintptr_t *offset; } v; union { const char **text; uintptr_t *offset; } v;
char cwd[256];
int is_dir_journal = 0;
/* Get the years list as directories matching a year. */ /* Get the years list as directories matching a year. */
if(!getcwd(cwd, sizeof cwd) || chdir(dir_journal) == -1) goto catch; /*if(!getcwd(cwd, sizeof cwd) || chdir(dir_journal) == -1) goto catch;
is_dir_journal = 1; is_dir_journal = 1;*/
if(!(dir = opendir("."))) goto catch; if(!(dir = opendir("."))) goto catch;
while((de = readdir(dir))) { while((de = readdir(dir))) {
struct stat st; struct stat st;
@@ -145,8 +153,7 @@ struct journal journal(const char *const dir_journal) {
if(closedir(dir)) { dir = 0; goto catch; } dir = 0; if(closedir(dir)) { dir = 0; goto catch; } dir = 0;
/* Sort the years. */ /* Sort the years. */
qsort(years.data, years.size, sizeof *years.data, &void_int_cmp); qsort(years.data, years.size, sizeof *years.data, &void_int_cmp);
fprintf(stderr, "Years in <<%s>>: %s.\n", fprintf(stderr, "Loading years: %s.\n", int_array_to_string(&years));
dir_journal, int_array_to_string(&years));
/* Go though each year. */ /* Go though each year. */
for(y = years.data, y_end = y + years.size; y < y_end; y++) { for(y = years.data, y_end = y + years.size; y < y_end; y++) {
@@ -208,7 +215,7 @@ struct journal journal(const char *const dir_journal) {
m = 0, int_array_clear(&months); m = 0, int_array_clear(&months);
if(chdir("..") == -1) goto catch; if(chdir("..") == -1) goto catch;
} }
if(chdir("../..") == -1 || !day_tree_bulk_finish(&j.days)) goto catch; if(!day_tree_bulk_finish(&j.days)) goto catch;
/* Structure is now stable because we aren't going to move it; /* Structure is now stable because we aren't going to move it;
convert all of offsets back to pointers. */ convert all of offsets back to pointers. */
@@ -218,17 +225,17 @@ struct journal journal(const char *const dir_journal) {
goto finally; goto finally;
catch: catch:
fprintf(stderr, "On date: %s/%d-%.2d-%.2d.\n", fprintf(stderr, "On date: %d-%.2d-%.2d.\n",
dir_journal, y ? *y : 0, m ? *m : 0, d ? *d : 0); y ? *y : 0, m ? *m : 0, d ? *d : 0);
if(intent) fprintf(stderr, "(%s)\n", intent); if(intent) fprintf(stderr, "(%s)\n", intent);
recatch: recatch:
journal_(&j); journal_(&j);
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_dir_journal) { /*if(is_dir_journal) {
if(chdir(cwd) == -1) { is_dir_journal = 0; goto recatch; } if(chdir(cwd) == -1) { is_dir_journal = 0; goto recatch; }
is_dir_journal = 0; is_dir_journal = 0;
} }*/
int_array_(&years), int_array_(&months), int_array_(&days); /* Temporary. */ int_array_(&years), int_array_(&months), int_array_(&days); /* Temporary. */
return j; return j;
} }

View File

@@ -78,7 +78,7 @@ static void kjvcount_to_string(const union kjvcite x, const unsigned count,
/* Parse filename of books. */ /* Parse filename of books. */
/*!re2c /**/ /*!re2c /**/
re2c:yyfill:enable = 0; re2c:yyfill:enable = 0;
re2c:define:YYCTYPE = char; re2c:define:YYCTYPE = "unsigned char";
natural = [1-9][0-9]*; natural = [1-9][0-9]*;
whitespace = [ \t\v\f]; whitespace = [ \t\v\f];
word = [^ \t\v\f\n\x00]+; word = [^ \t\v\f\n\x00]+;
@@ -86,13 +86,14 @@ word = [^ \t\v\f\n\x00]+;
/** `fn` contains "<number>[*].txt", sticks that in `book_no`, otherwise /** `fn` contains "<number>[*].txt", sticks that in `book_no`, otherwise
returns false. */ returns false. */
static int looks_like_book_fn(const char *fn, unsigned *const book_no) { static int looks_like_book_fn(const char *fn, unsigned *const book_no) {
const char *YYCURSOR = fn, *YYMARKER, *yyt1, *yyt2, *s0, *s1; const unsigned char *YYCURSOR = (const unsigned char *)fn,
*YYMARKER, *yyt1, *yyt2, *s0, *s1;
assert(fn && book_no); assert(fn && book_no);
/*!re2c /**/ /*!re2c /**/
* *
{ return 0; } { return 0; }
@s0 natural @s1 [^.\x00]* ".txt" "\x00" @s0 natural @s1 [^.\x00]* ".txt" "\x00"
{ return pair_to_natural(s0, s1, book_no); } { return pair_to_natural(pair_u(s0, s1), book_no); }
*/ */
} }
@@ -100,22 +101,23 @@ static int looks_like_book_fn(const char *fn, unsigned *const book_no) {
/* This is the contents of the <fn:looks_like_book_fn>. */ /* This is the contents of the <fn:looks_like_book_fn>. */
struct lex { struct lex {
size_t line; size_t line;
const char *cursor; const unsigned char *cursor;
int error; int error;
uint32_t chapter, verse, words; uint32_t chapter, verse, words;
}; };
static struct lex lex(const char *cursor) { static struct lex lex(const char *cursor) {
struct lex lex; struct lex lex;
union { const unsigned char *u; const char *s; } flex = { .s = cursor };
assert(cursor); assert(cursor);
lex.line = 1; lex.line = 1;
lex.cursor = cursor; lex.cursor = flex.u;
lex.error = 0; lex.error = 0;
lex.chapter = lex.verse = lex.words = 0; lex.chapter = lex.verse = lex.words = 0;
return lex; return lex;
} }
/*!conditions:re2c*/ /*!conditions:re2c*/
static int lex_next_verse(struct lex *const lex) { static int lex_next_verse(struct lex *const lex) {
const char *YYMARKER, *yyt1 = 0, *yyt2 = 0, *s0, *s1, *t0, *t1; const unsigned char *YYMARKER, *yyt1 = 0, *yyt2 = 0, *s0, *s1, *t0, *t1;
enum YYCONDTYPE condition = yycline; enum YYCONDTYPE condition = yycline;
/*!re2c /**/ /*!re2c /**/
re2c:define:YYCURSOR = lex->cursor; re2c:define:YYCURSOR = lex->cursor;
@@ -131,8 +133,8 @@ scan:
<line> [^[\]\n\x00]* "\n" { lex->line++; goto scan; } <line> [^[\]\n\x00]* "\n" { lex->line++; goto scan; }
<line> "\x00" { return 0; } <line> "\x00" { return 0; }
<line> "[" @s0 natural @s1 ":" @t0 natural @t1 "]" => verse { <line> "[" @s0 natural @s1 ":" @t0 natural @t1 "]" => verse {
if(!pair_to_natural(s0, s1, &lex->chapter) if(!pair_to_natural(pair_u(s0, s1), &lex->chapter)
|| !pair_to_natural(t0, t1, &lex->verse)) || !pair_to_natural(pair_u(t0, t1), &lex->verse))
return errno = EILSEQ, lex->error = 1, 0; return errno = EILSEQ, lex->error = 1, 0;
lex->words = 0; lex->words = 0;
/*printf("%u:%u", lex->chapter, lex->verse);*/ /*printf("%u:%u", lex->chapter, lex->verse);*/

View File

@@ -1,3 +1,11 @@
/** Tyler Durden: calculates a day number according to the Gregorian calendar. */
function g(y,m,d)
m = (m + 9) % 12
y = y - m/10
return 365*y + y/4 - y/100 + y/400 + (m*306 + 5)/10 + ( d - 1 )
Difference between two dates = g(y2,m2,d2) - g(y1,m1,d1)
/** Tomohiko Sakamoto comp.lang.c 1993-04-10. */ /** Tomohiko Sakamoto comp.lang.c 1993-04-10. */
static unsigned weekday(union date32 d) { static unsigned weekday(union date32 d) {
d.year -= d.month < 3; d.year -= d.month < 3;

View File

@@ -18,34 +18,48 @@ struct pair pair(const char *const a, const char *const b) {
return p; return p;
} }
/** @returns Constructs `a` and `b` as unsigned. */
struct pair pair_u(const unsigned char *const a, const unsigned char *const b)
{ return pair((const char *)a, (const char *)b); }
/** Doesn't check if the number is actually in [0, 9]. /** Doesn't check if the number is actually in [0, 9].
@return Whether it was able to parse unsigned [`a`, `b`] to `n`. */ @return Whether it was able to parse unsigned [`a`, `b`] to `n`. */
int pair_to_natural(const char *a, const char *const b, uint32_t *const n) { int pair_to_natural(struct pair p, uint32_t *const n) {
uint32_t accum = 0; uint32_t accum = 0;
while(a < b) { while(p.a < p.b) {
unsigned next = accum * 10 + (unsigned)(*a - '0'); uint32_t next = accum * 10 + (uint32_t)(*p.a - '0');
if(accum > next) return errno = ERANGE, 0; if(accum > next) return errno = ERANGE, 0;
accum = next; accum = next;
a++; p.a++;
} }
return *n = accum, 1; return *n = accum, 1;
} }
/** `h0` "1" `h1` ":" `m0` "30" `m1` -> 90 `n` @return Valid. */ static int pair_to_64(struct pair p, uint64_t *const n) {
int pair_colon_to_minutes(const char *h0, const char *const h1, uint64_t accum = 0;
const char *m0, const char *const m1, uint32_t *const n) { while(p.a < p.b) {
uint64_t next = accum * 10 + (uint64_t)(*p.a - '0');
if(accum > next) return errno = ERANGE, 0;
accum = next;
p.a++;
}
return *n = accum, 1;
}
/** `h` "1" ":" `m` "30" -> 90 `n` @return Valid. */
int pair_colon_to_minutes(struct pair h, struct pair m, uint32_t *const n) {
uint32_t hours, minutes; uint32_t hours, minutes;
return pair_to_natural(h0, h1, &hours) && pair_to_natural(m0, m1, &minutes) return pair_to_natural(h, &hours) && pair_to_natural(m, &minutes)
&& minutes < 60 && hours <= UINT32_MAX / 60 - minutes && minutes < 60 && hours <= UINT32_MAX / 60 - minutes
? (*n = hours * 60 + minutes, 1) : 0; ? (*n = hours * 60 + minutes, 1) : 0;
} }
/** `h0` "1" `h1` "." `m0` "5" `m1` -> 90 `n` @return Valid. */ /** `h0` "1" `h1` "." `m0` "5" `m1` -> 90 `n` @return Valid. */
int pair_hours_to_minutes(const char *h0, const char *const h1, int pair_decimal_hours_to_minutes(struct pair h, struct pair m,
const char *m0, const char *const m1, uint32_t *const n) { uint32_t *const n) {
uint32_t hours, minutes; uint32_t hours, minutes;
/* fixme: more precision? */ /* fixme: more precision? */
return pair_to_natural(h0, h1, &hours) && pair_to_natural(m0, m1, &minutes) return pair_to_natural(h, &hours) && pair_to_natural(m, &minutes)
&& minutes <= 9 && hours <= UINT32_MAX / 60 - minutes * 6 && minutes <= 9 && hours <= UINT32_MAX / 60 - minutes * 6
? (*n = hours * 60 + minutes * 6, 1) : 0; ? (*n = hours * 60 + minutes * 6, 1) : 0;
} }
@@ -98,12 +112,12 @@ no:
@return Success. @return Success.
@throws[ERANGE] Year is more then 23 bits. @throws[ERANGE] Year is more then 23 bits.
@throws[EILSEQ] The is not a date? */ @throws[EILSEQ] The is not a date? */
int pair_to_date(const char *a, union date32 *const d) { int pair_to_date(const unsigned char *a, union date32 *const d) {
uint32_t year = 0, month, day; uint32_t year = 0, month, day;
union date32 temp; union date32 temp;
assert(a && d); assert(d);
while(*a >= '0' && *a <= '9') { while(a[0] >= '0' && a[0] <= '9') {
year = year * 10 + (unsigned)(*a - '0'); year = year * 10 + (unsigned)(a[0] - '0');
if(year > 0x7FFFFF) return errno = ERANGE, 0; /* 23 bits */ if(year > 0x7FFFFF) return errno = ERANGE, 0; /* 23 bits */
a++; a++;
} }
@@ -117,8 +131,28 @@ int pair_to_date(const char *a, union date32 *const d) {
return *d = temp, 1; return *d = temp, 1;
} }
int pair_to_cents(struct pair p, int64_t *const cents) {
uint64_t d, c;
int is_negative;
assert(p.a < p.b && cents);
if(p.a[0] == '-') is_negative = 1, p.a++; else is_negative = 0;
if(p.a + 2 < p.b && p.b[-3] == '.') { /* dollars.cents */
if(!pair_to_64(pair(p.a, p.b - 3), &d)) return 0;
c = (uint64_t)(p.b[-2] - '0') * 10 + (uint64_t)(p.b[-1] - '0');
} else { /* dollars */
if(!pair_to_64(pair(p.a, p.b), &d)) return 0;
c = 0;
}
assert(-INT64_MAX >= INT64_MIN);
if(INT64_MAX / 100 < d || INT64_MAX - d * 100 < c)
return errno = ERANGE, 0;
/* Misses one in 2's. Not a very nuanced conversion. */
*cents = (is_negative ? -1 : 1) * (int64_t)(d * 100 + c);
return 1;
}
/** @return A djb2 <http://www.cse.yorku.ca/~oz/hash.html> hash of `p`. */ /** @return A djb2 <http://www.cse.yorku.ca/~oz/hash.html> hash of `p`. */
static uint32_t pair_djb2(struct pair p) { uint32_t pair_djb2(struct pair p) {
uint32_t hash = 5381, c; uint32_t hash = 5381, c;
while(p.a < p.b) { while(p.a < p.b) {
c = (unsigned char)*p.a++; c = (unsigned char)*p.a++;

View File

@@ -5,16 +5,17 @@
struct pair { const char *a, *b; }; struct pair { const char *a, *b; };
struct pair pair(const char *const a, const char *const b); struct pair pair(const char *, const char *);
int pair_to_natural(const char *, const char *, uint32_t *); struct pair pair_u(const unsigned char *, const unsigned char *);
int pair_colon_to_minutes(const char *, const char *, int pair_to_natural(struct pair, uint32_t *);
const char *, const char *, uint32_t *); int pair_colon_to_minutes(struct pair h, struct pair m, uint32_t *);
int pair_hours_to_minutes(const char *h0, const char *const h1, int pair_decimal_hours_to_minutes(struct pair h, struct pair m, uint32_t *const n);
const char *m0, const char *const m1, uint32_t *const n);
int pair_is_equal(struct pair, struct pair); int pair_is_equal(struct pair, struct pair);
int pair_is_string(struct pair, const char *); int pair_is_string(struct pair, const char *);
#include "journal.h" /* date32 */ #include "journal.h" /* date32 */
int pair_to_date(const char *a, union date32 *const d); int pair_to_date(const unsigned char *a, union date32 *);
int pair_to_cents(struct pair p, int64_t *);
uint32_t pair_djb2(struct pair);
/* Supporting pair -> size_t for looking up in arrays. */ /* Supporting pair -> size_t for looking up in arrays. */
#define TABLE_NAME pairmap #define TABLE_NAME pairmap

View File

@@ -7,11 +7,52 @@
#define TREE_VALUE size_t #define TREE_VALUE size_t
#define TREE_HEAD #define TREE_HEAD
#include "../src/tree.h" #include "../src/tree.h"
#define TREE_NAME linepair
#define TREE_KEY union line64
#define TREE_VALUE struct pair
#define TREE_HEAD
#include "../src/tree.h"
/* Source array. */ /* Eg, source array. */
struct source { struct pair name, desc; }; struct kvpair { struct pair key, value; };
#define ARRAY_NAME source #define ARRAY_NAME kvpair
#define ARRAY_TYPE struct source #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"
struct kvdate { union date32 key; struct pair value; };
#define TREE_NAME linekvdate
#define TREE_KEY union line64
#define TREE_VALUE struct kvdate
#define TREE_HEAD
#include "../src/tree.h"
enum currency {
NONE,
CAD, /* Canadian $. */
USD, /* US Dollar $usd. */
EUR, /* Euro €. */
GBP, /* Pound £. */
MXN, /* Mexican pesos $mxn. */
CUP, /* Cuban pesos, (US) $cup. */
CUC, /* Cuban convertible $cuc. */
};
#include <stdint.h>
struct money { int64_t cents; enum currency currency; };
struct kvmoney { struct pair key; struct money value; };
#define TREE_NAME linekvmoney
#define TREE_KEY union line64
#define TREE_VALUE struct kvmoney
#define TREE_HEAD
#include "../src/tree.h"
/* Place array. */
struct place { struct pair name; double x, y; };
#define ARRAY_NAME place
#define ARRAY_TYPE struct place
#define ARRAY_HEAD #define ARRAY_HEAD
#include "../src/array.h" #include "../src/array.h"
@@ -26,6 +67,17 @@ struct score {
#define ARRAY_HEAD #define ARRAY_HEAD
#include "../src/array.h" #include "../src/array.h"
/* Edit array. */
struct edit {
union date32 edit;
struct pair desc;
};
#define ARRAY_NAME edit
#define ARRAY_TYPE struct edit
#define ARRAY_HEAD
#include "../src/array.h"
/* Glider array. */ /* Glider array. */
#define LAUNCH_TYPE \ #define LAUNCH_TYPE \
X(MotorCarTow),\ X(MotorCarTow),\
@@ -65,7 +117,7 @@ struct flight {
#include "kjv.h" #include "kjv.h"
#define TREE_NAME kjvline #define TREE_NAME kjv
#define TREE_KEY union line64 #define TREE_KEY union line64
#define TREE_VALUE struct kjvrange #define TREE_VALUE struct kjvrange
#define TREE_HEAD #define TREE_HEAD
@@ -74,24 +126,41 @@ struct flight {
struct scan { struct scan {
struct { struct {
struct source_array array; struct kvpair_array array;
struct pairmap_table map; struct pairmap_table map;
struct linemap_tree dates; struct linemap_tree dates;
} sources; } sources, documents;
struct {
struct place_array array;
struct pairmap_table map;
struct linemap_tree dates;
} places;
struct { struct {
struct score_array array; struct score_array array;
struct pairmap_table map; struct pairmap_table map;
struct linemap_tree dates; struct linemap_tree dates;
} scores; } scores;
struct {
struct edit_array array;
struct pairmap_table map;
struct linemap_tree dates;
} edits;
struct linepair_tree dreams;
struct linekvpair_tree contacts, books, tvs, movies, ideas,
vaccines, medications, labs, mails, couches;
struct linekvdate_tree froms;
struct linekvmoney_tree taxes, incomes;
struct glider_tree gliders; struct glider_tree gliders;
struct flight_tree flights; struct flight_tree flights;
struct kjvline_tree kjvs; struct kjv_tree kjvs;
}; };
void scan_(struct scan *); void scan_(struct scan *);
struct scan scan(struct journal *); struct scan scan(struct journal *);
const struct source *scan_source_lookup(struct scan *, const union line64); const struct kvpair *scan_source_lookup(struct scan *, const union line64);
void scan_score_graph(struct scan *); void scan_score_graph(struct scan *);
void scan_labs_graph(struct scan *);
void scan_glider_graph(struct scan *); void scan_glider_graph(struct scan *);
void scan_flight_graph(struct scan *); void scan_flight_graph(struct scan *);
void scan_kjv_graph(struct scan *); void scan_kjv_graph(struct scan *);
void scan_dream_graph(struct scan *);

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,8 @@
#include "text.h" #include "text.h"
#include <stdio.h> #include <stdio.h>
#include <limits.h>
#include <stdint.h>
#define ARRAY_NAME char #define ARRAY_NAME char
#define ARRAY_TYPE char #define ARRAY_TYPE char
@@ -28,10 +30,14 @@ char *text_append_file(struct char_array *text, const char *const fn) {
assert(text && fn); assert(text && fn);
start = text->size; start = text->size;
if(!(fp = fopen(fn, "r"))) goto catch; if(!(fp = fopen(fn, "r"))) goto catch;
/* Read entire file in chunks. */ /* Read entire file in chunks. We don't allow any text file to go over
`INT_MAX` and `UINT32_MAX` because `printf("%.*s", int, char *)` is used
and we store it in an `uint32_t`. */
do if(!(cursor = char_array_buffer(text, granularity)) do if(!(cursor = char_array_buffer(text, granularity))
|| (nread = fread(cursor, 1, granularity, fp), ferror(fp)) || (nread = fread(cursor, 1, granularity, fp), ferror(fp))
|| !char_array_append(text, nread)) goto catch; || !char_array_append(text, nread)
|| text->size - start >= (INT_MAX < UINT32_MAX ? INT_MAX : UINT32_MAX))
goto catch;
while(nread == granularity); while(nread == granularity);
/* File to `C` string. */ /* File to `C` string. */
if(!(cursor = char_array_new(text))) goto catch; if(!(cursor = char_array_new(text))) goto catch;

View File

@@ -33,8 +33,8 @@
tree, <Sedgewick, 2008, LLRB>. The above illustration is 5. tree, <Sedgewick, 2008, LLRB>. The above illustration is 5.
@param[TREE_DEFAULT] @param[TREE_DEFAULT]
Default trait; a name that satisfies `C` naming conventions when mangled and a Default trait which must be set to a <typedef:<PB>value>, used in
<typedef:<PB>value> used in <fn:<B>tree<D>get>. <fn:<B>tree<D>get>.
@param[TREE_TO_STRING] @param[TREE_TO_STRING]
To string trait `<STR>` contained in <src/to_string.h>. Require To string trait `<STR>` contained in <src/to_string.h>. Require
@@ -42,7 +42,8 @@
@param[TREE_EXPECT_TRAIT, TREE_TRAIT] @param[TREE_EXPECT_TRAIT, TREE_TRAIT]
Named traits are obtained by including `tree.h` multiple times with 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] @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
@@ -244,7 +245,7 @@ static int PB_(next)(struct PB_(iterator) *const it) {
assert(it && it->root); assert(it && it->root);
/* Tree empty. */ /* Tree empty. */
if(!it->root->node || it->root->height == UINT_MAX) return 0; if(!it->root || !it->root->node || it->root->height == UINT_MAX) return 0;
/* Iterator empty; tree non-empty; point at first. */ /* Iterator empty; tree non-empty; point at first. */
if(!it->ref.node) { if(!it->ref.node) {
@@ -291,7 +292,7 @@ static int PB_(previous)(struct PB_(iterator) *const it) {
assert(it && it->root); assert(it && it->root);
/* Tree empty. */ /* Tree empty. */
if(!it->root->node || it->root->height == UINT_MAX) return 0; if(!it->root || !it->root->node || it->root->height == UINT_MAX) return 0;
/* Iterator empty; tree non-empty; point at last. */ /* Iterator empty; tree non-empty; point at last. */
if(!it->ref.node) { if(!it->ref.node) {
@@ -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 /** 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); } static void B_(tree_clear)(struct B_(tree) *const tree) { PB_(clear)(tree); }
/** Private: counts a sub-tree, `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 /* <!-- map */ #ifdef TREE_VALUE /* <!-- map */
/** Packs `key` on the right side of `tree` without doing the usual /** Only if `TREE_VALUE` is set; the set version is <fn:<B>tree_try>. Packs
restructuring. All other topology modification functions should be avoided `key` on the right side of `tree` without doing the usual restructuring. All
until followed by <fn:<B>tree_bulk_finish>. other topology modification functions should be avoided until followed by
<fn:<B>tree_bulk_finish>.
@param[value] A pointer to the key's value which is set by the function on @param[value] A pointer to the key's value which is set by the function on
returning true. A null pointer in this parameter causes the value to go returning true. Can be null.
uninitialized. This parameter is not there if one didn't specify `TREE_VALUE`.
@return One of <tag:tree_result>: `TREE_ERROR` and `errno` will be set, @return One of <tag:tree_result>: `TREE_ERROR` and `errno` will be set,
`TREE_PRESENT` if the key is already (the highest) in the tree, and `TREE_PRESENT` if the key is already (the highest) in the tree, and
`TREE_ABSENT`, added, the `value` (if applicable) is uninitialized. `TREE_ABSENT`, added, the `value` (if applicable) is uninitialized.
@@ -598,8 +600,8 @@ static enum tree_result B_(tree_bulk_assign)(struct B_(tree) *const tree,
#elif defined TREE_VALUE /* map --><!-- null: For braces matching. */ #elif defined TREE_VALUE /* map --><!-- null: For braces matching. */
} }
#else /* null --><!-- set */ #else /* null --><!-- set */
/** Packs `key` on the right side of `tree`. See <fn:<B>tree_assign>, which is /** Only if `TREE_VALUE` is not set; see <fn:<B>tree_assign>, which is
the map version. @allow */ the map version. Packs `key` on the right side of `tree`. @allow */
static enum tree_result B_(tree_bulk_try)(struct B_(tree) *const tree, static enum tree_result B_(tree_bulk_try)(struct B_(tree) *const tree,
PB_(key) key) { PB_(key) key) {
#endif #endif
@@ -1636,7 +1638,7 @@ static void PBT_(to_string)(const struct PB_(ref) *const r,
#define PB_D_(n, m) TREE_CAT(tree, B_D_(n, m)) #define PB_D_(n, m) TREE_CAT(tree, B_D_(n, m))
#endif #endif
/* `TREE_DEFAULT` is a valid <tag:<PB>value>. */ /* `TREE_DEFAULT` is a valid <tag:<PB>value>. */
static const PB_(value) PB_D_(default, value) = (TREE_DEFAULT); static const PB_(value) PB_D_(default, value) = TREE_DEFAULT;
/** This is functionally identical to <fn:<B>tree_get_or>, but a with a trait /** This is functionally identical to <fn:<B>tree_get_or>, but a with a trait
specifying a constant default value. specifying a constant default value.
@return The value associated with `key` in `tree`, (which can be null.) If @return The value associated with `key` in `tree`, (which can be null.) If

View File

@@ -7,7 +7,7 @@
int main(void) { int main(void) {
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 journal j = journal("../journal"); struct journal j = journal(/*"../journal"*/);
int success = EXIT_SUCCESS; int success = EXIT_SUCCESS;
if(errno) goto catch; if(errno) goto catch;
printf("Journal: %s.\n", journal_to_string(&j)); printf("Journal: %s.\n", journal_to_string(&j));

View File

@@ -7,29 +7,29 @@
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 journal jrnl = journal("../journal"); struct journal jrnl = journal(/*"../journal"*/);
struct scan scn = scan(&jrnl); struct scan scn = scan(&jrnl);
if(errno) goto catch; if(errno) goto catch;
const union line64 agenda = {{4,{{20,04,1996}}}}, const union line64 agenda = {{4,{{20,04,1996}}}},
before = {{1,{{1,1,1900}}}}, before = {{1,{{1,1,1900}}}},
noentry = {{3,{{1,6,1995}}}}; noentry = {{3,{{1,6,1995}}}};
const struct source *source; const struct kvpair *source;
source = scan_source_lookup(&scn, agenda); source = scan_source_lookup(&scn, agenda);
printf("agenda: <%.*s>\n", printf("agenda: <%.*s>\n",
(int)(source->name.b - source->name.a), source->name.a); (int)(source->key.b - source->key.a), source->key.a);
assert(pair_is_string(source->name, "1995agenda")); assert(pair_is_string(source->key, "1995agenda"));
source = scan_source_lookup(&scn, before); source = scan_source_lookup(&scn, before);
printf("before: <%.*s>\n", printf("before: <%.*s>\n",
(int)(source->name.b - source->name.a), source->name.a); (int)(source->key.b - source->key.a), source->key.a);
assert(pair_is_string(source->name, 0)); assert(pair_is_string(source->key, 0));
source = scan_source_lookup(&scn, noentry); source = scan_source_lookup(&scn, noentry);
printf("noentry: <%.*s>\n", printf("noentry: <%.*s>\n",
(int)(source->name.b - source->name.a), source->name.a); (int)(source->key.b - source->key.a), source->key.a);
assert(pair_is_string(source->name, 0)); assert(pair_is_string(source->key, 0));
goto finally; goto finally;
catch: catch:

3
time.txt Normal file
View File

@@ -0,0 +1,3 @@
set xdata time
set timefmt myTimeFmt
set xrange ['2000-01-01':*]