From efa4921b3ee9c8b39c172951777c4a4a63c8d195 Mon Sep 17 00:00:00 2001 From: seleznevae Date: Tue, 24 Apr 2018 21:36:07 +0300 Subject: [PATCH] [A] Added wprintf --- include/fort.h | 4 + src/cell.c | 13 +++ src/cell.h | 8 +- src/fort.c | 77 +++++++++++++++- src/fort_impl.c | 16 ++++ src/fort_impl.h | 1 + src/row.c | 186 ++++++++++++++++++++++++++++++++++++--- src/row.h | 28 +++--- tests/test_table_basic.c | 39 +++++++- 9 files changed, 341 insertions(+), 31 deletions(-) diff --git a/include/fort.h b/include/fort.h index 178037c..d417e53 100644 --- a/include/fort.h +++ b/include/fort.h @@ -594,6 +594,10 @@ FT_EXTERN void ft_set_memory_funcs(void *(*f_malloc)(size_t size), void (*f_free #ifdef FT_HAVE_WCHAR +FT_EXTERN int ft_wprintf(FTABLE *table, const wchar_t *fmt, ...); +FT_EXTERN int ft_wprintf_ln(FTABLE *table, const wchar_t *fmt, ...); + + #define ft_wwrite(table, ...)\ (0 ? CHECK_IF_ARGS_ARE_WSTRINGS(__VA_ARGS__) : ft_nwwrite(table, PP_NARG(__VA_ARGS__), __VA_ARGS__)) #define ft_wwrite_ln(table, ...)\ diff --git a/src/cell.c b/src/cell.c index edef0ca..41db71a 100644 --- a/src/cell.c +++ b/src/cell.c @@ -135,6 +135,7 @@ clear: return -1; } +#ifdef FT_HAVE_WCHAR int cell_wprintf(fort_cell_t *cell, size_t row, wchar_t *buf, size_t buf_len, const context_t *context) { wchar_t space_char = L' '; @@ -175,6 +176,7 @@ int cell_wprintf(fort_cell_t *cell, size_t row, wchar_t *buf, size_t buf_len, co clear: return -1; } +#endif fort_status_t fill_cell_from_string(fort_cell_t *cell, const char *str) @@ -185,6 +187,17 @@ fort_status_t fill_cell_from_string(fort_cell_t *cell, const char *str) return fill_buffer_from_string(cell->str_buffer, str); } +#ifdef FT_HAVE_WCHAR +fort_status_t fill_cell_from_wstring(fort_cell_t *cell, const wchar_t *str) +{ + assert(str); + assert(cell); + + return fill_buffer_from_wstring(cell->str_buffer, str); +} + +#endif + string_buffer_t *cell_get_string_buffer(fort_cell_t *cell) { assert(cell); diff --git a/src/cell.h b/src/cell.h index b7d768f..244715a 100644 --- a/src/cell.h +++ b/src/cell.h @@ -24,11 +24,13 @@ size_t 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, char *buf, size_t buf_len, const context_t *context); -int cell_wprintf(fort_cell_t *cell, size_t row, 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); +#ifdef FT_HAVE_WCHAR +int cell_wprintf(fort_cell_t *cell, size_t row, wchar_t *buf, size_t buf_len, const context_t *context); +fort_status_t fill_cell_from_wstring(fort_cell_t *cell, const wchar_t *str); +#endif + string_buffer_t* cell_get_string_buffer(fort_cell_t *cell); #endif /* CELL_H */ diff --git a/src/fort.c b/src/fort.c index dd00d9a..cb7d215 100644 --- a/src/fort.c +++ b/src/fort.c @@ -127,13 +127,14 @@ void ft_set_cur_cell(FTABLE *table, size_t row, size_t col) static int ft_row_printf_impl(FTABLE *table, size_t row, const char *fmt, va_list *va) { +#define CREATE_ROW_FROM_FMT_STRING create_row_from_fmt_string size_t i = 0; size_t new_cols = 0; if (table == NULL) return -1; - fort_row_t *new_row = create_row_from_fmt_string(fmt, va); + fort_row_t *new_row = CREATE_ROW_FROM_FMT_STRING(fmt, va); if (new_row == NULL) { return -1; @@ -167,8 +168,56 @@ static int ft_row_printf_impl(FTABLE *table, size_t row, const char *fmt, va_lis clear: destroy_row(new_row); return -1; +#undef CREATE_ROW_FROM_FMT_STRING } +#ifdef FT_HAVE_WCHAR +static int ft_row_wprintf_impl(FTABLE *table, size_t row, const wchar_t *fmt, va_list *va) +{ +#define CREATE_ROW_FROM_FMT_STRING create_row_from_fmt_wstring + size_t i = 0; + size_t new_cols = 0; + + if (table == NULL) + return -1; + + fort_row_t *new_row = CREATE_ROW_FROM_FMT_STRING(fmt, va); + + if (new_row == NULL) { + return -1; + } + + fort_row_t **cur_row_p = NULL; + size_t sz = vector_size(table->rows); + if (row >= sz) { + size_t push_n = row - sz + 1; + for (i = 0; i < push_n; ++i) { + fort_row_t *padding_row = create_row(); + if (padding_row == NULL) + goto clear; + + if (IS_ERROR(vector_push(table->rows, &padding_row))) { + destroy_row(padding_row); + goto clear; + } + } + } + /* todo: clearing pushed items in case of error ?? */ + + new_cols = columns_in_row(new_row); + cur_row_p = (fort_row_t **)vector_at(table->rows, row); + swap_row(*cur_row_p, new_row, table->cur_col); + + table->cur_col += new_cols; + destroy_row(new_row); + return new_cols; + +clear: + destroy_row(new_row); + return -1; +#undef CREATE_ROW_FROM_FMT_STRING +} +#endif #if defined(FT_CLANG_COMPILER) || defined(FT_GCC_COMPILER) #define FT_PRINTF ft_printf @@ -208,6 +257,32 @@ int FT_PRINTF_LN(FTABLE *table, const char *fmt, ...) #undef FT_HDR_PRINTF #undef FT_HDR_PRINTF_LN +#ifdef FT_HAVE_WCHAR +int ft_wprintf(FTABLE *table, const wchar_t *fmt, ...) +{ + assert(table); + va_list va; + va_start(va, fmt); + int result = ft_row_wprintf_impl(table, table->cur_row, fmt, &va); + va_end(va); + return result; +} + +int ft_wprintf_ln(FTABLE *table, const wchar_t *fmt, ...) +{ + assert(table); + va_list va; + va_start(va, fmt); + int result = ft_row_wprintf_impl(table, table->cur_row, fmt, &va); + if (result >= 0) { + ft_ln(table); + } + va_end(va); + return result; +} + +#endif + static int ft_write_impl(FTABLE *table, const char *cell_content) { diff --git a/src/fort_impl.c b/src/fort_impl.c index 001f834..95f570e 100644 --- a/src/fort_impl.c +++ b/src/fort_impl.c @@ -140,6 +140,22 @@ size_t number_of_columns_in_format_string(const char *fmt) return separator_counter + 1; } +size_t number_of_columns_in_format_wstring(const wchar_t *fmt) +{ + int separator_counter = 0; + const wchar_t *pos = fmt; + while (1) { + pos = wcschr(pos, FORT_COL_SEPARATOR); + if (pos == NULL) + break; + + separator_counter++; + ++pos; + } + return separator_counter + 1; +} + + int snprint_n_chars(char *buf, size_t length, size_t n, char ch) { if (length <= n) diff --git a/src/fort_impl.h b/src/fort_impl.h index 8e692f8..7e1f777 100644 --- a/src/fort_impl.h +++ b/src/fort_impl.h @@ -116,6 +116,7 @@ void set_memory_funcs(void *(*f_malloc)(size_t size), void (*f_free)(void *ptr)) 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_wstring(const wchar_t *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); diff --git a/src/row.c b/src/row.c index 9a2be71..e09d1ea 100644 --- a/src/row.c +++ b/src/row.c @@ -338,8 +338,15 @@ clear: fort_row_t *create_row_from_string(const char *str) { - char *pos = NULL; - char *base_pos = NULL; + typedef char char_type; + char_type *(*strdup_)(const char_type * str) = F_STRDUP; + const char_type zero_char = '\0'; + fort_status_t (*fill_cell_from_string_)(fort_cell_t *cell, const char *str) = fill_cell_from_string; + const char_type *const zero_string = ""; +#define STRCHR strchr + + char_type *pos = NULL; + char_type *base_pos = NULL; unsigned int number_of_separators = 0; fort_row_t *row = create_row(); @@ -349,7 +356,7 @@ fort_row_t *create_row_from_string(const char *str) if (str == NULL) return row; - char *str_copy = F_STRDUP(str); + char_type *str_copy = strdup_(str); if (str_copy == NULL) goto clear; @@ -357,9 +364,9 @@ fort_row_t *create_row_from_string(const char *str) base_pos = str_copy; number_of_separators = 0; while (*pos) { - pos = strchr(pos, FORT_COL_SEPARATOR); + pos = STRCHR(pos, FORT_COL_SEPARATOR); if (pos != NULL) { - *(pos) = '\0'; + *(pos) = zero_char; ++pos; number_of_separators++; } @@ -368,8 +375,7 @@ fort_row_t *create_row_from_string(const char *str) if (cell == NULL) goto clear; - /* int status = fill_buffer_from_string(cell->str_buffer, base_pos); */ - int status = fill_cell_from_string(cell, base_pos); + int status = fill_cell_from_string_(cell, base_pos); if (IS_ERROR(status)) { destroy_cell(cell); goto clear; @@ -392,8 +398,7 @@ fort_row_t *create_row_from_string(const char *str) if (cell == NULL) goto clear; - /* int status = fill_buffer_from_string(cell->str_buffer, ""); */ - int status = fill_cell_from_string(cell, ""); + int status = fill_cell_from_string_(cell, zero_string); if (IS_ERROR(status)) { destroy_cell(cell); goto clear; @@ -413,24 +418,117 @@ clear: destroy_row(row); F_FREE(str_copy); return NULL; + +#undef STRCHR } +#ifdef FT_HAVE_WCHAR +fort_row_t *create_row_from_wstring(const wchar_t *str) +{ + typedef wchar_t char_type; + char_type *(*strdup_)(const char_type * str) = F_WCSDUP; + const char_type zero_char = L'\0'; + fort_status_t (*fill_cell_from_string_)(fort_cell_t *cell, const wchar_t *str) = fill_cell_from_wstring; + const char_type *const zero_string = L""; +#define STRCHR wcschr + + char_type *pos = NULL; + char_type *base_pos = NULL; + unsigned int number_of_separators = 0; + + fort_row_t *row = create_row(); + if (row == NULL) + return NULL; + + if (str == NULL) + return row; + + char_type *str_copy = strdup_(str); + if (str_copy == NULL) + goto clear; + + pos = str_copy; + base_pos = str_copy; + number_of_separators = 0; + while (*pos) { + pos = STRCHR(pos, FORT_COL_SEPARATOR); + if (pos != NULL) { + *(pos) = zero_char; + ++pos; + number_of_separators++; + } + + fort_cell_t *cell = create_cell(); + if (cell == NULL) + goto clear; + + int status = fill_cell_from_string_(cell, base_pos); + if (IS_ERROR(status)) { + destroy_cell(cell); + goto clear; + } + + status = vector_push(row->cells, &cell); + if (IS_ERROR(status)) { + destroy_cell(cell); + goto clear; + } + + if (pos == NULL) + break; + base_pos = pos; + } + + /* special case if in format string last cell is empty */ + while (vector_size(row->cells) < (number_of_separators + 1)) { + fort_cell_t *cell = create_cell(); + if (cell == NULL) + goto clear; + + int status = fill_cell_from_string_(cell, zero_string); + if (IS_ERROR(status)) { + destroy_cell(cell); + goto clear; + } + + status = vector_push(row->cells, &cell); + if (IS_ERROR(status)) { + destroy_cell(cell); + goto clear; + } + } + + F_FREE(str_copy); + return row; + +clear: + destroy_row(row); + F_FREE(str_copy); + return NULL; +#undef STRCHR +} +#endif fort_row_t *create_row_from_fmt_string(const char *fmt, va_list *va_args) { +#define VSNPRINTF vsnprintf +#define STR_FILED cstr +#define CREATE_ROW_FROM_STRING create_row_from_string +#define NUMBER_OF_COLUMNS_IN_FORMAT_STRING number_of_columns_in_format_string + string_buffer_t *buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, CharBuf); if (buffer == NULL) return NULL; - size_t cols_origin = number_of_columns_in_format_string(fmt); + size_t cols_origin = NUMBER_OF_COLUMNS_IN_FORMAT_STRING(fmt); size_t cols = 0; while (1) { va_list va; va_copy(va, *va_args); - int virtual_sz = vsnprintf(buffer->str.cstr, string_buffer_capacity(buffer), fmt, va); + int virtual_sz = VSNPRINTF(buffer->str.STR_FILED, string_buffer_capacity(buffer), fmt, va); va_end(va); /* If error encountered */ if (virtual_sz < 0) @@ -445,10 +543,10 @@ fort_row_t *create_row_from_fmt_string(const char *fmt, va_list *va_args) goto clear; } - cols = number_of_columns_in_format_string(buffer->str.cstr); + cols = NUMBER_OF_COLUMNS_IN_FORMAT_STRING(buffer->str.STR_FILED); if (cols == cols_origin) { - fort_row_t *row = create_row_from_string(buffer->str.cstr); + fort_row_t *row = CREATE_ROW_FROM_STRING(buffer->str.STR_FILED); if (row == NULL) { goto clear; } @@ -462,8 +560,70 @@ fort_row_t *create_row_from_fmt_string(const char *fmt, va_list *va_args) clear: destroy_string_buffer(buffer); return NULL; +#undef VSNPRINTF +#undef STR_FILED +#undef CREATE_ROW_FROM_STRING +#undef NUMBER_OF_COLUMNS_IN_FORMAT_STRING } +#ifdef FT_HAVE_WCHAR +fort_row_t *create_row_from_fmt_wstring(const wchar_t *fmt, va_list *va_args) +{ +#define VSNPRINTF vswprintf +#define STR_FILED wstr +#define CREATE_ROW_FROM_STRING create_row_from_wstring +#define NUMBER_OF_COLUMNS_IN_FORMAT_STRING number_of_columns_in_format_wstring + + + string_buffer_t *buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, CharBuf); + if (buffer == NULL) + return NULL; + + size_t cols_origin = NUMBER_OF_COLUMNS_IN_FORMAT_STRING(fmt); + size_t cols = 0; + + while (1) { + va_list va; + va_copy(va, *va_args); + int virtual_sz = VSNPRINTF(buffer->str.STR_FILED, string_buffer_capacity(buffer), fmt, va); + va_end(va); + /* If error encountered */ + if (virtual_sz < 0) + goto clear; + + /* Successful write */ + if ((size_t)virtual_sz < string_buffer_capacity(buffer)) + break; + + /* Otherwise buffer was too small, so incr. buffer size ant try again. */ + if (!IS_SUCCESS(realloc_string_buffer_without_copy(buffer))) + goto clear; + } + + cols = NUMBER_OF_COLUMNS_IN_FORMAT_STRING(buffer->str.STR_FILED); + if (cols == cols_origin) { + + fort_row_t *row = CREATE_ROW_FROM_STRING(buffer->str.STR_FILED); + if (row == NULL) { + goto clear; + } + + destroy_string_buffer(buffer); + return row; + } + + /* todo: add processing of cols != cols_origin */ + +clear: + destroy_string_buffer(buffer); + return NULL; +#undef VSNPRINTF +#undef STR_FILED +#undef CREATE_ROW_FROM_STRING +#undef NUMBER_OF_COLUMNS_IN_FORMAT_STRING +} +#endif + 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) diff --git a/src/row.h b/src/row.h index dcfdbf7..6225d22 100644 --- a/src/row.h +++ b/src/row.h @@ -6,17 +6,12 @@ #include "stdarg.h" #include "options.h" +#ifdef FT_HAVE_WCHAR +#include +#endif struct fort_row; typedef struct fort_row fort_row_t; -/* -enum ft_row_type -{ - FT_ROW_COMMON, - FT_ROW_HEADER -}; -*/ - fort_row_t * create_row(void); void destroy_row(fort_row_t *row); @@ -40,11 +35,7 @@ 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); + @@ -52,8 +43,19 @@ int wprint_row_separator(wchar_t *buffer, size_t buffer_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); + +#ifdef FT_HAVE_WCHAR +fort_row_t *create_row_from_wstring(const wchar_t *str); +fort_row_t* create_row_from_fmt_wstring(const wchar_t* fmt, va_list *va_args); + +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); 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); +#endif #endif /* ROW_H */ diff --git a/tests/test_table_basic.c b/tests/test_table_basic.c index 0bb4b46..c3d6fea 100644 --- a/tests/test_table_basic.c +++ b/tests/test_table_basic.c @@ -658,8 +658,45 @@ void test_table_write(void) ft_destroy_table(table); } +#ifdef FT_HAVE_WCHAR SCENARIO("Test printf functions(wide strings)") { - /* todo: need to implement */ + table = ft_create_table(); + assert_true(table != NULL); + assert_true(set_test_options_for_table(table) == FT_SUCCESS); + + ft_set_cell_option(table, 0, FT_ANY_COLUMN, FT_COPT_ROW_TYPE, FT_ROW_HEADER); + int n = ft_wprintf_ln(table, L"%d|%c|%s|%f", 3, 'c', "234", 3.14); + assert_true(n == 4); + n = ft_wprintf(table, L"%c|%s|%f|%d", 'c', "235", 3.15, 5); + assert_true(n == 4); + ft_ln(table); + n = ft_wprintf_ln(table, L"%s|%f|%d|%c", "234", 3.14, 3, 'c'); + assert_true(n == 4); + + /* Replace old values */ + ft_set_cur_cell(table, 1, 1); + n = ft_wprintf_ln(table, L"%s|%f|%d", "234", 3.14, 3); + assert_true(n == 3); + + const wchar_t *table_str = ft_to_wstring(table); + assert_true(table_str != NULL); + const wchar_t *table_str_etalon = + L"+-----+----------+----------+----------+\n" + L"| | | | |\n" + L"| 3 | c | 234 | 3.140000 |\n" + L"| | | | |\n" + L"+-----+----------+----------+----------+\n" + L"| | | | |\n" + L"| c | 234 | 3.140000 | 3 |\n" + L"| | | | |\n" + L"+-----+----------+----------+----------+\n" + L"| | | | |\n" + L"| 234 | 3.140000 | 3 | c |\n" + L"| | | | |\n" + L"+-----+----------+----------+----------+\n"; + assert_wcs_equal(table_str, table_str_etalon); + ft_destroy_table(table); } +#endif }