// Copyright 2011-2021 David Robillard // SPDX-License-Identifier: ISC #include "serd_config.h" #include "serd/input_stream.h" #include "serd/status.h" #include "serd/stream.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(const SerdReadFunc read_func, const SerdErrorFunc error_func, const SerdCloseFunc 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 (void)posix_fadvise(fileno(file), 0, 0, POSIX_FADV_SEQUENTIAL); #endif input.stream = file; input.read = (SerdReadFunc)fread; input.error = (SerdErrorFunc)ferror; input.close = (SerdCloseFunc)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_BAD_STREAM : SERD_SUCCESS; }