aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.clang-tidy1
-rw-r--r--src/byte_source.c155
-rw-r--r--src/byte_source.h56
-rw-r--r--src/input_stream.c150
-rw-r--r--src/node_syntax.c12
-rw-r--r--src/reader.c10
6 files changed, 220 insertions, 164 deletions
diff --git a/src/.clang-tidy b/src/.clang-tidy
index 6daee064..4245a751 100644
--- a/src/.clang-tidy
+++ b/src/.clang-tidy
@@ -3,7 +3,6 @@ Checks: >
-*-magic-numbers,
-*-uppercase-literal-suffix,
-altera-*,
- -android-cloexec-fopen,
-bugprone-branch-clone,
-bugprone-easily-swappable-parameters,
-bugprone-reserved-identifier,
diff --git a/src/byte_source.c b/src/byte_source.c
index 567beee8..47753d83 100644
--- a/src/byte_source.c
+++ b/src/byte_source.c
@@ -17,21 +17,13 @@
#include "byte_source.h"
#include "caret.h"
-#include "serd_config.h"
#include "system.h"
#include "serd/serd.h"
-#include <sys/stat.h>
-
-#if USE_POSIX_FADVISE && USE_FILENO
-# include <fcntl.h>
-#endif
-
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -39,21 +31,21 @@ SerdStatus
serd_byte_source_page(SerdByteSource* const source)
{
uint8_t* const buf =
- (source->page_size > 1 ? source->file_buf : &source->read_byte);
+ (source->block_size > 1 ? source->block : &source->read_byte);
const size_t n_read =
- source->read_func(buf, 1, source->page_size, source->stream);
+ source->in->read(buf, 1, source->block_size, source->in->stream);
source->buf_size = n_read;
source->read_head = 0;
source->eof = false;
- if (n_read < source->page_size) {
+ if (n_read < source->block_size) {
buf[n_read] = '\0';
if (n_read == 0) {
source->eof = true;
- return (source->error_func(source->stream) ? SERD_ERR_UNKNOWN
- : SERD_FAILURE);
+ return (source->in->error(source->in->stream) ? SERD_ERR_UNKNOWN
+ : SERD_FAILURE);
}
}
@@ -63,43 +55,34 @@ serd_byte_source_page(SerdByteSource* const source)
static void
serd_byte_source_init_buffer(SerdByteSource* const source)
{
- if (source->page_size > 1) {
- source->file_buf = (uint8_t*)serd_allocate_buffer(source->page_size);
- source->read_buf = source->file_buf;
- memset(source->file_buf, '\0', source->page_size);
+ if (source->block_size > 1) {
+ source->block = (uint8_t*)serd_allocate_buffer(source->block_size);
+ source->read_buf = source->block;
+ memset(source->block, '\0', source->block_size);
} else {
source->read_buf = &source->read_byte;
}
}
SerdByteSource*
-serd_byte_source_new_function(const SerdReadFunc read_func,
- const SerdStreamErrorFunc error_func,
- const SerdStreamCloseFunc close_func,
- void* const stream,
- const SerdNode* const name,
- const size_t page_size)
+serd_byte_source_new_input(SerdInputStream* const input,
+ const SerdNode* const name,
+ const size_t block_size)
{
- assert(read_func);
- assert(error_func);
+ assert(input);
- if (!page_size) {
+ if (!block_size || !input->stream) {
return NULL;
}
SerdByteSource* source = (SerdByteSource*)calloc(1, sizeof(SerdByteSource));
- source->read_func = read_func;
- source->error_func = error_func;
- source->close_func = close_func;
- source->stream = stream;
- source->page_size = page_size;
- source->buf_size = page_size;
- source->type = FROM_FUNCTION;
-
source->name =
- name ? serd_node_copy(name) : serd_new_string(SERD_STRING("func"));
+ name ? serd_node_copy(name) : serd_new_string(SERD_STRING("input"));
+ source->in = input;
+ source->block_size = block_size;
+ source->buf_size = block_size;
source->caret.file = source->name;
source->caret.line = 1u;
source->caret.col = 1u;
@@ -109,107 +92,27 @@ serd_byte_source_new_function(const SerdReadFunc read_func,
return source;
}
-static bool
-is_directory(const char* const path)
-{
-#ifdef _MSC_VER
- struct stat st;
- return !stat(path, &st) && (st.st_mode & _S_IFDIR);
-#else
- struct stat st;
- return !stat(path, &st) && S_ISDIR(st.st_mode);
-#endif
-}
-
-SerdByteSource*
-serd_byte_source_new_filename(const char* const path, const size_t page_size)
+void
+serd_byte_source_free(SerdByteSource* const source)
{
- assert(path);
-
- if (page_size == 0 || is_directory(path)) {
- return NULL;
- }
+ if (source) {
+ if (source->block_size > 1) {
+ serd_free_aligned(source->block);
+ }
- FILE* const fd = fopen(path, "rb");
- if (!fd) {
- return NULL;
+ serd_node_free(source->name);
+ free(source);
}
-
- SerdByteSource* source = (SerdByteSource*)calloc(1, sizeof(SerdByteSource));
-
- source->read_func = (SerdReadFunc)fread;
- source->error_func = (SerdStreamErrorFunc)ferror;
- source->close_func = (SerdStreamCloseFunc)fclose;
- source->stream = fd;
- source->page_size = page_size;
- source->buf_size = page_size;
-
- source->name = serd_new_file_uri(SERD_STRING(path), SERD_EMPTY_STRING());
- source->type = FROM_FILENAME;
-
- source->caret.file = source->name;
- source->caret.line = 1u;
- source->caret.col = 1u;
-
- serd_byte_source_init_buffer(source);
-
-#if USE_POSIX_FADVISE && USE_FILENO
- posix_fadvise(fileno(fd), 0, 0, POSIX_FADV_SEQUENTIAL);
-#endif
-
- return source;
-}
-
-SerdByteSource*
-serd_byte_source_new_string(const char* const string,
- const SerdNode* const name)
-{
- assert(string);
-
- SerdByteSource* source = (SerdByteSource*)calloc(1, sizeof(SerdByteSource));
-
- source->page_size = 1;
- source->read_buf = (const uint8_t*)string;
- source->type = FROM_STRING;
-
- source->name =
- name ? serd_node_copy(name) : serd_new_string(SERD_STRING("string"));
-
- source->caret.file = source->name;
- source->caret.line = 1u;
- source->caret.col = 1u;
-
- return source;
}
SerdStatus
serd_byte_source_prepare(SerdByteSource* const source)
{
source->prepared = true;
- if (source->type != FROM_STRING) {
- if (source->page_size > 1) {
- return serd_byte_source_page(source);
- }
- return serd_byte_source_advance(source);
+ if (source->block_size > 1) {
+ return serd_byte_source_page(source);
}
- return SERD_SUCCESS;
-}
-
-void
-serd_byte_source_free(SerdByteSource* const source)
-{
- if (source) {
- if (source->close_func) {
- source->close_func(source->stream);
- }
-
- if (source->page_size > 1) {
- serd_free_aligned(source->file_buf);
- }
-
- serd_node_free(source->name);
- free(source);
- }
+ return serd_byte_source_advance(source);
}
diff --git a/src/byte_source.h b/src/byte_source.h
index d054e156..2bd06bdf 100644
--- a/src/byte_source.h
+++ b/src/byte_source.h
@@ -1,5 +1,5 @@
/*
- Copyright 2011-2020 David Robillard <d@drobilla.net>
+ Copyright 2011-2021 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -26,29 +26,27 @@
#include <stddef.h>
#include <stdint.h>
-typedef enum {
- FROM_STRING, ///< Reading from a user-provided buffer
- FROM_FILENAME, ///< Reading from a file we opened
- FROM_FUNCTION, ///< Reading from a user-provided function
-} SerdByteSourceType;
-
-struct SerdByteSourceImpl {
- 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
- size_t buf_size; ///< Number of bytes in file_buf
- SerdNode* name; ///< Name of stream (referenced by cur)
- SerdCaret caret; ///< File position for error reporting
- uint8_t* file_buf; ///< Buffer iff reading pages from a file
- const uint8_t* read_buf; ///< Pointer to file_buf or read_byte
- size_t read_head; ///< Offset into read_buf
- SerdByteSourceType type; ///< Type of input
- uint8_t read_byte; ///< 1-byte 'buffer' used when not paging
- bool prepared; ///< True iff prepared for reading
- bool eof; ///< True iff end of file reached
-};
+typedef struct {
+ SerdInputStream* in; ///< Input stream to read from
+ size_t block_size; ///< Number of bytes to read at a time
+ size_t buf_size; ///< Number of bytes in block
+ SerdNode* name; ///< Name of stream (for caret)
+ SerdCaret caret; ///< File position for error reporting
+ uint8_t* block; ///< Buffer if reading blocks
+ const uint8_t* read_buf; ///< Pointer to block or read_byte
+ size_t read_head; ///< Offset into read_buf
+ uint8_t read_byte; ///< 1-byte 'buffer' if reading bytes
+ bool prepared; ///< True iff prepared for reading
+ bool eof; ///< True iff end of file reached
+} SerdByteSource;
+
+SerdByteSource*
+serd_byte_source_new_input(SerdInputStream* input,
+ const SerdNode* name,
+ size_t block_size);
+
+void
+serd_byte_source_free(SerdByteSource* source);
SerdStatus
serd_byte_source_prepare(SerdByteSource* source);
@@ -71,6 +69,8 @@ serd_byte_source_advance(SerdByteSource* source)
const bool was_eof = source->eof;
switch (serd_byte_source_peek(source)) {
+ case '\0':
+ break;
case '\n':
++source->caret.line;
source->caret.col = 0;
@@ -79,12 +79,8 @@ serd_byte_source_advance(SerdByteSource* source)
++source->caret.col;
}
- if (source->type != FROM_STRING) {
- if (++source->read_head >= source->buf_size) {
- st = serd_byte_source_page(source);
- }
- } else if (!source->eof) {
- source->eof = source->read_buf[++source->read_head] == '\0';
+ if (++source->read_head >= source->buf_size) {
+ st = serd_byte_source_page(source);
}
return (was_eof && source->eof) ? SERD_FAILURE : st;
diff --git a/src/input_stream.c b/src/input_stream.c
new file mode 100644
index 00000000..42dfc6f8
--- /dev/null
+++ b/src/input_stream.c
@@ -0,0 +1,150 @@
+/*
+ Copyright 2011-2021 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "serd_config.h"
+
+#include "serd/serd.h"
+
+#include <sys/stat.h>
+
+#if USE_POSIX_FADVISE && USE_FILENO
+# include <fcntl.h>
+#endif
+
+// IWYU pragma: no_include <features.h>
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+static size_t
+serd_string_read(void* const buf,
+ const size_t size,
+ const size_t nmemb,
+ void* const stream)
+{
+ const char** position = (const char**)stream;
+
+ size_t n_read = 0u;
+ const size_t len = size * nmemb;
+ while (n_read < len && **position) {
+ ((char*)buf)[n_read++] = **position;
+
+ ++(*position);
+ }
+
+ return n_read;
+}
+
+static int
+serd_string_error(void* const stream)
+{
+ (void)stream;
+ return 0;
+}
+
+static int
+serd_string_close(void* const stream)
+{
+ (void)stream;
+ return 0;
+}
+
+SerdInputStream
+serd_open_input_stream(SerdReadFunc SERD_NONNULL read_func,
+ SerdStreamErrorFunc SERD_NONNULL error_func,
+ SerdStreamCloseFunc SERD_NULLABLE close_func,
+ void* const stream)
+{
+ assert(read_func);
+ assert(error_func);
+
+ SerdInputStream input = {stream, read_func, error_func, close_func};
+ return input;
+}
+
+static bool
+is_directory(const char* const path)
+{
+#ifdef _MSC_VER
+ struct stat st;
+ return !stat(path, &st) && (st.st_mode & _S_IFDIR);
+#else
+ struct stat st;
+ return !stat(path, &st) && S_ISDIR(st.st_mode);
+#endif
+}
+
+SerdInputStream
+serd_open_input_string(const char** const position)
+{
+ assert(position);
+ assert(*position);
+
+ const SerdInputStream input = {
+ position, serd_string_read, serd_string_error, serd_string_close};
+
+ return input;
+}
+
+SerdInputStream
+serd_open_input_file(const char* const path)
+{
+ assert(path);
+
+ SerdInputStream input = {NULL, NULL, NULL, NULL};
+ if (is_directory(path)) {
+ return input;
+ }
+
+#ifdef __GLIBC__
+ FILE* const file = fopen(path, "rbe");
+#else
+ FILE* const file = fopen(path, "rb");
+#endif
+
+ if (!file) {
+ return input;
+ }
+
+#if USE_POSIX_FADVISE && USE_FILENO
+ posix_fadvise(fileno(file), 0, 0, POSIX_FADV_SEQUENTIAL);
+#endif
+
+ input.stream = file;
+ input.read = (SerdReadFunc)fread;
+ input.error = (SerdStreamErrorFunc)ferror;
+ input.close = (SerdStreamCloseFunc)fclose;
+
+ return input;
+}
+
+SerdStatus
+serd_close_input(SerdInputStream* const input)
+{
+ int ret = 0;
+
+ if (input) {
+ if (input->close && input->stream) {
+ ret = input->close(input->stream);
+ input->stream = NULL;
+ }
+
+ input->stream = NULL;
+ }
+
+ return ret ? SERD_ERR_UNKNOWN : SERD_SUCCESS;
+}
diff --git a/src/node_syntax.c b/src/node_syntax.c
index d2768c3e..5c579b84 100644
--- a/src/node_syntax.c
+++ b/src/node_syntax.c
@@ -54,8 +54,7 @@ serd_node_from_syntax_in(const char* const str,
SerdWorld* const world = serd_world_new();
SerdSink* const sink = serd_sink_new(&object, on_node_string_event, NULL);
- SerdByteSource* const source = serd_byte_source_new_string(doc, NULL);
- SerdReader* const reader =
+ SerdReader* const reader =
serd_reader_new(world,
syntax,
SERD_READ_RELATIVE | SERD_READ_GLOBAL | SERD_READ_GENERATED,
@@ -63,11 +62,16 @@ serd_node_from_syntax_in(const char* const str,
sink,
1024 + doc_len);
- serd_reader_start(reader, source);
+ const SerdNode* string_name =
+ serd_nodes_string(serd_world_nodes(world), SERD_STRING("string"));
+
+ const char* position = doc;
+ SerdInputStream in = serd_open_input_string(&position);
+ serd_reader_start(reader, &in, string_name, 1);
serd_reader_read_document(reader);
serd_reader_finish(reader);
+ serd_close_input(&in);
serd_reader_free(reader);
- serd_byte_source_free(source);
serd_sink_free(sink);
serd_world_free(world);
free(doc);
diff --git a/src/reader.c b/src/reader.c
index c8a66c42..d051c34a 100644
--- a/src/reader.c
+++ b/src/reader.c
@@ -310,14 +310,17 @@ skip_bom(SerdReader* const me)
}
SerdStatus
-serd_reader_start(SerdReader* const reader, SerdByteSource* const byte_source)
+serd_reader_start(SerdReader* const reader,
+ SerdInputStream* const input,
+ const SerdNode* const input_name,
+ const size_t block_size)
{
assert(reader);
- assert(byte_source);
+ assert(input);
serd_reader_finish(reader);
- reader->source = byte_source;
+ reader->source = serd_byte_source_new_input(input, input_name, block_size);
return reader->source ? SERD_SUCCESS : SERD_ERR_BAD_ARG;
}
@@ -358,6 +361,7 @@ serd_reader_finish(SerdReader* const reader)
{
assert(reader);
+ serd_byte_source_free(reader->source);
reader->source = NULL;
return SERD_SUCCESS;
}