2022-02-10 23:30:11 -05:00
|
|
|
/** @license 2022 Neil Edelman, distributed under the terms of the
|
|
|
|
[MIT License](https://opensource.org/licenses/MIT).
|
|
|
|
|
|
|
|
Lexer for journal entries.
|
|
|
|
|
|
|
|
@std C89/90 */
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
/* This defines `enum condition`. */
|
|
|
|
/*!types:re2c*/
|
|
|
|
enum symbol { END, TEXT, BANG, WHITE, MAP };
|
|
|
|
|
|
|
|
/** scanner reads a file and extracts semantic information. Valid to access
|
|
|
|
only while underlying pointers do not change. */
|
|
|
|
struct scanner {
|
|
|
|
/* `re2c` variables; these point directly into `buffer`. */
|
|
|
|
const char *marker, *ctx_marker, *from, *cursor;
|
|
|
|
/* Weird `c2re` stuff: these fields have to come after when >5? */
|
|
|
|
const char *label, *buffer, *s0, *s1;
|
|
|
|
enum condition condition;
|
|
|
|
enum symbol symbol;
|
|
|
|
size_t line;
|
|
|
|
int ws_before;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!re2c
|
|
|
|
re2c:yyfill:enable = 0;
|
|
|
|
re2c:flags:tags = 1;
|
|
|
|
re2c:define:YYCTYPE = char;
|
|
|
|
re2c:define:YYCURSOR = s->cursor;
|
|
|
|
re2c:define:YYMARKER = s->marker;
|
|
|
|
re2c:define:YYCTXMARKER = s->ctx_marker;
|
|
|
|
re2c:define:YYCONDTYPE = 'condition';
|
|
|
|
re2c:define:YYGETCONDITION = 's->condition';
|
|
|
|
re2c:define:YYGETCONDITION:naked = 1;
|
|
|
|
re2c:define:YYSETCONDITION = 's->condition = @@;';
|
|
|
|
re2c:define:YYSETCONDITION:naked = 1;
|
|
|
|
|
|
|
|
// Eof is marked by null when preparing files for lexing.
|
|
|
|
// Mutually exclusive; only !, [, are not covered.
|
|
|
|
end = "\x00";
|
|
|
|
newline = "\n" | "\r" "\n"?;
|
|
|
|
ws = [ \t\v\f];
|
|
|
|
glyph = [^ \t\n\r\v\f![\x00];
|
|
|
|
glyphs = glyph+;
|
|
|
|
|
|
|
|
// inside the block
|
|
|
|
decimal = [1-9][0-9]*;
|
|
|
|
number = ([1-9][0-9]* | [0])? "." [0-9]+ | [1-9][0-9]* | [0];
|
|
|
|
id = [a-zA-Z_][a-zA-Z_\-0-9]{0,63};
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int lex(struct scanner *const s) {
|
|
|
|
const char *s0, *s1;
|
|
|
|
/*!stags:re2c format = 'const char *@@;\n'; */
|
|
|
|
s->ws_before = 0;
|
|
|
|
scan:
|
|
|
|
/*!re2c
|
|
|
|
<text> end { return s->symbol = END, 1; }
|
|
|
|
// fixme: paragraphs.
|
|
|
|
<text> newline { s->line++; s->ws_before = 1; goto scan; }
|
|
|
|
<text> ws+ { s->ws_before = 1; goto scan; }
|
|
|
|
<text> @s0 glyph+ @s1 { s->s0 = s0, s->s1 = s1;
|
|
|
|
return s->symbol = TEXT, 1; }
|
|
|
|
<text> @s0 "!" @s1 { s->s0 = s0, s->s1 = s1;
|
|
|
|
return s->symbol = BANG, 1; }
|
|
|
|
<text> "![" :=> image
|
|
|
|
<text> "[" :=> command
|
|
|
|
<image> * { return 0; }
|
|
|
|
<image> ws* "osm" ws* "](geo:" @s0 number "," @s1 number ")" {
|
|
|
|
s->condition = yyctext;
|
|
|
|
s->s0 = s0, s->s1 = s1;
|
|
|
|
printf("Got a map.\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
<command> * { return 0; }
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2022-02-11 03:28:28 -05:00
|
|
|
/*#define POOL_NAME char
|
|
|
|
#define POOL_TYPE char
|
|
|
|
#include "../src/pool.h"*/
|
2022-02-10 23:30:11 -05:00
|
|
|
|
2022-02-11 03:28:28 -05:00
|
|
|
struct year_listlink;
|
|
|
|
static int year_link_compare(const struct year_listlink *,
|
|
|
|
const struct year_listlink *);
|
|
|
|
static void yearlist_to_string(const struct year_listlink *, char (*)[12]);
|
|
|
|
#define LIST_NAME year
|
|
|
|
#define LIST_EXPECT_TRAIT
|
|
|
|
#include "../src/list.h"
|
|
|
|
#define LIST_COMPARE &year_link_compare
|
|
|
|
#define LIST_EXPECT_TRAIT
|
|
|
|
#include "../src/list.h"
|
|
|
|
#define LIST_TO_STRING &yearlist_to_string
|
|
|
|
#include "../src/list.h"
|
|
|
|
struct year {
|
|
|
|
struct year_listlink link;
|
|
|
|
int year;
|
|
|
|
char as_string[8];
|
|
|
|
};
|
|
|
|
static const size_t year_string_size = sizeof ((struct year *)0)->as_string;
|
|
|
|
static int year_link_compare(const struct year_listlink *const al,
|
|
|
|
const struct year_listlink *const bl) {
|
|
|
|
const struct year *const a = (const struct year *)al,
|
|
|
|
*const b = (const struct year *)bl;
|
|
|
|
return (b->year < a->year) - (a->year < b->year);
|
2022-02-10 23:30:11 -05:00
|
|
|
}
|
2022-02-11 03:28:28 -05:00
|
|
|
#define POOL_NAME year
|
|
|
|
#define POOL_TYPE struct year
|
|
|
|
#include "../src/pool.h"
|
|
|
|
static unsigned hash_year(const struct year *const year)
|
|
|
|
{ return (unsigned)(year->year - INT_MIN); }
|
|
|
|
static int year_is_equal(const struct year *const a, const struct year *const b)
|
|
|
|
{ return a->year == b->year; }
|
|
|
|
static void year_to_string(const struct year *const y, char (*const a)[12])
|
|
|
|
{ strncpy(*a, y->as_string, sizeof(*a) - 1), (*a)[sizeof(*a) - 1] = '\0'; }
|
|
|
|
static void yearlist_to_string(const struct year_listlink *const y,
|
|
|
|
char (*const a)[12]) { year_to_string((const struct year *)y, a); }
|
|
|
|
#define TABLE_NAME year
|
|
|
|
#define TABLE_KEY struct year *
|
|
|
|
#define TABLE_UINT unsigned
|
|
|
|
#define TABLE_HASH &hash_year
|
|
|
|
#define TABLE_IS_EQUAL &year_is_equal
|
|
|
|
#define TABLE_EXPECT_TRAIT
|
|
|
|
#include "../src/table.h"
|
|
|
|
#define TABLE_DEFAULT 0
|
|
|
|
#define TABLE_EXPECT_TRAIT
|
|
|
|
#include "../src/table.h"
|
|
|
|
#define TABLE_TO_STRING &year_to_string
|
|
|
|
#include "../src/table.h"
|
2022-02-10 23:30:11 -05:00
|
|
|
|
2022-02-11 03:28:28 -05:00
|
|
|
#include <unistd.h> /* chdir (POSIX) */
|
|
|
|
#include <sys/types.h> /* mode_t (POSIX) */
|
|
|
|
#include <sys/stat.h> /* umask (POSIX) */
|
|
|
|
#include <dirent.h> /* opendir readdir closedir */
|
|
|
|
#include <limits.h>
|
2022-02-10 23:30:11 -05:00
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
int success = EXIT_FAILURE;
|
2022-02-11 03:28:28 -05:00
|
|
|
DIR *year_dir;
|
|
|
|
struct dirent *year_de;
|
|
|
|
struct year_pool year_pool = POOL_IDLE;
|
|
|
|
struct year_list order;
|
|
|
|
struct year_table years = TABLE_IDLE;
|
|
|
|
|
|
|
|
/* Get the years list. fixme: this is way overkill; `int_array`. */
|
|
|
|
errno = 0;
|
|
|
|
year_list_clear(&order);
|
2022-02-10 23:30:11 -05:00
|
|
|
if(argc != 2) { fprintf(stderr, "Needs journal location.\n"
|
|
|
|
"(should contain <year>/<month>/<day>.txt)\n"); goto finally; }
|
2022-02-11 03:28:28 -05:00
|
|
|
if(chdir(argv[1]) == -1 || !(year_dir = opendir("."))) goto catch;
|
|
|
|
while((year_de = readdir(year_dir))) {
|
|
|
|
struct stat st;
|
|
|
|
char *const start = year_de->d_name, *end;
|
|
|
|
long year = strtol(start, &end, 0); /* Need better. */
|
|
|
|
struct year *y;
|
|
|
|
if(errno || *end != '\0' || (size_t)(end - start) >= year_string_size
|
|
|
|
|| year < INT_MIN || year > INT_MAX)
|
|
|
|
{ /*fprintf(stderr, "%s: doesn't look like a year.\n",
|
|
|
|
year_de->d_name);*/ errno = 0; continue; }
|
|
|
|
if(stat(year_de->d_name, &st)) goto catch;
|
|
|
|
if(!S_ISDIR(st.st_mode)) { /*fprintf(stderr,
|
|
|
|
"%s: isn't a directory.\n", year_de->d_name);*/ continue; }
|
|
|
|
if(!(y = year_pool_new(&year_pool))) goto catch;
|
|
|
|
y->year = (int)year;
|
|
|
|
strcpy(y->as_string, year_de->d_name);
|
|
|
|
year_list_push(&order, &y->link);
|
|
|
|
}
|
|
|
|
year_list_sort(&order);
|
|
|
|
fprintf(stderr, "Years: %s\n", year_list_to_string(&order));
|
2022-02-10 23:30:11 -05:00
|
|
|
|
2022-02-11 03:28:28 -05:00
|
|
|
/* Go though each of the years, in order, and extract meta-information. */
|
2022-02-10 23:30:11 -05:00
|
|
|
{ success = EXIT_SUCCESS; goto finally; }
|
|
|
|
catch:
|
|
|
|
perror("interpret");
|
|
|
|
finally:
|
2022-02-11 03:28:28 -05:00
|
|
|
year_table_(&years);
|
|
|
|
year_pool_(&year_pool);
|
2022-02-10 23:30:11 -05:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|