[C] Refactoring of setting row type

This commit is contained in:
seleznevae 2018-03-05 21:08:14 +03:00
parent ff3ba95d85
commit 8ba3d99565
15 changed files with 1058 additions and 163 deletions

View File

@ -1,10 +1,41 @@
#include <stdio.h> #include <stdio.h>
#include "fort.h" #include "fort.h"
#include <wchar.h>
#include <locale.h>
int main() 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, 0, FT_OPT_TEXT_ALIGN, CenterAligned);
ft_set_cell_option(table, FT_ANY_ROW, 1, FT_OPT_TEXT_ALIGN, LeftAligned); ft_set_cell_option(table, FT_ANY_ROW, 1, FT_OPT_TEXT_ALIGN, LeftAligned);
@ -83,5 +114,11 @@ int main()
printf("Table:\n"); printf("Table:\n");
printf("%s\n", ft_to_string(table)); printf("%s\n", ft_to_string(table));
ft_destroy_table(table); ft_destroy_table(table);
/*-------------------------------------------------------------*/
table = NULL; table = NULL;
} }

View File

@ -87,6 +87,11 @@ SOFTWARE.
#endif #endif
/*
* Wchar support
*/
#define FORT_HAVE_WCHAR
/* /*
* Helper macros * Helper macros
*/ */
@ -103,6 +108,12 @@ static inline int fort_check_if_string_helper(const char*str)
return 0; return 0;
} }
static inline int fort_check_if_wstring_helper(const wchar_t*str)
{
(void)str;
return 0;
}
#define PP_ARG_N( \ #define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ _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(...) \ #define PP_NARG(...) \
PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) 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 * 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(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); FORT_EXTERN int ft_write_ln(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT cell_content);
#define FT_NWRITE(table, ...)\ #define FT_NWRITE(table, ...)\
(0 ? CHECK_IF_ARGS_ARE_STRINGS(__VA_ARGS__) : ft_nwrite(table, PP_NARG(__VA_ARGS__), __VA_ARGS__)) (0 ? CHECK_IF_ARGS_ARE_STRINGS(__VA_ARGS__) : ft_nwrite(table, PP_NARG(__VA_ARGS__), __VA_ARGS__))
#define FT_NWRITE_LN(table, ...)\ #define FT_NWRITE_LN(table, ...)\
(0 ? CHECK_IF_ARGS_ARE_STRINGS(__VA_ARGS__) : ft_nwrite_ln(table, PP_NARG(__VA_ARGS__), __VA_ARGS__)) (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(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, ...); 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(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[]); 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 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); //FORT_EXTERN ssize_t ft_n_to_string(const FTABLE *FORT_RESTRICT table, char *FORT_RESTRICT dst, size_t dst_len);

View File

@ -18,7 +18,7 @@ fort_cell_t * create_cell()
fort_cell_t *cell = F_CALLOC(sizeof(fort_cell_t), 1); fort_cell_t *cell = F_CALLOC(sizeof(fort_cell_t), 1);
if (cell == NULL) if (cell == NULL)
return 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) { if (cell->str_buffer == NULL) {
F_FREE(cell); F_FREE(cell);
return NULL; 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_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 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; 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 += 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)); 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_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 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; 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); size_t text_height = buffer_text_height(cell->str_buffer);
result += text_height == 0 ? cell_empty_string_height : text_height; 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) 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 if (cell == NULL || buf_len == 0
|| (buf_len <= hint_width_cell(cell, context))) { || (buf_len <= hint_width_cell(cell, context))) {
return -1; 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) if (row >= hint_height_cell(cell, context)
|| row < cell_padding_top || row < cell_padding_top
|| row >= (cell_padding_top + buffer_text_height(cell->str_buffer))) { || 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; return k;
} else { } else {
int written = 0; int written = 0;
int left = cell_padding_left; int left = cell_padding_left;
int right = cell_padding_right; 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) 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 else
written += snprint_n_chars(buf + written, buf_len - 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, ' '); written += snprint_n_chars_(buf + written, buf_len - written, right, space_char);
return written; 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) fort_status_t fill_cell_from_string(fort_cell_t *cell, const char *str)

View File

@ -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); //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_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); fort_status_t fill_cell_from_string(fort_cell_t *cell, const char *str);

