aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--serd/serd.h5
-rw-r--r--src/byte_source.c15
-rw-r--r--src/byte_source.h9
-rw-r--r--src/reader.c57
-rw-r--r--src/serd_internal.h22
-rw-r--r--src/serdi.c76
-rw-r--r--src/world.c23
-rw-r--r--src/world.h2
-rw-r--r--tests/serd_test.c40
9 files changed, 123 insertions, 126 deletions
diff --git a/serd/serd.h b/serd/serd.h
index 7b24fd74..0f937b24 100644
--- a/serd/serd.h
+++ b/serd/serd.h
@@ -903,12 +903,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.
diff --git a/src/byte_source.c b/src/byte_source.c
index c48d8ef7..25184f13 100644
--- a/src/byte_source.c
+++ b/src/byte_source.c
@@ -39,6 +39,7 @@ SerdStatus
serd_byte_source_open_source(SerdByteSource* source,
SerdSource 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 = (char*)serd_bufalloc(page_size);
@@ -92,11 +94,16 @@ 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;
}
SerdStatus
diff --git a/src/byte_source.h b/src/byte_source.h
index c6c4702e..fa016ee5 100644
--- a/src/byte_source.h
+++ b/src/byte_source.h
@@ -23,6 +23,8 @@
#include <stddef.h>
#include <stdio.h>
+typedef int (*SerdStreamCloseFunc)(void*);
+
typedef struct {
const char* filename;
unsigned line;
@@ -32,6 +34,7 @@ typedef struct {
typedef struct {
SerdSource 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
@@ -45,17 +48,13 @@ typedef struct {
} SerdByteSource;
SerdStatus
-serd_byte_source_open_file(SerdByteSource* source,
- FILE* file,
- bool bulk);
-
-SerdStatus
serd_byte_source_open_string(SerdByteSource* source, const char* utf8);
SerdStatus
serd_byte_source_open_source(SerdByteSource* source,
SerdSource 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 9a3da25f..28c2b2f0 100644
--- a/src/reader.c
+++ b/src/reader.c
@@ -219,37 +219,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) {
- free(path);
- return SERD_ERR_UNKNOWN;
- }
-
- SerdStatus st = serd_reader_start_stream(
- reader, (SerdSource)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)
{
@@ -276,7 +245,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 ? (SerdSource)fread : serd_file_read_byte,
+ (SerdStreamErrorFunc)ferror,
+ (SerdStreamCloseFunc)fclose,
+ fd,
+ uri,
+ bulk ? SERD_PAGE_SIZE : 1);
}
SerdStatus
diff --git a/src/serd_internal.h b/src/serd_internal.h
index 601af56c..9200776d 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 <fcntl.h>
#endif
@@ -42,19 +42,17 @@
# 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;
+ 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 01484c8c..2c87e5e9 100644
--- a/src/serdi.c
+++ b/src/serdi.c
@@ -22,6 +22,7 @@
#include <string.h>
#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__);
@@ -115,19 +116,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)
-{
- 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)
{
@@ -135,25 +123,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;
@@ -172,8 +158,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') {
@@ -214,22 +199,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;
}
@@ -245,7 +217,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);
}
@@ -292,19 +264,26 @@ 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 ? (SerdSource)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);
+ }
+
+ if (!status) {
+ status = serd_reader_read_document(reader);
}
- status = serd_reader_read_document(reader);
+ if (status) {
+ SERDI_ERRORF("read error: %s\n", serd_strerror(status));
+ }
serd_reader_end_stream(reader);
@@ -314,13 +293,8 @@ main(int argc, char** argv)
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 55ea4559..62517f88 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 <stdarg.h>
+#include <stdio.h>
+#if defined(HAVE_POSIX_FADVISE)
+# include <fcntl.h>
+#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 98f1950b..dab5254d 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 serd_world_errorf(SerdWorld* world,
diff --git a/tests/serd_test.c b/tests/serd_test.c
index 5b60a03c..f5761fe7 100644
--- a/tests/serd_test.c
+++ b/tests/serd_test.c
@@ -632,8 +632,8 @@ main(void)
// Rewind and test reader
fseek(fd, 0, SEEK_SET);
- ReaderTest* rt = (ReaderTest*)calloc(1, sizeof(ReaderTest));
- SerdSinkInterface sink = { rt, NULL, NULL, test_sink, NULL };
+ ReaderTest rt = { 0, NULL };
+ SerdSinkInterface sink = { &rt, NULL, NULL, test_sink, NULL };
SerdReader* reader = serd_reader_new(world, SERD_TURTLE, &sink);
if (!reader) {
FAIL("Failed to create reader\n");
@@ -645,23 +645,25 @@ main(void)
serd_reader_add_blank_prefix(reader, NULL);
serd_node_free(g);
- if (!serd_reader_read_file(reader, "http://notafile")) {
- FAIL("Apparently read an http URI\n");
- } else if (!serd_reader_read_file(reader, "file:///better/not/exist")) {
- FAIL("Apparently read a non-existent file\n");
- } else if (!serd_reader_read_file(reader, "file://")) {
- FAIL("Apparently read a file with no path\n");
- }
-
- const SerdStatus st = serd_reader_read_file(reader, path);
- if (st) {
- FAILF("Error reading file (%s)\n", serd_strerror(st));
- } else if (rt->n_statements != 13) {
- FAILF("Bad statement count %d\n", rt->n_statements);
- } else if (!rt->graph || !serd_node_get_string(rt->graph) ||
- strcmp(serd_node_get_string(rt->graph), "http://example.org/")) {
- FAILF("Bad graph %p\n", rt->graph);
- }
+ if (!serd_reader_start_file(reader, "http://notafile", false)) {
+ FAIL("Apparently can read an http URI\n");
+ } else if (!serd_reader_start_file(reader, "file://invalid", false)) {
+ FAIL("Apparently can read an invalid file URI\n");
+ } else if (!serd_reader_start_file(reader, "file:///nonexistant", false)) {
+ FAIL("Apparently can read a non-existent file\n");
+ }
+
+ if (serd_reader_start_file(reader, path, true)) {
+ FAIL("Failed to open test file\n");
+ } else if (serd_reader_read_document(reader)) {
+ FAIL("Failed reading test document\n");
+ } else if (rt.n_statements != 13) {
+ FAILF("Bad statement count %d\n", rt.n_statements);
+ } else if (!rt.graph || !serd_node_get_string(rt.graph) ||
+ strcmp(serd_node_get_string(rt.graph), "http://example.org/")) {
+ FAILF("Bad graph %p\n", rt.graph);
+ }
+ serd_reader_end_stream(reader);
if (!serd_reader_read_string(reader, "This isn't Turtle at all.")) {
FAIL("Parsed invalid string successfully.\n");