From 512ba5176d862bcd0f0f799385ea15637b3aa5a2 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 26 Dec 2018 19:25:51 -0500 Subject: Hide fopen wrapper and use reader interface consistently --- serd/serd.h | 14 +++------- src/byte_source.c | 15 ++++++++--- src/byte_source.h | 9 +++---- src/reader.c | 70 ++++++++++++++++++----------------------------- src/serd_internal.h | 25 ++++++++--------- src/serdi.c | 78 +++++++++++++++-------------------------------------- src/world.c | 23 ++++++++++++++++ src/world.h | 2 ++ tests/serd_test.c | 24 ++++++++--------- 9 files changed, 115 insertions(+), 145 deletions(-) diff --git a/serd/serd.h b/serd/serd.h index 3ecd6e98..8f56ef02 100644 --- a/serd/serd.h +++ b/serd/serd.h @@ -922,12 +922,11 @@ serd_reader_set_default_graph(SerdReader* reader, const SerdNode* graph); /** - Read a file at a given `uri`. + Prepare to read from the file at a local file `uri`. */ SERD_API SerdStatus -serd_reader_read_file(SerdReader* reader, - const char* uri); +serd_reader_start_file(SerdReader* reader, const char* uri, bool bulk); /** Prepare to read from a stream. @@ -979,14 +978,7 @@ serd_reader_read_document(SerdReader* reader); */ SERD_API SerdStatus -serd_reader_end_stream(SerdReader* reader); - -/** - Read `utf8`. -*/ -SERD_API -SerdStatus -serd_reader_read_string(SerdReader* reader, const char* utf8); +serd_reader_finish(SerdReader* reader); /** Free `reader`. diff --git a/src/byte_source.c b/src/byte_source.c index 5c38e53c..2d79e161 100644 --- a/src/byte_source.c +++ b/src/byte_source.c @@ -39,6 +39,7 @@ SerdStatus serd_byte_source_open_source(SerdByteSource* source, SerdReadFunc read_func, SerdStreamErrorFunc error_func, + SerdStreamCloseFunc close_func, void* stream, const char* name, size_t page_size) @@ -46,12 +47,13 @@ serd_byte_source_open_source(SerdByteSource* source, const Cursor cur = { name, 1, 1 }; memset(source, '\0', sizeof(*source)); + source->read_func = read_func; + source->error_func = error_func; + source->close_func = close_func; source->stream = stream; - source->from_stream = true; source->page_size = page_size; source->cur = cur; - source->error_func = error_func; - source->read_func = read_func; + source->from_stream = true; if (page_size > 1) { source->file_buf = (uint8_t*)serd_bufalloc(page_size); @@ -92,9 +94,14 @@ serd_byte_source_open_string(SerdByteSource* source, const char* utf8) SerdStatus serd_byte_source_close(SerdByteSource* source) { + SerdStatus st = SERD_SUCCESS; + if (source->close_func) { + st = source->close_func(source->stream) ? SERD_ERR_UNKNOWN + : SERD_SUCCESS; + } if (source->page_size > 1) { free(source->file_buf); } memset(source, '\0', sizeof(*source)); - return SERD_SUCCESS; + return st; } diff --git a/src/byte_source.h b/src/byte_source.h index fc5947fa..b642c0a2 100644 --- a/src/byte_source.h +++ b/src/byte_source.h @@ -23,6 +23,8 @@ #include #include +typedef int (*SerdStreamCloseFunc)(void*); + typedef struct { const char* filename; unsigned line; @@ -32,6 +34,7 @@ typedef struct { typedef struct { SerdReadFunc read_func; ///< Read function (e.g. fread) SerdStreamErrorFunc error_func; ///< Error function (e.g. ferror) + SerdStreamCloseFunc close_func; ///< Function for closing stream void* stream; ///< Stream (e.g. FILE) size_t page_size; ///< Number of bytes to read at a time Cursor cur; ///< Cursor for error reporting @@ -44,11 +47,6 @@ typedef struct { bool eof; ///< True iff end of file reached } SerdByteSource; -SerdStatus -serd_byte_source_open_file(SerdByteSource* source, - FILE* file, - bool bulk); - SerdStatus serd_byte_source_open_string(SerdByteSource* source, const char* utf8); @@ -56,6 +54,7 @@ SerdStatus serd_byte_source_open_source(SerdByteSource* source, SerdReadFunc read_func, SerdStreamErrorFunc error_func, + SerdStreamCloseFunc close_func, void* stream, const char* name, size_t page_size); diff --git a/src/reader.c b/src/reader.c index a9db44f9..f8459e45 100644 --- a/src/reader.c +++ b/src/reader.c @@ -218,37 +218,6 @@ serd_reader_set_default_graph(SerdReader* reader, reader->default_graph = serd_node_copy(graph); } -SerdStatus -serd_reader_read_file(SerdReader* reader, - const char* uri) -{ - char* const path = serd_file_uri_parse(uri, NULL); - if (!path) { - return SERD_ERR_BAD_ARG; - } - - FILE* fd = serd_fopen(path, "rb"); - if (!fd) { - serd_free(path); - return SERD_ERR_UNKNOWN; - } - - SerdStatus st = serd_reader_start_stream( - reader, (SerdReadFunc)fread, (SerdStreamErrorFunc)ferror, - fd, path, SERD_PAGE_SIZE); - - if (!st) { - st = serd_reader_read_document(reader); - } - - const SerdStatus est = serd_reader_end_stream(reader); - - fclose(fd); - free(path); - - return st ? st : est; -} - static SerdStatus skip_bom(SerdReader* me) { @@ -275,7 +244,31 @@ serd_reader_start_stream(SerdReader* reader, size_t page_size) { return serd_byte_source_open_source( - &reader->source, read_func, error_func, stream, name, page_size); + &reader->source, read_func, error_func, NULL, stream, name, page_size); +} + +SerdStatus +serd_reader_start_file(SerdReader* reader, const char* uri, bool bulk) +{ + char* const path = serd_file_uri_parse(uri, NULL); + if (!path) { + return SERD_ERR_BAD_ARG; + } + + FILE* fd = serd_world_fopen(reader->world, path, "rb"); + free(path); + if (!fd) { + return SERD_ERR_UNKNOWN; + } + + return serd_byte_source_open_source( + &reader->source, + bulk ? (SerdReadFunc)fread : serd_file_read_byte, + (SerdStreamErrorFunc)ferror, + (SerdStreamCloseFunc)fclose, + fd, + uri, + bulk ? SERD_PAGE_SIZE : 1); } SerdStatus @@ -312,18 +305,7 @@ serd_reader_read_chunk(SerdReader* reader) } SerdStatus -serd_reader_end_stream(SerdReader* reader) +serd_reader_finish(SerdReader* reader) { return serd_byte_source_close(&reader->source); } - -SerdStatus -serd_reader_read_string(SerdReader* reader, const char* utf8) -{ - serd_reader_start_string(reader, utf8); - - const SerdStatus st = serd_reader_read_document(reader); - const SerdStatus est = serd_byte_source_close(&reader->source); - - return st ? st : est; -} diff --git a/src/serd_internal.h b/src/serd_internal.h index 601af56c..f06c7051 100644 --- a/src/serd_internal.h +++ b/src/serd_internal.h @@ -29,7 +29,7 @@ #include "world.h" -#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_FILENO) +#if defined(HAVE_FILENO) # include #endif @@ -42,19 +42,20 @@ # define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif -static inline FILE* -serd_fopen(const char* path, const char* mode) +/** fread-like wrapper for getc (which is faster). */ +static inline size_t +serd_file_read_byte(void* buf, size_t size, size_t nmemb, void* stream) { - FILE* fd = fopen(path, mode); - if (!fd) { - fprintf(stderr, "error: failed to open file %s (%s)\n", - path, strerror(errno)); - return NULL; + (void)size; + (void)nmemb; + + const int c = getc((FILE*)stream); + if (c == EOF) { + *((uint8_t*)buf) = 0; + return 0; } -#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_FILENO) - posix_fadvise(fileno(fd), 0, 0, POSIX_FADV_SEQUENTIAL); -#endif - return fd; + *((uint8_t*)buf) = (uint8_t)c; + return 1; } static inline void* diff --git a/src/serdi.c b/src/serdi.c index c132eaf8..04919941 100644 --- a/src/serdi.c +++ b/src/serdi.c @@ -22,6 +22,7 @@ #include #include "string_utils.h" +#include "world.h" #define SERDI_ERROR(msg) fprintf(stderr, "serdi: " msg); #define SERDI_ERRORF(fmt, ...) fprintf(stderr, "serdi: " fmt, __VA_ARGS__); @@ -117,22 +118,6 @@ quiet_error_sink(void* handle, const SerdError* e) return SERD_SUCCESS; } -/** fread-like wrapper for getc (which is faster). */ -static size_t -serd_file_read_byte(void* buf, size_t size, size_t nmemb, void* stream) -{ - (void)size; - (void)nmemb; - - const int c = getc((FILE*)stream); - if (c == EOF) { - *((uint8_t*)buf) = 0; - return 0; - } - *((uint8_t*)buf) = (uint8_t)c; - return 1; -} - int main(int argc, char** argv) { @@ -140,25 +125,23 @@ main(int argc, char** argv) return print_usage(argv[0], true); } - FILE* in_fd = NULL; SerdSyntax input_syntax = (SerdSyntax)0; SerdSyntax output_syntax = (SerdSyntax)0; - bool from_file = true; + bool from_string = false; + bool from_stdin = false; bool ascii = false; bool bulk_read = true; bool bulk_write = false; bool full_uris = false; bool lax = false; bool quiet = false; - const char* in_name = NULL; const char* add_prefix = NULL; const char* chop_prefix = NULL; const char* root_uri = NULL; int a = 1; for (; a < argc && argv[a][0] == '-'; ++a) { if (argv[a][1] == '\0') { - in_name = (const char*)"(stdin)"; - in_fd = stdin; + from_stdin = true; break; } else if (argv[a][1] == 'a') { ascii = true; @@ -177,8 +160,7 @@ main(int argc, char** argv) } else if (argv[a][1] == 'v') { return print_version(); } else if (argv[a][1] == 's') { - in_name = (const char*)"(string)"; - from_file = false; + from_string = true; ++a; break; } else if (argv[a][1] == 'i') { @@ -219,22 +201,9 @@ main(int argc, char** argv) return 1; } - char* input_path = NULL; - const char* input = (const char*)argv[a++]; - if (from_file) { - in_name = in_name ? in_name : input; - if (!in_fd) { - if (!strncmp(input, "file:", 5)) { - input_path = serd_file_uri_parse(input, NULL); - input = input_path; - } - if (!input || !(in_fd = serd_fopen(input, "rb"))) { - return 1; - } - } - } + const char* input = (const char*)argv[a++]; - if (!input_syntax && !(input_syntax = guess_syntax(in_name))) { + if (!input_syntax && !(input_syntax = guess_syntax(input))) { input_syntax = SERD_TRIG; } @@ -250,7 +219,7 @@ main(int argc, char** argv) if (a < argc) { // Base URI given on command line base = serd_node_new_uri_from_string( (const char*)argv[a], NULL, &base_uri); - } else if (from_file && in_fd != stdin) { // Use input file URI + } else if (!from_string && !from_stdin) { // Use input file URI base = serd_node_new_file_uri(input, NULL, &base_uri, true); } @@ -301,35 +270,32 @@ main(int argc, char** argv) serd_node_free(root); SerdStatus status = SERD_SUCCESS; - if (!from_file) { + if (from_string) { status = serd_reader_start_string(reader, input); + } else if (from_stdin) { + status = serd_reader_start_stream(reader, + serd_file_read_byte, + (SerdStreamErrorFunc)ferror, + stdin, + "(stdin)", + 1); } else { - status = serd_reader_start_stream( - reader, - bulk_read ? (SerdReadFunc)fread : serd_file_read_byte, - (SerdStreamErrorFunc)ferror, - in_fd, - in_name, - bulk_read ? SERD_PAGE_SIZE : 1); + status = serd_reader_start_file(reader, input, bulk_read); } - status = serd_reader_read_document(reader); - - serd_reader_end_stream(reader); + if (!status) { + status = serd_reader_read_document(reader); + } + serd_reader_finish(reader); serd_reader_free(reader); serd_writer_finish(writer); serd_writer_free(writer); serd_env_free(env); serd_node_free(base); serd_world_free(world); - free(input_path); - - if (from_file) { - fclose(in_fd); - } - if (fclose(out_fd)) { + if (fclose(stdout)) { perror("serdi: write error"); status = SERD_ERR_UNKNOWN; } diff --git a/src/world.c b/src/world.c index 0210760d..7ec483e8 100644 --- a/src/world.c +++ b/src/world.c @@ -14,12 +14,35 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define _POSIX_C_SOURCE 200809L /* for posix_fadvise */ + #include "serd_internal.h" +#include "serd_config.h" #include +#include +#if defined(HAVE_POSIX_FADVISE) +# include +#endif #include "world.h" +FILE* +serd_world_fopen(SerdWorld* world, const char* path, const char* mode) +{ + FILE* fd = fopen(path, mode); + if (!fd) { + serd_world_errorf(world, SERD_ERR_INTERNAL, + "failed to open file %s (%s)\n", + path, strerror(errno)); + return NULL; + } +#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_FILENO) + posix_fadvise(fileno(fd), 0, 0, POSIX_FADV_SEQUENTIAL); +#endif + return fd; +} + SerdStatus serd_world_error(const SerdWorld* world, const SerdError* e) { diff --git a/src/world.h b/src/world.h index 7e451b0e..aeea70c2 100644 --- a/src/world.h +++ b/src/world.h @@ -24,6 +24,8 @@ struct SerdWorldImpl { void* error_handle; }; +FILE* serd_world_fopen(SerdWorld* world, const char* path, const char* mode); + SerdStatus serd_world_error(const SerdWorld* world, const SerdError* e); SerdStatus diff --git a/tests/serd_test.c b/tests/serd_test.c index da567a35..4278a089 100644 --- a/tests/serd_test.c +++ b/tests/serd_test.c @@ -532,8 +532,8 @@ main(void) // Rewind and test reader fseek(fd, 0, SEEK_SET); - ReaderTest* rt = (ReaderTest*)calloc(1, sizeof(ReaderTest)); - SerdSink sink = { rt, NULL, NULL, test_sink, NULL }; + ReaderTest rt = { 0, NULL }; + SerdSink sink = { &rt, NULL, NULL, test_sink, NULL }; SerdReader* reader = serd_reader_new(world, SERD_TURTLE, &sink); assert(reader); @@ -543,20 +543,18 @@ main(void) serd_reader_add_blank_prefix(reader, NULL); serd_node_free(g); - assert(serd_reader_read_file(reader, "http://notafile")); - assert(serd_reader_read_file(reader, "file:///better/not/exist")); - assert(serd_reader_read_file(reader, "file://")); + assert(serd_reader_start_file(reader, "http://notafile", false)); + assert(serd_reader_start_file(reader, "file://invalid", false)); + assert(serd_reader_start_file(reader, "file:///nonexistant", false)); - const SerdStatus st = serd_reader_read_file(reader, path); - assert(!st); - assert(rt->n_statements == 13); - assert(rt->graph && serd_node_get_string(rt->graph) && - !strcmp(serd_node_get_string(rt->graph), "http://example.org/")); - - assert(serd_reader_read_string(reader, "This isn't Turtle at all.")); + assert(!serd_reader_start_file(reader, path, true)); + assert(!serd_reader_read_document(reader)); + assert(rt.n_statements == 13); + assert(rt.graph && serd_node_get_string(rt.graph) && + !strcmp(serd_node_get_string(rt.graph), "http://example.org/")); + serd_reader_finish(reader); serd_reader_free(reader); - free(rt); fclose(fd); serd_env_free(env); -- cgit v1.2.1