View File

@ -171,7 +171,10 @@ int FT_HDR_PRINTF(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT fmt, ..
if (result >= 0 && table->rows) { if (result >= 0 && table->rows) {
int sz = vector_size(table->rows); int sz = vector_size(table->rows);
if (sz != 0) { 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; 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) { if (result >= 0 && table->rows) {
int sz = vector_size(table->rows); int sz = vector_size(table->rows);
if (sz != 0) { 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) { if (result >= 0) {
@ -251,7 +257,32 @@ int ft_write_ln(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT cell_cont
return status; 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); assert(table);
int status = ft_write(table, cell_content); 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; 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); assert(table);
int status = ft_write(table, cell_content); 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[]) FORT_EXTERN int ft_row_write(FTABLE *FORT_RESTRICT table, size_t cols, const char* FORT_RESTRICT cells[])
{ {
assert(table); assert(table);
@ -396,6 +472,16 @@ const char* ft_to_string(const FTABLE *FORT_RESTRICT table)
} \ } \
dev += k; 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); assert(table);
/* Determing size of table string representation */ /* 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 */ /* Allocate string buffer for string representation */
if (table->conv_buffer == NULL) { 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) if (table->conv_buffer == NULL)
return 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))) { if (IS_ERROR(realloc_string_buffer_without_copy(table->conv_buffer))) {
return NULL; return NULL;
} }
} }
char *buffer = table->conv_buffer->str; char_type *buffer = buffer_get_data(table->conv_buffer);
size_t cols = 0; 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); status = table_rows_and_cols_geometry(table, &col_width_arr, &cols, &row_height_arr, &rows);
if (rows == 0) if (rows == 0)
return F_STRDUP(""); return cur_F_STRDUP(empty_string);
if (IS_ERROR(status)) if (IS_ERROR(status))
return NULL; 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_sep = (i < sep_size) ? (*(separator_t **)vector_at(table->separators, i)) : NULL;
cur_row = *(fort_row_t**)vector_at(table->rows, i); cur_row = *(fort_row_t**)vector_at(table->rows, i);
enum HorSeparatorPos separatorPos = (i == 0) ? TopSeparator : InsideSeparator; 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; 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; prev_row = cur_row;
} }
cur_row = NULL; cur_row = NULL;
cur_sep = (i < sep_size) ? (*(separator_t **)vector_at(table->separators, i)) : 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); F_FREE(col_width_arr);
@ -471,7 +651,6 @@ clear:
/* /*
* TMP * TMP
*/ */

View File

@ -1,4 +1,5 @@
#include "fort_impl.h" #include "fort_impl.h"
#include <wchar.h>
@ -11,7 +12,7 @@ char *fort_strdup(const char* str)
return NULL; return NULL;
size_t sz = strlen(str); 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) if (str_copy == NULL)
return NULL; return NULL;
@ -19,6 +20,20 @@ char *fort_strdup(const char* str)
return str_copy; 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) size_t number_of_columns_in_format_string(const char *fmt)
{ {
int separator_counter = 0; 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) if (length <= n)
return -1; return -1;
if (n == 0)
return 0;
int status = snprintf(buf, length, "%0*d", (int)n, 0); int status = snprintf(buf, length, "%0*d", (int)n, 0);
if (status < 0) if (status < 0)
return status; return status;
@ -49,3 +67,23 @@ int snprint_n_chars(char *buf, size_t length, size_t n, char ch)
} }
return n; 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;
}

View File

@ -16,6 +16,7 @@
#define F_REALLOC realloc #define F_REALLOC realloc
#define F_FREE free #define F_FREE free
#define F_STRDUP fort_strdup #define F_STRDUP fort_strdup
#define F_WCSDUP fort_wcsdup
#define F_CREATE(type) ((type *)F_CALLOC(sizeof(type), 1)) #define F_CREATE(type) ((type *)F_CALLOC(sizeof(type), 1))
@ -107,7 +108,10 @@ typedef struct separator separator_t;
* LIBFORT helpers * LIBFORT helpers
*****************************************************************************/ *****************************************************************************/
char *fort_strdup(const char* str); 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); 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 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 #endif // FORT_IMPL_H

View File

