88 lines
2.6 KiB
C
88 lines
2.6 KiB
C
/** @license 20xx Neil Edelman, distributed under the terms of the
|
|
[GNU General Public License 3](https://opensource.org/licenses/GPL-3.0).
|
|
@license 20xx Neil Edelman, distributed under the terms of the
|
|
[MIT License](https://opensource.org/licenses/MIT).
|
|
|
|
This is a standard C file.
|
|
|
|
@std C89 */
|
|
|
|
#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;
|
|
}
|
|
|
|
int main(void) {
|
|
int success = EXIT_SUCCESS;
|
|
DIR *dir = 0;
|
|
struct dirent *de = 0;
|
|
struct char_array book[66] = { 0 };
|
|
const unsigned book_size = sizeof book / sizeof *book;
|
|
unsigned i;
|
|
errno = 0;
|
|
|
|
/* Read all files in <KJV/>. */
|
|
if(chdir("KJV") == -1 || !(dir = opendir("."))) goto catch;
|
|
while((de = readdir(dir))) {
|
|
unsigned book_no;
|
|
if(!kjv_filename(de->d_name, &book_no))
|
|
{ fprintf(stderr, "Ignored <%s>.\n", de->d_name); continue; }
|
|
printf("<%s> book_no: %u\n", de->d_name, book_no);
|
|
if(!book_no || book_no > book_size || book[book_no - 1].data)
|
|
{ errno = ERANGE; goto catch; }
|
|
if(!append_file(book + book_no - 1, de->d_name)) goto catch;
|
|
}
|
|
closedir(dir), de = 0, dir = 0;
|
|
|
|
/* Check to see if all books are accounted for. */
|
|
for(i = 0; i < book_size; i++)
|
|
if(!book[i].data) { errno = EDOM; goto catch; }
|
|
|
|
/**/
|
|
goto finally;
|
|
catch:
|
|
success = EXIT_FAILURE;
|
|
perror(de ? de->d_name : "kjv");
|
|
if(dir && closedir(dir)) perror("dir");
|
|
finally:
|
|
for(i = 0; i < book_size; i++) char_array_(&book[i]);
|
|
return success;
|
|
}
|