diff --git a/CMakeLists.txt b/CMakeLists.txt index cb3d08e..4aae845 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,7 @@ endif(FORT_COMPILER STREQUAL "MSVC") # Sources and executables # ------------------------------------------------------------------------------ -FILE(GLOB_RECURSE FortHeaders "include/*.h" "tests/*.h" "src/*.h") +FILE(GLOB_RECURSE FortHeaders "include/*.h" "include/*.hpp" "tests/*.h" "src/*.h") add_custom_target(headers SOURCES ${FortHeaders}) @@ -74,6 +74,11 @@ add_executable(${PROJECT_NAME}_example ${EXAMPLE_SOURCES} ${FORT_SOURCES}) +set(EXAMPLE_CPP_SOURCES + example/main.cpp) +add_executable(${PROJECT_NAME}_example_cpp + ${EXAMPLE_CPP_SOURCES} + ${FORT_SOURCES}) set(TEST_SOURCES tests/test.c @@ -107,6 +112,7 @@ if(FORT_COMPILER STREQUAL "GNU" OR FORT_COMPILER STREQUAL "Clang") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") if(FORT_COMPILER STREQUAL "GNU") target_link_libraries(${PROJECT_NAME}_example asan) + target_link_libraries(${PROJECT_NAME}_example_cpp asan) target_link_libraries(${PROJECT_NAME}_test asan) endif(FORT_COMPILER STREQUAL "GNU") endif(FORT_BUILD_TYPE STREQUAL "asan") @@ -117,6 +123,7 @@ if(FORT_COMPILER STREQUAL "GNU" OR FORT_COMPILER STREQUAL "Clang") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-sanitize-recover") #to force fail if(FORT_COMPILER STREQUAL "GNU") target_link_libraries(${PROJECT_NAME}_example ubsan) + target_link_libraries(${PROJECT_NAME}_example_cpp ubsan) target_link_libraries(${PROJECT_NAME}_test ubsan) endif(FORT_COMPILER STREQUAL "GNU") endif(FORT_BUILD_TYPE STREQUAL "ubsan") diff --git a/example/main.cpp b/example/main.cpp new file mode 100644 index 0000000..9978853 --- /dev/null +++ b/example/main.cpp @@ -0,0 +1,21 @@ +#include +#include "fort.hpp" + + +int main() +{ + fort::FTable table; + + // Fill table with data + table << fort::header + << "Rank" << "Title" << "Year" << "Rating" << fort::endl + << "1" << "The Shawshank Redemption" << "1994" << "9.5" << fort::endl + << "2" << "12 Angry Men" << "1957" << "8.8" << fort::endl + << "3" << "It's a Wonderful Life" << "1946" << "8.6" << fort::endl + << fort::separator + << "4" << "2001: A Space Odyssey" << "1968" << "8.5" << fort::endl + << "5" << "Blade Runner" << "1982" << "8.1" << fort::endl; + + std::cout << table.to_string(); + return 0; +} diff --git a/include/fort.h b/include/fort.h index 5659edd..f651bd7 100644 --- a/include/fort.h +++ b/include/fort.h @@ -107,9 +107,6 @@ SOFTWARE. #endif -#define STRING2(x) #x -#define STRING(x) STRING2(x) - /* * Wchar support @@ -138,23 +135,6 @@ static FT_INLINE int ft_check_if_wstring_helper(const wchar_t *str) return 0; } -/* -#define PP_ARG_N( \ - _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ - _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ - _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ - _31, N, ...) N -#define PP_RSEQ_N() \ - 31,30, \ - 29,28,27,26,25,24,23,22,21,20, \ - 19,18,17,16,15,14,13,12,11,10, \ - 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 -#define PP_NARG_(...) \ - PP_ARG_N(__VA_ARGS__) -#define PP_NARG(...) \ - PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) -*/ - #define FORT_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 PP_NARG(...) \ @@ -193,11 +173,15 @@ static FT_INLINE int ft_check_if_wstring_helper(const wchar_t *str) #define CHECK_IF_STRING_2(checker,arg,...) (checker(arg),FT_EXPAND_(CHECK_IF_STRING_1(checker,__VA_ARGS__))) #define CHECK_IF_STRING_1(checker,arg) (checker(arg)) -#define CHECK_IF_ARGS_ARE_STRINGS__(checker,func, ...) FT_EXPAND_(func(checker,__VA_ARGS__)) -#define CHECK_IF_ARGS_ARE_STRINGS_(checker,basis, n, ...) CHECK_IF_ARGS_ARE_STRINGS__(checker,STR_2_CAT_(basis, n), __VA_ARGS__) -#define CHECK_IF_ARGS_ARE_STRINGS(...) CHECK_IF_ARGS_ARE_STRINGS_(ft_check_if_string_helper,CHECK_IF_STRING_,PP_NARG(__VA_ARGS__), __VA_ARGS__) +#define CHECK_IF_ARGS_ARE_STRINGS__(checker,func, ...) \ + FT_EXPAND_(func(checker,__VA_ARGS__)) +#define CHECK_IF_ARGS_ARE_STRINGS_(checker,basis, n, ...) \ + CHECK_IF_ARGS_ARE_STRINGS__(checker,STR_2_CAT_(basis, n), __VA_ARGS__) +#define CHECK_IF_ARGS_ARE_STRINGS(...) \ + CHECK_IF_ARGS_ARE_STRINGS_(ft_check_if_string_helper,CHECK_IF_STRING_,PP_NARG(__VA_ARGS__), __VA_ARGS__) #ifdef FT_HAVE_WCHAR -#define CHECK_IF_ARGS_ARE_WSTRINGS(...) CHECK_IF_ARGS_ARE_STRINGS_(ft_check_if_wstring_helper,CHECK_IF_STRING_,PP_NARG(__VA_ARGS__), __VA_ARGS__) +#define CHECK_IF_ARGS_ARE_WSTRINGS(...) \ + CHECK_IF_ARGS_ARE_STRINGS_(ft_check_if_wstring_helper,CHECK_IF_STRING_,PP_NARG(__VA_ARGS__), __VA_ARGS__) #endif /* @@ -209,11 +193,35 @@ FT_BEGIN_DECLS struct fort_table; typedef struct fort_table FTABLE; +/** + * Create formatted table. + * + * @return + * The pointer to the new allocated FTABLE, on success. NULL on error + * with ft_errno set appropriately. + */ FT_EXTERN FTABLE *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. + */ FT_EXTERN void ft_destroy_table(FTABLE *table); - +/** + * Move current position to the first cell of the next line(row). + * + * @param table + * Pointer to formatted table. + */ FT_EXTERN void ft_ln(FTABLE *table); +FT_EXTERN size_t ft_cur_row(FTABLE *table); +FT_EXTERN size_t ft_cur_col(FTABLE *table); #if defined(FT_CLANG_COMPILER) || defined(FT_GCC_COMPILER) @@ -262,44 +270,70 @@ FT_EXTERN int ft_table_write_ln(FTABLE *table, size_t rows, size_t cols, const c - +/** + * Add separator after the current row. + * + * @param table + * Formatted table. + * @return + * - 0: Success; separator was added. + * - (-1): !!!!!!!! todo + */ FT_EXTERN int ft_add_separator(FTABLE *table); - +/** + * Convert table to string representation. + * + * FTABLE 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 remaines valid + * until table is destroyed with ft_destroy_table or 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 with ft_errno set appropriately. + */ FT_EXTERN const char *ft_to_string(const FTABLE *table); /* * Setting table appearance */ -#define FT_ANY_COLUMN (UINT_MAX) -#define FT_ANY_ROW (UINT_MAX) +#define FT_ANY_COLUMN (UINT_MAX) +#define FT_ANY_ROW (UINT_MAX) -#define FT_ROW_UNSPEC (UINT_MAX-1) -#define FT_COLUMN_UNSPEC (UINT_MAX-1) +#define FT_CUR_COLUMN (UINT_MAX - 1) +#define FT_CUR_ROW (UINT_MAX - 1) -/* +#define FT_ROW_UNSPEC (UINT_MAX - 2) +#define FT_COLUMN_UNSPEC (UINT_MAX - 2) + +/** * Cell options */ -#define FT_COPT_MIN_WIDTH ((uint32_t)(0x01U << (0))) -#define FT_COPT_TEXT_ALIGN ((uint32_t)(0x01U << (1))) -#define FT_COPT_TOP_PADDING ((uint32_t)(0x01U << (2))) -#define FT_COPT_BOTTOM_PADDING ((uint32_t)(0x01U << (3))) -#define FT_COPT_LEFT_PADDING ((uint32_t)(0x01U << (4))) -#define FT_COPT_RIGHT_PADDING ((uint32_t)(0x01U << (5))) -#define FT_COPT_EMPTY_STR_HEIGHT ((uint32_t)(0x01U << (6))) -#define FT_COPT_ROW_TYPE ((uint32_t)(0x01U << (7))) +#define FT_COPT_MIN_WIDTH (0x01U << 0) /**< Minimum width */ +#define FT_COPT_TEXT_ALIGN (0x01U << 1) /**< Text alignmemnt */ +#define FT_COPT_TOP_PADDING (0x01U << 2) /**< Top padding for cell content */ +#define FT_COPT_BOTTOM_PADDING (0x01U << 3) /**< Bottom padding for cell content */ +#define FT_COPT_LEFT_PADDING (0x01U << 4) /**< Left padding for cell content */ +#define FT_COPT_RIGHT_PADDING (0x01U << 5) /**< Right padding for cell content */ +#define FT_COPT_EMPTY_STR_HEIGHT (0x01U << 6) /**< Height of empty cell */ +#define FT_COPT_ROW_TYPE (0x01U << 7) /**< Row type */ -/* +/** * Table options */ -#define FT_TOPT_LEFT_MARGIN ((uint32_t)(0x01U << (0))) -#define FT_TOPT_TOP_MARGIN ((uint32_t)(0x01U << (1))) -#define FT_TOPT_RIGHT_MARGIN ((uint32_t)(0x01U << (2))) -#define FT_TOPT_BOTTOM_MARGIN ((uint32_t)(0x01U << (3))) +#define FT_TOPT_LEFT_MARGIN (0x01U << 0) +#define FT_TOPT_TOP_MARGIN (0x01U << 1) +#define FT_TOPT_RIGHT_MARGIN (0x01U << 2) +#define FT_TOPT_BOTTOM_MARGIN (0x01U << 3) + enum TextAlignment { LeftAligned, diff --git a/include/fort.hpp b/include/fort.hpp new file mode 100644 index 0000000..f173a5c --- /dev/null +++ b/include/fort.hpp @@ -0,0 +1,85 @@ +#ifndef LIBFORT_HPP +#define LIBFORT_HPP + +#include "fort.h" +#include +#include + +#include + + + +namespace fort +{ + +class FTableManipulator { +public: + explicit FTableManipulator(int i) + :value(i) + { + } + friend class FTable; +private: + int value; +}; + +const FTableManipulator header(0); +const FTableManipulator endl(1); +const FTableManipulator separator(2); + +class FTable { +public: + FTable() + :table(ft_create_table()) + { + if (table == NULL) + throw std::runtime_error("Runtime error"); + } + + ~FTable() + { + ft_destroy_table(table); + } + + std::string to_string() const + { + const char *str = ft_to_string(table); + if (str == NULL) + throw std::runtime_error("Runtime error"); + return str; + } + + const char *c_str() const + { + return ft_to_string(table); + } + + template + FTable &operator<<(const T &arg) + { + std::stringstream stream; + stream << arg; + ft_nwrite(table, 1, stream.str().c_str()); + return *this; + } + + FTable &operator<<(const FTableManipulator &arg) + { + if (arg.value == header.value) + ft_set_cell_option(table, FT_CUR_ROW, FT_ANY_ROW, FT_COPT_ROW_TYPE, Header); + else if (arg.value == endl.value) + ft_ln(table); + else if (arg.value == separator.value) + ft_add_separator(table); + return *this; + } + + + +private: + FTABLE *table; +}; + +} + +#endif // LIBFORT_HPP diff --git a/src/cell.c b/src/cell.c index 3314e18..40419d3 100644 --- a/src/cell.c +++ b/src/cell.c @@ -7,7 +7,6 @@ * CELL * ***************************************************************************/ - struct fort_cell { string_buffer_t *str_buffer; fort_table_options_t *options; diff --git a/src/fort.c b/src/fort.c index 3ac709b..9750344 100644 --- a/src/fort.c +++ b/src/fort.c @@ -105,6 +105,17 @@ void ft_ln(FTABLE *table) table->cur_row++; } +size_t ft_cur_row(FTABLE *table) +{ + assert(table); + return table->cur_row; +} + +size_t ft_cur_col(FTABLE *table) +{ + assert(table); + return table->cur_col; +} static int ft_row_printf_impl(FTABLE *table, size_t row, const char *fmt, va_list *va) { @@ -829,6 +840,12 @@ int ft_set_cell_option(FTABLE *table, unsigned row, unsigned col, uint32_t optio return FT_ERROR; } } + + if (row == FT_CUR_ROW) + row = table->cur_row; + if (row == FT_CUR_COLUMN) + col = table->cur_col; + return set_cell_option(table->options->cell_options, row, col, option, value); } diff --git a/src/options.h b/src/options.h index 9529457..4eb4c2d 100644 --- a/src/options.h +++ b/src/options.h @@ -5,20 +5,6 @@ #include #include -//enum TextAlignment -//{ -// LeftAligned, -// CenterAligned, -// RightAligned -//}; - -//enum RowType -//{ -// Common, -// Header -//}; - - struct fort_column_options { int col_min_width; @@ -34,21 +20,6 @@ fort_column_options_t create_column_options(void); struct vector; typedef struct vector vector_t; -#define FT_ANY_COLUMN (UINT_MAX) -#define FT_ANY_ROW (UINT_MAX) - -#define FT_ROW_UNSPEC (UINT_MAX-1) -#define FT_COLUMN_UNSPEC (UINT_MAX-1) - -#define FT_COPT_MIN_WIDTH ((uint32_t)(0x01U << (0))) -#define FT_COPT_TEXT_ALIGN ((uint32_t)(0x01U << (1))) -#define FT_COPT_TOP_PADDING ((uint32_t)(0x01U << (2))) -#define FT_COPT_BOTTOM_PADDING ((uint32_t)(0x01U << (3))) -#define FT_COPT_LEFT_PADDING ((uint32_t)(0x01U << (4))) -#define FT_COPT_RIGHT_PADDING ((uint32_t)(0x01U << (5))) -#define FT_COPT_EMPTY_STR_HEIGHT ((uint32_t)(0x01U << (6))) -#define FT_COPT_ROW_TYPE ((uint32_t)(0x01U << (7))) - #define OPTION_IS_SET(ft_opts, option) ((ft_opts) & (option)) #define OPTION_SET(ft_opts, option) ((ft_opts) |=(option)) #define OPTION_UNSET(ft_opts, option) ((ft_opts) &= ~((uint32_t)option))