diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/.clang-tidy | 1 | ||||
-rw-r--r-- | src/byte_source.c | 155 | ||||
-rw-r--r-- | src/byte_source.h | 56 | ||||
-rw-r--r-- | src/input_stream.c | 150 | ||||
-rw-r--r-- | src/node_syntax.c | 12 | ||||
-rw-r--r-- | src/reader.c | 10 |
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; } |