109 lines
3.3 KiB
C
109 lines
3.3 KiB
C
/** @license 2022 Neil Edelman, distributed under the terms of the
|
|
[MIT License](https://opensource.org/licenses/MIT). */
|
|
|
|
#include "kjv.h"
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <dirent.h> /* opendir readdir closedir */
|
|
#include <unistd.h> /* chdir (POSIX) (because I'm lazy) */
|
|
|
|
#define ARRAY_NAME char
|
|
#define ARRAY_TYPE char
|
|
#include "array.h"
|
|
|
|
/** Append a text file, `fn`, to `c`, and add a '\0'.
|
|
@return Success. A partial read is failure. @throws[fopen, fread, malloc]
|
|
@throws[EISEQ] The text file has embedded nulls.
|
|
@throws[ERANGE] If the standard library does not follow POSIX. */
|
|
static int append_file(struct char_array *c, const char *const fn) {
|
|
FILE *fp = 0;
|
|
const size_t granularity = 1024;
|
|
size_t nread;
|
|
char *cursor;
|
|
int success = 0;
|
|
assert(c && fn);
|
|
if(!(fp = fopen(fn, "r"))) goto catch;
|
|
/* Read entire file in chunks. */
|
|
do if(!(cursor = char_array_buffer(c, granularity))
|
|
|| (nread = fread(cursor, 1, granularity, fp), ferror(fp))
|
|
|| !char_array_append(c, nread)) goto catch;
|
|
while(nread == granularity);
|
|
/* File to `C` string. */
|
|
if(!(cursor = char_array_new(c))) goto catch;
|
|
*cursor = '\0';
|
|
/* Binary files with embedded '\0' are not allowed. */
|
|
if(strchr(c->data, '\0') != cursor) { errno = EILSEQ; goto catch; }
|
|
{ success = 1; goto finally; }
|
|
catch:
|
|
if(!errno) errno = EILSEQ; /* Will never be true on POSIX. */
|
|
finally:
|
|
if(fp) fclose(fp);
|
|
return success;
|
|
}
|
|
|
|
#define ARRAY_NAME verse
|
|
#define ARRAY_TYPE struct verse_array
|
|
#include "array.h"
|
|
|
|
struct book { struct char_array backing; struct verse_array chapter; };
|
|
|
|
int main_new_chapter(struct book *const book) {
|
|
assert(book);
|
|
return 0;
|
|
}
|
|
|
|
struct verse *main_new_verse(struct verse_array *const chapter) {
|
|
assert(chapter);
|
|
return verse_array_new(chapter);
|
|
}
|
|
|
|
int main(void) {
|
|
const char *const dir_name = "KJV";
|
|
struct book kjv[KJV_BOOK_SIZE] = { 0 };
|
|
int success = EXIT_SUCCESS;
|
|
DIR *dir = 0;
|
|
struct dirent *de = 0;
|
|
unsigned i;
|
|
errno = 0;
|
|
|
|
/* Read in the kjv from all files.
|
|
fixme: this is lazy; all one object would be best. */
|
|
if(chdir(dir_name) == -1 || !(dir = opendir("."))) goto catch;
|
|
while((de = readdir(dir))) { /* For all files in directory. */
|
|
unsigned ordinal;
|
|
enum kjv_book b;
|
|
if(!kjv_filename(de->d_name, &ordinal)) /* Extract ordinal. */
|
|
{ fprintf(stderr, "Ignored <%s>.\n", de->d_name); continue; }
|
|
printf("<%s> ordinal: %u\n", de->d_name, ordinal);
|
|
if(ordinal < 1 || ordinal > KJV_BOOK_SIZE)
|
|
{ errno = ERANGE; goto catch; } /* Not in range. */
|
|
if(kjv[b = ordinal - 1].backing.data) /* Convert to zero-based. */
|
|
{ errno = EDOM; goto catch; } /* Duplicate. */
|
|
if(!append_file(&kjv[b].backing, de->d_name)) goto catch;
|
|
}
|
|
closedir(dir), de = 0, dir = 0;
|
|
|
|
/* Parse the files into chapters. */
|
|
for(i = 0; i < KJV_BOOK_SIZE; i++) {
|
|
if(!kjv[i].backing.data) { fprintf(stderr, "Missing book %u.\n", i + 1);
|
|
errno = EDOM; goto catch; }
|
|
/*for( ; ; ) { switch(kjv_chapter(kjv + i)) {
|
|
case KJV_ERROR: goto catch;
|
|
case KJV_DONE: goto finally;
|
|
case KJV_CHAPTER: break;
|
|
}}*/
|
|
}
|
|
|
|
goto finally;
|
|
catch:
|
|
success = EXIT_FAILURE;
|
|
perror(de ? de->d_name : dir_name);
|
|
if(dir && closedir(dir)) perror(dir_name);
|
|
finally:
|
|
for(i = 0; i < KJV_BOOK_SIZE; i++)
|
|
char_array_(&kjv[i].backing), verse_array_(&kjv[i].chapter);
|
|
return success;
|
|
}
|