star-buffer

Load 1D arrays in binary format
git clone git://git.meso-star.fr/star-buffer.git
Log | Files | Refs | README | LICENSE

commit 55d6dcdd77b4f3119a5b1303feb4d86f56b9c35f
parent e69db656ac7a8aaa346fecb0ca453fef60905330
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 24 Mar 2022 19:17:31 +0100

Implement the Star-Buffer library

Diffstat:
Acmake/CMakeLists.txt | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sbuf.c | 299+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sbuf.h | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sbuf_c.h | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/sbuf_log.c | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sbuf_log.h | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sbuf.c | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 832 insertions(+), 0 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -0,0 +1,118 @@ +# Copyright (C) 2020, 2021, 2022 |Meso|Star> (contact@meso-star.com) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +cmake_minimum_required(VERSION 3.1) +project(sbuf C) +enable_testing() + +set(SBUF_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src) +option(NO_TEST "Do not build tests" OFF) + +################################################################################ +# Check dependencies +################################################################################ +find_package(RCMake 0.4 REQUIRED) +find_package(RSys 0.10 REQUIRED) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR}) +include(rcmake) +include(rcmake_runtime) + +include_directories(${RSys_INCLUDE_DIR}) + +################################################################################ +# Configure and define targets +################################################################################ +set(VERSION_MAJOR 0) +set(VERSION_MINOR 0) +set(VERSION_PATCH 0) +set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) + +set(SBUF_FILES_SRC + sbuf.c + sbuf_log.c) +set(SBUF_FILES_INC + sbuf_c.h + sbuf_log.h) +set(SBUF_FILES_INC_API + sbuf.h) + +set(SBUF_FILES_DOC COPYING README.md) + +# Prepend each file in the `SBUF_FILES_<SRC|INC>' list by `SBUF_SOURCE_DIR' +rcmake_prepend_path(SBUF_FILES_SRC ${SBUF_SOURCE_DIR}) +rcmake_prepend_path(SBUF_FILES_INC ${SBUF_SOURCE_DIR}) +rcmake_prepend_path(SBUF_FILES_INC_API ${SBUF_SOURCE_DIR}) +rcmake_prepend_path(SBUF_FILES_DOC ${PROJECT_SOURCE_DIR}/../) + +add_library(sbuf SHARED ${SBUF_FILES_SRC} ${SBUF_FILES_INC} ${SBUF_FILES_INC_API}) +target_link_libraries(sbuf RSys) + +set_target_properties(sbuf PROPERTIES + DEFINE_SYMBOL SBUF_SHARED_BUILD + VERSION ${VERSION} + SOVERSION ${VERSION_MAJOR}) + +rcmake_setup_devel(sbuf StarBuffer ${VERSION} star/sbuf_version.h) + +################################################################################ +# Add tests +################################################################################ +if(NOT NO_TEST) + function(build_test _name) + add_executable(${_name} ${SBUF_SOURCE_DIR}/${_name}.c) + target_link_libraries(${_name} sbuf RSys ${ARGN}) + endfunction() + + function(new_test _name) + build_test(${_name} ${ARGN}) + add_test(${_name} ${_name}) + endfunction() + + new_test(test_sbuf) + #new_test(test_sbuf_load) +endif() + +################################################################################ +# Man page +############################################################################### +find_program(SCDOC NAMES scdoc) +if(NOT SCDOC) + message(WARNING + "The `scdoc' program is missing. " + "The Star-Buffer man page cannot be generated.") +else() + set(_src ${PROJECT_SOURCE_DIR}/../doc/sbuf.5.scd) + add_custom_command( + OUTPUT sbuf.5 + COMMAND ${SCDOC} < ${_src} > sbuf.5 + DEPENDS ${_src} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Buid ROFF man page sbuf.5" + VERBATIM) + add_custom_target(man-roff ALL DEPENDS sbuf.5) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sbuf.5 DESTINATION share/man/man5) +endif() + +################################################################################ +# Define output & install directories +################################################################################ +install(TARGETS sbuf + ARCHIVE DESTINATION bin + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin) +install(FILES ${SBUF_FILES_INC_API} DESTINATION include/star) +install(FILES ${SBUF_FILES_DOC} DESTINATION share/doc/star-buffer) + diff --git a/src/sbuf.c b/src/sbuf.c @@ -0,0 +1,299 @@ +/* Copyright (C) 2022 |Méso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#define _POSIX_C_SOURCE 200809L /* mmap support */ +#define _DEFAULT_SOURCE 1 /* MAP_POPULATE support */ +#define _BSD_SOURCE 1 /* MAP_POPULATE for glibc < 2.19 */ + +#include "sbuf.h" +#include "sbuf_c.h" +#include "sbuf_log.h" + +#include <rsys/mem_allocator.h> + +#include <errno.h> +#include <unistd.h> +#include <sys/mman.h> /* mmap */ + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static INLINE res_T +check_sbuf_create_args(const struct sbuf_create_args* args) +{ + /* Nothing to check. Only return RES_BAD_ARG if args is NULL */ + return args ? RES_OK : RES_BAD_ARG; +} + +static void +reset_sbuf(struct sbuf* sbuf) +{ + ASSERT(sbuf); + sbuf->pagesize = 0; + sbuf->count = 0; + sbuf->szelmt = 0; + sbuf->alelmt = 0; + if(sbuf->buffer && sbuf->buffer != MAP_FAILED) + munmap(sbuf->buffer, sbuf->map_len); + sbuf->buffer = NULL; + sbuf->map_len= 0; +} + +static res_T +map_data + (struct sbuf* sbuf, + const char* stream_name, + const int fd, /* File descriptor */ + const size_t filesz, /* Overall filesize */ + const off_t offset, /* Offset of the data into file */ + const size_t map_len, + void** out_map) /* Lenght of the data to map */ +{ + void* map = NULL; + res_T res = RES_OK; + ASSERT(sbuf && stream_name && filesz && map_len && out_map); + ASSERT(IS_ALIGNED((size_t)offset, (size_t)sbuf->pagesize)); + + if((size_t)offset + map_len > filesz) { + log_err(sbuf, "%s: the amount of data to load exceed the file size.\n", + stream_name); + res = RES_IO_ERR; + goto error; + } + + map = mmap(NULL, map_len, PROT_READ, MAP_PRIVATE|MAP_POPULATE, fd, offset); + if(map == MAP_FAILED) { + log_err(sbuf, "%s: could not map the data -- %s.\n", + stream_name, strerror(errno)); + res = RES_IO_ERR; + goto error; + } + +exit: + *out_map = map; + return res; +error: + if(map == MAP_FAILED) map = NULL; + goto exit; +} + +static res_T +load_stream(struct sbuf* sbuf, FILE* stream, const char* stream_name) +{ + off_t offset; + size_t filesz; + res_T res = RES_OK; + ASSERT(sbuf && stream && stream_name); + + reset_sbuf(sbuf); + + /* Read file header */ + #define READ(Var, N, Name) { \ + if(fread((Var), sizeof(*(Var)), (N), stream) != (N)) { \ + log_err(sbuf, "%s: could not read the %s.\n", stream_name, (Name)); \ + res = RES_IO_ERR; \ + goto error; \ + } \ + } (void)0 + READ(&sbuf->pagesize, 1, "page size"); + READ(&sbuf->count, 1, "number of elements"); + READ(&sbuf->szelmt, 1, "size of an element"); + READ(&sbuf->alelmt, 1, "alignment of an element"); + #undef READ + + if(!IS_ALIGNED(sbuf->pagesize, sbuf->pagesize_os)) { + log_err(sbuf, + "%s: invalid page size %li. The page size attribute must be aligned on " + "the page size of the operating system (%lu).\n", + stream_name, sbuf->pagesize, (unsigned long)sbuf->pagesize_os); + res = RES_BAD_ARG; + goto error; + } + if(!sbuf->szelmt) { + log_err(sbuf, + "%s: invalid element size `%lu'.\n", + stream_name, (unsigned long)sbuf->szelmt); + res = RES_BAD_ARG; + goto error; + } + if(!IS_POW2(!sbuf->alelmt)) { + log_err(sbuf, + "%s: invalid element alignment `%lu'. It must be a power of 2.\n", + stream_name, (unsigned long)sbuf->alelmt); + res = RES_BAD_ARG; + goto error; + } + if(sbuf->alelmt > sbuf->pagesize) { + log_err(sbuf, + "%s: invalid element alignment `%lu'. " + "It must be less than the provided pagesize `%lu'.\n", + stream_name, (unsigned long)sbuf->alelmt, (unsigned long)sbuf->pagesize); + res = RES_BAD_ARG; + goto error; + + } + + sbuf->pitch = ALIGN_SIZE(sbuf->szelmt, sbuf->alelmt); + + /* Compute the length in bytes of the data to map */ + sbuf->map_len = sbuf->count * sbuf->pitch * sbuf->count; + sbuf->map_len = ALIGN_SIZE(sbuf->map_len, (size_t)sbuf->pagesize); + + /* Find the offsets of the data into the stream */ + offset = (off_t)ALIGN_SIZE((uint64_t)ftell(stream), sbuf->pagesize); + + /* Retrieve the overall filesize */ + fseek(stream, 0, SEEK_END); + filesz = (size_t)ftell(stream); + + /* Map the data */ + res = map_data(sbuf, stream_name, fileno(stream), filesz, offset, + sbuf->map_len, &sbuf->buffer); + if(res != RES_OK) goto error; + +exit: + return res; +error: + reset_sbuf(sbuf); + goto exit; +} + + +static void +release_sbuf(ref_T* ref) +{ + struct sbuf* sbuf; + ASSERT(ref); + sbuf = CONTAINER_OF(ref, struct sbuf, ref); + reset_sbuf(sbuf); + if(sbuf->logger == &sbuf->logger__) logger_release(&sbuf->logger__); + MEM_RM(sbuf->allocator, sbuf); +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +sbuf_create + (const struct sbuf_create_args* args, + struct sbuf** out_sbuf) +{ + struct sbuf* sbuf = NULL; + struct mem_allocator* allocator = NULL; + res_T res = RES_OK; + + if(!out_sbuf) { res = RES_BAD_ARG; goto error; } + res = check_sbuf_create_args(args); + if(res != RES_OK) goto error; + + allocator = args->allocator ? args->allocator : &mem_default_allocator; + sbuf = MEM_CALLOC(allocator, 1, sizeof(*sbuf)); + if(!sbuf) { + if(args->verbose) { + #define ERR_STR "Could not allocate the Star-Buffer device.\n" + if(args->logger) { + logger_print(args->logger, LOG_ERROR, ERR_STR); + } else { + fprintf(stderr, MSG_ERROR_PREFIX ERR_STR); + } + #undef ERR_STR + } + res = RES_MEM_ERR; + goto error; + } + ref_init(&sbuf->ref); + sbuf->allocator = allocator; + sbuf->verbose = args->verbose; + sbuf->pagesize_os = (size_t)sysconf(_SC_PAGESIZE); + if(args->logger) { + sbuf->logger = args->logger; + } else { + setup_log_default(sbuf); + } + +exit: + if(out_sbuf) *out_sbuf = sbuf; + return res; +error: + if(sbuf) { SBUF(ref_put(sbuf)); sbuf = NULL; } + goto exit; +} + +res_T +sbuf_ref_get(struct sbuf* sbuf) +{ + if(!sbuf) return RES_BAD_ARG; + ref_get(&sbuf->ref); + return RES_OK; +} + +res_T +sbuf_ref_put(struct sbuf* sbuf) +{ + if(!sbuf) return RES_BAD_ARG; + ref_put(&sbuf->ref, release_sbuf); + return RES_OK; +} + + +res_T +sbuf_load(struct sbuf* sbuf, const char* path) +{ + FILE* file = NULL; + res_T res = RES_OK; + + if(!sbuf || !path) { + res = RES_BAD_ARG; + goto error; + } + + file = fopen(path, "r"); + if(!file) { + log_err(sbuf, "%s: error opening file `%s'.\n", FUNC_NAME, path); + res = RES_IO_ERR; + goto error; + } + + res = load_stream(sbuf, file, path); + if(res != RES_OK) goto error; + +exit: + if(file) fclose(file); + return res; +error: + goto exit; +} + +res_T +sbuf_load_stream + (struct sbuf* sbuf, + FILE* stream, + const char* stream_name) +{ + if(!sbuf || !stream) return RES_BAD_ARG; + return load_stream(sbuf, stream, stream_name ? stream_name : "<stream>"); +} + +res_T +sbuf_get_desc(const struct sbuf* sbuf, struct sbuf_desc* desc) +{ + if(!sbuf || !desc) return RES_BAD_ARG; + desc->buffer = sbuf->buffer; + desc->count = sbuf->count; + desc->szelmt = (size_t)sbuf->szelmt; + desc->alelmt = (size_t)sbuf->alelmt; + desc->pitch = (size_t)sbuf->pitch; + return RES_OK; +} diff --git a/src/sbuf.h b/src/sbuf.h @@ -0,0 +1,110 @@ +/* Copyright (C) 2022 |Méso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef SBUF_H +#define SBUF_H + +#include <rsys/rsys.h> + +/* Library symbol management */ +#if defined(SBUF_SHARED_BUILD) /* Build shared library */ + #define SBUF_API extern EXPORT_SYM +#elif defined(SBUF_STATIC) /* Use/build static library */ + #define SBUF_API extern LOCAL_SYM +#else /* Use shared library */ + #define SBUF_API extern IMPORT_SYM +#endif + +/* Helper macro that asserts if the invocation of the smsh function `Func' + * returns an error. One should use this macro on smsh function calls for + * which no explicit error checking is performed */ +#ifndef NDEBUG + #define SBUF(Func) ASSERT(sbuf_ ## Func == RES_OK) +#else + #define SBUF(Func) sbuf_ ## Func +#endif + +/* Forward declaration of external data types */ +struct logger; +struct mem_allocator; + +struct sbuf_create_args { + struct logger* logger; /* May be NULL <=> default logger */ + struct mem_allocator* allocator; /* NULL <=> use default allocator */ + int verbose; /* Verbosity level */ +}; +#define SBUF_CREATE_ARGS_DEFAULT__ {NULL, NULL, 0} +static const struct sbuf_create_args SBUF_CREATE_ARGS_DEFAULT = + SBUF_CREATE_ARGS_DEFAULT__; + +struct sbuf_desc { + const void* buffer; + size_t count; /* #elements in the buffer */ + size_t szelmt; /* Size of a buffer element */ + size_t alelmt; /* Alignment of a buffer element */ + size_t pitch; /* #bytes between 2 consecutive elements */ +}; +#define SBUF_DESC_NULL__ {NULL, 0, 0, 0, 0} +static const struct sbuf_desc SBUF_DESC_NULL = SBUF_DESC_NULL__; + +/* Forward declaration of opaque data types */ +struct sbuf; + +BEGIN_DECLS + +/******************************************************************************* + * Star-Buffer API + ******************************************************************************/ +SBUF_API res_T +sbuf_create + (const struct sbuf_create_args* args, + struct sbuf** sbuf); + +SBUF_API res_T +sbuf_ref_get + (struct sbuf* sbuf); + +SBUF_API res_T +sbuf_ref_put + (struct sbuf* sbuf); + +SBUF_API res_T +sbuf_load + (struct sbuf* sbuf, + const char* path); + +SBUF_API res_T +sbuf_load_stream + (struct sbuf* sbuf, + FILE* stream, + const char* stream_name); /* NULL <=> use default stream name */ + +SBUF_API res_T +sbuf_get_desc + (const struct sbuf* sbuf, + struct sbuf_desc* desc); + +static INLINE const void* +sbuf_desc_at + (const struct sbuf_desc* desc, + const size_t ielement) +{ + ASSERT(desc && ielement < desc->count); + return (char*)desc->buffer + ielement*desc->pitch; +} + +END_DECLS + +#endif /* SBUF_H */ diff --git a/src/sbuf_c.h b/src/sbuf_c.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2022 |Méso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef SBUF_C_H +#define SBUF_C_H + +#include <rsys/logger.h> +#include <rsys/ref_count.h> + +struct mem_allocator; + +struct sbuf { + uint64_t pagesize; + uint64_t count; + uint64_t szelmt; /* Size of an element */ + uint64_t alelmt; /* Alignment of an element */ + uint64_t pitch; /* #bytes between 2 consecutive elements */ + + void* buffer; + size_t map_len; + + size_t pagesize_os; + + struct mem_allocator* allocator; + struct logger* logger; + struct logger logger__; /* Default logger */ + int verbose; + ref_T ref; +}; + +#endif /* SBUF_C_H */ diff --git a/src/sbuf_log.c b/src/sbuf_log.c @@ -0,0 +1,124 @@ +/* Copyright (C) 2022 |Méso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "sbuf_c.h" +#include "sbuf_log.h" + +#include <rsys/cstr.h> +#include <rsys/logger.h> + +#include <stdarg.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static INLINE void +log_msg + (const struct sbuf* sbuf, + const enum log_type stream, + const char* msg, + va_list vargs) +{ + ASSERT(sbuf && msg); + if(sbuf->verbose) { + res_T res; (void)res; + res = logger_vprint(sbuf->logger, stream, msg, vargs); + ASSERT(res == RES_OK); + } +} + +static void +print_info(const char* msg, void* ctx) +{ + (void)ctx; + fprintf(stderr, MSG_INFO_PREFIX"%s", msg); +} + +static void +print_err(const char* msg, void* ctx) +{ + (void)ctx; + fprintf(stderr, MSG_ERROR_PREFIX"%s", msg); +} + +static void +print_warn(const char* msg, void* ctx) +{ + (void)ctx; + fprintf(stderr, MSG_WARNING_PREFIX"%s", msg); +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +res_T +setup_log_default(struct sbuf* sbuf) +{ + res_T res = RES_OK; + ASSERT(sbuf); + + res = logger_init(sbuf->allocator, &sbuf->logger__); + if(res != RES_OK) { + if(sbuf->verbose) { + fprintf(stderr, + MSG_ERROR_PREFIX + "Could not setup the Star-Buffer default logger -- %s.\n", + res_to_cstr(res)); + } + goto error; + } + logger_set_stream(&sbuf->logger__, LOG_OUTPUT, print_info, NULL); + logger_set_stream(&sbuf->logger__, LOG_ERROR, print_err, NULL); + logger_set_stream(&sbuf->logger__, LOG_WARNING, print_warn, NULL); + sbuf->logger = &sbuf->logger__; + +exit: + return res; +error: + goto exit; +} + +void +log_info(const struct sbuf* sbuf, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(sbuf && msg); + + va_start(vargs_list, msg); + log_msg(sbuf, LOG_OUTPUT, msg, vargs_list); + va_end(vargs_list); +} + +void +log_err(const struct sbuf* sbuf, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(sbuf && msg); + + va_start(vargs_list, msg); + log_msg(sbuf, LOG_ERROR, msg, vargs_list); + va_end(vargs_list); +} + +void +log_warn(const struct sbuf* sbuf, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(sbuf && msg); + + va_start(vargs_list, msg); + log_msg(sbuf, LOG_WARNING, msg, vargs_list); + va_end(vargs_list); +} diff --git a/src/sbuf_log.h b/src/sbuf_log.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2022 |Méso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef SBUF_LOG_H +#define SBUF_LOG_H + +#include <rsys/rsys.h> + +#define MSG_INFO_PREFIX "Star-Buffer:\x1b[1m\x1b[32minfo\x1b[0m: " +#define MSG_ERROR_PREFIX "Star-Buffer:\x1b[1m\x1b[31merror\x1b[0m: " +#define MSG_WARNING_PREFIX "Star-Buffer:\x1b[1m\x1b[33mwarning\x1b[0m: " + +struct sbuf; +struct logger; + +extern LOCAL_SYM res_T +setup_log_default + (struct sbuf* sbuf); + +/* Conditionally log a message on the LOG_OUTPUT stream of the sbuf logger, + * with respect to its verbose flag */ +extern LOCAL_SYM void +log_info + (const struct sbuf* sbuf, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#endif +; + +/* Conditionally log a message on the LOG_ERROR stream of the sbuf logger, + * with respect to its verbose flag */ +extern LOCAL_SYM void +log_err + (const struct sbuf* sbuf, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#endif +; + +/* Conditionally log a message on the LOG_WARNING stream of the sbuf logger, + * with respect to its verbose flag */ +extern LOCAL_SYM void +log_warn + (const struct sbuf* sbuf, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#endif +; + +#endif /* SBUF_LOG_H */ diff --git a/src/test_sbuf.c b/src/test_sbuf.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2022 |Méso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "sbuf.h" + +#include <rsys/logger.h> + +static void +log_stream(const char* msg, void* ctx) +{ + ASSERT(msg); + (void)msg, (void)ctx; + printf("%s\n", msg); +} + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct logger logger; + struct sbuf_create_args args = SBUF_CREATE_ARGS_DEFAULT; + struct sbuf* sbuf; + (void)argc, (void)argv; + + CHK(sbuf_create(NULL, &sbuf) == RES_BAD_ARG); + CHK(sbuf_create(&args, NULL) == RES_BAD_ARG); + CHK(sbuf_create(&args, &sbuf) == RES_OK); + + CHK(sbuf_ref_get(NULL) == RES_BAD_ARG); + CHK(sbuf_ref_get(sbuf) == RES_OK); + CHK(sbuf_ref_put(NULL) == RES_BAD_ARG); + CHK(sbuf_ref_put(sbuf) == RES_OK); + CHK(sbuf_ref_put(sbuf) == RES_OK); + + CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); + args.allocator = &allocator; + args.verbose = 1; + CHK(sbuf_create(&args, &sbuf) == RES_OK); + CHK(sbuf_ref_put(sbuf) == RES_OK); + + CHK(logger_init(&allocator, &logger) == RES_OK); + logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL); + logger_set_stream(&logger, LOG_ERROR, log_stream, NULL); + logger_set_stream(&logger, LOG_WARNING, log_stream, NULL); + + args.logger = &logger; + args.verbose = 0; + CHK(sbuf_create(&args, &sbuf) == RES_OK); + CHK(sbuf_ref_put(sbuf) == RES_OK); + args.allocator = NULL; + CHK(sbuf_create(&args, &sbuf) == RES_OK); + CHK(sbuf_ref_put(sbuf) == RES_OK); + + logger_release(&logger); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +}