diff --git a/CMakeLists.txt b/CMakeLists.txt index 93ef7c3..e086f6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,6 @@ endif() set(CMAKE_VERBOSE_MAKEFILE ON) - # ------------------------------------------------------------------------------ # Add WChar support for the build # ------------------------------------------------------------------------------ @@ -33,6 +32,14 @@ if(FORT_ENABLE_WCHAR) add_definitions(-DFT_CONGIG_HAVE_WCHAR) endif() +set(FORT_HAVE_WCHAR "${FORT_ENABLE_WCHAR}" CACHE STRING "fort option") + + + + +add_subdirectory(lib) +add_subdirectory(src) + # ------------------------------------------------------------------------------ # Includes @@ -79,99 +86,6 @@ else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -std=c++11") endif() - -# ------------------------------------------------------------------------------ -# Sources and executables -# ------------------------------------------------------------------------------ - -file(GLOB_RECURSE FortHeaders - "lib/*.h" - "lib/*.hpp" - "tests/*.h" - "tests/*.hpp" - "src/*.h") -add_custom_target(headers SOURCES ${FortHeaders}) - - -set(FORT_DEV_SOURCES - src/fort_impl.c - src/vector.c - src/string_buffer.c - src/properties.c - src/cell.c - src/row.c - src/table.c - src/fort_utils.c - src/wcwidth.c) - - -set(EXAMPLE_SOURCES - example/main.c) -add_executable(${PROJECT_NAME}_example - ${EXAMPLE_SOURCES} - lib/fort.c) - -set(EXAMPLE_CPP_SOURCES - example/main.cpp) -add_executable(${PROJECT_NAME}_example_cpp - ${EXAMPLE_CPP_SOURCES} - lib/fort.c) - -set(TEST_SOURCES_DEV - tests/main_test.c - tests/wb_tests/test_vector.c - tests/wb_tests/test_string_buffer.c - tests/wb_tests/test_table_geometry.c - tests/bb_tests/test_table_basic.c - tests/bb_tests/test_table_border_style.c - tests/bb_tests/test_table_properties.c - tests/bb_tests/test_memory_errors.c - tests/tests.c - tests/test_utils.c) -add_executable(${PROJECT_NAME}_test_dev - ${FORT_DEV_SOURCES} - ${TEST_SOURCES_DEV}) - -target_compile_definitions(${PROJECT_NAME}_test_dev - PUBLIC FORT_WB_TESTING_ENABLED=1) - -set(TEST_SOURCES - tests/main_test.c - tests/bb_tests/test_table_basic.c - tests/bb_tests/test_table_border_style.c - tests/bb_tests/test_table_properties.c - tests/bb_tests/test_memory_errors.c - tests/tests.c - tests/test_utils.c) -add_executable(${PROJECT_NAME}_test - lib/fort.c - ${TEST_SOURCES}) - - -set(TEST_SOURCES_CPP - tests/main_test_cpp.cpp - tests/bb_tests_cpp/test_table_basic.cpp - tests/bb_tests_cpp/test_table_properties.cpp - tests/tests.c - tests/test_utils.cpp) -add_executable(${PROJECT_NAME}_test_cpp - lib/fort.c - ${TEST_SOURCES_CPP}) - -if(FORT_CXX_BUILD) - set_source_files_properties(${FORT_DEV_SOURCES} PROPERTIES LANGUAGE CXX) - set_source_files_properties(${EXAMPLE_SOURCES} PROPERTIES LANGUAGE CXX) - set_source_files_properties(${TEST_SOURCES} PROPERTIES LANGUAGE CXX) -endif() - - -# ------------------------------------------------------------------------------ -# Set preprocessor macros for all test builds -# ------------------------------------------------------------------------------ -target_compile_definitions(${PROJECT_NAME}_test_dev PRIVATE FT_TEST_BUILD=1) -target_compile_definitions(${PROJECT_NAME}_test_cpp PRIVATE FT_TEST_BUILD=1) -target_compile_definitions(${PROJECT_NAME}_test PRIVATE FT_TEST_BUILD=1) - # ------------------------------------------------------------------------------ # Sanitizers # ------------------------------------------------------------------------------ @@ -223,6 +137,116 @@ if("${FORT_COMPILER}" STREQUAL "GNU") endif() + +# ------------------------------------------------------------------------------ +# Sources and executables +# ------------------------------------------------------------------------------ + +file(GLOB_RECURSE FortHeaders + "lib/*.h" + "lib/*.hpp" + "tests/*.h" + "tests/*.hpp" + "src/*.h") +add_custom_target(headers SOURCES ${FortHeaders}) + + +#set(FORT_DEV_SOURCES +# src/fort_impl.c +# src/vector.c +# src/string_buffer.c +# src/properties.c +# src/cell.c +# src/row.c +# src/table.c +# src/fort_utils.c +# src/wcwidth.c) + + +set(EXAMPLE_SOURCES + example/main.c) +#add_executable(${PROJECT_NAME}_example +# ${EXAMPLE_SOURCES} +# lib/fort.c) +add_executable(${PROJECT_NAME}_example + ${EXAMPLE_SOURCES}) +target_link_libraries(${PROJECT_NAME}_example + fort) + +set(EXAMPLE_CPP_SOURCES + example/main.cpp) +#add_executable(${PROJECT_NAME}_example_cpp +# ${EXAMPLE_CPP_SOURCES} +# lib/fort.c) +add_executable(${PROJECT_NAME}_example_cpp + ${EXAMPLE_CPP_SOURCES}) +target_link_libraries(${PROJECT_NAME}_example_cpp + fort) + +set(TEST_SOURCES_DEV + tests/main_test.c + tests/wb_tests/test_vector.c + tests/wb_tests/test_string_buffer.c + tests/wb_tests/test_table_geometry.c + tests/bb_tests/test_table_basic.c + tests/bb_tests/test_table_border_style.c + tests/bb_tests/test_table_properties.c + tests/bb_tests/test_memory_errors.c + tests/tests.c + tests/test_utils.c) +#add_executable(${PROJECT_NAME}_test_dev +# ${FORT_DEV_SOURCES} +# ${TEST_SOURCES_DEV}) +add_executable(${PROJECT_NAME}_test_dev + ${TEST_SOURCES_DEV}) +target_link_libraries(${PROJECT_NAME}_test_dev + fort_dev) + +target_compile_definitions(${PROJECT_NAME}_test_dev + PUBLIC FORT_WB_TESTING_ENABLED=1) + +set(TEST_SOURCES + tests/main_test.c + tests/bb_tests/test_table_basic.c + tests/bb_tests/test_table_border_style.c + tests/bb_tests/test_table_properties.c + tests/bb_tests/test_memory_errors.c + tests/tests.c + tests/test_utils.c) +#add_executable(${PROJECT_NAME}_test +# lib/fort.c +# ${TEST_SOURCES}) +add_executable(${PROJECT_NAME}_test + ${TEST_SOURCES}) +target_link_libraries(${PROJECT_NAME}_test + fort) + +set(TEST_SOURCES_CPP + tests/main_test_cpp.cpp + tests/bb_tests_cpp/test_table_basic.cpp + tests/bb_tests_cpp/test_table_properties.cpp + tests/tests.c + tests/test_utils.cpp) +# hack - explicitly set fort.c +add_executable(${PROJECT_NAME}_test_cpp + lib/fort.c + ${TEST_SOURCES_CPP}) + + +if(FORT_CXX_BUILD) +# set_source_files_properties(${FORT_DEV_SOURCES} PROPERTIES LANGUAGE CXX) + set_source_files_properties(${EXAMPLE_SOURCES} PROPERTIES LANGUAGE CXX) + set_source_files_properties(${TEST_SOURCES} PROPERTIES LANGUAGE CXX) +endif() + + +# ------------------------------------------------------------------------------ +# Set preprocessor macros for all test builds +# ------------------------------------------------------------------------------ +target_compile_definitions(${PROJECT_NAME}_test_dev PRIVATE FT_TEST_BUILD=1) +target_compile_definitions(${PROJECT_NAME}_test_cpp PRIVATE FT_TEST_BUILD=1) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE FT_TEST_BUILD=1) + # ------------------------------------------------------------------------------ # Astyle # ------------------------------------------------------------------------------ diff --git a/amalgamate.py b/amalgamate.py index 8bea797..4469a6f 100644 --- a/amalgamate.py +++ b/amalgamate.py @@ -1,5 +1,6 @@ import os +import shutil import sys def comment_line(line): @@ -106,6 +107,10 @@ def main(): ]; amalgamate(config) + # copy header files + shutil.copyfile('./src/fort.h', './lib/fort.h') + shutil.copyfile('./src/fort.hpp', './lib/fort.hpp') + diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..be8cda0 --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,17 @@ +option(FORT_HAVE_WCHAR "Enable wchar support" ON) + +message("FORT_HAVE_WCHAR in fort = ${FORT_HAVE_WCHAR}") +add_library(fort + fort.c) + +target_include_directories(fort + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +if(FORT_HAVE_WCHAR) + target_compile_definitions(fort + PRIVATE + -DFT_CONGIG_HAVE_WCHAR + ) +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..1a1cc80 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,33 @@ +option(FORT_HAVE_WCHAR "Enable wchar support" ON) +option(FORT_TEST_BUILD "Export some internal symbols for tests" ON) + +message("FORT_HAVE_WCHAR in fort_dev = ${FORT_HAVE_WCHAR}") +add_library(fort_dev + fort_impl.c + vector.c + string_buffer.c + properties.c + cell.c + row.c + table.c + fort_utils.c + wcwidth.c) + +target_include_directories(fort_dev + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +if(FORT_HAVE_WCHAR) + target_compile_definitions(fort_dev + PRIVATE + -DFT_CONGIG_HAVE_WCHAR + ) +endif() + +if(FORT_TEST_BUILD) + target_compile_definitions(fort_dev + PRIVATE + -DFT_TEST_BUILD=1 + ) +endif() diff --git a/src/fort.h b/src/fort.h new file mode 100644 index 0000000..897c838 --- /dev/null +++ b/src/fort.h @@ -0,0 +1,889 @@ +/* +libfort + +MIT License + +Copyright (c) 2017 - 2018 Seleznev Anton + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * @file fort.h + * @brief Main header file describing libfort API. + * + * This file contains declarations of all libfort functions and macro + * definitions. + */ + +#ifndef LIBFORT_H +#define LIBFORT_H + +#include +#include +#include +#include + +/***************************************************************************** + * Configuration + *****************************************************************************/ +/** + * libfort configuration macros + * (to enable/disable some options this macros should be defined/undefined) + */ +/** #define FT_CONGIG_HAVE_WCHAR */ + +#if defined(FT_CONGIG_HAVE_WCHAR) +#define FT_HAVE_WCHAR +#endif + + +/***************************************************************************** + * RETURN CODES + *****************************************************************************/ +typedef int fort_status_t; +#define FT_SUCCESS 0 +#define FT_MEMORY_ERROR -1 +#define FT_ERROR -2 +#define FT_EINVAL -3 +#define FT_IS_SUCCESS(arg) ((arg) >= 0) +#define FT_IS_ERROR(arg) ((arg) < 0) + + + + +/** + * @cond HELPER_MACROS + */ + +/***************************************************************************** + * Determine compiler + *****************************************************************************/ + +#if defined(__clang__) +#define FT_CLANG_COMPILER +#elif defined(__GNUC__) +#define FT_GCC_COMPILER +#elif defined(_MSC_VER) +#define FT_MICROSOFT_COMPILER +#else +#define FT_UNDEFINED_COMPILER +#endif + + +/***************************************************************************** + * Declare inline + *****************************************************************************/ + +#if defined(__cplusplus) +#define FT_INLINE inline +#else +#define FT_INLINE __inline +#endif /* if defined(__cplusplus) */ + + +/***************************************************************************** + * C++ needs to know that types and declarations are C, not C++. + *****************************************************************************/ + +#ifdef __cplusplus +# define FT_BEGIN_DECLS extern "C" { +# define FT_END_DECLS } +#else +# define FT_BEGIN_DECLS +# define FT_END_DECLS +#endif + + +/***************************************************************************** + * Helper macros + *****************************************************************************/ + +#define FT_STR_2_CAT_(arg1, arg2) \ + arg1##arg2 +#define FT_STR_2_CAT(arg1, arg2) \ + FT_STR_2_CAT_(arg1, arg2) + +/** + * @interanl + */ +static FT_INLINE int ft_check_if_string_helper(const char *str) +{ + (void)str; + return 0; +} + +/** + * @interanl + */ +static FT_INLINE int ft_check_if_wstring_helper(const wchar_t *str) +{ + (void)str; + return 0; +} + +#define FT_NARGS_IMPL_(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,N,...) N +#define FT_EXPAND_(x) x +#define FT_PP_NARG_(...) \ + FT_EXPAND_(FT_NARGS_IMPL_(__VA_ARGS__,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) + +#define FT_CHECK_IF_STR_32(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_31(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_31(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_30(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_30(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_29(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_29(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_28(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_28(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_27(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_27(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_26(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_26(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_25(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_25(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_24(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_24(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_23(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_23(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_22(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_22(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_21(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_21(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_20(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_20(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_19(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_19(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_18(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_18(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_17(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_17(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_16(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_16(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_15(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_15(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_14(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_14(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_13(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_13(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_12(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_12(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_11(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_11(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_10(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_10(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_9(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_9(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_8(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_8(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_7(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_7(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_6(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_6(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_5(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_5(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_4(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_4(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_3(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_3(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_2(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_2(checker,arg,...) (checker(arg),FT_EXPAND_(FT_CHECK_IF_STR_1(checker,__VA_ARGS__))) +#define FT_CHECK_IF_STR_1(checker,arg) (checker(arg)) + +#define FT_CHECK_IF_ARGS_ARE_STRINGS__(checker,func, ...) \ + FT_EXPAND_(func(checker,__VA_ARGS__)) +#define FT_CHECK_IF_ARGS_ARE_STRINGS_(checker,basis, n, ...) \ + FT_CHECK_IF_ARGS_ARE_STRINGS__(checker,FT_STR_2_CAT_(basis, n), __VA_ARGS__) +#define FT_CHECK_IF_ARGS_ARE_STRINGS(...) \ + FT_CHECK_IF_ARGS_ARE_STRINGS_(ft_check_if_string_helper,FT_CHECK_IF_STR_,FT_PP_NARG_(__VA_ARGS__), __VA_ARGS__) + +#ifdef FT_HAVE_WCHAR +#define CHECK_IF_ARGS_ARE_WSTRINGS(...) \ + FT_CHECK_IF_ARGS_ARE_STRINGS_(ft_check_if_wstring_helper,FT_CHECK_IF_STR_,FT_PP_NARG_(__VA_ARGS__), __VA_ARGS__) +#endif + +/** + * @endcond + */ + + +/***************************************************************************** + * Attribute format for argument checking + *****************************************************************************/ + +#if defined(FT_CLANG_COMPILER) || defined(FT_GCC_COMPILER) +#define FT_PRINTF_ATTRIBUTE_FORMAT(string_index, first_to_check) \ + __attribute__ ((format (printf, string_index, first_to_check))) +#else +#define FT_PRINTF_ATTRIBUTE_FORMAT(string_index, first_to_check) +#endif /* defined(FT_CLANG_COMPILER) || defined(FT_GCC_COMPILER) */ + + +/***************************************************************************** + * libfort API + *****************************************************************************/ + +FT_BEGIN_DECLS + +/** + * The main structure of libfort containing information about formatted table. + */ +struct ft_table; + +/** + * The main structure of libfort containing information about formatted table. + * + * ft_table_t objects should be created by a call to ft_create_table and + * destroyed with ft_destroy_table. + */ +typedef struct ft_table ft_table_t; + +/** + * Create formatted table. + * + * @return + * The pointer to the new allocated ft_table_t, on success. NULL on error. + */ +ft_table_t *ft_create_table(void); + +/** + * Destroy formatted table. + * + * Destroy formatted table and free all resources allocated during table creation + * and work with it. + * + * @param table + * Pointer to formatted table previousley created with ft_create_table. If + * table is a null pointer, the function does nothing. + */ +void ft_destroy_table(ft_table_t *table); + +/** + * Copy formatted table. + * + * @param table + * Pointer to formatted table previousley created with ft_create_table. If + * table is a null pointer, the function returns null. + * @return + * The pointer to the new allocated ft_table_t, on success. NULL on error. + */ +ft_table_t *ft_copy_table(ft_table_t *table); + +/** + * Move current position to the first cell of the next line(row). + * + * @param table + * Pointer to formatted table. + */ +void ft_ln(ft_table_t *table); + +/** + * Get row number of the current cell. + * + * @param table + * Pointer to formatted table. + * @return + * Row number of the current cell. + */ +size_t ft_cur_row(ft_table_t *table); + +/** + * Get column number of the current cell. + * + * @param table + * Pointer to formatted table. + * @return + * Column number of the current cell. + */ +size_t ft_cur_col(ft_table_t *table); + +/** + * Set current cell position. + * + * Current cell - cell that will be edited with all modifiing functions + * (ft_printf, ft_write ...). + * + * @param table + * Pointer to formatted table. + * @param row + * New row number for the current cell. + * @param col + * New row number for the current cell. + */ +void ft_set_cur_cell(ft_table_t *table, size_t row, size_t col); + + + +#if defined(FT_CLANG_COMPILER) || defined(FT_GCC_COMPILER) + +/** + * Write data formatted acording to the format string to a variety of table + * cells. + * + * @param table + * Pointer to formatted table. + * @param fmt + * Pointer to a null-terminated multibyte string specifying how to interpret + * the data. The format string consists of ordinary characters (except % and |), + * which are copied unchanged into the output stream, and conversion + * specifications. Conversion specifications are the same as for standard + * printf function. Character '|' (wich can be changed with + * {@link ft_set_default_printf_field_separator}) in the format string is treated as + * a cell separator. + * @param ... + * Arguments specifying data to print. Similarly to standard printf-like + * functions if any argument after default conversions is not the type + * expected by the corresponding conversion specifier, or if there are fewer + * arguments than required by format, the behavior is undefined. If there are + * more arguments than required by format, the extraneous arguments are + * evaluated and ignored. + * @return + * - Number of printed cells + * - (<0): In case of error + */ +int ft_printf(ft_table_t *table, const char *fmt, ...) FT_PRINTF_ATTRIBUTE_FORMAT(2, 3); + +/** + * Write data formatted acording to the format string to a variety of table + * cells and move current position to the first cell of the next line(row). + * + * @param table + * Pointer to formatted table. + * @param fmt + * Pointer to a null-terminated multibyte string specifying how to interpret + * the data. The format string consists of ordinary characters (except % and |), + * which are copied unchanged into the output stream, and conversion + * specifications. Conversion specifications are the same as for standard + * printf function. Character '|' (wich can be changed with + * {@link ft_set_default_printf_field_separator}) in the format string is treated as + * a cell separator. + * @param ... + * Arguments specifying data to print. Similarly to standard printf-like + * functions if any argument after default conversions is not the type + * expected by the corresponding conversion specifier, or if there are fewer + * arguments than required by format, the behavior is undefined. If there are + * more arguments than required by format, the extraneous arguments are + * evaluated and ignored. + * @return + * - Number of printed cells. + * - (<0): In case of error. + */ +int ft_printf_ln(ft_table_t *table, const char *fmt, ...) FT_PRINTF_ATTRIBUTE_FORMAT(2, 3); + +#else + +/** + * @cond IGNORE_DOC + */ + +int ft_printf_impl(ft_table_t *table, const char *fmt, ...) FT_PRINTF_ATTRIBUTE_FORMAT(2, 3); +int ft_printf_ln_impl(ft_table_t *table, const char *fmt, ...) FT_PRINTF_ATTRIBUTE_FORMAT(2, 3); + +#define ft_printf(table, ...) \ + (( 0 ? fprintf(stderr, __VA_ARGS__) : 1), ft_printf_impl(table, __VA_ARGS__)) +#define ft_printf_ln(table, ...) \ + (( 0 ? fprintf(stderr, __VA_ARGS__) : 1), ft_printf_ln_impl(table, __VA_ARGS__)) + +/** + * @endcond + */ +#endif + +/** + * Set field separator for {@link ft_printf}, {@link ft_printf_ln} + * (default separator is '|'). + * + * @param separator + * New separator. + */ +void ft_set_default_printf_field_separator(char separator); + + +/** + * Write strings to the table. + * + * Write specified strings to the same number of consecutive cells in the + * current row. + * + * @param table + * Pointer to formatted table. + * @param ... + * Strings to write. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ +#define ft_write(table, ...)\ + (0 ? FT_CHECK_IF_ARGS_ARE_STRINGS(__VA_ARGS__) : ft_nwrite(table, FT_PP_NARG_(__VA_ARGS__), __VA_ARGS__)) + +/** + * Write strings to the table and go to the next line. + * + * Write specified strings to the same number of consecutive cells in the + * current row and move current position to the first cell of the next + * line(row). + * + * @param table + * Pointer to formatted table. + * @param ... + * Strings to write. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ +#define ft_write_ln(table, ...)\ + (0 ? FT_CHECK_IF_ARGS_ARE_STRINGS(__VA_ARGS__) : ft_nwrite_ln(table, FT_PP_NARG_(__VA_ARGS__), __VA_ARGS__)) + +/** + * Write specified number of strings to the table. + * + * Write specified number of strings to the same number of consecutive cells in + * the current row. + * + * @note In most cases it is more preferable to use MACRO @ref ft_write instead + * of @ref ft_nwrite, which is more safe (@ref ft_write automatically counts the + * number of string arguments and at compile check that all passed arguments are + * strings). + * + * @param table + * Pointer to formatted table. + * @param count + * Number of strings to write. + * @param cell_content + * First string to write. + * @param ... + * Other strings to write. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ +int ft_nwrite(ft_table_t *table, size_t count, const char *cell_content, ...); + +/** + * Write specified number of strings to the table and go to the next line. + * + * Write specified number of strings to the same number of consecutive cells + * in the current row and move current position to the first cell of the next + * line(row). + * + * @note In most cases it is more preferable to use MACRO @ref ft_write instead + * of @ref ft_nwrite, which is more safe (@ref ft_write automatically counts the + * number of string arguments and at compile check that all passed arguments are + * strings). + * + * @param table + * Pointer to formatted table. + * @param count + * Number of strings to write. + * @param cell_content + * First string to write. + * @param ... + * Other strings to write. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ +int ft_nwrite_ln(ft_table_t *table, size_t count, const char *cell_content, ...); + + + + + +/** + * Write strings from the array to the table. + * + * Write specified number of strings from the array to the same number of + * consecutive cells in the current row. + * + * @param table + * Pointer to formatted table. + * @param cols + * Number of elements in row_cells. + * @param row_cells + * Array of strings to write. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ +int ft_row_write(ft_table_t *table, size_t cols, const char *row_cells[]); + +/** + * Write strings from the array to the table and go to the next line. + * + * Write specified number of strings from the array to the same number of + * consecutive cells in the current row and move current position to the first + * cell of the next line(row). + * + * @param table + * Pointer to formatted table. + * @param cols + * Number of elements in row_cells. + * @param row_cells + * Array of strings to write. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ +int ft_row_write_ln(ft_table_t *table, size_t cols, const char *row_cells[]); + + +/** + * Write strings from the 2D array to the table. + * + * Write specified number of strings from the 2D array to the formatted table. + * + * @param table + * Pointer to formatted table. + * @param rows + * Number of rows in the 2D array. + * @param cols + * Number of columns in the 2D array. + * @param table_cells + * 2D array of strings to write. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ +int ft_table_write(ft_table_t *table, size_t rows, size_t cols, const char *table_cells[]); + +/** + * Write strings from the 2D array to the table and go to the next line. + * + * Write specified number of strings from the 2D array to the formatted table + * and move current position to the first cell of the next line(row). + * + * @param table + * Pointer to formatted table. + * @param rows + * Number of rows in the 2D array. + * @param cols + * Number of columns in the 2D array. + * @param table_cells + * 2D array of strings to write. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ +int ft_table_write_ln(ft_table_t *table, size_t rows, size_t cols, const char *table_cells[]); + + +/** + * Add separator after the current row. + * + * @param table + * Formatted table. + * @return + * - 0: Success; separator was added. + * - (<0): In case of error + */ +int ft_add_separator(ft_table_t *table); + + +/** + * Convert table to string representation. + * + * ft_table_t has ownership of the returned pointer. So there is no need to + * free it. To take ownership user should explicitly copy the returned + * string with strdup or similar functions. + * + * Returned pointer may be later invalidated by: + * - Calling ft_destroy_table; + * - Other invocations of ft_to_string. + * + * @param table + * Formatted table. + * @return + * - The pointer to the string representation of formatted table, on success. + * - NULL on error. + */ +const char *ft_to_string(const ft_table_t *table); + + + + + + + +/** + * Structure describing border appearance. + */ +struct ft_border_chars { + const char *top_border_ch; + const char *separator_ch; + const char *bottom_border_ch; + const char *side_border_ch; + const char *out_intersect_ch; + const char *in_intersect_ch; +}; + +/** + * Structure describing border style. + */ +struct ft_border_style { + struct ft_border_chars border_chs; + struct ft_border_chars header_border_chs; + const char *hor_separator_char; +}; + +/** + * @defgroup BasicStyles + * @name Built-in table border styles. + * @{ + */ +extern struct ft_border_style *const FT_BASIC_STYLE; +extern struct ft_border_style *const FT_BASIC2_STYLE; +extern struct ft_border_style *const FT_SIMPLE_STYLE; +extern struct ft_border_style *const FT_PLAIN_STYLE; +extern struct ft_border_style *const FT_DOT_STYLE; +extern struct ft_border_style *const FT_EMPTY_STYLE; +extern struct ft_border_style *const FT_EMPTY2_STYLE; +extern struct ft_border_style *const FT_SOLID_STYLE; +extern struct ft_border_style *const FT_SOLID_ROUND_STYLE; +extern struct ft_border_style *const FT_NICE_STYLE; +extern struct ft_border_style *const FT_DOUBLE_STYLE; +extern struct ft_border_style *const FT_DOUBLE2_STYLE; +extern struct ft_border_style *const FT_BOLD_STYLE; +extern struct ft_border_style *const FT_BOLD2_STYLE; +extern struct ft_border_style *const FT_FRAME_STYLE; +/** @} */ + + + +/** + * Set default border style for all new formatted tables. + * + * @param style + * Pointer to border style. + * @return + * - 0: Success; default border style was changed. + * - (<0): In case of error + */ +int ft_set_default_border_style(const struct ft_border_style *style); + +/** + * Set border style for the table. + * + * @param table + * A pointer to the ft_table_t structure. + * @param style + * Pointer to border style. + * @return + * - 0: Success; table border style was changed. + * - (<0): In case of error + */ +int ft_set_border_style(ft_table_t *table, const struct ft_border_style *style); + + + +/** + * @name Special macros to define cell position (row and column). + * @{ + */ +#define FT_ANY_COLUMN (UINT_MAX) /**< Any column (can be used to refer to all cells in a row)*/ +#define FT_CUR_COLUMN (UINT_MAX - 1) /**< Current column */ +#define FT_ANY_ROW (UINT_MAX) /**< Any row (can be used to refer to all cells in a column)*/ +#define FT_CUR_ROW (UINT_MAX - 1) /**< Current row */ +/** @} */ + + + +/** + * @name Cell properties identifiers. + * @{ + */ +#define FT_CPROP_MIN_WIDTH (0x01U << 0) /**< Minimum width */ +#define FT_CPROP_TEXT_ALIGN (0x01U << 1) /**< Text alignment */ +#define FT_CPROP_TOP_PADDING (0x01U << 2) /**< Top padding for cell content */ +#define FT_CPROP_BOTTOM_PADDING (0x01U << 3) /**< Bottom padding for cell content */ +#define FT_CPROP_LEFT_PADDING (0x01U << 4) /**< Left padding for cell content */ +#define FT_CPROP_RIGHT_PADDING (0x01U << 5) /**< Right padding for cell content */ +#define FT_CPROP_EMPTY_STR_HEIGHT (0x01U << 6) /**< Height of empty cell */ +#define FT_CPROP_ROW_TYPE (0x01U << 7) /**< Row type */ +#define FT_CPROP_CONT_FG_COLOR (0x01U << 8) /**< Cell content foreground text color */ +#define FT_CPROP_CELL_BG_COLOR (0x01U << 9) /**< Cell background color */ +#define FT_CPROP_CONT_BG_COLOR (0x01U << 10) /**< Cell content background color */ +#define FT_CPROP_CELL_TEXT_STYLE (0x01U << 11) /**< Cell text style */ +#define FT_CPROP_CONT_TEXT_STYLE (0x01U << 12) /**< Cell content text style */ +/** @} */ + + +/** + * Colors. + */ +enum ft_color { + FT_COLOR_DEFAULT = 0, /**< Default color */ + FT_COLOR_BLACK = 1, /**< Black color*/ + FT_COLOR_RED = 2, /**< Red color */ + FT_COLOR_GREEN = 3, /**< Green color */ + FT_COLOR_YELLOW = 4, /**< Yellow color */ + FT_COLOR_BLUE = 5, /**< Blue color */ + FT_COLOR_MAGENTA = 6, /**< Magenta color */ + FT_COLOR_CYAN = 7, /**< Cyan color */ + FT_COLOR_LIGHT_GRAY = 8, /**< Light gray color */ + FT_COLOR_DARK_GRAY = 9, /**< Dark gray color */ + FT_COLOR_LIGHT_RED = 10, /**< Light red color */ + FT_COLOR_LIGHT_GREEN = 11, /**< Light green color */ + FT_COLOR_LIGHT_YELLOW = 12, /**< Light yellow color */ + FT_COLOR_LIGHT_BLUE = 13, /**< Light blue color */ + FT_COLOR_LIGHT_MAGENTA = 15, /**< Light magenta color */ + FT_COLOR_LIGHT_CYAN = 16, /**< Light cyan color */ + FT_COLOR_LIGHT_WHYTE = 17 /**< Light whyte color */ +}; + +/** + * Text styles. + */ +enum ft_text_style { + FT_TSTYLE_DEFAULT = (1U << 0), /**< Default style */ + FT_TSTYLE_BOLD = (1U << 1), /**< Bold */ + FT_TSTYLE_DIM = (1U << 2), /**< Dim */ + FT_TSTYLE_ITALIC = (1U << 3), /**< Italic */ + FT_TSTYLE_UNDERLINED = (1U << 4), /**< Underlined */ + FT_TSTYLE_BLINK = (1U << 5), /**< Blink */ + FT_TSTYLE_INVERTED = (1U << 6), /**< Reverse (invert the foreground and background colors) */ + FT_TSTYLE_HIDDEN = (1U << 7) /**< Hidden (useful for passwords) */ +}; + + +/** + * Alignment of cell content. + */ +enum ft_text_alignment { + FT_ALIGNED_LEFT = 0, /**< Align left */ + FT_ALIGNED_CENTER, /**< Align center */ + FT_ALIGNED_RIGHT /**< Align right */ +}; + +/** + * Type of table row. Determines appearance of row. + */ +enum ft_row_type { + FT_ROW_COMMON = 0, /**< Common row */ + FT_ROW_HEADER /**< Header row */ +}; + +/** + * Set default cell property for all new formatted tables. + * + * @param property + * Cell property identifier. + * @param value + * Cell property value. + * @return + * - 0: Success; default cell property was changed. + * - (<0): In case of error + */ +int ft_set_default_cell_prop(uint32_t property, int value); + +/** + * Set property for the specified cell of the table. + * + * @param table + * A pointer to the ft_table_t structure. + * @param row + * Cell row. + * @param col + * Cell column. + * @param property + * Cell property identifier. + * @param value + * Cell property value. + * @return + * - 0: Success; cell property was changed. + * - (<0): In case of error + */ +int ft_set_cell_prop(ft_table_t *table, size_t row, size_t col, uint32_t property, int value); + + +/** + * @name Table properties identifiers. + * @{ + */ +#define FT_TPROP_LEFT_MARGIN (0x01U << 0) +#define FT_TPROP_TOP_MARGIN (0x01U << 1) +#define FT_TPROP_RIGHT_MARGIN (0x01U << 2) +#define FT_TPROP_BOTTOM_MARGIN (0x01U << 3) +/** @} */ + + + +/** + * Set default table property. + * + * @param property + * Table property identifier. + * @param value + * Table property value. + * @return + * - 0: Success; default table property was changed. + * - (<0): In case of error + */ +int ft_set_default_tbl_prop(uint32_t property, int value); + +/** + * Set table property. + * + * @param table + * A pointer to the ft_table_t structure. + * @param property + * Table property identifier. + * @param value + * Table property value. + * @return + * - 0: Success; default table property was changed. + * - (<0): In case of error + */ +int ft_set_tbl_prop(ft_table_t *table, uint32_t property, int value); + + +/** + * Set column span for the specified cell of the table. + * + * @param table + * A pointer to the ft_table_t structure. + * @param row + * Cell row. + * @param col + * Cell column. + * @param hor_span + * Column span. + * @return + * - 0: Success; cell span was changed. + * - (<0): In case of error + */ +int ft_set_cell_span(ft_table_t *table, size_t row, size_t col, size_t hor_span); + + +/** + * Set functions for memory allocation and deallocation to be used instead of + * standard ones. + * + * @param f_malloc + * Pointer to a function for memory allocation that should be used instead of + * malloc. + * @param f_free + * Pointer to a function for memory deallocation that should be used instead + * of free. + * @note + * To return memory allocation/deallocation functions to their standard values + * set f_malloc and f_free to NULL. + */ +void ft_set_memory_funcs(void *(*f_malloc)(size_t size), void (*f_free)(void *ptr)); + + + + +#ifdef FT_HAVE_WCHAR + + +int ft_wprintf(ft_table_t *table, const wchar_t *fmt, ...); +int ft_wprintf_ln(ft_table_t *table, const wchar_t *fmt, ...); + + +#define ft_wwrite(table, ...)\ + (0 ? CHECK_IF_ARGS_ARE_WSTRINGS(__VA_ARGS__) : ft_nwwrite(table, FT_PP_NARG_(__VA_ARGS__), __VA_ARGS__)) +#define ft_wwrite_ln(table, ...)\ + (0 ? CHECK_IF_ARGS_ARE_WSTRINGS(__VA_ARGS__) : ft_nwwrite_ln(table, FT_PP_NARG_(__VA_ARGS__), __VA_ARGS__)) +int ft_nwwrite(ft_table_t *table, size_t n, const wchar_t *cell_content, ...); +int ft_nwwrite_ln(ft_table_t *table, size_t n, const wchar_t *cell_content, ...); + +int ft_row_wwrite(ft_table_t *table, size_t cols, const wchar_t *row_cells[]); +int ft_row_wwrite_ln(ft_table_t *table, size_t cols, const wchar_t *row_cells[]); + +int ft_table_wwrite(ft_table_t *table, size_t rows, size_t cols, const wchar_t *table_cells[]); +int ft_table_wwrite_ln(ft_table_t *table, size_t rows, size_t cols, const wchar_t *table_cells[]); + +const wchar_t *ft_to_wstring(const ft_table_t *table); +#endif + + + +FT_END_DECLS + +#endif /* LIBFORT_H */ diff --git a/src/fort.hpp b/src/fort.hpp new file mode 100644 index 0000000..bd7598f --- /dev/null +++ b/src/fort.hpp @@ -0,0 +1,1001 @@ +/* +libfort + +MIT License + +Copyright (c) 2017 - 2018 Seleznev Anton + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * @file fort.hpp + * @brief Main header file describing libfort C++ API . + * + * This files contains C++ wrappers around libfort API that can + * be used in C++ code. + */ +#ifndef LIBFORT_HPP +#define LIBFORT_HPP + +#include +#include +#include + +#include "fort.h" + +namespace fort +{ + +/** + * Alignment of cell content. + */ +enum class text_align { + left = FT_ALIGNED_LEFT, + center = FT_ALIGNED_CENTER, + right = FT_ALIGNED_RIGHT +}; + +/** + * Type of table row. Determines appearance of row. + */ +enum class row_type { + common = FT_ROW_COMMON, + header = FT_ROW_HEADER +}; + +/** + * Colors. + */ +enum class color { + default_color = FT_COLOR_DEFAULT, + black = FT_COLOR_BLACK, + red = FT_COLOR_RED, + green = FT_COLOR_GREEN, + yellow = FT_COLOR_YELLOW, + blue = FT_COLOR_BLUE, + magenta = FT_COLOR_MAGENTA, + cyan = FT_COLOR_CYAN, + light_gray = FT_COLOR_LIGHT_GRAY, + dark_gray = FT_COLOR_DARK_GRAY, + light_red = FT_COLOR_LIGHT_RED, + light_green = FT_COLOR_LIGHT_GREEN, + light_yellow = FT_COLOR_LIGHT_YELLOW, + light_blue = FT_COLOR_LIGHT_BLUE, + light_magenta = FT_COLOR_LIGHT_MAGENTA, + light_cyan = FT_COLOR_LIGHT_CYAN, + light_whyte = FT_COLOR_LIGHT_WHYTE +}; + +/** + * Text styles. + */ +enum class text_style { + default_style = FT_TSTYLE_DEFAULT, + bold = FT_TSTYLE_BOLD, + dim = FT_TSTYLE_DIM, + italic = FT_TSTYLE_ITALIC, + underlined = FT_TSTYLE_UNDERLINED, + blink = FT_TSTYLE_BLINK, + inverted = FT_TSTYLE_INVERTED, + hidden = FT_TSTYLE_HIDDEN +}; + +/** + * Table manipulator. + * + * Table manipulators can be used to change current cell and change appearance + * of cells. + */ +class table_manipulator { +public: + explicit table_manipulator(int i) + :value(i) + { + } + friend class table; +private: + int value; +}; + +/** + * Table manipulator to set current row as a header. + */ +const table_manipulator header(0); + +/** + * Table manipulator to move current cell to the first cell of the next row. + */ +const table_manipulator endr(1); + +/** + * Table manipulator to add separator to the table. + */ +const table_manipulator separator(2); + +/** + * Property owner. + * + * property_owner is a base class for all objects (table, row, column, cell) for + * which user can specify properties. + */ +template +class property_owner { +public: + + property_owner(std::size_t row_idx, std::size_t coll_idx, table *tbl, bool def = false) + :ps_row_idx_(row_idx), ps_coll_idx_(coll_idx), + ps_table_(tbl), set_default_properties_(def) {} + + /** + * Set min width for the specified cell of the table. + * + * @param value + * Value of the min width. + * @return + * - true: Success; cell property was changed. + * - false: In case of error + */ + bool set_cell_min_width(unsigned value) + { + return set_property(FT_CPROP_MIN_WIDTH, value); + } + + /** + * Set text alignment for the specified cell of the table. + * + * @param value + * Value of the text alignment. + * @return + * - true: Success; cell property was changed. + * - false: In case of error + */ + bool set_cell_text_align(enum fort::text_align value) + { + return set_property(FT_CPROP_TEXT_ALIGN, static_cast(value)); + } + + /** + * Set top padding for the specified cell of the table. + * + * @param value + * Value of the top padding. + * @return + * - true: Success; cell property was changed. + * - false: In case of error. + */ + bool set_cell_top_padding(unsigned value) + { + return set_property(FT_CPROP_TOP_PADDING, value); + } + + /** + * Set bottom padding for the specified cell of the table. + * + * @param value + * Value of the bottom padding. + * @return + * - true: Success; cell property was changed. + * - false: In case of error. + */ + bool set_cell_bottom_padding(unsigned value) + { + return set_property(FT_CPROP_BOTTOM_PADDING, value); + } + + /** + * Set left padding for the specified cell of the table. + * + * @param value + * Value of the left padding. + * @return + * - true: Success; cell property was changed. + * - false: In case of error. + */ + bool set_cell_left_padding(unsigned value) + { + return set_property(FT_CPROP_LEFT_PADDING, value); + } + + /** + * Set right padding for the specified cell of the table. + * + * @param value + * Value of the left padding. + * @return + * - true: Success; cell property was changed. + * - false: In case of error. + */ + bool set_cell_right_padding(unsigned value) + { + return set_property(FT_CPROP_RIGHT_PADDING, value); + } + + /** + * Set row type for the specified cell of the table. + * + * @param value + * Value of the row type. + * @return + * - true: Success; cell property was changed. + * - false: In case of error. + */ + bool set_cell_row_type(enum fort::row_type value) + { + return set_property(FT_CPROP_ROW_TYPE, static_cast(value)); + } + + /** + * Set empty string height for the specified cell of the table. + * + * @param value + * Value of the empty string height. + * @return + * - true: Success; cell property was changed. + * - false: In case of error. + */ + bool set_cell_empty_str_height(unsigned value) + { + return set_property(FT_CPROP_EMPTY_STR_HEIGHT, value); + } + + /** + * Set content foreground color for the specified cell of the table. + * + * @param value + * Color. + * @return + * - true: Success; cell property was changed. + * - false: In case of error. + */ + bool set_cell_content_fg_color(enum fort::color value) + { + return set_property(FT_CPROP_CONT_FG_COLOR, static_cast(value)); + } + + /** + * Set cell background color for the specified cell of the table. + * + * @param value + * Color. + * @return + * - true: Success; cell property was changed. + * - false: In case of error. + */ + bool set_cell_bg_color(enum fort::color value) + { + return set_property(FT_CPROP_CELL_BG_COLOR, static_cast(value)); + } + + /** + * Set content background color for the specified cell of the table. + * + * @param value + * Color. + * @return + * - true: Success; cell property was changed. + * - false: In case of error. + */ + bool set_cell_content_bg_color(enum fort::color value) + { + return set_property(FT_CPROP_CONT_BG_COLOR, static_cast(value)); + } + + /** + * Set cell text style for the specified cell of the table. + * + * @param value + * Text style. + * @return + * - true: Success; cell property was changed. + * - false: In case of error. + */ + bool set_cell_text_style(enum fort::text_style value) + { + return set_property(FT_CPROP_CELL_TEXT_STYLE, static_cast(value)); + } + + /** + * Set content text style for the specified cell of the table. + * + * @param value + * Text style. + * @return + * - true: Success; cell property was changed. + * - false: In case of error. + */ + bool set_cell_content_text_style(enum fort::text_style value) + { + return set_property(FT_CPROP_CONT_TEXT_STYLE, static_cast(value)); + } + +protected: + std::size_t ps_row_idx_; + std::size_t ps_coll_idx_; + table *ps_table_; + bool set_default_properties_; + + bool set_property(uint32_t property, int value) + { + int status; + if (set_default_properties_) { + status = ft_set_default_cell_prop(property, value); + } else { + status = ft_set_cell_prop(ps_table_->table_, ps_row_idx_, ps_coll_idx_, property, value); + } + return FT_IS_SUCCESS(status); + } +}; + +/** + * Formatted table. + * + * Table class is a C++ wrapper around struct ft_table. + */ +class table: public property_owner { +public: + + /** + * Default constructor. + */ + table() + :property_owner(FT_ANY_ROW, FT_ANY_COLUMN, this), table_(ft_create_table()) + { + + if (table_ == NULL) + throw std::runtime_error("Libfort runtime error"); + } + + /** + * Destructor. + */ + ~table() + { + ft_destroy_table(table_); + } + + /** + * Copy contstructor. + */ + table(const table& tbl) + :property_owner(FT_ANY_ROW, FT_ANY_COLUMN, this), table_(NULL) + { + if (tbl.table_) { + ft_table_t *table_copy = ft_copy_table(tbl.table_); + if (table_copy == NULL) + throw std::runtime_error("Libfort runtime error"); + + stream_.str(std::string()); + if (tbl.stream_.tellp() >= 0) { + stream_ << tbl.stream_.str(); + } + table_ = table_copy; + } + } + + /** + * Move contstructor. + */ + table(table&& tbl) + :property_owner(FT_ANY_ROW, FT_ANY_COLUMN, this), table_(tbl.table_) + { + if (tbl.stream_.tellp() >= 0) { + stream_ << tbl.stream_.str(); + tbl.stream_.str(std::string()); + } + tbl.table_ = 0; + } + + /** + * Copy assignment operator. + */ + table& operator=(const table& tbl) + { + if (&tbl == this) + return *this; + + if (tbl.table_) { + ft_table_t *table_copy = ft_copy_table(tbl.table_); + if (table_copy == NULL) + throw std::runtime_error("Libfort runtime error"); + + stream_.str(std::string()); + if (tbl.stream_.tellp() >= 0) { + stream_ << tbl.stream_.str(); + } + ft_destroy_table(table_); + table_ = table_copy; + } + return *this; + } + + /** + * Move assignment operator. + */ + table& operator=(table&& tbl) + { + if (&tbl == this) + return *this; + + if (tbl.table_) { + stream_.str(std::string()); + if (tbl.stream_.tellp() >= 0) { + stream_ << tbl.stream_.str(); + tbl.stream_.str(std::string()); + } + ft_destroy_table(table_); + table_ = tbl.table_; + tbl.table_ = NULL; + } + return *this; + } + + /** + * Convert table to string representation. + * + * @return + * - String representation of formatted table, on success. + * - In case of error std::runtime_error is thrown. + */ + std::string to_string() const + { + const char *str = ft_to_string(table_); + if (str == NULL) + throw std::runtime_error("Libfort runtime error"); + return str; + } + + /** + * Convert table to string representation. + * + * Table object has ownership of the returned pointer. So there is no need to + * free it. To take ownership user should explicitly copy the returned + * string with strdup or similar functions. + * + * Returned pointer may be later invalidated by: + * - Calling destroying the table; + * - Other invocations of c_str or to_string. + * + * @return + * - The pointer to the string representation of formatted table, on success. + * - NULL on error. + */ + const char *c_str() const + { + return ft_to_string(table_); + } + + /** + * Write provided object to the table. + * + * To convert object to the string representation conversion for + * std::ostream is used. + * + * @param arg + * Obect that would be inserted in the current cell. + * @return + * - Reference to the current table. + */ + template + table &operator<<(const T &arg) + { + stream_ << arg; + if (stream_.tellp() >= 0) { + ft_nwrite(table_, 1, stream_.str().c_str()); + stream_.str(std::string()); + } + return *this; + } + + table &operator<<(const table_manipulator &arg) + { + if (arg.value == header.value) + ft_set_cell_prop(table_, FT_CUR_ROW, FT_ANY_ROW, FT_CPROP_ROW_TYPE, FT_ROW_HEADER); + else if (arg.value == endr.value) + ft_ln(table_); + else if (arg.value == separator.value) + ft_add_separator(table_); + return *this; + } + + /** + * Write string to the the table. + * + * Write specified string to the current cell. + * + * @param str + * String to write. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ + bool write(const char *str) + { + return FT_IS_SUCCESS(ft_write(table_, str)); + } + + /** + * Write string to the the table and go to the next line. + * + * Write specified string to the current cell and move current position to + * the first cell of the next line(row). + * + * @param str + * String to write. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ + bool write_ln(const char *str) + { + return FT_IS_SUCCESS(ft_write_ln(table_, str)); + } + + /** + * Write string to the the table. + * + * Write specified string to the current cell. + * + * @param str + * String to write. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ + bool write(const std::string &str) + { + return write(str.c_str()); + } + + /** + * Write string to the the table and go to the next line. + * + * Write specified string to the current cell and move current position to + * the first cell of the next line(row). + * + * @param str + * String to write. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ + bool write_ln(const std::string &str) + { + return write_ln(str.c_str()); + } + +#ifdef __cpp_variadic_templates + /** + * Write strings to the table. + * + * Write specified strings to the same number of consecutive cells in the + * current row. + * + * @param str + * String to write. + * @param strings + * Strings to write. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ + template + bool write(const T &str, const Ts &...strings) + { + return write(str) && write(strings...); + } + + /** + * Write strings to the table and go to the next line. + * + * Write specified strings to the same number of consecutive cells in the + * current row and move current position to the first cell of the next + * line(row). + * + * @param str + * String to write. + * @param strings + * Strings to write. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ + template + bool write_ln(const T &str, const Ts &...strings) + { + return write(str) && write_ln(strings...); + } +#else /* __cpp_variadic_templates */ + + template + bool write(const T_0 &arg_0, const T_1 &arg_1) + { + return write(arg_0) && write(arg_1); + } + + template + bool write(const T_0 &arg_0, const T_1 &arg_1, const T_2 &arg_2) + { + return write(arg_0) && write(arg_1, arg_2); + } + + template + bool write(const T_0 &arg_0, const T_1 &arg_1, const T_2 &arg_2, const T_3 &arg_3) + { + return write(arg_0) && write(arg_1, arg_2, arg_3); + } + + template + bool write(const T_0 &arg_0, const T_1 &arg_1, const T_2 &arg_2, const T_3 &arg_3, const T_4 &arg_4) + { + return write(arg_0) && write(arg_1, arg_2, arg_3, arg_4); + } + + template + bool write(const T_0 &arg_0, const T_1 &arg_1, const T_2 &arg_2, const T_3 &arg_3, const T_4 &arg_4, const T_5 &arg_5) + { + return write(arg_0) && write(arg_1, arg_2, arg_3, arg_4, arg_5); + } + + template + bool write(const T_0 &arg_0, const T_1 &arg_1, const T_2 &arg_2, const T_3 &arg_3, const T_4 &arg_4, const T_5 &arg_5, const T_6 &arg_6) + { + return write(arg_0) && write(arg_1, arg_2, arg_3, arg_4, arg_5, arg_6); + } + + template + bool write(const T_0 &arg_0, const T_1 &arg_1, const T_2 &arg_2, const T_3 &arg_3, const T_4 &arg_4, const T_5 &arg_5, const T_6 &arg_6, const T_7 &arg_7) + { + return write(arg_0) && write(arg_1, arg_2, arg_3, arg_4, arg_5, arg_6, arg_7); + } + + + template + bool write_ln(const T_0 &arg_0, const T_1 &arg_1) + { + return write(arg_0) && write_ln(arg_1); + } + + template + bool write_ln(const T_0 &arg_0, const T_1 &arg_1, const T_2 &arg_2) + { + return write(arg_0) && write_ln(arg_1, arg_2); + } + + template + bool write_ln(const T_0 &arg_0, const T_1 &arg_1, const T_2 &arg_2, const T_3 &arg_3) + { + return write(arg_0) && write_ln(arg_1, arg_2, arg_3); + } + + template + bool write_ln(const T_0 &arg_0, const T_1 &arg_1, const T_2 &arg_2, const T_3 &arg_3, const T_4 &arg_4) + { + return write(arg_0) && write_ln(arg_1, arg_2, arg_3, arg_4); + } + + template + bool write_ln(const T_0 &arg_0, const T_1 &arg_1, const T_2 &arg_2, const T_3 &arg_3, const T_4 &arg_4, const T_5 &arg_5) + { + return write(arg_0) && write_ln(arg_1, arg_2, arg_3, arg_4, arg_5); + } + + template + bool write_ln(const T_0 &arg_0, const T_1 &arg_1, const T_2 &arg_2, const T_3 &arg_3, const T_4 &arg_4, const T_5 &arg_5, const T_6 &arg_6) + { + return write(arg_0) && write_ln(arg_1, arg_2, arg_3, arg_4, arg_5, arg_6); + } + + template + bool write_ln(const T_0 &arg_0, const T_1 &arg_1, const T_2 &arg_2, const T_3 &arg_3, const T_4 &arg_4, const T_5 &arg_5, const T_6 &arg_6, const T_7 &arg_7) + { + return write(arg_0) && write_ln(arg_1, arg_2, arg_3, arg_4, arg_5, arg_6, arg_7); + } + +#endif /* __cpp_variadic_templates */ + + /** + * Write elements from range to the table. + * + * Write objects from range to consecutive cells in the current row. + * + * @param first, last + * Range of elements. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ + template + bool range_write(InputIt first, InputIt last) + { + while (first != last) { + *this << *first; + ++first; + } + return true; + } + + /** + * Write elements from range to the table and go to the next line. + * + * Write objects from range to consecutive cells in the current row and + * move current position to the first cell of the next line(row). + * + * @param first, last + * Range of elements. + * @return + * - 0: Success; data were written + * - (<0): In case of error + */ + template + bool range_write_ln(InputIt first, InputIt last) + { + while (first != last) { + *this << *first; + ++first; + } + ft_ln(table_); + return true; + } + + /** + * Set border style for the table. + * + * @param style + * Pointer to border style. + * @return + * - True: Success; table border style was changed. + * - False: Error + */ + bool set_border_style(struct ft_border_style *style) + { + return FT_IS_SUCCESS(ft_set_border_style(table_, style)); + } + + /** + * Set current cell position. + * + * Current cell - cell that will be edited with all modifiing functions. + * + * @param row_i + * New row number for the current cell. + * @param col_i + * New row number for the current cell. + */ + void set_cur_cell(size_t row_i, size_t col_i) + { + ft_set_cur_cell(table_, row_i, col_i); + } + + + /** + * Set table left margin. + * + * @param value + * Left margin. + * @return + * - true: Success; table property was changed. + * - false: In case of error. + */ + bool set_left_margin(unsigned value) + { + return FT_IS_SUCCESS(ft_set_tbl_prop(table_, FT_TPROP_LEFT_MARGIN, value)); + } + + /** + * Set table top margin. + * + * @param value + * Top margin. + * @return + * - true: Success; table property was changed. + * - false: In case of error. + */ + bool set_top_margin(unsigned value) + { + return FT_IS_SUCCESS(ft_set_tbl_prop(table_, FT_TPROP_TOP_MARGIN, value)); + } + + /** + * Set table right margin. + * + * @param value + * Right margin. + * @return + * - true: Success; table property was changed. + * - false: In case of error. + */ + bool set_right_margin(unsigned value) + { + return FT_IS_SUCCESS(ft_set_tbl_prop(table_, FT_TPROP_RIGHT_MARGIN, value)); + } + + /** + * Set table bottom margin. + * + * @param value + * Bottom margin. + * @return + * - true: Success; table property was changed. + * - false: In case of error. + */ + bool set_bottom_margin(unsigned value) + { + return FT_IS_SUCCESS(ft_set_tbl_prop(table_, FT_TPROP_BOTTOM_MARGIN, value)); + } +private: + ft_table_t *table_; + mutable std::stringstream stream_; + friend class property_owner
; + + +public: + + /* Iterators */ + /* todo: implement chains like table[0][0] = table [0][1] = "somethings" */ + + /** + * Table cell. + */ + class table_cell: public property_owner
+ { + public: + table_cell(std::size_t row_idx, std::size_t coll_idx, table &tbl) + :property_owner(row_idx, coll_idx, &tbl) {} + + table_cell& operator=(const char *str) + { + ft_set_cur_cell(ps_table_->table_, ps_row_idx_, ps_coll_idx_); + ps_table_->write(str); + return *this; + } + + table_cell& operator=(const std::string &str) + { + return operator=(str.c_str()); + } + + /** + * Set column span for the specified cell of the table. + * + * @param hor_span + * Column span. + * @return + * - true: Success; cell span was changed. + * - false: In case of error. + */ + bool set_cell_span(size_t hor_span) + { + if (set_default_properties_) + return false; + + return FT_IS_SUCCESS(ft_set_cell_span(ps_table_->table_, ps_row_idx_, ps_coll_idx_, hor_span)); + } + }; + + /** + * Table row. + */ + class table_row: public property_owner
+ { + public: + table_row(std::size_t row_idx, table &tbl) + :property_owner(row_idx, FT_ANY_COLUMN, &tbl) {} + + class table_cell + operator[](std::size_t coll_idx) + { + return table_cell(ps_row_idx_, coll_idx, *ps_table_); + } + }; + + /** + * Table column. + */ + class table_column: public property_owner
+ { + public: + table_column(std::size_t col_idx, table &tbl) + :property_owner(FT_ANY_ROW, col_idx, &tbl) {} + }; + + class default_properties: public property_owner
+ { + public: + default_properties(table *tbl) + :property_owner(FT_ANY_ROW, FT_ANY_COLUMN, tbl, true) {} + }; + + class table_row + operator[](std::size_t row_idx) + { + return table_row(row_idx, *this); + } + + + /** + * Get cell. + * + * @param row_idx + * Row index. + * @param col_idx + * Column index. + * @return + * table_cell object. + */ + class table_cell + cell(std::size_t row_idx, std::size_t col_idx) + { + return (*this)[row_idx][col_idx]; + } + + /** + * Get row. + * + * @param row_idx + * Row index. + * @return + * table_row object. + */ + class table_row + row(std::size_t row_idx) + { + return table_row(row_idx, *this); + } + + /** + * Get column. + * + * @param col_idx + * Column index. + * @return + * table_column object. + */ + class table_column + column(std::size_t col_idx) + { + return table_column(col_idx, *this); + } + + static class default_properties + default_props() + { + return default_properties(NULL); + } +}; + + +/** + * Set default border style for all new formatted tables. + * + * @param style + * Pointer to border style. + * @return + * - True: Success; table border style was changed. + * - False: Error + */ +inline bool set_default_border_style(struct ft_border_style *style) +{ + return FT_IS_SUCCESS(ft_set_default_border_style(style)); +} + + +} + +#endif // LIBFORT_HPP