From b3892cb6e4963e1bbeb346a8124101b7c3cf379b Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 14 Aug 2021 01:51:55 -0400 Subject: Simplify input stream API More or less the same rationale as the previous commit, but for reading. This makes for nice symmetry with writing, at the cost of a slightly more annoying reader interface since the source doesn't know its block size or name. --- src/input_stream.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 src/input_stream.c (limited to 'src/input_stream.c') 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 + + 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 + +#if USE_POSIX_FADVISE && USE_FILENO +# include +#endif + +// IWYU pragma: no_include + +#include +#include +#include + +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; +} -- cgit v1.2.1