From 8ba3d995650175a288b81893fe8f29ca50fbd2a4 Mon Sep 17 00:00:00 2001 From: seleznevae Date: Mon, 5 Mar 2018 21:08:14 +0300 Subject: [PATCH] [C] Refactoring of setting row type --- example/main.c | 39 ++++- include/fort.h | 105 ++++++++----- src/cell.c | 59 ++++++-- src/cell.h | 2 + src/fort.c | 203 +++++++++++++++++++++++-- src/fort_impl.c | 40 ++++- src/fort_impl.h | 4 + src/options.c | 6 + src/options.h | 8 + src/row.c | 239 +++++++++++++++++++++++++----- src/row.h | 20 ++- src/string_buffer.c | 296 ++++++++++++++++++++++++++++++++----- src/string_buffer.h | 24 ++- tests/test_string_buffer.c | 175 +++++++++++++++++++--- tests/test_table.c | 1 + 15 files changed, 1058 insertions(+), 163 deletions(-) diff --git a/example/main.c b/example/main.c index 1b63c0f..0df9125 100644 --- a/example/main.c +++ b/example/main.c @@ -1,10 +1,41 @@ #include #include "fort.h" +#include +#include int main() { - FTABLE *table = ft_create_table(); + FTABLE *table = NULL; + +#ifdef FORT_HAVE_WCHAR + setlocale(LC_CTYPE, ""); + + + table = ft_create_table(); + ft_set_cell_option(table, FT_ANY_ROW, 0, FT_OPT_TEXT_ALIGN, CenterAligned); + ft_set_cell_option(table, FT_ANY_ROW, 1, FT_OPT_TEXT_ALIGN, LeftAligned); + + FT_NWWRITE_LN(table, L"1", L"Побег из Шоушенка", L"1994", L"9.5"); + FT_NWWRITE_LN(table, L"2", L"12 разгневанных мужчин", L"1957", L"8.8"); + FT_NWWRITE_LN(table, L"3", L"Космическая одиссея 2001 года", L"1968", L"8.5"); + FT_NWWRITE_LN(table, L"4", L"Бегущий по лезвию", L"1982", L"8.1"); + + fwprintf(stderr, L"Table:\n"); + fwprintf(stderr, L"%ls\n", ft_to_wstring(table)); + ft_destroy_table(table); +#endif + + + + + + + + + + /*-------------------------------------------------------------*/ + table = ft_create_table(); ft_set_cell_option(table, FT_ANY_ROW, 0, FT_OPT_TEXT_ALIGN, CenterAligned); ft_set_cell_option(table, FT_ANY_ROW, 1, FT_OPT_TEXT_ALIGN, LeftAligned); @@ -83,5 +114,11 @@ int main() printf("Table:\n"); printf("%s\n", ft_to_string(table)); ft_destroy_table(table); + + /*-------------------------------------------------------------*/ + + + + table = NULL; } diff --git a/include/fort.h b/include/fort.h index b31a7c6..b21c4dc 100644 --- a/include/fort.h +++ b/include/fort.h @@ -87,6 +87,11 @@ SOFTWARE. #endif +/* + * Wchar support + */ +#define FORT_HAVE_WCHAR + /* * Helper macros */ @@ -103,6 +108,12 @@ static inline int fort_check_if_string_helper(const char*str) return 0; } +static inline int fort_check_if_wstring_helper(const wchar_t*str) +{ + (void)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, \ @@ -118,44 +129,47 @@ static inline int fort_check_if_string_helper(const char*str) #define PP_NARG(...) \ PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) -#define CHECK_IF_ARG_IS_STRING_32(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_31(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_31(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_30(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_30(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_29(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_29(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_28(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_28(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_27(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_27(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_26(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_26(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_25(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_25(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_24(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_24(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_23(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_23(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_22(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_22(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_21(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_21(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_20(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_20(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_19(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_19(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_18(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_18(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_17(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_17(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_16(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_16(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_15(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_15(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_14(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_14(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_13(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_13(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_12(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_12(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_11(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_11(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_10(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_10(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_9(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_9(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_8(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_8(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_7(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_7(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_6(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_6(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_5(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_5(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_4(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_4(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_3(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_3(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_2(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_2(arg,...) (fort_check_if_string_helper(arg),CHECK_IF_ARG_IS_STRING_1(__VA_ARGS__)) -#define CHECK_IF_ARG_IS_STRING_1(arg) (fort_check_if_string_helper(arg)) - -#define CHECK_IF_ARGS_ARE_STRINGS__(func, ...) func(__VA_ARGS__) -#define CHECK_IF_ARGS_ARE_STRINGS_(basis, n, ...) CHECK_IF_ARGS_ARE_STRINGS__(STR_2_CAT_(basis, n), __VA_ARGS__) -#define CHECK_IF_ARGS_ARE_STRINGS(...) CHECK_IF_ARGS_ARE_STRINGS_(CHECK_IF_ARG_IS_STRING_,PP_NARG(__VA_ARGS__), __VA_ARGS__) +#define CHECK_IF_ARG_IS_STRING_32(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_31(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_31(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_30(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_30(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_29(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_29(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_28(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_28(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_27(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_27(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_26(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_26(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_25(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_25(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_24(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_24(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_23(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_23(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_22(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_22(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_21(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_21(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_20(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_20(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_19(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_19(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_18(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_18(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_17(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_17(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_16(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_16(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_15(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_15(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_14(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_14(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_13(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_13(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_12(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_12(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_11(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_11(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_10(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_10(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_9(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_9(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_8(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_8(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_7(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_7(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_6(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_6(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_5(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_5(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_4(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_4(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_3(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_3(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_2(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_2(checker,arg,...) (checker(arg),CHECK_IF_ARG_IS_STRING_1(checker,__VA_ARGS__)) +#define CHECK_IF_ARG_IS_STRING_1(checker,arg) (checker(arg)) + +#define CHECK_IF_ARGS_ARE_STRINGS__(checker,func, ...) 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_(fort_check_if_string_helper,CHECK_IF_ARG_IS_STRING_,PP_NARG(__VA_ARGS__), __VA_ARGS__) +#ifdef FORT_HAVE_WCHAR +#define CHECK_IF_ARGS_ARE_WSTRINGS(...) CHECK_IF_ARGS_ARE_STRINGS_(fort_check_if_wstring_helper,CHECK_IF_ARG_IS_STRING_,PP_NARG(__VA_ARGS__), __VA_ARGS__) +#endif /* * libfort structures and functions declarations @@ -202,19 +216,27 @@ FORT_EXTERN int ft_hdr_printf_ln_impl(FTABLE *FORT_RESTRICT table, const char* F FORT_EXTERN int ft_write(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT cell_content); FORT_EXTERN int ft_write_ln(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT cell_content); - - - #define FT_NWRITE(table, ...)\ (0 ? CHECK_IF_ARGS_ARE_STRINGS(__VA_ARGS__) : ft_nwrite(table, PP_NARG(__VA_ARGS__), __VA_ARGS__)) - #define FT_NWRITE_LN(table, ...)\ (0 ? CHECK_IF_ARGS_ARE_STRINGS(__VA_ARGS__) : ft_nwrite_ln(table, PP_NARG(__VA_ARGS__), __VA_ARGS__)) - FORT_EXTERN int ft_nwrite(FTABLE *FORT_RESTRICT table, size_t n, const char* FORT_RESTRICT cell_content, ...); FORT_EXTERN int ft_nwrite_ln(FTABLE *FORT_RESTRICT table, size_t n, const char* FORT_RESTRICT cell_content, ...); +#ifdef FORT_HAVE_WCHAR +FORT_EXTERN int ft_wwrite(FTABLE *FORT_RESTRICT table, const wchar_t* FORT_RESTRICT cell_content); +FORT_EXTERN int ft_wwrite_ln(FTABLE *FORT_RESTRICT table, const wchar_t* FORT_RESTRICT cell_content); + +#define FT_NWWRITE(table, ...)\ + (0 ? CHECK_IF_ARGS_ARE_WSTRINGS(__VA_ARGS__) : ft_nwwrite(table, PP_NARG(__VA_ARGS__), __VA_ARGS__)) +#define FT_NWWRITE_LN(table, ...)\ + (0 ? CHECK_IF_ARGS_ARE_WSTRINGS(__VA_ARGS__) : ft_nwwrite_ln(table, PP_NARG(__VA_ARGS__), __VA_ARGS__)) +FORT_EXTERN int ft_nwwrite(FTABLE *FORT_RESTRICT table, size_t n, const wchar_t* FORT_RESTRICT cell_content, ...); +FORT_EXTERN int ft_nwwrite_ln(FTABLE *FORT_RESTRICT table, size_t n, const wchar_t* FORT_RESTRICT cell_content, ...); +#endif + + FORT_EXTERN int ft_row_write(FTABLE *FORT_RESTRICT table, size_t cols, const char* FORT_RESTRICT row_cells[]); FORT_EXTERN int ft_row_write_ln(FTABLE *FORT_RESTRICT table, size_t cols, const char* FORT_RESTRICT row_cells[]); @@ -238,6 +260,7 @@ FORT_EXTERN int ft_add_separator(FTABLE *FORT_RESTRICT table); FORT_EXTERN const char* ft_to_string(const FTABLE *FORT_RESTRICT table); +FORT_EXTERN const wchar_t* ft_to_wstring(const FTABLE *FORT_RESTRICT table); //FORT_EXTERN ssize_t ft_n_to_string(const FTABLE *FORT_RESTRICT table, char *FORT_RESTRICT dst, size_t dst_len); diff --git a/src/cell.c b/src/cell.c index e5de962..bfae636 100644 --- a/src/cell.c +++ b/src/cell.c @@ -18,7 +18,7 @@ fort_cell_t * create_cell() fort_cell_t *cell = F_CALLOC(sizeof(fort_cell_t), 1); if (cell == NULL) return NULL; - cell->str_buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE); + cell->str_buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, CharBuf); if (cell->str_buffer == NULL) { F_FREE(cell); return NULL; @@ -49,7 +49,7 @@ int hint_width_cell(const fort_cell_t *cell, const context_t *context) int cell_padding_left = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_LEFT_PADDING); int cell_padding_right = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_RIGHT_PADDING); int result = cell_padding_left + cell_padding_right; - if (cell->str_buffer && cell->str_buffer->str) { + if (cell->str_buffer && cell->str_buffer->data) { result += buffer_text_width(cell->str_buffer); } result = MAX(result, get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_MIN_WIDTH)); @@ -64,7 +64,7 @@ int hint_height_cell(const fort_cell_t *cell, const context_t *context) int cell_padding_bottom = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_BOTTOM_PADDING); int cell_empty_string_height = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_EMPTY_STR_HEIGHT); int result = cell_padding_top + cell_padding_bottom; - if (cell->str_buffer && cell->str_buffer->str) { + if (cell->str_buffer && cell->str_buffer->data) { size_t text_height = buffer_text_height(cell->str_buffer); result += text_height == 0 ? cell_empty_string_height : text_height; } @@ -94,6 +94,11 @@ int hint_height_cell(const fort_cell_t *cell, const context_t *context) int cell_printf(fort_cell_t *cell, size_t row, size_t column, char *buf, size_t buf_len, const context_t *context) { + char space_char = ' '; + int (*buffer_printf_)(string_buffer_t *, size_t , size_t , char *, size_t , const context_t *) = buffer_printf; + int (*snprint_n_chars_)(char *, size_t , size_t , char) = snprint_n_chars; + + if (cell == NULL || buf_len == 0 || (buf_len <= hint_width_cell(cell, context))) { return -1; @@ -106,26 +111,62 @@ int cell_printf(fort_cell_t *cell, size_t row, size_t column, char *buf, size_t if (row >= hint_height_cell(cell, context) || row < cell_padding_top || row >= (cell_padding_top + buffer_text_height(cell->str_buffer))) { - int k = snprint_n_chars(buf, buf_len, buf_len - 1, ' '); + int k = snprint_n_chars_(buf, buf_len, buf_len - 1, space_char); return k; } else { int written = 0; int left = cell_padding_left; int right = cell_padding_right; - written += snprint_n_chars(buf + written, buf_len - written, left, ' '); + written += snprint_n_chars_(buf + written, buf_len - written, left, space_char); if (cell->str_buffer) - written += buffer_printf(cell->str_buffer, row - cell_padding_top, column, buf + written, buf_len - written - right, context); + written += buffer_printf_(cell->str_buffer, row - cell_padding_top, column, buf + written, buf_len - written - right, context); else - written += snprint_n_chars(buf + written, buf_len - written, buf_len - written - right, ' '); - written += snprint_n_chars(buf + written, buf_len - written, right, ' '); + written += snprint_n_chars_(buf + written, buf_len - written, buf_len - written - right, space_char); + written += snprint_n_chars_(buf + written, buf_len - written, right, space_char); return written; } - } +int cell_wprintf(fort_cell_t *cell, size_t row, size_t column, wchar_t *buf, size_t buf_len, const context_t *context) +{ + wchar_t space_char = L' '; + int (*buffer_printf_)(string_buffer_t *, size_t , size_t , wchar_t *, size_t , const context_t *) = buffer_wprintf; + int (*snprint_n_chars_)(wchar_t *, size_t , size_t , wchar_t) = wsnprint_n_chars; + + + if (cell == NULL || buf_len == 0 + || (buf_len <= hint_width_cell(cell, context))) { + return -1; + } + + int cell_padding_top = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_TOP_PADDING); + int cell_padding_left = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_LEFT_PADDING); + int cell_padding_right = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_RIGHT_PADDING); + + if (row >= hint_height_cell(cell, context) + || row < cell_padding_top + || row >= (cell_padding_top + buffer_text_height(cell->str_buffer))) { + int k = snprint_n_chars_(buf, buf_len, buf_len - 1, space_char); + return k; + } else { + int written = 0; + int left = cell_padding_left; + int right = cell_padding_right; + + written += snprint_n_chars_(buf + written, buf_len - written, left, space_char); + + if (cell->str_buffer) + written += buffer_printf_(cell->str_buffer, row - cell_padding_top, column, buf + written, buf_len - written - right, context); + else + written += snprint_n_chars_(buf + written, buf_len - written, buf_len - written - right, space_char); + written += snprint_n_chars_(buf + written, buf_len - written, right, space_char); + + return written; + } +} fort_status_t fill_cell_from_string(fort_cell_t *cell, const char *str) diff --git a/src/cell.h b/src/cell.h index a90df85..cd81e34 100644 --- a/src/cell.h +++ b/src/cell.h @@ -25,6 +25,8 @@ int hint_height_cell(const fort_cell_t *cell, const context_t *context); //static int lines_number_cell(fort_cell_t *cell); int cell_printf(fort_cell_t *cell, size_t row, size_t column, char *buf, size_t buf_len, const context_t *context); +int cell_wprintf(fort_cell_t *cell, size_t row, size_t column, wchar_t *buf, size_t buf_len, const context_t *context); + fort_status_t fill_cell_from_string(fort_cell_t *cell, const char *str); diff --git a/src/fort.c b/src/fort.c index 166bb8c..463fe42 100644 --- a/src/fort.c +++ b/src/fort.c @@ -171,7 +171,10 @@ int FT_HDR_PRINTF(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT fmt, .. if (result >= 0 && table->rows) { int sz = vector_size(table->rows); if (sz != 0) { - set_row_type(*(fort_row_t**)vector_at(table->rows, sz - 1), Header); +// set_row_type(*(fort_row_t**)vector_at(table->rows, sz - 1), Header); + int ignore = ft_set_cell_option(table, sz - 1, FT_ANY_COLUMN, FT_OPT_ROW_TYPE, Header); + (void)ignore; + assert(ignore == F_SUCCESS); } } return result; @@ -189,7 +192,10 @@ int FT_HDR_PRINTF_LN(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT fmt, if (result >= 0 && table->rows) { int sz = vector_size(table->rows); if (sz != 0) { - set_row_type(*(fort_row_t**)vector_at(table->rows, sz - 1), Header); +// set_row_type(*(fort_row_t**)vector_at(table->rows, sz - 1), Header); + int ignore = ft_set_cell_option(table, sz - 1, FT_ANY_COLUMN, FT_OPT_ROW_TYPE, Header); + (void)ignore; + assert(ignore == F_SUCCESS); } } if (result >= 0) { @@ -251,7 +257,32 @@ int ft_write_ln(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT cell_cont return status; } -FORT_EXTERN int ft_nwrite(FTABLE *FORT_RESTRICT table, size_t n, const char* FORT_RESTRICT cell_content, ...) +int ft_wwrite(FTABLE *FORT_RESTRICT table, const wchar_t* FORT_RESTRICT cell_content) +{ + assert(table); + string_buffer_t *str_buffer = get_cur_str_buffer_and_create_if_not_exists(table); + if (str_buffer == NULL) + return F_ERROR; + + int status = fill_buffer_from_wstring(str_buffer, cell_content); + if (IS_SUCCESS(status)) { + table->cur_col++; + } + return status; +} + +int ft_wwrite_ln(FTABLE *FORT_RESTRICT table, const wchar_t* FORT_RESTRICT cell_content) +{ + assert(table); + int status = ft_wwrite(table, cell_content); + if (IS_SUCCESS(status)) { + ft_ln(table); + } + return status; +} + + +int ft_nwrite(FTABLE *FORT_RESTRICT table, size_t n, const char* FORT_RESTRICT cell_content, ...) { assert(table); int status = ft_write(table, cell_content); @@ -271,7 +302,7 @@ FORT_EXTERN int ft_nwrite(FTABLE *FORT_RESTRICT table, size_t n, const char* FOR return status; } -FORT_EXTERN int ft_nwrite_ln(FTABLE *FORT_RESTRICT table, size_t n, const char* FORT_RESTRICT cell_content, ...) +int ft_nwrite_ln(FTABLE *FORT_RESTRICT table, size_t n, const char* FORT_RESTRICT cell_content, ...) { assert(table); int status = ft_write(table, cell_content); @@ -296,6 +327,51 @@ FORT_EXTERN int ft_nwrite_ln(FTABLE *FORT_RESTRICT table, size_t n, const char* } +int ft_nwwrite(FTABLE *FORT_RESTRICT table, size_t n, const wchar_t* FORT_RESTRICT cell_content, ...) +{ + assert(table); + int status = ft_wwrite(table, cell_content); + if (IS_ERROR(status)) + return status; + + va_list va; + va_start(va, cell_content); + --n; + for (size_t i = 0; i < n; ++i) { + const wchar_t *cell = va_arg(va, const wchar_t*); + status = ft_wwrite(table, cell); + if (IS_ERROR(status)) + return status; + } + va_end(va); + return status; +} + +int ft_nwwrite_ln(FTABLE *FORT_RESTRICT table, size_t n, const wchar_t* FORT_RESTRICT cell_content, ...) +{ + assert(table); + int status = ft_wwrite(table, cell_content); + if (IS_ERROR(status)) + return status; + + va_list va; + va_start(va, cell_content); + --n; + for (size_t i = 0; i < n; ++i) { + const wchar_t *cell = va_arg(va, const wchar_t*); + status = ft_wwrite(table, cell); + if (IS_ERROR(status)) { + va_end(va); + return status; + } + } + va_end(va); + + ft_ln(table); + return status; +} + + FORT_EXTERN int ft_row_write(FTABLE *FORT_RESTRICT table, size_t cols, const char* FORT_RESTRICT cells[]) { assert(table); @@ -396,6 +472,16 @@ const char* ft_to_string(const FTABLE *FORT_RESTRICT table) } \ dev += k; + typedef char char_type; + const char_type *empty_string = ""; + const enum str_buf_type buf_type = CharBuf; +#define cur_F_STRDUP F_STRDUP + int (*snprintf_row_)(const fort_row_t *, char *, size_t, size_t *, size_t, size_t, const context_t *) = snprintf_row; + int (*print_row_separator_)(char *, size_t , + const size_t *, size_t , + const fort_row_t *, const fort_row_t *, + enum HorSeparatorPos , const separator_t *, + const context_t *) = print_row_separator; assert(table); /* Determing size of table string representation */ @@ -409,16 +495,16 @@ const char* ft_to_string(const FTABLE *FORT_RESTRICT table) /* Allocate string buffer for string representation */ if (table->conv_buffer == NULL) { - ((FTABLE *)table)->conv_buffer = create_string_buffer(sz); + ((FTABLE *)table)->conv_buffer = create_string_buffer(sz, buf_type); if (table->conv_buffer == NULL) return NULL; } - while (table->conv_buffer->str_sz < sz) { + while (string_buffer_capacity(table->conv_buffer) < sz) {// table->conv_buffer->str_sz < sz) { if (IS_ERROR(realloc_string_buffer_without_copy(table->conv_buffer))) { return NULL; } } - char *buffer = table->conv_buffer->str; + char_type *buffer = buffer_get_data(table->conv_buffer); size_t cols = 0; @@ -428,7 +514,7 @@ const char* ft_to_string(const FTABLE *FORT_RESTRICT table) status = table_rows_and_cols_geometry(table, &col_width_arr, &cols, &row_height_arr, &rows); if (rows == 0) - return F_STRDUP(""); + return cur_F_STRDUP(empty_string); if (IS_ERROR(status)) return NULL; @@ -446,14 +532,108 @@ const char* ft_to_string(const FTABLE *FORT_RESTRICT table) cur_sep = (i < sep_size) ? (*(separator_t **)vector_at(table->separators, i)) : NULL; cur_row = *(fort_row_t**)vector_at(table->rows, i); enum HorSeparatorPos separatorPos = (i == 0) ? TopSeparator : InsideSeparator; - CHECK_RESULT_AND_MOVE_DEV(print_row_separator(buffer + dev, sz - dev, col_width_arr, cols, prev_row, cur_row, separatorPos, cur_sep, &context)); context.row = i; - CHECK_RESULT_AND_MOVE_DEV(snprintf_row(cur_row, buffer + dev, sz - dev, col_width_arr, cols, row_height_arr[i], &context)); + CHECK_RESULT_AND_MOVE_DEV(print_row_separator_(buffer + dev, sz - dev, col_width_arr, cols, prev_row, cur_row, separatorPos, cur_sep, &context)); + CHECK_RESULT_AND_MOVE_DEV(snprintf_row_(cur_row, buffer + dev, sz - dev, col_width_arr, cols, row_height_arr[i], &context)); prev_row = cur_row; } cur_row = NULL; cur_sep = (i < sep_size) ? (*(separator_t **)vector_at(table->separators, i)) : NULL; - CHECK_RESULT_AND_MOVE_DEV(print_row_separator(buffer + dev, sz - dev, col_width_arr, cols, prev_row, cur_row, BottomSeparator, cur_sep, &context)); + CHECK_RESULT_AND_MOVE_DEV(print_row_separator_(buffer + dev, sz - dev, col_width_arr, cols, prev_row, cur_row, BottomSeparator, cur_sep, &context)); + + + F_FREE(col_width_arr); + F_FREE(row_height_arr); + return buffer; + +clear: + F_FREE(col_width_arr); + F_FREE(row_height_arr); + F_FREE(buffer); + return NULL; + +#undef cur_F_STRDUP +#undef CHECK_RESULT_AND_MOVE_DEV +} + + +const wchar_t* ft_to_wstring(const FTABLE *FORT_RESTRICT table) +{ +#define CHECK_RESULT_AND_MOVE_DEV(statement) \ + k = statement; \ + if (k < 0) {\ + goto clear; \ + } \ + dev += k; + + typedef wchar_t char_type; + const char_type *empty_string = L""; + const enum str_buf_type buf_type = WCharBuf; +#define cur_F_STRDUP F_WCSDUP + int (*snprintf_row_)(const fort_row_t *, wchar_t *, size_t, size_t *, size_t, size_t, const context_t *) = wsnprintf_row; + int (*print_row_separator_)(wchar_t *, size_t , + const size_t *, size_t , + const fort_row_t *, const fort_row_t *, + enum HorSeparatorPos , const separator_t *, + const context_t *) = wprint_row_separator; + assert(table); + + /* Determing size of table string representation */ + size_t height = 0; + size_t width = 0; + int status = table_geometry(table, &height, &width); + if (IS_ERROR(status)) { + return NULL; + } + size_t sz = height * width + 1; + + /* Allocate string buffer for string representation */ + if (table->conv_buffer == NULL) { + ((FTABLE *)table)->conv_buffer = create_string_buffer(sz, buf_type); + if (table->conv_buffer == NULL) + return NULL; + } + while (string_buffer_capacity(table->conv_buffer) < sz) {// table->conv_buffer->str_sz < sz) { + if (IS_ERROR(realloc_string_buffer_without_copy(table->conv_buffer))) { + return NULL; + } + } + char_type *buffer = buffer_get_data(table->conv_buffer); + + + size_t cols = 0; + size_t rows = 0; + size_t *col_width_arr = NULL; + size_t *row_height_arr = NULL; + status = table_rows_and_cols_geometry(table, &col_width_arr, &cols, &row_height_arr, &rows); + + if (rows == 0) + return cur_F_STRDUP(empty_string); + + if (IS_ERROR(status)) + return NULL; + + int dev = 0; + int k = 0; + context_t context; + context.table_options = (table->options ? table->options : &g_table_options); + fort_row_t *prev_row = NULL; + fort_row_t *cur_row = NULL; + separator_t *cur_sep = NULL; + size_t sep_size = vector_size(table->separators); + size_t i = 0; + for (i = 0; i < rows; ++i) { + cur_sep = (i < sep_size) ? (*(separator_t **)vector_at(table->separators, i)) : NULL; + cur_row = *(fort_row_t**)vector_at(table->rows, i); + enum HorSeparatorPos separatorPos = (i == 0) ? TopSeparator : InsideSeparator; + context.row = i; + CHECK_RESULT_AND_MOVE_DEV(print_row_separator_(buffer + dev, sz - dev, col_width_arr, cols, prev_row, cur_row, separatorPos, cur_sep, &context)); + CHECK_RESULT_AND_MOVE_DEV(snprintf_row_(cur_row, buffer + dev, sz - dev, col_width_arr, cols, row_height_arr[i], &context)); + prev_row = cur_row; + } + cur_row = NULL; + cur_sep = (i < sep_size) ? (*(separator_t **)vector_at(table->separators, i)) : NULL; + CHECK_RESULT_AND_MOVE_DEV(print_row_separator_(buffer + dev, sz - dev, col_width_arr, cols, prev_row, cur_row, BottomSeparator, cur_sep, &context)); F_FREE(col_width_arr); @@ -471,7 +651,6 @@ clear: - /* * TMP */ diff --git a/src/fort_impl.c b/src/fort_impl.c index e075356..5e95aae 100644 --- a/src/fort_impl.c +++ b/src/fort_impl.c @@ -1,4 +1,5 @@ #include "fort_impl.h" +#include @@ -11,7 +12,7 @@ char *fort_strdup(const char* str) return NULL; size_t sz = strlen(str); - char *str_copy = (char*)F_MALLOC(sz + 1); + char *str_copy = (char*)F_MALLOC((sz + 1)*sizeof(char)); if (str_copy == NULL) return NULL; @@ -19,6 +20,20 @@ char *fort_strdup(const char* str) return str_copy; } +wchar_t *fort_wcsdup(const wchar_t* str) +{ + if (str == NULL) + return NULL; + + size_t sz = wcslen(str); + wchar_t *str_copy = (wchar_t*)F_MALLOC((sz + 1)*sizeof(wchar_t)); + if (str_copy == NULL) + return NULL; + + wcscpy(str_copy, str); + return str_copy; +} + size_t number_of_columns_in_format_string(const char *fmt) { int separator_counter = 0; @@ -39,6 +54,9 @@ int snprint_n_chars(char *buf, size_t length, size_t n, char ch) if (length <= n) return -1; + if (n == 0) + return 0; + int status = snprintf(buf, length, "%0*d", (int)n, 0); if (status < 0) return status; @@ -49,3 +67,23 @@ int snprint_n_chars(char *buf, size_t length, size_t n, char ch) } return n; } + + +int wsnprint_n_chars(wchar_t *buf, size_t length, size_t n, wchar_t ch) +{ + if (length <= n) + return -1; + + if (n == 0) + return 0; + + int status = swprintf(buf, length, L"%0*d", (int)n, 0); + if (status < 0) + return status; + + for (size_t i = 0; i < n; ++i) { + *buf = ch; + buf++; + } + return n; +} diff --git a/src/fort_impl.h b/src/fort_impl.h index 342fb71..62cb345 100644 --- a/src/fort_impl.h +++ b/src/fort_impl.h @@ -16,6 +16,7 @@ #define F_REALLOC realloc #define F_FREE free #define F_STRDUP fort_strdup +#define F_WCSDUP fort_wcsdup #define F_CREATE(type) ((type *)F_CALLOC(sizeof(type), 1)) @@ -107,7 +108,10 @@ typedef struct separator separator_t; * LIBFORT helpers *****************************************************************************/ char *fort_strdup(const char* str); +wchar_t *fort_wcsdup(const wchar_t* str); size_t number_of_columns_in_format_string(const char *fmt); int snprint_n_chars(char *buf, size_t length, size_t n, char ch); +int wsnprint_n_chars(wchar_t *buf, size_t length, size_t n, wchar_t ch); + #endif // FORT_IMPL_H diff --git a/src/options.c b/src/options.c index fd17fdd..6e7dcb2 100644 --- a/src/options.c +++ b/src/options.c @@ -23,6 +23,8 @@ struct fort_cell_options g_default_cell_option = 1, /* cell_padding_left */ 1, /* cell_padding_right */ 1, /* cell_empty_string_height */ + + Common, /* row_type */ }; static int get_option_value_if_exists_otherwise_default(const struct fort_cell_options *cell_opts, uint32_t option) @@ -46,6 +48,8 @@ static int get_option_value_if_exists_otherwise_default(const struct fort_cell_o return cell_opts->cell_padding_right; case FT_OPT_EMPTY_STR_HEIGHT: return cell_opts->cell_empty_string_height; + case FT_OPT_ROW_TYPE: + return cell_opts->row_type; default: // todo: implement later exit(333); @@ -164,6 +168,8 @@ static fort_status_t set_cell_option_impl(fort_cell_options_t *opt, uint32_t opt opt->cell_padding_right = value; } else if (OPTION_IS_SET(option, FT_OPT_EMPTY_STR_HEIGHT)) { opt->cell_empty_string_height = value; + } else if (OPTION_IS_SET(option, FT_OPT_ROW_TYPE)) { + opt->row_type = value; } return F_SUCCESS; diff --git a/src/options.h b/src/options.h index 2a87c5a..5b357ec 100644 --- a/src/options.h +++ b/src/options.h @@ -12,6 +12,12 @@ enum TextAlignment RightAligned }; +enum RowType +{ + Common, + Header +}; + struct fort_column_options { @@ -41,6 +47,7 @@ typedef struct vector vector_t; #define FT_OPT_LEFT_PADDING ((uint32_t)(0x01U << (4))) #define FT_OPT_RIGHT_PADDING ((uint32_t)(0x01U << (5))) #define FT_OPT_EMPTY_STR_HEIGHT ((uint32_t)(0x01U << (6))) +#define FT_OPT_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)) @@ -58,6 +65,7 @@ struct fort_cell_options int cell_padding_left; int cell_padding_right; int cell_empty_string_height; + enum RowType row_type; }; typedef struct fort_cell_options fort_cell_options_t; diff --git a/src/row.c b/src/row.c index 7f579f7..53cee32 100644 --- a/src/row.c +++ b/src/row.c @@ -24,7 +24,7 @@ fort_row_t * create_row() return NULL; } // row->is_header = F_FALSE; - row->type = Common; +// row->type = Common; return row; } @@ -120,22 +120,26 @@ int print_row_separator(char *buffer, size_t buffer_sz, } \ dev += k; + typedef char char_type; + char new_line_char = '\n'; + int (*snprint_n_chars_)(char *, size_t , size_t , char) = snprint_n_chars; + + assert(buffer); assert(context); int dev = 0; int k = 0; - const fort_row_t *main_row = NULL; - if (upper_row != NULL && lower_row != NULL) { - main_row = lower_row->type == Header ? lower_row : upper_row; - } else if (upper_row != NULL && lower_row == NULL) { - main_row = upper_row; - } else if (upper_row == NULL && lower_row != NULL) { - main_row = lower_row; - } else if (upper_row == NULL && lower_row == NULL) { - main_row = NULL; + enum RowType lower_row_type = Common; + if (lower_row != NULL) { + lower_row_type = get_cell_opt_value_hierarcial(context->table_options, context->row, FT_ANY_COLUMN, FT_OPT_ROW_TYPE); } + enum RowType upper_row_type = Common; + if (upper_row != NULL) { + upper_row_type = get_cell_opt_value_hierarcial(context->table_options, context->row-1, FT_ANY_COLUMN, FT_OPT_ROW_TYPE); + } + /* Row separator anatomy * @@ -147,10 +151,9 @@ int print_row_separator(char *buffer, size_t buffer_sz, const char *R = NULL; const char (*border_chars)[BorderItemPosSize] = NULL; - if (main_row && main_row->type == Header) { + border_chars = &context->table_options->border_chars; + if (upper_row_type == Header || lower_row_type == Header) { border_chars = &context->table_options->header_border_chars; - } else { - border_chars = &context->table_options->border_chars; } if (sep && sep->enabled) { @@ -183,21 +186,21 @@ int print_row_separator(char *buffer, size_t buffer_sz, } } - /* If all chars are not printable, skip line separator */ + /* If all chars are not printable, skip line separator */ /* todo: add processing for wchar_t */ if (!isprint(*L) && !isprint(*I) && !isprint(*IV) && !isprint(*R)) return 0; for (size_t i = 0; i < cols; ++i) { if (i == 0) { - CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, 1, *L)); + CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, 1, (char_type)*L)); } else { - CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, 1, *IV)); + CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, 1, (char_type)*IV)); } - CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, col_width_arr[i], *I)); + CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, col_width_arr[i], (char_type)*I)); } - CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, 1, *R)); + CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, 1, (char_type)*R)); - CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, 1, '\n')); + CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, 1, new_line_char)); return dev; @@ -209,6 +212,110 @@ clear: +int wprint_row_separator(wchar_t *buffer, size_t buffer_sz, + const size_t *col_width_arr, size_t cols, + const fort_row_t *upper_row, const fort_row_t *lower_row, + enum HorSeparatorPos separatorPos, const separator_t *sep, + const context_t *context) +{ +#define CHECK_RESULT_AND_MOVE_DEV(statement) \ + k = statement; \ + if (k < 0) {\ + goto clear; \ + } \ + dev += k; + + typedef wchar_t char_type; + char new_line_char = L'\n'; + int (*snprint_n_chars_)(wchar_t*, size_t , size_t , wchar_t) = wsnprint_n_chars; + + + assert(buffer); + assert(context); + + int dev = 0; + int k = 0; + + enum RowType lower_row_type = Common; + if (lower_row != NULL) { + lower_row_type = get_cell_opt_value_hierarcial(context->table_options, context->row, FT_ANY_COLUMN, FT_OPT_ROW_TYPE); + } + enum RowType upper_row_type = Common; + if (upper_row != NULL) { + upper_row_type = get_cell_opt_value_hierarcial(context->table_options, context->row-1, FT_ANY_COLUMN, FT_OPT_ROW_TYPE); + } + + /* Row separator anatomy + * + * L I I I IV I I I R + */ + const char *L = NULL; + const char *I = NULL; + const char *IV = NULL; + const char *R = NULL; + + const char (*border_chars)[BorderItemPosSize] = NULL; + border_chars = &context->table_options->border_chars; + if (upper_row_type == Header || lower_row_type == Header) { + border_chars = &context->table_options->header_border_chars; + } + + + if (sep && sep->enabled) { + L = &(context->table_options->separator_chars[LH_sip]); + I = &(context->table_options->separator_chars[IH_sip]); + IV = &(context->table_options->separator_chars[II_sip]); + R = &(context->table_options->separator_chars[RH_sip]); + } else { + switch (separatorPos) { + case TopSeparator: + L = &(*border_chars)[TL_bip]; + I = &(*border_chars)[TT_bip]; + IV = &(*border_chars)[TV_bip]; + R = &(*border_chars)[TR_bip]; + break; + case InsideSeparator: + L = &(*border_chars)[LH_bip]; + I = &(*border_chars)[IH_bip]; + IV = &(*border_chars)[II_bip]; + R = &(*border_chars)[RH_bip]; + break; + case BottomSeparator: + L = &(*border_chars)[BL_bip]; + I = &(*border_chars)[BB_bip]; + IV = &(*border_chars)[BV_bip]; + R = &(*border_chars)[BR_bip]; + break; + default: + break; + } + } + + /* If all chars are not printable, skip line separator */ /* todo: add processing for wchar_t */ + if (!isprint(*L) && !isprint(*I) && !isprint(*IV) && !isprint(*R)) + return 0; + + for (size_t i = 0; i < cols; ++i) { + if (i == 0) { + CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, 1, (char_type)*L)); + } else { + CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, 1, (char_type)*IV)); + } + CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, col_width_arr[i], (char_type)*I)); + } + CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, 1, (char_type)*R)); + + CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, 1, new_line_char)); + + return dev; + +clear: + return -1; + +#undef CHECK_RESULT_AND_MOVE_DEV +} + + fort_row_t* create_row_from_string(const char *str) { @@ -290,7 +397,7 @@ clear: fort_row_t* create_row_from_fmt_string(const char* FORT_RESTRICT fmt, va_list *va_args) { - string_buffer_t *buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE); + string_buffer_t *buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, CharBuf); if (buffer == NULL) return NULL; @@ -299,14 +406,14 @@ fort_row_t* create_row_from_fmt_string(const char* FORT_RESTRICT fmt, va_list *v while (1) { va_list va; va_copy(va, *va_args); - int virtual_sz = vsnprintf(buffer->str, buffer->str_sz, fmt, va); + int virtual_sz = vsnprintf(buffer->cstr, string_buffer_capacity(buffer)/*buffer->str_sz*/, fmt, va); va_end(va); /* If error encountered */ if (virtual_sz == -1) goto clear; /* Successful write */ - if (virtual_sz < buffer->str_sz) + if (virtual_sz < string_buffer_capacity(buffer))// buffer->str_sz) break; /* Otherwise buffer was too small, so incr. buffer size ant try again. */ @@ -314,10 +421,10 @@ fort_row_t* create_row_from_fmt_string(const char* FORT_RESTRICT fmt, va_list *v goto clear; } - int cols = number_of_columns_in_format_string(buffer->str); + int cols = number_of_columns_in_format_string(buffer->cstr); if (cols == cols_origin) { - fort_row_t *row = create_row_from_string(buffer->str); + fort_row_t *row = create_row_from_string(buffer->cstr); if (row == NULL) { goto clear; } @@ -337,6 +444,13 @@ clear: int snprintf_row(const fort_row_t *row, char *buffer, size_t buf_sz, size_t *col_width_arr, size_t col_width_arr_sz, size_t row_height, const context_t *context) { + typedef char char_type; + char space_char = ' '; + char new_line_char = '\n'; + int (*snprint_n_chars_)(char *, size_t , size_t , char) = snprint_n_chars; + int (*cell_printf_)(fort_cell_t *, size_t, size_t, char *, size_t, const context_t *) = cell_printf; + + assert(context); if (row == NULL) return -1; @@ -350,7 +464,8 @@ int snprintf_row(const fort_row_t *row, char *buffer, size_t buf_sz, size_t *col * L data IV data IV data R */ - const char (*bord_chars)[BorderItemPosSize] = (row->type == Header) + enum RowType row_type = get_cell_opt_value_hierarcial(context->table_options, context->row, FT_ANY_COLUMN, FT_OPT_ROW_TYPE); + const char (*bord_chars)[BorderItemPosSize] = (row_type == Header) ? (&context->table_options->header_border_chars) : (&context->table_options->border_chars); const char *L = &(*bord_chars)[LL_bip]; @@ -360,30 +475,86 @@ int snprintf_row(const fort_row_t *row, char *buffer, size_t buf_sz, size_t *col int dev = 0; for (size_t i = 0; i < row_height; ++i) { - dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, *L); + dev += snprint_n_chars_(buffer + dev, buf_sz - dev, 1, (char_type)*L); for (size_t j = 0; j < col_width_arr_sz; ++j) { ((context_t *)context)->column = j; if (j < cols_in_row) { fort_cell_t *cell = *(fort_cell_t**)vector_at(row->cells, j); - dev += cell_printf(cell, i, j, buffer + dev, col_width_arr[j] + 1, context); + dev += cell_printf_(cell, i, j, buffer + dev, col_width_arr[j] + 1, context); } else { - dev += snprint_n_chars(buffer + dev, buf_sz - dev, col_width_arr[j], ' '); + dev += snprint_n_chars_(buffer + dev, buf_sz - dev, col_width_arr[j], space_char); } if (j == col_width_arr_sz - 1) { - dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, *R); + dev += snprint_n_chars_(buffer + dev, buf_sz - dev, 1, (char_type)*R); } else { - dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, *IV); + dev += snprint_n_chars_(buffer + dev, buf_sz - dev, 1, (char_type)*IV); } } - dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, '\n'); + dev += snprint_n_chars_(buffer + dev, buf_sz - dev, 1, new_line_char); } return dev; } -void set_row_type(fort_row_t *row, enum RowType type) +int wsnprintf_row(const fort_row_t *row, wchar_t *buffer, size_t buf_sz, size_t *col_width_arr, size_t col_width_arr_sz, + size_t row_height, const context_t *context) { - assert(row); - row->type = type; + typedef wchar_t char_type; + char space_char = L' '; + char new_line_char = L'\n'; + int (*snprint_n_chars_)(wchar_t *, size_t , size_t , wchar_t) = wsnprint_n_chars; + int (*cell_printf_)(fort_cell_t *, size_t, size_t, wchar_t *, size_t, const context_t *) = cell_wprintf; + + + assert(context); + if (row == NULL) + return -1; + + int cols_in_row = columns_in_row(row); + if (cols_in_row > col_width_arr_sz) + return -1; + + /* Row separator anatomy + * + * L data IV data IV data R + */ + + enum RowType row_type = get_cell_opt_value_hierarcial(context->table_options, context->row, FT_ANY_COLUMN, FT_OPT_ROW_TYPE); + const char (*bord_chars)[BorderItemPosSize] = (row_type) + ? (&context->table_options->header_border_chars) + : (&context->table_options->border_chars); + const char *L = &(*bord_chars)[LL_bip]; + const char *IV = &(*bord_chars)[IV_bip]; + const char *R = &(*bord_chars)[RR_bip]; + + + int dev = 0; + for (size_t i = 0; i < row_height; ++i) { + dev += snprint_n_chars_(buffer + dev, buf_sz - dev, 1, (char_type)*L); + for (size_t j = 0; j < col_width_arr_sz; ++j) { + ((context_t *)context)->column = j; + if (j < cols_in_row) { + fort_cell_t *cell = *(fort_cell_t**)vector_at(row->cells, j); + dev += cell_printf_(cell, i, j, buffer + dev, col_width_arr[j] + 1, context); + } else { + dev += snprint_n_chars_(buffer + dev, buf_sz - dev, col_width_arr[j], space_char); + } + if (j == col_width_arr_sz - 1) { + dev += snprint_n_chars_(buffer + dev, buf_sz - dev, 1, (char_type)*R); + } else { + dev += snprint_n_chars_(buffer + dev, buf_sz - dev, 1, (char_type)*IV); + } + } + dev += snprint_n_chars_(buffer + dev, buf_sz - dev, 1, new_line_char); + } + return dev; } + + + +//void set_row_type(fort_row_t *row, enum RowType type) +//{ +// assert(row); +// row->type = type; +//} diff --git a/src/row.h b/src/row.h index a7762b7..6367fd0 100644 --- a/src/row.h +++ b/src/row.h @@ -8,11 +8,11 @@ struct fort_row; typedef struct fort_row fort_row_t; -enum RowType -{ - Common, - Header -}; +//enum RowType +//{ +// Common, +// Header +//}; fort_row_t * create_row(); @@ -36,6 +36,12 @@ int print_row_separator(char *buffer, size_t buffer_sz, enum HorSeparatorPos separatorPos, const separator_t *sep, const context_t *context); +int wprint_row_separator(wchar_t *buffer, size_t buffer_sz, + const size_t *col_width_arr, size_t cols, + const fort_row_t *upper_row, const fort_row_t *lower_row, + enum HorSeparatorPos separatorPos, const separator_t *sep, + const context_t *context); + @@ -44,7 +50,9 @@ fort_row_t* create_row_from_fmt_string(const char* FORT_RESTRICT fmt, va_list *v int snprintf_row(const fort_row_t *row, char *buffer, size_t buf_sz, size_t *col_width_arr, size_t col_width_arr_sz, size_t row_height, const context_t *context); +int wsnprintf_row(const fort_row_t *row, wchar_t *buffer, size_t buf_sz, size_t *col_width_arr, size_t col_width_arr_sz, + size_t row_height, const context_t *context); -void set_row_type(fort_row_t *row, enum RowType type); +//void set_row_type(fort_row_t *row, enum RowType type); #endif // ROW_H diff --git a/src/string_buffer.c b/src/string_buffer.c index 7bf2ddd..158c434 100644 --- a/src/string_buffer.c +++ b/src/string_buffer.c @@ -1,11 +1,22 @@ #include "string_buffer.h" #include "options.h" #include "assert.h" +#include "wchar.h" /***************************************************************************** * STRING BUFFER * ***************************************************************************/ +static size_t buf_str_len(const string_buffer_t*buf) +{ + assert(buf); + if (buf->type == CharBuf) { + return strlen(buf->cstr); + } else { + return wcslen(buf->wstr); + } +} + size_t strchr_count(const char* str, char ch) { if (str == NULL) @@ -21,6 +32,21 @@ size_t strchr_count(const char* str, char ch) return count; } +size_t wstrchr_count(const wchar_t* str, wchar_t ch) +{ + if (str == NULL) + return 0; + + size_t count = 0; + str = wcschr(str, ch); + while (str) { + count++; + str++; + str = wcschr(str, ch); + } + return count; +} + const char* str_n_substring_beg(const char* str, char ch_separator, size_t n) { if (str == NULL) @@ -41,6 +67,26 @@ const char* str_n_substring_beg(const char* str, char ch_separator, size_t n) return str ? (str + 1) : NULL; } +const wchar_t* wstr_n_substring_beg(const wchar_t* str, wchar_t ch_separator, size_t n) +{ + if (str == NULL) + return NULL; + + if (n == 0) + return str; + + str = wcschr(str, ch_separator); + --n; + while (n > 0) { + if (str == NULL) + return NULL; + --n; + str++; + str = wcschr(str, ch_separator); + } + return str ? (str + 1) : NULL; +} + void str_n_substring(const char* str, char ch_separator, size_t n, const char **begin, const char **end) { const char *beg = str_n_substring_beg(str, ch_separator, n); @@ -60,18 +106,39 @@ void str_n_substring(const char* str, char ch_separator, size_t n, const char ** return; } - -string_buffer_t* create_string_buffer(size_t sz) +void wstr_n_substring(const wchar_t* str, wchar_t ch_separator, size_t n, const wchar_t **begin, const wchar_t **end) { + const wchar_t *beg = wstr_n_substring_beg(str, ch_separator, n); + if (beg == NULL) { + *begin = NULL; + *end = NULL; + return; + } + + const wchar_t *en = wcschr(beg, ch_separator); + if (en == NULL) { + en = str + wcslen(str); + } + + *begin = beg; + *end = en; + return; +} + + +string_buffer_t* create_string_buffer(size_t number_of_chars, enum str_buf_type type) +{ + size_t sz = (number_of_chars) * (type == CharBuf ? sizeof(char) : sizeof(wchar_t)); string_buffer_t *result = (string_buffer_t *)F_MALLOC(sizeof(string_buffer_t)); if (result == NULL) return NULL; - result->str = F_MALLOC(sz); - if (result->str == NULL) { + result->data = F_MALLOC(sz); + if (result->data == NULL) { F_FREE(result); return NULL; } - result->str_sz = sz; + result->data_sz = sz; + result->type = type; return result; } @@ -80,21 +147,21 @@ void destroy_string_buffer(string_buffer_t *buffer) { if (buffer == NULL) return; - F_FREE(buffer->str); - buffer->str = NULL; + F_FREE(buffer->data); + buffer->data = NULL; F_FREE(buffer); } fort_status_t realloc_string_buffer_without_copy(string_buffer_t *buffer) { assert(buffer); - char *new_str = (char*)F_MALLOC(buffer->str_sz * 2); + char *new_str = (char*)F_MALLOC(buffer->data_sz * 2); if (new_str == NULL) { return F_MEMORY_ERROR; } - F_FREE(buffer->str); - buffer->str = new_str; - buffer->str_sz *= 2; + F_FREE(buffer->data); + buffer->data = new_str; + buffer->data_sz *= 2; return F_SUCCESS; } @@ -108,14 +175,38 @@ fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str) if (copy == NULL) return F_MEMORY_ERROR; - while (sz >= buffer->str_sz) { + while (sz >= string_buffer_capacity(buffer)) { int status = realloc_string_buffer_without_copy(buffer); if (!IS_SUCCESS(status)) { return status; } } - F_FREE(buffer->str); - buffer->str = copy; + F_FREE(buffer->data); + buffer->cstr = copy; + buffer->type = CharBuf; + + return F_SUCCESS; +} + +fort_status_t fill_buffer_from_wstring(string_buffer_t *buffer, const wchar_t *str) +{ + assert(buffer); + assert(str); + + size_t sz = wcslen(str); + wchar_t * copy = F_WCSDUP(str); + if (copy == NULL) + return F_MEMORY_ERROR; + + while (sz >= string_buffer_capacity(buffer)) { + int status = realloc_string_buffer_without_copy(buffer); + if (!IS_SUCCESS(status)) { + return status; + } + } + F_FREE(buffer->data); + buffer->wstr = copy; + buffer->type = WCharBuf; return F_SUCCESS; } @@ -124,32 +215,59 @@ fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str) size_t buffer_text_height(string_buffer_t *buffer) { - if (buffer == NULL || buffer->str == NULL || strlen(buffer->str) == 0) { + if (buffer == NULL || buffer->data == NULL || buf_str_len(buffer) == 0) { return 0; } - return 1 + strchr_count(buffer->str, '\n'); + if (buffer->type == CharBuf) + return 1 + strchr_count(buffer->cstr, '\n'); + else + return 1 + wstrchr_count(buffer->wstr, L'\n'); } size_t buffer_text_width(string_buffer_t *buffer) { size_t max_length = 0; int n = 0; - while (1) { - const char *beg = NULL; - const char *end = NULL; - str_n_substring(buffer->str, '\n', n, &beg, &end); - if (beg == NULL || end == NULL) - return max_length; + if (buffer->type == CharBuf) { + while (1) { + const char *beg = NULL; + const char *end = NULL; + str_n_substring(buffer->cstr, '\n', n, &beg, &end); + if (beg == NULL || end == NULL) + return max_length; - max_length = MAX(max_length, (end - beg)); - ++n; + max_length = MAX(max_length, (end - beg)); + ++n; + } + } else { + while (1) { + const wchar_t *beg = NULL; + const wchar_t *end = NULL; + wstr_n_substring(buffer->wstr, L'\n', n, &beg, &end); + if (beg == NULL || end == NULL) + return max_length; + + max_length = MAX(max_length, (end - beg)); + ++n; + } } } + int buffer_printf(string_buffer_t *buffer, size_t buffer_row, size_t table_column, char *buf, size_t buf_len, const context_t *context) { - if (buffer == NULL || buffer->str == NULL +#define CHAR_TYPE char +#define NULL_CHAR '\0' +#define NEWLINE_CHAR '\n' +#define SPACE_CHAR ' ' +#define SNPRINTF_FMT_STR "%*s" +#define SNPRINTF snprintf +#define BUFFER_STR cstr +#define SNPRINT_N_CHARS snprint_n_chars +#define STR_N_SUBSTRING str_n_substring + + if (buffer == NULL || buffer->data == NULL || buffer_row >= buffer_text_height(buffer) || buf_len == 0) { return -1; } @@ -161,7 +279,6 @@ int buffer_printf(string_buffer_t *buffer, size_t buffer_row, size_t table_colum int left = 0; int right = 0; -// switch (fort_options_column_alignment(context, table_column)) { switch (get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_TEXT_ALIGN)) { case LeftAligned: left = 0; @@ -184,29 +301,134 @@ int buffer_printf(string_buffer_t *buffer, size_t buffer_row, size_t table_colum int written = 0; - written += snprint_n_chars(buf + written, buf_len - written, left, ' '); + written += SNPRINT_N_CHARS(buf + written, buf_len - written, left, SPACE_CHAR); if (written < 0) return written; - - const char *beg = NULL; - const char *end = NULL; - str_n_substring(buffer->str, '\n', buffer_row, &beg, &end); + const CHAR_TYPE *beg = NULL; + const CHAR_TYPE *end = NULL; + STR_N_SUBSTRING(buffer->BUFFER_STR, NEWLINE_CHAR, buffer_row, &beg, &end); if (beg == NULL || end == NULL) return -1; - char old_value = *end; - *(char *)end = '\0'; + CHAR_TYPE old_value = *end; + *(CHAR_TYPE *)end = NULL_CHAR; - written += snprintf(buf + written, buf_len - written, "%*s", (int)(end - beg), beg); - *(char *)end = old_value; + written += SNPRINTF(buf + written, buf_len - written, SNPRINTF_FMT_STR, (int)(end - beg), beg); + *(CHAR_TYPE *)end = old_value; if (written < 0) return written; - written += snprint_n_chars(buf + written, buf_len - written, (int)(content_width - (end - beg)), ' '); + written += SNPRINT_N_CHARS(buf + written, buf_len - written, (int)(content_width - (end - beg)), SPACE_CHAR); if (written < 0) return written; - written += snprint_n_chars(buf + written, buf_len - written, right, ' '); + written += SNPRINT_N_CHARS(buf + written, buf_len - written, right, SPACE_CHAR); return written; + +#undef CHAR_TYPE +#undef NULL_CHAR +#undef NEWLINE_CHAR +#undef SPACE_CHAR +#undef SNPRINTF_FMT_STR +#undef SNPRINTF +#undef BUFFER_STR +#undef SNPRINT_N_CHARS +#undef STR_N_SUBSTRING } + +int buffer_wprintf(string_buffer_t *buffer, size_t buffer_row, size_t table_column, wchar_t *buf, size_t buf_len, const context_t *context) +{ +#define CHAR_TYPE wchar_t +#define NULL_CHAR L'\0' +#define NEWLINE_CHAR L'\n' +#define SPACE_CHAR L' ' +#define SNPRINTF_FMT_STR L"%*ls" +#define SNPRINTF swprintf +#define BUFFER_STR wstr +#define SNPRINT_N_CHARS wsnprint_n_chars +#define STR_N_SUBSTRING wstr_n_substring + + if (buffer == NULL || buffer->data == NULL + || buffer_row >= buffer_text_height(buffer) || buf_len == 0) { + return -1; + } + + size_t content_width = buffer_text_width(buffer); + if ((buf_len - 1) < content_width) + return -1; + + int left = 0; + int right = 0; + + switch (get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_TEXT_ALIGN)) { + case LeftAligned: + left = 0; + right = (buf_len - 1) - content_width; + break; + case CenterAligned: + left = ((buf_len - 1) - content_width) / 2; + right = ((buf_len - 1) - content_width) - left; + break; + case RightAligned: + left = (buf_len - 1) - content_width; + right = 0; + break; + default: + assert(0); + break; + } + if (left < 0 || right < 0) + return -1; + + + int written = 0; + written += SNPRINT_N_CHARS(buf + written, buf_len - written, left, SPACE_CHAR); + if (written < 0) + return written; + + const CHAR_TYPE *beg = NULL; + const CHAR_TYPE *end = NULL; + STR_N_SUBSTRING(buffer->BUFFER_STR, NEWLINE_CHAR, buffer_row, &beg, &end); + if (beg == NULL || end == NULL) + return -1; + CHAR_TYPE old_value = *end; + *(CHAR_TYPE *)end = NULL_CHAR; + + written += SNPRINTF(buf + written, buf_len - written, SNPRINTF_FMT_STR, (int)(end - beg), beg); + *(CHAR_TYPE *)end = old_value; + if (written < 0) + return written; + written += SNPRINT_N_CHARS(buf + written, buf_len - written, (int)(content_width - (end - beg)), SPACE_CHAR); + if (written < 0) + return written; + + + written += SNPRINT_N_CHARS(buf + written, buf_len - written, right, SPACE_CHAR); + return written; + +#undef CHAR_TYPE +#undef NULL_CHAR +#undef NEWLINE_CHAR +#undef SPACE_CHAR +#undef SNPRINTF_FMT_STR +#undef SNPRINTF +#undef BUFFER_STR +#undef SNPRINT_N_CHARS +#undef STR_N_SUBSTRING +} + +size_t string_buffer_capacity(const string_buffer_t *buffer) +{ + assert(buffer); + if (buffer->type == CharBuf) + return buffer->data_sz; + else + return buffer->data_sz / sizeof(wchar_t); +} + +void *buffer_get_data(string_buffer_t *buffer) +{ + assert(buffer); + return buffer->data; +} diff --git a/src/string_buffer.h b/src/string_buffer.h index 680674c..e959f10 100644 --- a/src/string_buffer.h +++ b/src/string_buffer.h @@ -7,24 +7,42 @@ /***************************************************************************** * STRING BUFFER * ***************************************************************************/ +enum str_buf_type +{ + CharBuf, + WCharBuf +}; + struct string_buffer; typedef struct string_buffer string_buffer_t; struct string_buffer { - char *str; - size_t str_sz; + union { + char *cstr; + wchar_t *wstr; + void *data; + }; + size_t data_sz; + enum str_buf_type type; }; -string_buffer_t* create_string_buffer(size_t sz); +string_buffer_t* create_string_buffer(size_t number_of_chars, enum str_buf_type type); void destroy_string_buffer(string_buffer_t *buffer); fort_status_t realloc_string_buffer_without_copy(string_buffer_t *buffer); + fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str); +fort_status_t fill_buffer_from_wstring(string_buffer_t *buffer, const wchar_t *str); + size_t buffer_text_height(string_buffer_t *buffer); +size_t string_buffer_capacity(const string_buffer_t *buffer); +void *buffer_get_data(string_buffer_t *buffer); size_t buffer_text_width(string_buffer_t *buffer); int buffer_printf(string_buffer_t *buffer, size_t buffer_row, size_t table_column, char *buf, size_t buf_len, const context_t *context); +int buffer_wprintf(string_buffer_t *buffer, size_t buffer_row, size_t table_column, wchar_t *buf, size_t buf_len, const context_t *context); + #endif // STRING_BUFFER_H diff --git a/tests/test_string_buffer.c b/tests/test_string_buffer.c index c7a0888..6a6e2ac 100644 --- a/tests/test_string_buffer.c +++ b/tests/test_string_buffer.c @@ -2,10 +2,19 @@ #include "string_buffer.h" //#include "../src/fort.c" +#include "wchar.h" + size_t strchr_count(const char* str, int ch); +size_t wstrchr_count(const wchar_t* str, wchar_t ch); + const char* str_n_substring_beg(const char* str, int ch, int n); +const wchar_t* wstr_n_substring_beg(const wchar_t* str, wchar_t ch_separator, size_t n); + fort_status_t str_n_substring(const char* str, char ch_separator, size_t n, const char **begin, const char **end); +void wstr_n_substring(const wchar_t* str, wchar_t ch_separator, size_t n, const wchar_t **begin, const wchar_t **end); + + size_t buffer_text_width(string_buffer_t *buffer); @@ -42,6 +51,22 @@ void test_strchr_count(void) assert_true(strchr_count("\n123123\n123123\n\n\n123", '\n') == 5); assert_true(strchr_count("1a23123a123123aaa123", 'a') == 5); + + + assert_true(wstrchr_count(NULL, L'\n') == 0); + assert_true(wstrchr_count(L"", L'\n') == 0); + assert_true(wstrchr_count(L"asbd", L'\n') == 0); + + assert_true(wstrchr_count(L"asbd\n", L'\n') == 1); + assert_true(wstrchr_count(L"\nasbd", L'\n') == 1); + assert_true(wstrchr_count(L"a\nsbd", L'\n') == 1); + + assert_true(wstrchr_count(L"\n12\n123", L'\n') == 2); + assert_true(wstrchr_count(L"\n12\n123\n", L'\n') == 3); + assert_true(wstrchr_count(L"\n\n\n", '\n') == 3); + assert_true(wstrchr_count(L"\n123123\n123123\n\n\n123", L'\n') == 5); + + assert_true(wstrchr_count(L"1\xffffy23123\xffffy123123\xffffy\xffffy\xffffy123", L'\xffff') == 5); } @@ -52,6 +77,11 @@ void test_str_n_substring(void) assert_true(str_n_substring_beg(empty_str, '\n', 1) == NULL); assert_true(str_n_substring_beg(empty_str, '\n', 2) == NULL); + const wchar_t *empty_wstr = L""; + assert_true(wstr_n_substring_beg(empty_wstr, L'\n', 0) == empty_wstr); + assert_true(wstr_n_substring_beg(empty_wstr, L'\n', 1) == NULL); + assert_true(wstr_n_substring_beg(empty_wstr, L'\n', 2) == NULL); + const char *str = "123\n5678\n9"; assert_true(str_n_substring_beg(NULL, '\n', 0) == NULL); assert_true(str_n_substring_beg(str, '\n', 0) == str); @@ -61,6 +91,15 @@ void test_str_n_substring(void) assert_true(str_n_substring_beg(str, '\n', 2) == str + 9); assert_true(str_n_substring_beg(str, '\n', 3) == NULL); + const wchar_t *wstr = L"123\n5678\n9"; + assert_true(wstr_n_substring_beg(NULL, L'\n', 0) == NULL); + assert_true(wstr_n_substring_beg(wstr, L'\n', 0) == wstr); + assert_true(wstr_n_substring_beg(wstr, L'1', 0) == wstr); + + assert_true(wstr_n_substring_beg(wstr, L'\n', 1) == wstr + 4); + assert_true(wstr_n_substring_beg(wstr, L'\n', 2) == wstr + 9); + assert_true(wstr_n_substring_beg(wstr, L'\n', 3) == NULL); + const char *str2 = "\n123\n56\n\n9\n"; assert_true(str_n_substring_beg(str2, '\n', 0) == str2); assert_true(str_n_substring_beg(str2, '\n', 1) == str2 + 1); @@ -70,6 +109,15 @@ void test_str_n_substring(void) assert_true(str_n_substring_beg(str2, '\n', 5) == str2 + 11); assert_true(str_n_substring_beg(str2, '\n', 6) == NULL); + const wchar_t *wstr2 = L"\xff0fy23\xff0fy6\xff0f\xff0fy\xff0f"; + assert_true(wstr_n_substring_beg(wstr2, L'\xff0f', 0) == wstr2); + assert_true(wstr_n_substring_beg(wstr2, L'\xff0f', 1) == wstr2 + 1); + assert_true(wstr_n_substring_beg(wstr2, L'\xff0f', 2) == wstr2 + 5); + assert_true(wstr_n_substring_beg(wstr2, L'\xff0f', 3) == wstr2 + 8); + assert_true(wstr_n_substring_beg(wstr2, L'\xff0f', 4) == wstr2 + 9); + assert_true(wstr_n_substring_beg(wstr2, L'\xff0f', 5) == wstr2 + 11); + assert_true(wstr_n_substring_beg(wstr2, L'\xff0f', 6) == NULL); + const char *beg = NULL; const char *end = NULL; str_n_substring(empty_str, '\n', 0, &beg, &end); @@ -79,6 +127,15 @@ void test_str_n_substring(void) str_n_substring(empty_str, '\n', 2, &beg, &end); assert_true(beg == NULL && end == NULL); + const wchar_t *wbeg = NULL; + const wchar_t *wend = NULL; + wstr_n_substring(empty_wstr, L'\n', 0, &wbeg, &wend); + assert_true(wbeg == empty_wstr && wend == empty_wstr + wcslen(empty_wstr)); + wstr_n_substring(empty_wstr, L'\n', 1, &wbeg, &wend); + assert_true(wbeg == NULL && wend == NULL); + wstr_n_substring(empty_wstr, L'\n', 2, &wbeg, &wend); + assert_true(wbeg == NULL && wend == NULL); + str_n_substring(NULL, '\n', 0, &beg, &end); assert_true(beg == NULL && end == NULL); str_n_substring(str, '\n', 0, &beg, &end); @@ -86,6 +143,13 @@ void test_str_n_substring(void) str_n_substring(str, '2', 0, &beg, &end); assert_true(beg == str && end == str + 1); + wstr_n_substring(NULL, L'\n', 0, &wbeg, &wend); + assert_true(wbeg == NULL && wend == NULL); + wstr_n_substring(wstr, L'\n', 0, &wbeg, &wend); + assert_true(wbeg == wstr && wend == wstr + 3); + wstr_n_substring(wstr, L'2', 0, &wbeg, &wend); + assert_true(wbeg == wstr && wend == wstr + 1); + str_n_substring(str, '\n', 1, &beg, &end); assert_true(beg == str +4 && end == str + 8); str_n_substring(str, '\n', 2, &beg, &end); @@ -93,6 +157,12 @@ void test_str_n_substring(void) str_n_substring(str, '\n', 3, &beg, &end); assert_true(beg == NULL && end == NULL); + wstr_n_substring(wstr, L'\n', 1, &wbeg, &wend); + assert_true(wbeg == wstr +4 && wend == wstr + 8); + wstr_n_substring(wstr, L'\n', 2, &wbeg, &wend); + assert_true(wbeg == wstr + 9 && wend == wstr + wcslen(wstr)); + wstr_n_substring(wstr, L'\n', 3, &wbeg, &wend); + assert_true(wbeg == NULL && wend == NULL); str_n_substring(str2, '\n', 0, &beg, &end); assert_true(beg == str2 && end == str2); @@ -108,62 +178,129 @@ void test_str_n_substring(void) assert_true(beg == str2 + 11 && end == str2 + 11); str_n_substring(str2, '\n', 6, &beg, &end); assert_true(beg == NULL && end == NULL); + + + wstr_n_substring(wstr2, L'\xff0f', 0, &wbeg, &wend); + assert_true(wbeg == wstr2 && wend == wstr2); + wstr_n_substring(wstr2, L'\xff0f', 1, &wbeg, &wend); + assert_true(wbeg == wstr2 + 1 && wend == wstr2 + 4); + wstr_n_substring(wstr2, L'\xff0f', 2, &wbeg, &wend); + assert_true(wbeg == wstr2 + 5 && wend == wstr2 + 7); + wstr_n_substring(wstr2, L'\xff0f', 3, &wbeg, &wend); + assert_true(wbeg == wstr2 + 8 && wend == wstr2 + 8); + wstr_n_substring(wstr2, L'\xff0f', 4, &wbeg, &wend); + assert_true(wbeg == wstr2 + 9 && wend == wstr2 + 10); + wstr_n_substring(wstr2, L'\xff0f', 5, &wbeg, &wend); + assert_true(wbeg == wstr2 + 11 && wend == wstr2 + 11); + wstr_n_substring(wstr2, L'\xff0f', 6, &wbeg, &wend); + assert_true(wbeg == NULL && wend == NULL); } void test_buffer_text_width(void) { - string_buffer_t *buffer = create_string_buffer(200); - char *old_value = buffer->str; + string_buffer_t *buffer = create_string_buffer(200, CharBuf); + buffer->type = CharBuf; + char *old_value = buffer->cstr; - buffer->str = ""; + buffer->cstr = ""; assert_true(buffer_text_width(buffer) == 0); - buffer->str = "\n\n\n\n"; + buffer->cstr = "\n\n\n\n"; assert_true(buffer_text_width(buffer) == 0); - buffer->str = "12345"; + buffer->cstr = "12345"; assert_true(buffer_text_width(buffer) == 5); - buffer->str = "12345\n1234567"; + buffer->cstr = "12345\n1234567"; assert_true(buffer_text_width(buffer) == 7); - buffer->str = "12345\n1234567\n"; + buffer->cstr = "12345\n1234567\n"; assert_true(buffer_text_width(buffer) == 7); - buffer->str = "12345\n1234567\n123"; + buffer->cstr = "12345\n1234567\n123"; assert_true(buffer_text_width(buffer) == 7); - buffer->str = old_value; + + + buffer->type = WCharBuf; + + buffer->wstr = L""; + assert_true(buffer_text_width(buffer) == 0); + + buffer->wstr = L"\n\n\n\n"; + assert_true(buffer_text_width(buffer) == 0); + + buffer->wstr = L"12345"; + assert_true(buffer_text_width(buffer) == 5); + + buffer->wstr = L"12345\n1234567"; + assert_true(buffer_text_width(buffer) == 7); + + buffer->wstr = L"12345\n1234567\n"; + assert_true(buffer_text_width(buffer) == 7); + + buffer->wstr = L"12345\n1234567\n123"; + assert_true(buffer_text_width(buffer) == 7); + + + buffer->type = CharBuf; + buffer->cstr = old_value; destroy_string_buffer(buffer); } void test_buffer_text_height(void) { - string_buffer_t *buffer = create_string_buffer(200); - char *old_value = buffer->str; + string_buffer_t *buffer = create_string_buffer(200, CharBuf); + buffer->type = CharBuf; + char *old_value = buffer->cstr; - buffer->str = ""; + buffer->cstr = ""; assert_true(buffer_text_height(buffer) == 0); - buffer->str = "\n"; + buffer->cstr = "\n"; assert_true(buffer_text_height(buffer) == 2); - buffer->str = "\n\n"; + buffer->cstr = "\n\n"; assert_true(buffer_text_height(buffer) == 3); - buffer->str = "\n\n\n\n"; + buffer->cstr = "\n\n\n\n"; assert_true(buffer_text_height(buffer) == 5); - buffer->str = "12345"; + buffer->cstr = "12345"; assert_true(buffer_text_height(buffer) == 1); - buffer->str = "\n12345"; + buffer->cstr = "\n12345"; assert_true(buffer_text_height(buffer) == 2); - buffer->str = "\n12345\n\n2"; + buffer->cstr = "\n12345\n\n2"; assert_true(buffer_text_height(buffer) == 4); - buffer->str = old_value; + + buffer->type = WCharBuf; + buffer->wstr = L""; + assert_true(buffer_text_height(buffer) == 0); + + buffer->wstr = L"\n"; + assert_true(buffer_text_height(buffer) == 2); + + buffer->wstr = L"\n\n"; + assert_true(buffer_text_height(buffer) == 3); + + buffer->wstr = L"\n\n\n\n"; + assert_true(buffer_text_height(buffer) == 5); + + buffer->wstr = L"\xff0fy2345\xff0f"; + assert_true(buffer_text_height(buffer) == 1); + + buffer->wstr = L"\n12345"; + assert_true(buffer_text_height(buffer) == 2); + + buffer->wstr = L"\n12345\n\n2"; + assert_true(buffer_text_height(buffer) == 4); + + + buffer->type = CharBuf; + buffer->cstr = old_value; destroy_string_buffer(buffer); } diff --git a/tests/test_table.c b/tests/test_table.c index 12ede38..9dd8bde 100644 --- a/tests/test_table.c +++ b/tests/test_table.c @@ -791,6 +791,7 @@ void test_table_options(void **state) "| 3 | 4 | 55 | 67 |\n" "| | | | |\n" "+-----+-----+-----+-----+\n"; + // fprintf(stderr, "content:\n%s", table_str); assert_true( strcmp(table_str, table_str_etalon) == 0); ft_destroy_table(table);