@ -23,6 +23,8 @@ struct fort_cell_options g_default_cell_option =
1, /* cell_padding_left */ 1, /* cell_padding_left */
1, /* cell_padding_right */ 1, /* cell_padding_right */
1, /* cell_empty_string_height */ 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) 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; return cell_opts->cell_padding_right;
case FT_OPT_EMPTY_STR_HEIGHT: case FT_OPT_EMPTY_STR_HEIGHT:
return cell_opts->cell_empty_string_height; return cell_opts->cell_empty_string_height;
case FT_OPT_ROW_TYPE:
return cell_opts->row_type;
default: default:
// todo: implement later // todo: implement later
exit(333); 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; opt->cell_padding_right = value;
} else if (OPTION_IS_SET(option, FT_OPT_EMPTY_STR_HEIGHT)) { } else if (OPTION_IS_SET(option, FT_OPT_EMPTY_STR_HEIGHT)) {
opt->cell_empty_string_height = value; opt->cell_empty_string_height = value;
} else if (OPTION_IS_SET(option, FT_OPT_ROW_TYPE)) {
opt->row_type = value;
} }
return F_SUCCESS; return F_SUCCESS;

View File

@ -12,6 +12,12 @@ enum TextAlignment
RightAligned RightAligned
}; };
enum RowType
{
Common,
Header
};
struct fort_column_options 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_LEFT_PADDING ((uint32_t)(0x01U << (4)))
#define FT_OPT_RIGHT_PADDING ((uint32_t)(0x01U << (5))) #define FT_OPT_RIGHT_PADDING ((uint32_t)(0x01U << (5)))
#define FT_OPT_EMPTY_STR_HEIGHT ((uint32_t)(0x01U << (6))) #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_IS_SET(ft_opts, option) ((ft_opts) & (option))
#define OPTION_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_left;
int cell_padding_right; int cell_padding_right;
int cell_empty_string_height; int cell_empty_string_height;
enum RowType row_type;
}; };
typedef struct fort_cell_options fort_cell_options_t; typedef struct fort_cell_options fort_cell_options_t;

239
src/row.c
View File

@ -24,7 +24,7 @@ fort_row_t * create_row()
return NULL; return NULL;
} }
// row->is_header = F_FALSE; // row->is_header = F_FALSE;
row->type = Common; // row->type = Common;
return row; return row;
} }
@ -120,22 +120,26 @@ int print_row_separator(char *buffer, size_t buffer_sz,
} \ } \
dev += k; 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(buffer);
assert(context); assert(context);
int dev = 0; int dev = 0;
int k = 0; int k = 0;
const fort_row_t *main_row = NULL; enum RowType lower_row_type = Common;
if (upper_row != NULL && lower_row != NULL) { if (lower_row != NULL) {
main_row = lower_row->type == Header ? lower_row : upper_row; lower_row_type = get_cell_opt_value_hierarcial(context->table_options, context->row, FT_ANY_COLUMN, FT_OPT_ROW_TYPE);
} 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 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 /* Row separator anatomy
* *
@ -147,10 +151,9 @@ int print_row_separator(char *buffer, size_t buffer_sz,
const char *R = NULL; const char *R = NULL;
const char (*border_chars)[BorderItemPosSize] = NULL; const char (*border_chars)[BorderItemPosSize] = NULL;
if (main_row && main_row->type == Header) {
border_chars = &context->table_options->header_border_chars;
} else {
border_chars = &context->table_options->border_chars; 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) { 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)) if (!isprint(*L) && !isprint(*I) && !isprint(*IV) && !isprint(*R))
return 0; return 0;
for (size_t i = 0; i < cols; ++i) { for (size_t i = 0; i < cols; ++i) {
if (i == 0) { 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 { } 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; 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) 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) 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) if (buffer == NULL)
return 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) { while (1) {
va_list va; va_list va;
va_copy(va, *va_args); 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); va_end(va);
/* If error encountered */ /* If error encountered */
if (virtual_sz == -1) if (virtual_sz == -1)
goto clear; goto clear;
/* Successful write */ /* Successful write */
if (virtual_sz < buffer->str_sz) if (virtual_sz < string_buffer_capacity(buffer))// buffer->str_sz)
break; break;
/* Otherwise buffer was too small, so incr. buffer size ant try again. */ /* 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; 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) { 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) { if (row == NULL) {
goto clear; 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, 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) 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); assert(context);
if (row == NULL) if (row == NULL)
return -1; 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 * 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->header_border_chars)
: (&context->table_options->border_chars); : (&context->table_options->border_chars);
const char *L = &(*bord_chars)[LL_bip]; 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; int dev = 0;
for (size_t i = 0; i < row_height; ++i) { 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) { for (size_t j = 0; j < col_width_arr_sz; ++j) {
((context_t *)context)->column = j; ((context_t *)context)->column = j;
if (j < cols_in_row) { if (j < cols_in_row) {
fort_cell_t *cell = *(fort_cell_t**)vector_at(row->cells, j); 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 { } 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) { 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 { } 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; 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); typedef wchar_t char_type;
row->type = 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;
//}

View File

@ -8,11 +8,11 @@
struct fort_row; struct fort_row;
typedef struct fort_row fort_row_t; typedef struct fort_row fort_row_t;
enum RowType //enum RowType
{ //{
Common, // Common,
Header // Header
}; //};
fort_row_t * create_row(); 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, enum HorSeparatorPos separatorPos, const separator_t *sep,
const context_t *context); 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, 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); 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 #endif // ROW_H

View File

@ -1,11 +1,22 @@
#include "string_buffer.h" #include "string_buffer.h"
#include "options.h" #include "options.h"
#include "assert.h" #include "assert.h"
#include "wchar.h"
/***************************************************************************** /*****************************************************************************
* STRING BUFFER * 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) size_t strchr_count(const char* str, char ch)
{ {
if (str == NULL) if (str == NULL)
@ -21,6 +32,21 @@ size_t strchr_count(const char* str, char ch)
return count; 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) const char* str_n_substring_beg(const char* str, char ch_separator, size_t n)
{ {
if (str == NULL) 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; 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) 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); 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; return;
} }
void wstr_n_substring(const wchar_t* str, wchar_t ch_separator, size_t n, const wchar_t **begin, const wchar_t **end)
string_buffer_t* create_string_buffer(size_t sz)
{ {
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)); string_buffer_t *result = (string_buffer_t *)F_MALLOC(sizeof(string_buffer_t));
if (result == NULL) if (result == NULL)
return NULL; return NULL;
result->str = F_MALLOC(sz); result->data = F_MALLOC(sz);
if (result->str == NULL) { if (result->data == NULL) {
F_FREE(result); F_FREE(result);
return NULL; return NULL;
} }
result->str_sz = sz; result->data_sz = sz;
result->type = type;
return result; return result;
} }
@ -80,21 +147,21 @@ void destroy_string_buffer(string_buffer_t *buffer)
{ {
if (buffer == NULL) if (buffer == NULL)
return; return;
F_FREE(buffer->str); F_FREE(buffer->data);
buffer->str = NULL; buffer->data = NULL;
F_FREE(buffer); F_FREE(buffer);
} }
fort_status_t realloc_string_buffer_without_copy(string_buffer_t *buffer) fort_status_t realloc_string_buffer_without_copy(string_buffer_t *buffer)
{ {
assert(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) { if (new_str == NULL) {
return F_MEMORY_ERROR; return F_MEMORY_ERROR;
} }
F_FREE(buffer->str); F_FREE(buffer->data);
buffer->str = new_str; buffer->data = new_str;
buffer->str_sz *= 2; buffer->data_sz *= 2;
return F_SUCCESS; return F_SUCCESS;
} }
@ -108,14 +175,38 @@ fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str)
if (copy == NULL) if (copy == NULL)
return F_MEMORY_ERROR; return F_MEMORY_ERROR;
while (sz >= buffer->str_sz) { while (sz >= string_buffer_capacity(buffer)) {
int status = realloc_string_buffer_without_copy(buffer); int status = realloc_string_buffer_without_copy(buffer);
if (!IS_SUCCESS(status)) { if (!IS_SUCCESS(status)) {
return status; return status;
} }
} }
F_FREE(buffer->str); F_FREE(buffer->data);
buffer->str = copy; 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; return F_SUCCESS;
} }
@ -124,20 +215,35 @@ fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str)
size_t buffer_text_height(string_buffer_t *buffer) 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 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 buffer_text_width(string_buffer_t *buffer)
{ {
size_t max_length = 0; size_t max_length = 0;
int n = 0; int n = 0;
if (buffer->type == CharBuf) {
while (1) { while (1) {
const char *beg = NULL; const char *beg = NULL;
const char *end = NULL; const char *end = NULL;
str_n_substring(buffer->str, '\n', n, &beg, &end); 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;
}
} 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) if (beg == NULL || end == NULL)
return max_length; return max_length;
@ -145,11 +251,23 @@ size_t buffer_text_width(string_buffer_t *buffer)
++n; ++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) 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) { || buffer_row >= buffer_text_height(buffer) || buf_len == 0) {
return -1; 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 left = 0;
int right = 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)) { switch (get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_TEXT_ALIGN)) {
case LeftAligned: case LeftAligned:
left = 0; left = 0;
@ -184,29 +301,134 @@ int buffer_printf(string_buffer_t *buffer, size_t buffer_row, size_t table_colum
int written = 0; 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) if (written < 0)
return written; return written;
const CHAR_TYPE *beg = NULL;
const char *beg = NULL; const CHAR_TYPE *end = NULL;
const char *end = NULL; STR_N_SUBSTRING(buffer->BUFFER_STR, NEWLINE_CHAR, buffer_row, &beg, &end);
str_n_substring(buffer->str, '\n', buffer_row, &beg, &end);
if (beg == NULL || end == NULL) if (beg == NULL || end == NULL)
return -1; return -1;
char old_value = *end; CHAR_TYPE old_value = *end;
*(char *)end = '\0'; *(CHAR_TYPE *)end = NULL_CHAR;
written += snprintf(buf + written, buf_len - written, "%*s", (int)(end - beg), beg); written += SNPRINTF(buf + written, buf_len - written, SNPRINTF_FMT_STR, (int)(end - beg), beg);
*(char *)end = old_value; *(CHAR_TYPE *)end = old_value;
if (written < 0) if (written < 0)
return written; 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) if (written < 0)
return written; 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; 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;
}

View File

@ -7,24 +7,42 @@
/***************************************************************************** /*****************************************************************************
* STRING BUFFER * STRING BUFFER
* ***************************************************************************/ * ***************************************************************************/
enum str_buf_type
{
CharBuf,
WCharBuf
};
struct string_buffer; struct string_buffer;
typedef struct string_buffer string_buffer_t; typedef struct string_buffer string_buffer_t;
struct string_buffer struct string_buffer
{ {
char *str; union {
size_t str_sz; 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); void destroy_string_buffer(string_buffer_t *buffer);
fort_status_t realloc_string_buffer_without_copy(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_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 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); 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_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 #endif // STRING_BUFFER_H

View File

@ -2,10 +2,19 @@
#include "string_buffer.h" #include "string_buffer.h"
//#include "../src/fort.c" //#include "../src/fort.c"
#include "wchar.h"
size_t strchr_count(const char* str, int ch); 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 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); 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); 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("\n123123\n123123\n\n\n123", '\n') == 5);
assert_true(strchr_count("1a23123a123123aaa123", 'a') == 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', 1) == NULL);
assert_true(str_n_substring_beg(empty_str, '\n', 2) == 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"; const char *str = "123\n5678\n9";
assert_true(str_n_substring_beg(NULL, '\n', 0) == NULL); assert_true(str_n_substring_beg(NULL, '\n', 0) == NULL);
assert_true(str_n_substring_beg(str, '\n', 0) == str); 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', 2) == str + 9);
assert_true(str_n_substring_beg(str, '\n', 3) == NULL); 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"; 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', 0) == str2);
assert_true(str_n_substring_beg(str2, '\n', 1) == str2 + 1); 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', 5) == str2 + 11);
assert_true(str_n_substring_beg(str2, '\n', 6) == NULL); 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 *beg = NULL;
const char *end = NULL; const char *end = NULL;
str_n_substring(empty_str, '\n', 0, &beg, &end); 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); str_n_substring(empty_str, '\n', 2, &beg, &end);
assert_true(beg == NULL && end == NULL); 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); str_n_substring(NULL, '\n', 0, &beg, &end);
assert_true(beg == NULL && end == NULL); assert_true(beg == NULL && end == NULL);
str_n_substring(str, '\n', 0, &beg, &end); 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); str_n_substring(str, '2', 0, &beg, &end);
assert_true(beg == str && end == str + 1); 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); str_n_substring(str, '\n', 1, &beg, &end);
assert_true(beg == str +4 && end == str + 8); assert_true(beg == str +4 && end == str + 8);
str_n_substring(str, '\n', 2, &beg, &end); 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); str_n_substring(str, '\n', 3, &beg, &end);
assert_true(beg == NULL && end == NULL); 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); str_n_substring(str2, '\n', 0, &beg, &end);
assert_true(beg == str2 && end == str2); assert_true(beg == str2 && end == str2);
@ -108,62 +178,129 @@ void test_str_n_substring(void)
assert_true(beg == str2 + 11 && end == str2 + 11); assert_true(beg == str2 + 11 && end == str2 + 11);
str_n_substring(str2, '\n', 6, &beg, &end); str_n_substring(str2, '\n', 6, &beg, &end);
assert_true(beg == NULL && end == NULL); 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) void test_buffer_text_width(void)
{ {
string_buffer_t *buffer = create_string_buffer(200); string_buffer_t *buffer = create_string_buffer(200, CharBuf);
char *old_value = buffer->str; buffer->type = CharBuf;
char *old_value = buffer->cstr;
buffer->str = ""; buffer->cstr = "";
assert_true(buffer_text_width(buffer) == 0); 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); assert_true(buffer_text_width(buffer) == 0);
buffer->str = "12345"; buffer->cstr = "12345";
assert_true(buffer_text_width(buffer) == 5); assert_true(buffer_text_width(buffer) == 5);
buffer->str = "12345\n1234567"; buffer->cstr = "12345\n1234567";
assert_true(buffer_text_width(buffer) == 7); assert_true(buffer_text_width(buffer) == 7);
buffer->str = "12345\n1234567\n"; buffer->cstr = "12345\n1234567\n";
assert_true(buffer_text_width(buffer) == 7); assert_true(buffer_text_width(buffer) == 7);
buffer->str = "12345\n1234567\n123"; buffer->cstr = "12345\n1234567\n123";
assert_true(buffer_text_width(buffer) == 7); 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); destroy_string_buffer(buffer);
} }
void test_buffer_text_height(void) void test_buffer_text_height(void)
{ {
string_buffer_t *buffer = create_string_buffer(200); string_buffer_t *buffer = create_string_buffer(200, CharBuf);
char *old_value = buffer->str; buffer->type = CharBuf;
char *old_value = buffer->cstr;
buffer->str = ""; buffer->cstr = "";
assert_true(buffer_text_height(buffer) == 0); assert_true(buffer_text_height(buffer) == 0);
buffer->str = "\n"; buffer->cstr = "\n";
assert_true(buffer_text_height(buffer) == 2); assert_true(buffer_text_height(buffer) == 2);
buffer->str = "\n\n"; buffer->cstr = "\n\n";
assert_true(buffer_text_height(buffer) == 3); 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); assert_true(buffer_text_height(buffer) == 5);
buffer->str = "12345"; buffer->cstr = "12345";
assert_true(buffer_text_height(buffer) == 1); assert_true(buffer_text_height(buffer) == 1);
buffer->str = "\n12345"; buffer->cstr = "\n12345";
assert_true(buffer_text_height(buffer) == 2); assert_true(buffer_text_height(buffer) == 2);
buffer->str = "\n12345\n\n2"; buffer->cstr = "\n12345\n\n2";
assert_true(buffer_text_height(buffer) == 4); 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); destroy_string_buffer(buffer);
} }

View File

@ -791,6 +791,7 @@ void test_table_options(void **state)
"| 3 | 4 | 55 | 67 |\n" "| 3 | 4 | 55 | 67 |\n"
"| | | | |\n" "| | | | |\n"
"+-----+-----+-----+-----+\n"; "+-----+-----+-----+-----+\n";
// fprintf(stderr, "content:\n%s", table_str);
assert_true( strcmp(table_str, table_str_etalon) == 0); assert_true( strcmp(table_str, table_str_etalon) == 0);
ft_destroy_table(table); ft_destroy_table(table);