[C] Refactoring for utf-8

This commit is contained in:
seleznevae 2019-08-14 22:01:57 +03:00
parent d3d3e1821c
commit 3e961b053a
19 changed files with 3532 additions and 1738 deletions

View File

@ -99,6 +99,7 @@ def main():
"fort_utils.h", "fort_utils.h",
"vector.h", "vector.h",
"wcwidth.h", "wcwidth.h",
"utf8.h",
"string_buffer.h", "string_buffer.h",
"properties.h", "properties.h",
"cell.h", "cell.h",

View File

@ -231,6 +231,65 @@ void colorfull_table(void)
ft_destroy_table(table); ft_destroy_table(table);
#endif #endif
#if defined(FT_HAVE_UTF8)
table = ft_create_table();
ft_set_border_style(table, FT_NICE_STYLE);
ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER);
/* Filling table with data */
ft_u8write_ln(table, "Тест", "Итерации", "ms/op", "Тики", "Результат");
ft_u8write_ln(table, "n-body", "1000", "1.6", "1,500,000", "");
ft_add_separator(table);
ft_u8write_ln(table, "regex-redux", "1000", "0.8", "8,000,000");
ft_u8write_ln(table, "", "2500", "3.9", "27,000,000", "");
ft_u8write_ln(table, "", "10000", "12.5", "96,800,000");
ft_add_separator(table);
ft_u8write_ln(table, "mandelbrot", "1000", "8.1", "89,000,000");
ft_u8write_ln(table, "", "2500", "19.8", "320,000,000", "");
ft_u8write_ln(table, "", "10000", "60.7", "987,000,000");
ft_add_separator(table);
ft_set_cell_span(table, 8, 0, 4);
ft_u8write_ln(table, "Итог", "", "", "", "");
/* Setting text styles */
ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_CONT_TEXT_STYLE, FT_TSTYLE_BOLD);
ft_set_cell_prop(table, 8, FT_ANY_COLUMN, FT_CPROP_CONT_TEXT_STYLE, FT_TSTYLE_BOLD);
ft_set_cell_prop(table, FT_ANY_ROW, 0, FT_CPROP_CONT_TEXT_STYLE, FT_TSTYLE_BOLD);
ft_set_cell_prop(table, FT_ANY_ROW, 4, FT_CPROP_CONT_TEXT_STYLE, FT_TSTYLE_BOLD);
ft_set_cell_prop(table, FT_ANY_ROW, FT_ANY_COLUMN, FT_CPROP_CONT_TEXT_STYLE, FT_TSTYLE_ITALIC);
/* Set alignment */
ft_set_cell_prop(table, FT_ANY_ROW, 1, FT_CPROP_TEXT_ALIGN, FT_ALIGNED_RIGHT);
ft_set_cell_prop(table, FT_ANY_ROW, 2, FT_CPROP_TEXT_ALIGN, FT_ALIGNED_RIGHT);
ft_set_cell_prop(table, FT_ANY_ROW, 3, FT_CPROP_TEXT_ALIGN, FT_ALIGNED_RIGHT);
ft_set_cell_prop(table, FT_ANY_ROW, 4, FT_CPROP_TEXT_ALIGN, FT_ALIGNED_CENTER);
ft_set_cell_prop(table, 8, 0, FT_CPROP_TEXT_ALIGN, FT_ALIGNED_CENTER);
/* Set colors */
ft_set_cell_prop(table, 1, 4, FT_CPROP_CONT_FG_COLOR, FT_COLOR_GREEN);
ft_set_cell_prop(table, 3, 4, FT_CPROP_CONT_FG_COLOR, FT_COLOR_RED);
ft_set_cell_prop(table, 6, 4, FT_CPROP_CONT_FG_COLOR, FT_COLOR_GREEN);
ft_set_cell_prop(table, 8, 4, FT_CPROP_CONT_FG_COLOR, FT_COLOR_RED);
ft_set_cell_prop(table, 3, 2, FT_CPROP_CONT_FG_COLOR, FT_COLOR_RED);
ft_set_cell_prop(table, 4, 3, FT_CPROP_CONT_BG_COLOR, FT_COLOR_LIGHT_RED);
ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_CONT_FG_COLOR, FT_COLOR_LIGHT_BLUE);
/* Move table to the center of the screen */
ft_set_tbl_prop(table, FT_TPROP_TOP_MARGIN, 1);
ft_set_tbl_prop(table, FT_TPROP_LEFT_MARGIN, 10);
const char *table_str = ft_to_u8string(table);
if (table_wstr) {
printf("Table:\n%s\n\n ", table_str);
} else {
printf("Table conversion failed !!!\n ");
}
ft_destroy_table(table);
#endif
} }

2891
lib/fort.c

File diff suppressed because it is too large Load Diff

View File

@ -63,6 +63,10 @@ SOFTWARE.
#define FT_HAVE_WCHAR #define FT_HAVE_WCHAR
#endif #endif
#define FT_CONGIG_HAVE_UTF8
#if defined(FT_CONGIG_HAVE_UTF8)
#define FT_HAVE_UTF8
#endif
/***************************************************************************** /*****************************************************************************
* RETURN CODES * RETURN CODES
@ -483,8 +487,6 @@ int ft_nwrite_ln(ft_table_t *table, size_t count, const char *cell_content, ...)
/** /**
* Write strings from the array to the table. * Write strings from the array to the table.
* *
@ -899,6 +901,18 @@ const wchar_t *ft_to_wstring(const ft_table_t *table);
#ifdef FT_HAVE_UTF8
#define ft_u8write(table, ...)\
(ft_nu8write(table, FT_PP_NARG_(__VA_ARGS__), __VA_ARGS__))
#define ft_u8write_ln(table, ...)\
(ft_nu8write_ln(table, FT_PP_NARG_(__VA_ARGS__), __VA_ARGS__))
int ft_nu8write(ft_table_t *table, size_t n, const void *cell_content, ...);
int ft_nu8write_ln(ft_table_t *table, size_t n, const void *cell_content, ...);
const void *ft_to_u8string(const ft_table_t *table);
#endif /* FT_HAVE_UTF8 */
FT_END_DECLS FT_END_DECLS
#endif /* LIBFORT_H */ #endif /* LIBFORT_H */

View File

@ -14,7 +14,7 @@ fort_cell_t *create_cell(void)
fort_cell_t *cell = (fort_cell_t *)F_CALLOC(sizeof(fort_cell_t), 1); fort_cell_t *cell = (fort_cell_t *)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, CharBuf); cell->str_buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, CHAR_BUF);
if (cell->str_buffer == NULL) { if (cell->str_buffer == NULL) {
F_FREE(cell); F_FREE(cell);
return NULL; return NULL;
@ -78,7 +78,7 @@ size_t hint_width_cell(const fort_cell_t *cell, const context_t *context, enum r
size_t cell_padding_right = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_RIGHT_PADDING); size_t cell_padding_right = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_RIGHT_PADDING);
size_t result = cell_padding_left + cell_padding_right; size_t result = cell_padding_left + cell_padding_right;
if (cell->str_buffer && cell->str_buffer->str.data) { if (cell->str_buffer && cell->str_buffer->str.data) {
result += buffer_text_width(cell->str_buffer); result += buffer_text_visible_width(cell->str_buffer);
} }
result = MAX(result, (size_t)get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_MIN_WIDTH)); result = MAX(result, (size_t)get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_MIN_WIDTH));
@ -113,7 +113,7 @@ size_t hint_height_cell(const fort_cell_t *cell, const context_t *context)
size_t cell_empty_string_height = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_EMPTY_STR_HEIGHT); size_t cell_empty_string_height = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_EMPTY_STR_HEIGHT);
size_t result = cell_padding_top + cell_padding_bottom; size_t result = cell_padding_top + cell_padding_bottom;
if (cell->str_buffer && cell->str_buffer->str.data) { if (cell->str_buffer && cell->str_buffer->str.data) {
size_t text_height = buffer_text_height(cell->str_buffer); size_t text_height = buffer_text_visible_height(cell->str_buffer);
result += text_height == 0 ? cell_empty_string_height : text_height; result += text_height == 0 ? cell_empty_string_height : text_height;
} }
return result; return result;
@ -121,14 +121,12 @@ size_t hint_height_cell(const fort_cell_t *cell, const context_t *context)
FT_INTERNAL FT_INTERNAL
int cell_printf(fort_cell_t *cell, size_t row, char *buf, size_t buf_len, const context_t *context) int cell_printf(fort_cell_t *cell, size_t row, conv_context_t *cntx, size_t vis_width)
{ {
const char *space_char = " "; const context_t *context = cntx->cntx;
int (*buffer_printf_)(string_buffer_t *, size_t, char *, size_t, const context_t *, const char *, const char *) = buffer_printf; size_t buf_len = vis_width;
int (*snprint_n_strings_)(char *, size_t, size_t, const char *) = snprint_n_strings;
if (cell == NULL || buf_len == 0 if (cell == NULL || (vis_width < hint_width_cell(cell, context, VISIBLE_GEOMETRY))) {
|| (buf_len <= hint_width_cell(cell, context, VISIBLE_GEOMETRY))) {
return -1; return -1;
} }
@ -173,32 +171,35 @@ int cell_printf(fort_cell_t *cell, size_t row, char *buf, size_t buf_len, const
#define TOTAL_WRITTEN (written + invisible_written) #define TOTAL_WRITTEN (written + invisible_written)
#define RIGHT (cell_padding_right + extra_right) #define RIGHT (cell_padding_right + extra_right)
#define WRITE_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, cell_style_tag)) #define WRITE_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(print_n_strings(cntx, 1, cell_style_tag))
#define WRITE_RESET_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, reset_cell_style_tag)) #define WRITE_RESET_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(print_n_strings(cntx, 1, reset_cell_style_tag))
#define WRITE_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, content_style_tag)) #define WRITE_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(print_n_strings(cntx, 1, content_style_tag))
#define WRITE_RESET_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, reset_content_style_tag)) #define WRITE_RESET_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(print_n_strings(cntx, 1, reset_content_style_tag))
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_visible_height(cell->str_buffer))) {
WRITE_CELL_STYLE_TAG; WRITE_CELL_STYLE_TAG;
WRITE_CONTENT_STYLE_TAG; WRITE_CONTENT_STYLE_TAG;
WRITE_RESET_CONTENT_STYLE_TAG; WRITE_RESET_CONTENT_STYLE_TAG;
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len, buf_len - 1 - TOTAL_WRITTEN - R3, space_char)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, buf_len - TOTAL_WRITTEN - R3, FT_SPACE));
WRITE_RESET_CELL_STYLE_TAG; WRITE_RESET_CELL_STYLE_TAG;
return (int)TOTAL_WRITTEN; return (int)TOTAL_WRITTEN;
} }
WRITE_CELL_STYLE_TAG; WRITE_CELL_STYLE_TAG;
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, L2, space_char)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, L2, FT_SPACE));
if (cell->str_buffer) { if (cell->str_buffer) {
CHCK_RSLT_ADD_TO_WRITTEN(buffer_printf_(cell->str_buffer, row - cell_padding_top, buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN - R2 - R3, context, content_style_tag, reset_content_style_tag)); // CHCK_RSLT_ADD_TO_WRITTEN(buffer_printf2_(cell->str_buffer, row - cell_padding_top, cntx, buf_len - TOTAL_WRITTEN - R2 - R3, content_style_tag, reset_content_style_tag));
CHCK_RSLT_ADD_TO_WRITTEN(buffer_printf(cell->str_buffer, row - cell_padding_top, cntx, vis_width - L2 - R2 , content_style_tag, reset_content_style_tag));
} else { } else {
WRITE_CONTENT_STYLE_TAG; WRITE_CONTENT_STYLE_TAG;
WRITE_RESET_CONTENT_STYLE_TAG; WRITE_RESET_CONTENT_STYLE_TAG;
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN - R2 - R3, space_char)); // CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings2_(cntx, buf_len - TOTAL_WRITTEN - R2 - R3, FT_SPACE));
CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, vis_width - L2 - R2, FT_SPACE));
} }
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, R2, space_char)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, R2, FT_SPACE));
WRITE_RESET_CELL_STYLE_TAG; WRITE_RESET_CELL_STYLE_TAG;
return (int)TOTAL_WRITTEN; return (int)TOTAL_WRITTEN;
@ -213,101 +214,6 @@ clear:
#undef RIGHT #undef RIGHT
} }
#ifdef FT_HAVE_WCHAR
FT_INTERNAL
int cell_wprintf(fort_cell_t *cell, size_t row, wchar_t *buf, size_t buf_len, const context_t *context)
{
const char *space_char = " ";
int (*buffer_printf_)(string_buffer_t *, size_t, wchar_t *, size_t, const context_t *, const char *, const char *) = buffer_wprintf;
int (*snprint_n_strings_)(wchar_t *, size_t, size_t, const char *) = wsnprint_n_string;
if (cell == NULL || buf_len == 0
|| (buf_len <= hint_width_cell(cell, context, VISIBLE_GEOMETRY))) {
return -1;
}
unsigned int cell_padding_top = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_TOP_PADDING);
unsigned int cell_padding_left = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_LEFT_PADDING);
unsigned int cell_padding_right = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_RIGHT_PADDING);
size_t written = 0;
size_t invisible_written = 0;
int tmp = 0;
/* todo: Dirty hack with changing buf_len! need refactoring. */
/* Also maybe it is better to move all struff with colors to buffers? */
char cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_style_tag_for_cell(context->table_properties, context->row, context->column, cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
buf_len += strlen(cell_style_tag);
char reset_cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_reset_style_tag_for_cell(context->table_properties, context->row, context->column, reset_cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
buf_len += strlen(reset_cell_style_tag);
char content_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_style_tag_for_content(context->table_properties, context->row, context->column, content_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
buf_len += strlen(content_style_tag);
char reset_content_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_reset_style_tag_for_content(context->table_properties, context->row, context->column, reset_content_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
buf_len += strlen(reset_content_style_tag);
/* CELL_STYLE_T LEFT_PADDING CONTENT_STYLE_T CONTENT RESET_CONTENT_STYLE_T RIGHT_PADDING RESET_CELL_STYLE_T
* | | | | | | | |
* L1 R1
* L2 R2
* L3 R3
*/
size_t L2 = cell_padding_left;
size_t R2 = cell_padding_right;
size_t R3 = strlen(reset_cell_style_tag);
#define TOTAL_WRITTEN (written + invisible_written)
#define RIGHT (right + extra_right)
#define WRITE_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, cell_style_tag))
#define WRITE_RESET_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, reset_cell_style_tag))
#define WRITE_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, content_style_tag))
#define WRITE_RESET_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, reset_content_style_tag))
if (row >= hint_height_cell(cell, context)
|| row < cell_padding_top
|| row >= (cell_padding_top + buffer_text_height(cell->str_buffer))) {
WRITE_CELL_STYLE_TAG;
WRITE_CONTENT_STYLE_TAG;
WRITE_RESET_CONTENT_STYLE_TAG;
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len, buf_len - 1 - TOTAL_WRITTEN - R3, space_char));
WRITE_RESET_CELL_STYLE_TAG;
return (int)TOTAL_WRITTEN;
}
WRITE_CELL_STYLE_TAG;
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, L2, space_char));
if (cell->str_buffer) {
CHCK_RSLT_ADD_TO_WRITTEN(buffer_printf_(cell->str_buffer, row - cell_padding_top, buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN - R2 - R3, context, content_style_tag, reset_content_style_tag));
} else {
WRITE_CONTENT_STYLE_TAG;
WRITE_RESET_CONTENT_STYLE_TAG;
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN - R2 - R3, space_char));
}
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, R2, space_char));
WRITE_RESET_CELL_STYLE_TAG;
return (int)TOTAL_WRITTEN;
clear:
return -1;
#undef WRITE_CELL_STYLE_TAG
#undef WRITE_RESET_CELL_STYLE_TAG
#undef WRITE_CONTENT_STYLE_TAG
#undef WRITE_RESET_CONTENT_STYLE_TAG
#undef TOTAL_WRITTEN
#undef RIGHT
}
#endif
FT_INTERNAL FT_INTERNAL
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,15 +25,12 @@ FT_INTERNAL
enum CellType get_cell_type(const fort_cell_t *cell); enum CellType get_cell_type(const fort_cell_t *cell);
FT_INTERNAL FT_INTERNAL
int cell_printf(fort_cell_t *cell, size_t row, char *buf, size_t buf_len, const context_t *context); int cell_printf(fort_cell_t *cell, size_t row, conv_context_t *cntx, size_t cod_width);
FT_INTERNAL FT_INTERNAL
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);
#ifdef FT_HAVE_WCHAR #ifdef FT_HAVE_WCHAR
FT_INTERNAL
int cell_wprintf(fort_cell_t *cell, size_t row, wchar_t *buf, size_t buf_len, const context_t *context);
FT_INTERNAL FT_INTERNAL
fort_status_t fill_cell_from_wstring(fort_cell_t *cell, const wchar_t *str); fort_status_t fill_cell_from_wstring(fort_cell_t *cell, const wchar_t *str);
#endif #endif

View File

@ -63,6 +63,10 @@ SOFTWARE.
#define FT_HAVE_WCHAR #define FT_HAVE_WCHAR
#endif #endif
#define FT_CONGIG_HAVE_UTF8
#if defined(FT_CONGIG_HAVE_UTF8)
#define FT_HAVE_UTF8
#endif
/***************************************************************************** /*****************************************************************************
* RETURN CODES * RETURN CODES
@ -483,8 +487,6 @@ int ft_nwrite_ln(ft_table_t *table, size_t count, const char *cell_content, ...)
/** /**
* Write strings from the array to the table. * Write strings from the array to the table.
* *
@ -899,6 +901,18 @@ const wchar_t *ft_to_wstring(const ft_table_t *table);
#ifdef FT_HAVE_UTF8
#define ft_u8write(table, ...)\
(ft_nu8write(table, FT_PP_NARG_(__VA_ARGS__), __VA_ARGS__))
#define ft_u8write_ln(table, ...)\
(ft_nu8write_ln(table, FT_PP_NARG_(__VA_ARGS__), __VA_ARGS__))
int ft_nu8write(ft_table_t *table, size_t n, const void *cell_content, ...);
int ft_nu8write_ln(ft_table_t *table, size_t n, const void *cell_content, ...);
const void *ft_to_u8string(const ft_table_t *table);
#endif /* FT_HAVE_UTF8 */
FT_END_DECLS FT_END_DECLS
#endif /* LIBFORT_H */ #endif /* LIBFORT_H */

View File

@ -344,6 +344,23 @@ static int ft_write_impl(ft_table_t *table, const char *cell_content)
return status; return status;
} }
#ifdef FT_HAVE_UTF8
static int ft_u8write_impl(ft_table_t *table, const void *cell_content)
{
assert(table);
string_buffer_t *str_buffer = get_cur_str_buffer_and_create_if_not_exists(table);
if (str_buffer == NULL)
return FT_ERROR;
int status = fill_buffer_from_u8string(str_buffer, cell_content);
if (FT_IS_SUCCESS(status)) {
table->cur_col++;
}
return status;
}
#endif /* FT_HAVE_UTF8 */
#ifdef FT_HAVE_WCHAR #ifdef FT_HAVE_WCHAR
@ -412,6 +429,9 @@ int ft_nwrite_ln(ft_table_t *table, size_t count, const char *cell_content, ...)
return status; return status;
} }
#ifdef FT_HAVE_WCHAR #ifdef FT_HAVE_WCHAR
int ft_nwwrite(ft_table_t *table, size_t n, const wchar_t *cell_content, ...) int ft_nwwrite(ft_table_t *table, size_t n, const wchar_t *cell_content, ...)
@ -577,209 +597,111 @@ int ft_table_wwrite_ln(ft_table_t *table, size_t rows, size_t cols, const wchar_
} }
#endif #endif
static
const char * empty_str_arr[] = {"", (const char *)L"", ""};
static
const char *ft_to_string_impl(const ft_table_t *table, enum str_buf_type b_type)
{
assert(table);
const char *result = NULL;
/* Determing size of table string representation */
size_t cod_height = 0;
size_t cod_width = 0;
int status = table_internal_codepoints_geometry(table, &cod_height, &cod_width);
if (FT_IS_ERROR(status)) {
return NULL;
}
size_t n_codepoints = cod_height * cod_width + 1;
/* Allocate string buffer for string representation */
if (table->conv_buffer == NULL) {
((ft_table_t *)table)->conv_buffer = create_string_buffer(n_codepoints, b_type);
if (table->conv_buffer == NULL)
return NULL;
}
while (string_buffer_cod_width_capacity(table->conv_buffer) < n_codepoints) {
if (FT_IS_ERROR(realloc_string_buffer_without_copy(table->conv_buffer))) {
return NULL;
}
}
char *buffer = (char *)buffer_get_data(table->conv_buffer);
size_t cols = 0;
size_t rows = 0;
size_t *col_vis_width_arr = NULL;
size_t *row_vis_height_arr = NULL;
status = table_rows_and_cols_geometry(table, &col_vis_width_arr, &cols, &row_vis_height_arr, &rows, VISIBLE_GEOMETRY);
if (FT_IS_ERROR(status))
return NULL;
if (rows == 0) {
result = empty_str_arr[b_type];
goto clear;
}
int tmp = 0;
size_t i = 0;
context_t context;
context.table_properties = (table->properties ? table->properties : &g_table_properties);
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);
conv_context_t cntx;
cntx.buf_origin = buffer;
cntx.buf = buffer;
cntx.raw_avail = string_buffer_raw_capacity(table->conv_buffer);
cntx.cntx = &context;
cntx.b_type = b_type;
/* Print top margin */
for (i = 0; i < context.table_properties->entire_table_properties.top_margin; ++i) {
FT_CHECK(print_n_strings(&cntx, cod_width - 1/* minus new_line*/, FT_SPACE));
FT_CHECK(print_n_strings(&cntx, 1, FT_NEWLINE));
}
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;
FT_CHECK(print_row_separator(&cntx, col_vis_width_arr, cols, prev_row, cur_row, separatorPos, cur_sep));
FT_CHECK(snprintf_row(cur_row, &cntx, col_vis_width_arr, cols, row_vis_height_arr[i]));
prev_row = cur_row;
}
cur_row = NULL;
cur_sep = (i < sep_size) ? (*(separator_t **)vector_at(table->separators, i)) : NULL;
context.row = i;
FT_CHECK(print_row_separator(&cntx, col_vis_width_arr, cols, prev_row, cur_row, BottomSeparator, cur_sep));
/* Print bottom margin */
for (i = 0; i < context.table_properties->entire_table_properties.bottom_margin; ++i) {
FT_CHECK(print_n_strings(&cntx, cod_width - 1/* minus new_line*/, FT_SPACE));
FT_CHECK(print_n_strings(&cntx, 1, FT_NEWLINE));
}
result = buffer;
clear:
F_FREE(col_vis_width_arr);
F_FREE(row_vis_height_arr);
return result;
}
const char *ft_to_string(const ft_table_t *table) const char *ft_to_string(const ft_table_t *table)
{ {
typedef char char_type; return ft_to_string_impl(table, CHAR_BUF);
const enum str_buf_type buf_type = CharBuf;
const char *space_char = " ";
const char *new_line_char = "\n";
#define EMPTY_STRING ""
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;
int (*snprint_n_strings_)(char *, size_t, size_t, const char *) = snprint_n_strings;
assert(table);
/* Determing size of table string representation */
size_t height = 0;
size_t width = 0;
int status = table_geometry(table, &height, &width);
if (FT_IS_ERROR(status)) {
return NULL;
} }
size_t sz = height * width + 1;
/* Allocate string buffer for string representation */
if (table->conv_buffer == NULL) {
((ft_table_t *)table)->conv_buffer = create_string_buffer(sz, buf_type);
if (table->conv_buffer == NULL)
return NULL;
}
while (string_buffer_capacity(table->conv_buffer) < sz) {
if (FT_IS_ERROR(realloc_string_buffer_without_copy(table->conv_buffer))) {
return NULL;
}
}
char_type *buffer = (char_type *)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, VISIBLE_GEOMETRY);
if (FT_IS_ERROR(status))
return NULL;
if (rows == 0)
return EMPTY_STRING;
size_t written = 0;
int tmp = 0;
size_t i = 0;
context_t context;
context.table_properties = (table->properties ? table->properties : &g_table_properties);
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);
/* Print top margin */
for (i = 0; i < context.table_properties->entire_table_properties.top_margin; ++i) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, width - 1/* minus new_line*/, space_char));
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, 1, new_line_char));
}
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;
CHCK_RSLT_ADD_TO_WRITTEN(print_row_separator_(buffer + written, sz - written, col_width_arr, cols, prev_row, cur_row, separatorPos, cur_sep, &context));
CHCK_RSLT_ADD_TO_WRITTEN(snprintf_row_(cur_row, buffer + written, sz - written, 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;
context.row = i;
CHCK_RSLT_ADD_TO_WRITTEN(print_row_separator_(buffer + written, sz - written, col_width_arr, cols, prev_row, cur_row, BottomSeparator, cur_sep, &context));
/* Print bottom margin */
for (i = 0; i < context.table_properties->entire_table_properties.bottom_margin; ++i) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, width - 1/* minus new_line*/, space_char));
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, 1, new_line_char));
}
F_FREE(col_width_arr);
F_FREE(row_height_arr);
return buffer;
clear:
F_FREE(col_width_arr);
F_FREE(row_height_arr);
return NULL;
#undef EMPTY_STRING
}
#ifdef FT_HAVE_WCHAR #ifdef FT_HAVE_WCHAR
const wchar_t *ft_to_wstring(const ft_table_t *table) const wchar_t *ft_to_wstring(const ft_table_t *table)
{ {
typedef wchar_t char_type; return (const wchar_t *)ft_to_string_impl(table, W_CHAR_BUF);
const enum str_buf_type buf_type = WCharBuf;
const char *space_char = " ";
const char *new_line_char = "\n";
#define EMPTY_STRING L""
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;
int (*snprint_n_strings_)(wchar_t *, size_t, size_t, const char *) = wsnprint_n_string;
assert(table);
/* Determing size of table string representation */
size_t height = 0;
size_t width = 0;
int status = table_geometry(table, &height, &width);
if (FT_IS_ERROR(status)) {
return NULL;
} }
size_t sz = height * width + 1;
/* Allocate string buffer for string representation */
if (table->conv_buffer == NULL) {
((ft_table_t *)table)->conv_buffer = create_string_buffer(sz, buf_type);
if (table->conv_buffer == NULL)
return NULL;
}
while (string_buffer_capacity(table->conv_buffer) < sz) {
if (FT_IS_ERROR(realloc_string_buffer_without_copy(table->conv_buffer))) {
return NULL;
}
}
char_type *buffer = (char_type *)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, VISIBLE_GEOMETRY);
if (rows == 0)
return EMPTY_STRING;
if (FT_IS_ERROR(status))
return NULL;
size_t written = 0;
int tmp = 0;
size_t i = 0;
context_t context;
context.table_properties = (table->properties ? table->properties : &g_table_properties);
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);
/* Print top margin */
for (i = 0; i < context.table_properties->entire_table_properties.top_margin; ++i) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, width - 1/* minus new_line*/, space_char));
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, 1, new_line_char));
}
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;
CHCK_RSLT_ADD_TO_WRITTEN(print_row_separator_(buffer + written, sz - written, col_width_arr, cols, prev_row, cur_row, separatorPos, cur_sep, &context));
CHCK_RSLT_ADD_TO_WRITTEN(snprintf_row_(cur_row, buffer + written, sz - written, 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;
context.row = i;
CHCK_RSLT_ADD_TO_WRITTEN(print_row_separator_(buffer + written, sz - written, col_width_arr, cols, prev_row, cur_row, BottomSeparator, cur_sep, &context));
/* Print bottom margin */
for (i = 0; i < context.table_properties->entire_table_properties.bottom_margin; ++i) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, width - 1/* minus new_line*/, space_char));
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, 1, new_line_char));
}
F_FREE(col_width_arr);
F_FREE(row_height_arr);
return buffer;
clear:
F_FREE(col_width_arr);
F_FREE(row_height_arr);
return NULL;
#undef EMPTY_STRING
}
#endif #endif
@ -999,3 +921,61 @@ int ft_set_cell_span(ft_table_t *table, size_t row, size_t col, size_t hor_span)
return row_set_cell_span(row_p, col, hor_span); return row_set_cell_span(row_p, col, hor_span);
} }
#ifdef FT_HAVE_UTF8
int ft_nu8write(ft_table_t *table, size_t n, const void *cell_content, ...)
{
size_t i = 0;
assert(table);
int status = ft_u8write_impl(table, cell_content);
if (FT_IS_ERROR(status))
return status;
va_list va;
va_start(va, cell_content);
--n;
for (i = 0; i < n; ++i) {
const void *cell = va_arg(va, const void *);
status = ft_u8write_impl(table, cell);
if (FT_IS_ERROR(status)) {
va_end(va);
return status;
}
}
va_end(va);
ft_ln(table);
return status;
}
int ft_nu8write_ln(ft_table_t *table, size_t n, const void *cell_content, ...)
{
size_t i = 0;
assert(table);
int status = ft_u8write_impl(table, cell_content);
if (FT_IS_ERROR(status))
return status;
va_list va;
va_start(va, cell_content);
--n;
for (i = 0; i < n; ++i) {
const void *cell = va_arg(va, const void *);
status = ft_u8write_impl(table, cell);
if (FT_IS_ERROR(status)) {
va_end(va);
return status;
}
}
va_end(va);
ft_ln(table);
return status;
}
const void *ft_to_u8string(const ft_table_t *table)
{
return (const void *)ft_to_string_impl(table, UTF8_BUF);
}
#endif /* FT_HAVE_UTF8 */

View File

@ -2,6 +2,9 @@
#ifdef FT_HAVE_WCHAR #ifdef FT_HAVE_WCHAR
#include <wchar.h> #include <wchar.h>
#endif #endif
#if defined(FT_HAVE_UTF8)
#include "utf8.h"
#endif
char g_col_separator = FORT_DEFAULT_COL_SEPARATOR; char g_col_separator = FORT_DEFAULT_COL_SEPARATOR;
@ -169,9 +172,26 @@ size_t number_of_columns_in_format_wstring(const wchar_t *fmt)
} }
#endif #endif
#if defined(FT_HAVE_UTF8)
FT_INTERNAL FT_INTERNAL
int snprint_n_strings(char *buf, size_t length, size_t n, const char *str) size_t number_of_columns_in_format_u8string(const void *fmt)
{
size_t separator_counter = 0;
const char *pos = fmt;
while (1) {
pos = utf8chr(pos, g_col_separator);
if (pos == NULL)
break;
separator_counter++;
++pos;
}
return separator_counter + 1;
}
#endif
static
int snprint_n_strings_impl(char *buf, size_t length, size_t n, const char *str)
{ {
size_t str_len = strlen(str); size_t str_len = strlen(str);
if (length <= n * str_len) if (length <= n * str_len)
@ -200,17 +220,123 @@ int snprint_n_strings(char *buf, size_t length, size_t n, const char *str)
return (int)(n * str_len); return (int)(n * str_len);
} }
static
int snprint_n_strings(conv_context_t *cntx, size_t n, const char *str)
{
int w = snprint_n_strings_impl(cntx->buf, cntx->raw_avail, n, str);
if (w >= 0) {
cntx->buf += w;
cntx->raw_avail -= w;
}
return w;
}
#if defined(FT_HAVE_WCHAR)
static
int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *str);
#endif
#if defined(FT_HAVE_UTF8)
static
int u8nprint_n_strings(void *buf, size_t length, size_t n, const void *str);
#endif
FT_INTERNAL
int print_n_strings(conv_context_t *cntx, size_t n, const char *str)
{
int cod_w;
int raw_written;
switch (cntx->b_type) {
case CHAR_BUF:
return snprint_n_strings(cntx, n, str);
#ifdef FT_HAVE_WCHAR
case W_CHAR_BUF:
cod_w = wsnprint_n_string((wchar_t *)cntx->buf, cntx->raw_avail, n, str);
if (cod_w < 0)
return cod_w;
raw_written = sizeof(wchar_t) * cod_w;
cntx->buf += raw_written;
cntx->raw_avail -= raw_written;
return cod_w;
#endif /* FT_HAVE_WCHAR */
#ifdef FT_HAVE_UTF8
case UTF8_BUF:
/* Everying is very strange and differs with W_CHAR_BUF */
raw_written = u8nprint_n_strings(cntx->buf, cntx->raw_avail, n, str);
if (raw_written < 0) {
fprintf(stderr, " raw_written = %d\n", raw_written);
return raw_written;
}
cntx->buf += raw_written;
cntx->raw_avail -= raw_written;
return utf8len(str) * n;
#endif /* FT_HAVE_UTF8 */
default:
assert(0);
return -1;
}
}
FT_INTERNAL
int ft_nprint(conv_context_t *cntx, const char *str, size_t strlen)
{
if (cntx->raw_avail + 1/* for 0 */ < strlen)
return -1;
memcpy(cntx->buf, str, strlen);
cntx->buf += strlen;
cntx->raw_avail -= strlen;
*cntx->buf = '\0'; /* Do we need this ? */
return strlen;
}
#ifdef FT_HAVE_WCHAR
int ft_nwprint(conv_context_t *cntx, const wchar_t *str, size_t strlen)
{
if (cntx->raw_avail + 1/* for 0 */ < strlen)
return -1;
size_t raw_len = strlen * sizeof(wchar_t);
memcpy(cntx->buf, str, raw_len);
cntx->buf += raw_len;
cntx->raw_avail -= raw_len;
*(wchar_t *)cntx->buf = L'\0'; /* Do we need this ? */
return strlen;
}
#endif /* FT_HAVE_WCHAR */
#ifdef FT_HAVE_UTF8
FT_INTERNAL
int ft_nu8print(conv_context_t *cntx, const void *beg, const void *end)
{
const char *bc = beg;
const char *ec = end;
size_t raw_len = ec - bc;
if (cntx->raw_avail + 1 < raw_len)
return -1;
memcpy(cntx->buf, beg, raw_len);
cntx->buf += raw_len;
cntx->raw_avail -= raw_len;
*(char *)cntx->buf = '\0'; /* Do we need this ? */
return raw_len; /* what return here ? */
}
#endif /* FT_HAVE_UTF8 */
#if defined(FT_HAVE_WCHAR) #if defined(FT_HAVE_WCHAR)
#define WCS_SIZE 64 #define WCS_SIZE 64
FT_INTERNAL static
int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *str) int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *str)
{ {
size_t str_len = strlen(str); size_t str_len = strlen(str);
/* note: baybe it's, better to return -1 in case of multibyte character /* note: maybe it's, better to return -1 in case of multibyte character
* strings (not sure this case is done correctly). * strings (not sure this case is done correctly).
*/ */
if (str_len > 1) { if (str_len > 1) {
@ -269,3 +395,33 @@ int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *str)
return (int)(n * str_len); return (int)(n * str_len);
} }
#endif #endif
#if defined(FT_HAVE_UTF8)
static
int u8nprint_n_strings(void *buf, size_t length, size_t n, const void *str)
{
size_t str_size = utf8size(str) - 1; /* str_size - raw size in bytes, excluding \0 */
if (length <= n * str_size)
return -1;
if (n == 0)
return 0;
/* To ensure valid return value it is safely not print such big strings */
if (n * str_size > INT_MAX)
return -1;
if (str_size == 0)
return 0;
size_t i = n;
while (i) {
memcpy(buf, str, str_size);
buf = (char *)buf + str_size;
--i;
}
*(char *)buf = '\0';
return (int)(n * str_size);
}
#endif

View File

@ -35,12 +35,16 @@ extern char g_col_separator;
#define F_REALLOC fort_realloc #define F_REALLOC fort_realloc
#define F_STRDUP fort_strdup #define F_STRDUP fort_strdup
#define F_WCSDUP fort_wcsdup #define F_WCSDUP fort_wcsdup
/* @todo: replace with custom impl !!!*/
#define F_UTF8DUP utf8dup
#define F_CREATE(type) ((type *)F_CALLOC(sizeof(type), 1)) #define F_CREATE(type) ((type *)F_CALLOC(sizeof(type), 1))
#define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MIN(a,b) ((a) < (b) ? (a) : (b))
#define FT_NEWLINE "\n"
#define FT_SPACE " "
enum PolicyOnNull { enum PolicyOnNull {
Create, Create,
@ -53,6 +57,20 @@ enum F_BOOL {
F_TRUE = 1 F_TRUE = 1
}; };
enum str_buf_type {
CHAR_BUF,
#ifdef FT_HAVE_WCHAR
W_CHAR_BUF,
#endif /* FT_HAVE_WCHAR */
#ifdef FT_HAVE_UTF8
UTF8_BUF,
#endif /* FT_HAVE_WCHAR */
TYPE_END
};
typedef const char ** str_arr;
#define FT_STR_2_CAT_(arg1, arg2) \ #define FT_STR_2_CAT_(arg1, arg2) \
arg1##arg2 arg1##arg2
@ -117,6 +135,16 @@ enum request_geom_type {
INTERN_REPR_GEOMETRY INTERN_REPR_GEOMETRY
}; };
struct conv_context {
char *buf_origin;
char *buf;
size_t raw_avail;
struct fort_context *cntx;
enum str_buf_type b_type;
};
typedef struct conv_context conv_context_t;
/***************************************************************************** /*****************************************************************************
* LIBFORT helpers * LIBFORT helpers
*****************************************************************************/ *****************************************************************************/
@ -144,18 +172,38 @@ size_t number_of_columns_in_format_wstring(const wchar_t *fmt);
#endif #endif
FT_INTERNAL FT_INTERNAL
int snprint_n_strings(char *buf, size_t length, size_t n, const char *str); int print_n_strings(conv_context_t *cntx, size_t n, const char *str);
#if defined(FT_HAVE_WCHAR)
FT_INTERNAL FT_INTERNAL
int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *str); int ft_nprint(conv_context_t *cntx, const char *str, size_t strlen);
#endif #ifdef FT_HAVE_WCHAR
FT_INTERNAL
int ft_nwprint(conv_context_t *cntx, const wchar_t *str, size_t strlen);
#endif /* FT_HAVE_WCHAR */
#ifdef FT_HAVE_UTF8
FT_INTERNAL
int ft_nu8print(conv_context_t *cntx, const void *beg, const void *end);
#endif /* FT_HAVE_UTF8 */
/*#define PRINT_DEBUG_INFO fprintf(stderr, "error in %s(%s:%d)\n", __FUNCTION__, __FILE__, __LINE__);*/
#define PRINT_DEBUG_INFO
#define FT_CHECK(statement) \
do { \
tmp = statement; \
if (tmp < 0) {\
PRINT_DEBUG_INFO \
goto clear; \
} \
} while(0)
#define CHCK_RSLT_ADD_TO_WRITTEN(statement) \ #define CHCK_RSLT_ADD_TO_WRITTEN(statement) \
do { \ do { \
tmp = statement; \ tmp = statement; \
if (tmp < 0) {\ if (tmp < 0) {\
PRINT_DEBUG_INFO \
goto clear; \ goto clear; \
} \ } \
written += (size_t)tmp; \ written += (size_t)tmp; \
@ -165,6 +213,7 @@ int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *str);
do { \ do { \
tmp = statement; \ tmp = statement; \
if (tmp < 0) {\ if (tmp < 0) {\
PRINT_DEBUG_INFO \
goto clear; \ goto clear; \
} \ } \
invisible_written += (size_t)tmp; \ invisible_written += (size_t)tmp; \

353
src/row.c
View File

@ -225,22 +225,20 @@ fort_status_t row_set_cell_span(fort_row_t *row, size_t cell_column, size_t hor_
return FT_SUCCESS; return FT_SUCCESS;
} }
FT_INTERNAL FT_INTERNAL
int print_row_separator(char *buffer, size_t buffer_sz, int print_row_separator_impl(conv_context_t *cntx,
const size_t *col_width_arr, size_t cols, const size_t *col_width_arr, size_t cols,
const fort_row_t *upper_row, const fort_row_t *lower_row, const fort_row_t *upper_row, const fort_row_t *lower_row,
enum HorSeparatorPos separatorPos, enum HorSeparatorPos separatorPos,
const separator_t *sep, const context_t *context) const separator_t *sep)
{ {
int (*snprint_n_strings_)(char *, size_t, size_t, const char *) = snprint_n_strings; assert(cntx);
assert(buffer);
assert(context);
const char *space_char = " "; const char *space_char = " ";
int status = -1; int status = -1;
const context_t *context = cntx->cntx;
/* Get cell types /* Get cell types
* *
* Regions above top row and below bottom row areconsidered full of virtual * Regions above top row and below bottom row areconsidered full of virtual
@ -378,31 +376,31 @@ int print_row_separator(char *buffer, size_t buffer_sz,
} }
/* Print left margin */ /* Print left margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, context->table_properties->entire_table_properties.left_margin, space_char)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, context->table_properties->entire_table_properties.left_margin, space_char));
for (i = 0; i < cols; ++i) { for (i = 0; i < cols; ++i) {
if (i == 0) { if (i == 0) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *L)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *L));
} else { } else {
if ((top_row_types[i] == CommonCell || top_row_types[i] == GroupMasterCell) if ((top_row_types[i] == CommonCell || top_row_types[i] == GroupMasterCell)
&& (bottom_row_types[i] == CommonCell || bottom_row_types[i] == GroupMasterCell)) { && (bottom_row_types[i] == CommonCell || bottom_row_types[i] == GroupMasterCell)) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *IV)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *IV));
} else if (top_row_types[i] == GroupSlaveCell && bottom_row_types[i] == GroupSlaveCell) { } else if (top_row_types[i] == GroupSlaveCell && bottom_row_types[i] == GroupSlaveCell) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *II)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *II));
} else if (top_row_types[i] == GroupSlaveCell) { } else if (top_row_types[i] == GroupSlaveCell) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *IT)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *IT));
} else { } else {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *IB)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *IB));
} }
} }
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, col_width_arr[i], *I)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, col_width_arr[i], *I));
} }
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *R)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *R));
/* Print right margin */ /* Print right margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, context->table_properties->entire_table_properties.right_margin, space_char)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, context->table_properties->entire_table_properties.right_margin, space_char));
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, "\n")); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, "\n"));
status = (int)written; status = (int)written;
@ -411,194 +409,15 @@ clear:
return status; return status;
} }
#ifdef FT_HAVE_WCHAR
FT_INTERNAL FT_INTERNAL
int wprint_row_separator(wchar_t *buffer, size_t buffer_sz, int print_row_separator(conv_context_t *cntx,
const size_t *col_width_arr, size_t cols, const size_t *col_width_arr, size_t cols,
const fort_row_t *upper_row, const fort_row_t *lower_row, const fort_row_t *upper_row, const fort_row_t *lower_row,
enum HorSeparatorPos separatorPos, const separator_t *sep, enum HorSeparatorPos separatorPos, const separator_t *sep)
const context_t *context)
{ {
int (*snprint_n_strings_)(wchar_t *, size_t, size_t, const char *) = wsnprint_n_string; return print_row_separator_impl(cntx, col_width_arr, cols, upper_row, lower_row,
separatorPos, sep);
assert(buffer);
assert(context);
const char *space_char = " ";
int status = -1;
/* Get cell types
*
* Regions above top row and below bottom row areconsidered full of virtual
* GroupSlaveCell cells
*/
enum CellType *top_row_types = (enum CellType *)F_MALLOC(sizeof(enum CellType) * cols * 2);
if (top_row_types == NULL) {
return FT_MEMORY_ERROR;
} }
enum CellType *bottom_row_types = top_row_types + cols;
if (upper_row) {
get_row_cell_types(upper_row, top_row_types, cols);
} else {
size_t i = 0;
for (i = 0; i < cols; ++i)
top_row_types[i] = GroupSlaveCell;
}
if (lower_row) {
get_row_cell_types(lower_row, bottom_row_types, cols);
} else {
size_t i = 0;
for (i = 0; i < cols; ++i)
bottom_row_types[i] = GroupSlaveCell;
}
size_t written = 0;
int tmp = 0;
enum ft_row_type lower_row_type = FT_ROW_COMMON;
if (lower_row != NULL) {
lower_row_type = (enum ft_row_type)get_cell_property_value_hierarcial(context->table_properties, context->row, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE);
}
enum ft_row_type upper_row_type = FT_ROW_COMMON;
if (upper_row != NULL) {
upper_row_type = (enum ft_row_type)get_cell_property_value_hierarcial(context->table_properties, context->row - 1, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE);
}
/* Row separator anatomy
*
* | C11 | C12 C13 | C14 C15 |
* L I I I IV I I IT I I I IB I I II I I R
* | C21 | C22 | C23 C24 C25 |
*/
const char **L = NULL;
const char **I = NULL;
const char **IV = NULL;
const char **R = NULL;
const char **IT = NULL;
const char **IB = NULL;
const char **II = NULL;
typedef const char *(*border_chars_point_t)[BorderItemPosSize];
const char *(*border_chars)[BorderItemPosSize] = NULL;
border_chars = (border_chars_point_t)&context->table_properties->border_style.border_chars;
if (upper_row_type == FT_ROW_HEADER || lower_row_type == FT_ROW_HEADER) {
border_chars = (border_chars_point_t)&context->table_properties->border_style.header_border_chars;
}
if (sep && sep->enabled) {
L = &(context->table_properties->border_style.separator_chars[LH_sip]);
I = &(context->table_properties->border_style.separator_chars[IH_sip]);
IV = &(context->table_properties->border_style.separator_chars[II_sip]);
R = &(context->table_properties->border_style.separator_chars[RH_sip]);
IT = &(context->table_properties->border_style.separator_chars[TI_sip]);
IB = &(context->table_properties->border_style.separator_chars[BI_sip]);
II = &(context->table_properties->border_style.separator_chars[IH_sip]);
if (lower_row == NULL) {
L = &(*border_chars)[BL_bip];
R = &(*border_chars)[BR_bip];
} else if (upper_row == NULL) {
L = &(*border_chars)[TL_bip];
R = &(*border_chars)[TR_bip];
}
} 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];
IT = &(*border_chars)[TV_bip];
IB = &(*border_chars)[TV_bip];
II = &(*border_chars)[TT_bip];
break;
case InsideSeparator:
L = &(*border_chars)[LH_bip];
I = &(*border_chars)[IH_bip];
IV = &(*border_chars)[II_bip];
R = &(*border_chars)[RH_bip];
/*
IT = &(*border_chars)[TV_bip];
IB = &(*border_chars)[BV_bip];
*/
IT = &(*border_chars)[TI_bip];
IB = &(*border_chars)[BI_bip];
II = &(*border_chars)[IH_bip];
break;
case BottomSeparator:
L = &(*border_chars)[BL_bip];
I = &(*border_chars)[BB_bip];
IV = &(*border_chars)[BV_bip];
R = &(*border_chars)[BR_bip];
IT = &(*border_chars)[BV_bip];
IB = &(*border_chars)[BV_bip];
II = &(*border_chars)[BB_bip];
break;
default:
break;
}
}
size_t i = 0;
/* If all chars are not printable, skip line separator */
/* todo: add processing for wchar_t */
/*
if (!isprint(*L) && !isprint(*I) && !isprint(*IV) && !isprint(*R)) {
status = 0;
goto clear;
}
*/
if ((strlen(*L) == 0 || (strlen(*L) == 1 && !isprint(**L)))
&& (strlen(*I) == 0 || (strlen(*I) == 1 && !isprint(**I)))
&& (strlen(*IV) == 0 || (strlen(*IV) == 1 && !isprint(**IV)))
&& (strlen(*R) == 0 || (strlen(*R) == 1 && !isprint(**R)))) {
status = 0;
goto clear;
}
/* Print left margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, context->table_properties->entire_table_properties.left_margin, space_char));
for (i = 0; i < cols; ++i) {
if (i == 0) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *L));
} else {
if ((top_row_types[i] == CommonCell || top_row_types[i] == GroupMasterCell)
&& (bottom_row_types[i] == CommonCell || bottom_row_types[i] == GroupMasterCell)) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *IV));
} else if (top_row_types[i] == GroupSlaveCell && bottom_row_types[i] == GroupSlaveCell) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *II));
} else if (top_row_types[i] == GroupSlaveCell) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *IT));
} else {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *IB));
}
}
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, col_width_arr[i], *I));
}
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *R));
/* Print right margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, context->table_properties->entire_table_properties.right_margin, space_char));
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, "\n"));
status = (int)written;
clear:
F_FREE(top_row_types);
return status;
}
#endif
FT_INTERNAL FT_INTERNAL
fort_row_t *create_row_from_string(const char *str) fort_row_t *create_row_from_string(const char *str)
@ -784,7 +603,7 @@ fort_row_t *create_row_from_fmt_string(const char *fmt, va_list *va_args)
#define CREATE_ROW_FROM_STRING create_row_from_string #define CREATE_ROW_FROM_STRING create_row_from_string
#define NUMBER_OF_COLUMNS_IN_FORMAT_STRING number_of_columns_in_format_string #define NUMBER_OF_COLUMNS_IN_FORMAT_STRING number_of_columns_in_format_string
#define FILL_CELL_FROM_STRING fill_cell_from_string #define FILL_CELL_FROM_STRING fill_cell_from_string
#define STR_BUF_TYPE CharBuf #define STR_BUF_TYPE CHAR_BUF
string_buffer_t *buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, STR_BUF_TYPE); string_buffer_t *buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, STR_BUF_TYPE);
if (buffer == NULL) if (buffer == NULL)
@ -796,14 +615,14 @@ fort_row_t *create_row_from_fmt_string(const char *fmt, va_list *va_args)
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.STR_FILED, string_buffer_capacity(buffer), fmt, va); int virtual_sz = VSNPRINTF(buffer->str.STR_FILED, string_buffer_width_capacity(buffer), fmt, va);
va_end(va); va_end(va);
/* If error encountered */ /* If error encountered */
if (virtual_sz < 0) if (virtual_sz < 0)
goto clear; goto clear;
/* Successful write */ /* Successful write */
if ((size_t)virtual_sz < string_buffer_capacity(buffer)) if ((size_t)virtual_sz < string_buffer_width_capacity(buffer))
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. */
@ -870,7 +689,7 @@ fort_row_t *create_row_from_fmt_wstring(const wchar_t *fmt, va_list *va_args)
#define CREATE_ROW_FROM_STRING create_row_from_wstring #define CREATE_ROW_FROM_STRING create_row_from_wstring
#define NUMBER_OF_COLUMNS_IN_FORMAT_STRING number_of_columns_in_format_wstring #define NUMBER_OF_COLUMNS_IN_FORMAT_STRING number_of_columns_in_format_wstring
#define FILL_CELL_FROM_STRING fill_cell_from_wstring #define FILL_CELL_FROM_STRING fill_cell_from_wstring
#define STR_BUF_TYPE WCharBuf #define STR_BUF_TYPE W_CHAR_BUF
string_buffer_t *buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, STR_BUF_TYPE); string_buffer_t *buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, STR_BUF_TYPE);
if (buffer == NULL) if (buffer == NULL)
@ -882,14 +701,14 @@ fort_row_t *create_row_from_fmt_wstring(const wchar_t *fmt, va_list *va_args)
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.STR_FILED, string_buffer_capacity(buffer), fmt, va); int virtual_sz = VSNPRINTF(buffer->str.STR_FILED, string_buffer_width_capacity(buffer), fmt, va);
va_end(va); va_end(va);
/* If error encountered */ /* If error encountered */
if (virtual_sz < 0) if (virtual_sz < 0)
goto clear; goto clear;
/* Successful write */ /* Successful write */
if ((size_t)virtual_sz < string_buffer_capacity(buffer)) if ((size_t)virtual_sz < string_buffer_width_capacity(buffer))
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. */
@ -950,12 +769,10 @@ clear:
FT_INTERNAL FT_INTERNAL
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, conv_context_t *cntx, size_t *col_width_arr, size_t col_width_arr_sz,
size_t row_height, const context_t *context) size_t row_height)
{ {
int (*snprint_n_strings_)(char *, size_t, size_t, const char *) = snprint_n_strings; const context_t *context = cntx->cntx;
int (*cell_printf_)(fort_cell_t *, size_t, char *, size_t, const context_t *) = cell_printf;
assert(context); assert(context);
const char *space_char = " "; const char *space_char = " ";
const char *new_line_char = "\n"; const char *new_line_char = "\n";
@ -987,142 +804,50 @@ int snprintf_row(const fort_row_t *row, char *buffer, size_t buf_sz, size_t *col
size_t i = 0; size_t i = 0;
for (i = 0; i < row_height; ++i) { for (i = 0; i < row_height; ++i) {
/* Print left margin */ /* Print left margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, context->table_properties->entire_table_properties.left_margin, space_char)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, context->table_properties->entire_table_properties.left_margin, space_char));
/* Print left table boundary */ /* Print left table boundary */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, *L)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *L));
size_t j = 0; size_t j = 0;
while (j < col_width_arr_sz) { while (j < col_width_arr_sz) {
if (j < cols_in_row) { if (j < cols_in_row) {
((context_t *)context)->column = j; ((context_t *)context)->column = j;
fort_cell_t *cell = *(fort_cell_t **)vector_at(row->cells, j); fort_cell_t *cell = *(fort_cell_t **)vector_at(row->cells, j);
size_t cell_width = 0; size_t cell_vis_width = 0;
size_t group_slave_sz = group_cell_number(row, j); size_t group_slave_sz = group_cell_number(row, j);
cell_width = col_width_arr[j]; cell_vis_width = col_width_arr[j];
size_t slave_j = 0; size_t slave_j = 0;
size_t master_j = j; size_t master_j = j;
for (slave_j = master_j + 1; slave_j < (master_j + group_slave_sz); ++slave_j) { for (slave_j = master_j + 1; slave_j < (master_j + group_slave_sz); ++slave_j) {
cell_width += col_width_arr[slave_j] + FORT_COL_SEPARATOR_LENGTH; cell_vis_width += col_width_arr[slave_j] + FORT_COL_SEPARATOR_LENGTH;
++j; ++j;
} }
CHCK_RSLT_ADD_TO_WRITTEN(cell_printf_(cell, i, buffer + written, cell_width + 1, context)); CHCK_RSLT_ADD_TO_WRITTEN(cell_printf(cell, i, cntx, cell_vis_width));
} else { } else {
/* Print empty cell */ /* Print empty cell */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, col_width_arr[j], space_char)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, col_width_arr[j], space_char));
} }
/* Print boundary between cells */ /* Print boundary between cells */
if (j < col_width_arr_sz - 1) if (j < col_width_arr_sz - 1)
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, *IV)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *IV));
++j; ++j;
} }
/* Print right table boundary */ /* Print right table boundary */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, *R)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *R));
/* Print right margin */ /* Print right margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, context->table_properties->entire_table_properties.right_margin, space_char)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, context->table_properties->entire_table_properties.right_margin, space_char));
/* Print new line character */ /* Print new line character */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, new_line_char)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, new_line_char));
} }
return (int)written; return (int)written;
clear: clear:
return -1; return -1;
} }
#ifdef FT_HAVE_WCHAR
FT_INTERNAL
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)
{
int (*snprint_n_strings_)(wchar_t *, size_t, size_t, const char *) = wsnprint_n_string;
int (*cell_printf_)(fort_cell_t *, size_t, wchar_t *, size_t, const context_t *) = cell_wprintf;
assert(context);
const char *space_char = " ";
const char *new_line_char = "\n";
if (row == NULL)
return -1;
size_t 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
*/
typedef const char *(*border_chars_point_t)[BorderItemPosSize];
enum ft_row_type row_type = (enum ft_row_type)get_cell_property_value_hierarcial(context->table_properties, context->row, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE);
const char *(*bord_chars)[BorderItemPosSize] = (row_type == FT_ROW_HEADER)
? (border_chars_point_t)(&context->table_properties->border_style.header_border_chars)
: (border_chars_point_t)(&context->table_properties->border_style.border_chars);
const char **L = &(*bord_chars)[LL_bip];
const char **IV = &(*bord_chars)[IV_bip];
const char **R = &(*bord_chars)[RR_bip];
size_t written = 0;
int tmp = 0;
size_t i = 0;
for (i = 0; i < row_height; ++i) {
/* Print left margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, context->table_properties->entire_table_properties.left_margin, space_char));
/* Print left table boundary */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, *L));
size_t j = 0;
while (j < col_width_arr_sz) {
if (j < cols_in_row) {
((context_t *)context)->column = j;
fort_cell_t *cell = *(fort_cell_t **)vector_at(row->cells, j);
size_t cell_width = 0;
size_t group_slave_sz = group_cell_number(row, j);
cell_width = col_width_arr[j];
size_t slave_j = 0;
size_t master_j = j;
for (slave_j = master_j + 1; slave_j < (master_j + group_slave_sz); ++slave_j) {
cell_width += col_width_arr[slave_j] + FORT_COL_SEPARATOR_LENGTH;
++j;
}
CHCK_RSLT_ADD_TO_WRITTEN(cell_printf_(cell, i, buffer + written, cell_width + 1, context));
} else {
/* Print empty cell */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, col_width_arr[j], space_char));
}
/* Print boundary between cells */
if (j < col_width_arr_sz - 1)
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, *IV));
++j;
}
/* Print right table boundary */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, *R));
/* Print right margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, context->table_properties->entire_table_properties.right_margin, space_char));
/* Print new line character */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, new_line_char));
}
return (int)written;
clear:
return -1;
}
#endif

View File

@ -50,15 +50,14 @@ FT_INTERNAL
fort_status_t row_set_cell_span(fort_row_t *row, size_t cell_column, size_t hor_span); fort_status_t row_set_cell_span(fort_row_t *row, size_t cell_column, size_t hor_span);
FT_INTERNAL FT_INTERNAL
int print_row_separator(char *buffer, size_t buffer_sz, int print_row_separator(conv_context_t *cntx,
const size_t *col_width_arr, size_t cols, const size_t *col_width_arr, size_t cols,
const fort_row_t *upper_row, const fort_row_t *lower_row, const fort_row_t *upper_row, const fort_row_t *lower_row,
enum HorSeparatorPos separatorPos, const separator_t *sep, enum HorSeparatorPos separatorPos, const separator_t *sep);
const context_t *context);
FT_INTERNAL FT_INTERNAL
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, conv_context_t *cntx, size_t *col_width_arr, size_t col_width_arr_sz,
size_t row_height, const context_t *context); size_t row_height);
#ifdef FT_HAVE_WCHAR #ifdef FT_HAVE_WCHAR
FT_INTERNAL FT_INTERNAL
@ -66,17 +65,6 @@ fort_row_t *create_row_from_wstring(const wchar_t *str);
FT_INTERNAL FT_INTERNAL
fort_row_t *create_row_from_fmt_wstring(const wchar_t *fmt, va_list *va_args); fort_row_t *create_row_from_fmt_wstring(const wchar_t *fmt, va_list *va_args);
FT_INTERNAL
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);
FT_INTERNAL
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

View File

@ -3,8 +3,12 @@
#include "wcwidth.h" #include "wcwidth.h"
#include <assert.h> #include <assert.h>
#include <stddef.h> #include <stddef.h>
#ifdef FT_HAVE_WCHAR
#include <wchar.h> #include <wchar.h>
#endif
#if defined(FT_HAVE_UTF8)
#include "utf8.h"
#endif
static ptrdiff_t str_iter_width(const char *beg, const char *end) static ptrdiff_t str_iter_width(const char *beg, const char *end)
{ {
@ -25,11 +29,22 @@ static ptrdiff_t wcs_iter_width(const wchar_t *beg, const wchar_t *end)
static size_t buf_str_len(const string_buffer_t *buf) static size_t buf_str_len(const string_buffer_t *buf)
{ {
assert(buf); assert(buf);
if (buf->type == CharBuf) {
switch (buf->type) {
case CHAR_BUF:
return strlen(buf->str.cstr); return strlen(buf->str.cstr);
} else { #ifdef FT_HAVE_WCHAR
case W_CHAR_BUF:
return wcslen(buf->str.wstr); return wcslen(buf->str.wstr);
#endif
#ifdef FT_HAVE_UTF8
case UTF8_BUF:
return utf8len(buf->str.u8str);
#endif
} }
assert(0);
return 0;
} }
@ -49,7 +64,7 @@ size_t strchr_count(const char *str, char ch)
return count; return count;
} }
#ifdef FT_HAVE_WCHAR
FT_INTERNAL FT_INTERNAL
size_t wstrchr_count(const wchar_t *str, wchar_t ch) size_t wstrchr_count(const wchar_t *str, wchar_t ch)
{ {
@ -65,6 +80,34 @@ size_t wstrchr_count(const wchar_t *str, wchar_t ch)
} }
return count; return count;
} }
#endif
#if defined(FT_HAVE_UTF8)
/* todo: do something with code below!!! */
FT_INTERNAL
void *ut8next(const void *str)
{
utf8_int32_t out_codepoint;
return utf8codepoint(str, &out_codepoint);
}
FT_INTERNAL
size_t utf8chr_count(const void *str, utf8_int32_t ch)
{
if (str == NULL)
return 0;
size_t count = 0;
str = utf8chr(str, ch);
while (str) {
count++;
str = ut8next(str);
str = utf8chr(str, ch);
}
return count;
}
#endif /* FT_HAVE_UTF8 */
FT_INTERNAL FT_INTERNAL
@ -112,6 +155,29 @@ const wchar_t *wstr_n_substring_beg(const wchar_t *str, wchar_t ch_separator, si
} }
#endif /* FT_HAVE_WCHAR */ #endif /* FT_HAVE_WCHAR */
#if defined(FT_HAVE_UTF8)
FT_INTERNAL
const void *utf8_n_substring_beg(const void *str, utf8_int32_t ch_separator, size_t n)
{
if (str == NULL)
return NULL;
if (n == 0)
return str;
str = utf8chr(str, ch_separator);
--n;
while (n > 0) {
if (str == NULL)
return NULL;
--n;
str = ut8next(str);
str = utf8chr(str, ch_separator);
}
return str ? (ut8next(str)) : NULL;
}
#endif
FT_INTERNAL FT_INTERNAL
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)
@ -156,11 +222,34 @@ void wstr_n_substring(const wchar_t *str, wchar_t ch_separator, size_t n, const
} }
#endif /* FT_HAVE_WCHAR */ #endif /* FT_HAVE_WCHAR */
#if defined(FT_HAVE_UTF8)
FT_INTERNAL
void utf8_n_substring(const void *str, utf8_int32_t ch_separator, size_t n, const void **begin, const void **end)
{
const char *beg = utf8_n_substring_beg(str, ch_separator, n);
if (beg == NULL) {
*begin = NULL;
*end = NULL;
return;
}
const char *en = utf8chr(beg, ch_separator);
if (en == NULL) {
en = (const char *)str + strlen(str);
}
*begin = beg;
*end = en;
return;
}
#endif /* FT_HAVE_UTF8 */
FT_INTERNAL FT_INTERNAL
string_buffer_t *create_string_buffer(size_t number_of_chars, enum str_buf_type type) 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)); size_t sz = (number_of_chars) * (type == CHAR_BUF ? 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;
@ -172,10 +261,10 @@ string_buffer_t *create_string_buffer(size_t number_of_chars, enum str_buf_type
result->data_sz = sz; result->data_sz = sz;
result->type = type; result->type = type;
if (sz && type == CharBuf) { if (sz && type == CHAR_BUF) {
result->str.cstr[0] = '\0'; result->str.cstr[0] = '\0';
#ifdef FT_HAVE_WCHAR #ifdef FT_HAVE_WCHAR
} else if (sz && type == WCharBuf) { } else if (sz && type == W_CHAR_BUF) {
result->str.wstr[0] = L'\0'; result->str.wstr[0] = L'\0';
#endif /* FT_HAVE_WCHAR */ #endif /* FT_HAVE_WCHAR */
} }
@ -202,14 +291,14 @@ string_buffer_t *copy_string_buffer(const string_buffer_t *buffer)
if (result == NULL) if (result == NULL)
return NULL; return NULL;
switch (buffer->type) { switch (buffer->type) {
case CharBuf: case CHAR_BUF:
if (FT_IS_ERROR(fill_buffer_from_string(result, buffer->str.cstr))) { if (FT_IS_ERROR(fill_buffer_from_string(result, buffer->str.cstr))) {
destroy_string_buffer(result); destroy_string_buffer(result);
return NULL; return NULL;
} }
break; break;
#ifdef FT_HAVE_WCHAR #ifdef FT_HAVE_WCHAR
case WCharBuf: case W_CHAR_BUF:
if (FT_IS_ERROR(fill_buffer_from_wstring(result, buffer->str.wstr))) { if (FT_IS_ERROR(fill_buffer_from_wstring(result, buffer->str.wstr))) {
destroy_string_buffer(result); destroy_string_buffer(result);
return NULL; return NULL;
@ -250,7 +339,7 @@ fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str)
F_FREE(buffer->str.data); F_FREE(buffer->str.data);
buffer->str.cstr = copy; buffer->str.cstr = copy;
buffer->type = CharBuf; buffer->type = CHAR_BUF;
return FT_SUCCESS; return FT_SUCCESS;
} }
@ -269,31 +358,86 @@ fort_status_t fill_buffer_from_wstring(string_buffer_t *buffer, const wchar_t *s
F_FREE(buffer->str.data); F_FREE(buffer->str.data);
buffer->str.wstr = copy; buffer->str.wstr = copy;
buffer->type = WCharBuf; buffer->type = W_CHAR_BUF;
return FT_SUCCESS; return FT_SUCCESS;
} }
#endif /* FT_HAVE_WCHAR */ #endif /* FT_HAVE_WCHAR */
#ifdef FT_HAVE_UTF8
FT_INTERNAL
fort_status_t fill_buffer_from_u8string(string_buffer_t *buffer, const void *str)
{
assert(buffer);
assert(str);
void *copy = F_UTF8DUP(str);
if (copy == NULL)
return FT_MEMORY_ERROR;
F_FREE(buffer->str.u8str);
buffer->str.u8str = copy;
buffer->type = UTF8_BUF;
return FT_SUCCESS;
}
#endif /* FT_HAVE_UTF8 */
FT_INTERNAL FT_INTERNAL
size_t buffer_text_height(const string_buffer_t *buffer) size_t buffer_text_visible_height(const string_buffer_t *buffer)
{ {
if (buffer == NULL || buffer->str.data == NULL || buf_str_len(buffer) == 0) { if (buffer == NULL || buffer->str.data == NULL || buf_str_len(buffer) == 0) {
return 0; return 0;
} }
if (buffer->type == CharBuf) if (buffer->type == CHAR_BUF)
return 1 + strchr_count(buffer->str.cstr, '\n'); return 1 + strchr_count(buffer->str.cstr, '\n');
else #ifdef FT_HAVE_WCHAR
else if (buffer->type == W_CHAR_BUF)
return 1 + wstrchr_count(buffer->str.wstr, L'\n'); return 1 + wstrchr_count(buffer->str.wstr, L'\n');
#endif /* FT_HAVE_WCHAR */
#ifdef FT_HAVE_UTF8
else if (buffer->type == UTF8_BUF)
return 1 + utf8chr_count(buffer->str.u8str, '\n');
#endif /* FT_HAVE_WCHAR */
assert(0);
return 0;
} }
FT_INTERNAL
size_t string_buffer_cod_width_capacity(const string_buffer_t *buffer)
{
return string_buffer_width_capacity(buffer);
}
FT_INTERNAL FT_INTERNAL
size_t buffer_text_width(const string_buffer_t *buffer) size_t string_buffer_raw_capacity(const string_buffer_t *buffer)
{
return buffer->data_sz;
}
#ifdef FT_HAVE_UTF8
FT_INTERNAL
size_t ut8_width(const void *beg, const void *end)
{
size_t sz = (size_t)((const char *)end - (const char *)beg);
char *tmp = F_MALLOC(sizeof(char) * (sz + 1));
// @todo: add check to tmp
assert(tmp);
memcpy(tmp, beg, sz);
tmp[sz] = '\0';
size_t result = utf8len(tmp);
F_FREE(tmp);
return result;
}
#endif /* FT_HAVE_WCHAR */
FT_INTERNAL
size_t buffer_text_visible_width(const string_buffer_t *buffer)
{ {
size_t max_length = 0; size_t max_length = 0;
if (buffer->type == CharBuf) { if (buffer->type == CHAR_BUF) {
size_t n = 0; size_t n = 0;
while (1) { while (1) {
const char *beg = NULL; const char *beg = NULL;
@ -306,7 +450,7 @@ size_t buffer_text_width(const string_buffer_t *buffer)
++n; ++n;
} }
#ifdef FT_HAVE_WCHAR #ifdef FT_HAVE_WCHAR
} else { } else if (buffer->type == W_CHAR_BUF) {
size_t n = 0; size_t n = 0;
while (1) { while (1) {
const wchar_t *beg = NULL; const wchar_t *beg = NULL;
@ -323,149 +467,110 @@ size_t buffer_text_width(const string_buffer_t *buffer)
++n; ++n;
} }
#endif /* FT_HAVE_WCHAR */ #endif /* FT_HAVE_WCHAR */
#ifdef FT_HAVE_UTF8
} else if (buffer->type == UTF8_BUF) {
size_t n = 0;
while (1) {
const void *beg = NULL;
const void *end = NULL;
utf8_n_substring(buffer->str.u8str, '\n', n, &beg, &end);
if (beg == NULL || end == NULL)
return max_length;
max_length = MAX(max_length, (size_t)ut8_width(beg, end));
++n;
}
#endif /* FT_HAVE_WCHAR */
} }
return max_length; /* shouldn't be here */ return max_length; /* shouldn't be here */
} }
FT_INTERNAL static void
int buffer_printf(string_buffer_t *buffer, size_t buffer_row, char *buf, size_t total_buf_len, buffer_substring(const string_buffer_t *buffer, size_t buffer_row, void **begin, void **end, ptrdiff_t *str_it_width)
const context_t *context, const char *content_style_tag, const char *reset_content_style_tag)
{ {
#define CHAR_TYPE char switch (buffer->type) {
#define NULL_CHAR '\0' case CHAR_BUF:
#define NEWLINE_CHAR '\n' str_n_substring(buffer->str.cstr, '\n', buffer_row, (const char **)begin, (const char **)end);
#define SPACE_CHAR " " if ((*(const char **)begin) && (*(const char **)end))
#define SNPRINTF_FMT_STR "%*s" *str_it_width = str_iter_width(*(const char **)begin, *(const char **)end);
#define SNPRINTF snprintf
#define BUFFER_STR str.cstr
#define SNPRINT_N_STRINGS snprint_n_strings
#define STR_N_SUBSTRING str_n_substring
#define STR_ITER_WIDTH str_iter_width
size_t buf_len = total_buf_len - strlen(content_style_tag) - strlen(reset_content_style_tag);
if (buffer == NULL || buffer->str.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;
size_t left = 0;
size_t right = 0;
switch (get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_TEXT_ALIGN)) {
case FT_ALIGNED_LEFT:
left = 0;
right = (buf_len - 1) - content_width;
break; break;
case FT_ALIGNED_CENTER:
left = ((buf_len - 1) - content_width) / 2;
right = ((buf_len - 1) - content_width) - left;
break;
case FT_ALIGNED_RIGHT:
left = (buf_len - 1) - content_width;
right = 0;
break;
default:
assert(0);
break;
}
int set_old_value = 0;
size_t written = 0;
int tmp = 0;
ptrdiff_t str_it_width = 0;
const CHAR_TYPE *beg = NULL;
const CHAR_TYPE *end = NULL;
CHAR_TYPE old_value = (CHAR_TYPE)0;
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, left, SPACE_CHAR));
STR_N_SUBSTRING(buffer->BUFFER_STR, NEWLINE_CHAR, buffer_row, &beg, &end);
if (beg == NULL || end == NULL)
return -1;
old_value = *end;
*(CHAR_TYPE *)end = NULL_CHAR;
set_old_value = 1;
str_it_width = STR_ITER_WIDTH(beg, end);
if (str_it_width < 0 || content_width < (size_t)str_it_width)
goto clear;
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, 1, content_style_tag));
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINTF(buf + written, total_buf_len - written, SNPRINTF_FMT_STR, (int)(end - beg), beg));
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, 1, reset_content_style_tag));
*(CHAR_TYPE *)end = old_value;
set_old_value = 0;
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, (content_width - (size_t)str_it_width), SPACE_CHAR));
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, right, SPACE_CHAR));
return (int)written;
clear:
if (set_old_value)
*(CHAR_TYPE *)end = old_value;
return -1;
#undef CHAR_TYPE
#undef NULL_CHAR
#undef NEWLINE_CHAR
#undef SPACE_CHAR
#undef SNPRINTF_FMT_STR
#undef SNPRINTF
#undef BUFFER_STR
#undef SNPRINT_N_STRINGS
#undef STR_N_SUBSTRING
#undef STR_ITER_WIDTH
}
#ifdef FT_HAVE_WCHAR #ifdef FT_HAVE_WCHAR
FT_INTERNAL case W_CHAR_BUF:
int buffer_wprintf(string_buffer_t *buffer, size_t buffer_row, wchar_t *buf, size_t total_buf_len, wstr_n_substring(buffer->str.wstr, L'\n', buffer_row, (const wchar_t **)begin, (const wchar_t **)end);
const context_t *context, const char *content_style_tag, const char *reset_content_style_tag) if ((*(const wchar_t **)begin) && (*(const wchar_t **)end))
{ *str_it_width = wcs_iter_width(*(const wchar_t **)begin, *(const wchar_t **)end);
#define CHAR_TYPE wchar_t break;
#define NULL_CHAR L'\0' #endif /* FT_HAVE_WCHAR */
#define NEWLINE_CHAR L'\n' #ifdef FT_HAVE_UTF8
#define SPACE_CHAR " " case UTF8_BUF:
#define SNPRINTF_FMT_STR L"%*ls" utf8_n_substring(buffer->str.wstr, '\n', buffer_row, begin, end);
#define SNPRINTF swprintf if ((*(const char **)begin) && (*(const char **)end))
#define BUFFER_STR str.wstr *str_it_width = ut8_width(*begin, *end);
#define SNPRINT_N_STRINGS wsnprint_n_string break;
#define STR_N_SUBSTRING wstr_n_substring #endif /* FT_HAVE_UTF8 */
#define STR_ITER_WIDTH wcs_iter_width default:
assert(0);
}
}
size_t buf_len = total_buf_len - strlen(content_style_tag) - strlen(reset_content_style_tag);
static int
buffer_print_range(conv_context_t *cntx, const void *beg, const void *end)
{
size_t len;
switch (cntx->b_type) {
case CHAR_BUF:
len = (size_t)((const char *)end - (const char *)beg);
return ft_nprint(cntx, (const char *)beg, len);
#ifdef FT_HAVE_WCHAR
case W_CHAR_BUF:
len = (size_t)((const wchar_t *)end - (const wchar_t *)beg);
return ft_nwprint(cntx, (const wchar_t *)beg, len);
#endif /* FT_HAVE_WCHAR */
#ifdef FT_HAVE_UTF8
case UTF8_BUF:
return ft_nu8print(cntx, beg, end);
#endif /* FT_HAVE_UTF8 */
default:
assert(0);
return -1;
}
}
FT_INTERNAL
int buffer_printf(string_buffer_t *buffer, size_t buffer_row, conv_context_t *cntx, size_t vis_width,
const char *content_style_tag, const char *reset_content_style_tag)
{
const context_t *context = cntx->cntx;
fort_table_properties_t *props = context->table_properties;
size_t row = context->row;
size_t column = context->column;
if (buffer == NULL || buffer->str.data == NULL if (buffer == NULL || buffer->str.data == NULL
|| buffer_row >= buffer_text_height(buffer) || buf_len == 0) { || buffer_row >= buffer_text_visible_height(buffer)) {
return -1; return -1;
} }
size_t content_width = buffer_text_width(buffer); size_t content_width = buffer_text_visible_width(buffer);
if ((buf_len - 1) < content_width) if (vis_width < content_width)
return -1; return -1;
size_t left = 0; size_t left = 0;
size_t right = 0; size_t right = 0;
switch (get_cell_property_value_hierarcial(props, row, column, FT_CPROP_TEXT_ALIGN)) {
switch (get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_TEXT_ALIGN)) {
case FT_ALIGNED_LEFT: case FT_ALIGNED_LEFT:
left = 0; left = 0;
right = (buf_len - 1) - content_width; right = (vis_width) - content_width;
break; break;
case FT_ALIGNED_CENTER: case FT_ALIGNED_CENTER:
left = ((buf_len - 1) - content_width) / 2; left = ((vis_width) - content_width) / 2;
right = ((buf_len - 1) - content_width) - left; right = ((vis_width) - content_width) - left;
break; break;
case FT_ALIGNED_RIGHT: case FT_ALIGNED_RIGHT:
left = (buf_len - 1) - content_width; left = (vis_width) - content_width;
right = 0; right = 0;
break; break;
default: default:
@ -473,64 +578,41 @@ int buffer_wprintf(string_buffer_t *buffer, size_t buffer_row, wchar_t *buf, siz
break; break;
} }
int set_old_value = 0;
size_t written = 0; size_t written = 0;
int tmp = 0; int tmp = 0;
ptrdiff_t str_it_width = 0; ptrdiff_t str_it_width = 0;
const CHAR_TYPE *beg = NULL; const void *beg = NULL;
const CHAR_TYPE *end = NULL; const void *end = NULL;
CHAR_TYPE old_value = (CHAR_TYPE)0; buffer_substring(buffer, buffer_row, (void **)&beg, (void **)&end, &str_it_width);
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, left, SPACE_CHAR));
STR_N_SUBSTRING(buffer->BUFFER_STR, NEWLINE_CHAR, buffer_row, &beg, &end);
if (beg == NULL || end == NULL) if (beg == NULL || end == NULL)
return -1; return -1;
old_value = *end;
*(CHAR_TYPE *)end = NULL_CHAR;
set_old_value = 1;
str_it_width = STR_ITER_WIDTH(beg, end);
if (str_it_width < 0 || content_width < (size_t)str_it_width) if (str_it_width < 0 || content_width < (size_t)str_it_width)
goto clear; return -1;
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, 1, content_style_tag)); size_t padding = content_width - (size_t)str_it_width;
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINTF(buf + written, total_buf_len - written, SNPRINTF_FMT_STR, (int)(end - beg), beg));
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, 1, reset_content_style_tag));
*(CHAR_TYPE *)end = old_value; CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, left, FT_SPACE));
set_old_value = 0; CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, content_style_tag));
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, (content_width - (size_t)str_it_width), SPACE_CHAR)); CHCK_RSLT_ADD_TO_WRITTEN(buffer_print_range(cntx, beg, end));
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, right, SPACE_CHAR)); CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, reset_content_style_tag));
CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, padding, FT_SPACE));
CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, right, FT_SPACE));
return (int)written; return (int)written;
clear: clear:
if (set_old_value)
*(CHAR_TYPE *)end = old_value;
return -1; return -1;
#undef CHAR_TYPE
#undef NULL_CHAR
#undef NEWLINE_CHAR
#undef SPACE_CHAR
#undef SNPRINTF_FMT_STR
#undef SNPRINTF
#undef BUFFER_STR
#undef SNPRINT_N_STRINGS
#undef STR_N_SUBSTRING
#undef STR_ITER_WIDTH
} }
#endif /* FT_HAVE_WCHAR */
FT_INTERNAL FT_INTERNAL
size_t string_buffer_capacity(const string_buffer_t *buffer) size_t string_buffer_width_capacity(const string_buffer_t *buffer)
{ {
assert(buffer); assert(buffer);
if (buffer->type == CharBuf) if (buffer->type == CHAR_BUF)
return buffer->data_sz; return buffer->data_sz;
else else if (buffer->type == W_CHAR_BUF)
return buffer->data_sz / sizeof(wchar_t); return buffer->data_sz / sizeof(wchar_t);
else if (buffer->type == UTF8_BUF)
return buffer->data_sz / 4;
} }

View File

@ -7,17 +7,16 @@
/***************************************************************************** /*****************************************************************************
* STRING BUFFER * STRING BUFFER
* ***************************************************************************/ * ***************************************************************************/
enum str_buf_type {
CharBuf,
#ifdef FT_HAVE_WCHAR
WCharBuf
#endif /* FT_HAVE_WCHAR */
};
struct string_buffer { struct string_buffer {
union { union {
char *cstr; char *cstr;
#ifdef FT_HAVE_WCHAR
wchar_t *wstr; wchar_t *wstr;
#endif
#ifdef FT_HAVE_UTF8
void *u8str;
#endif
void *data; void *data;
} str; } str;
size_t data_sz; size_t data_sz;
@ -44,26 +43,31 @@ FT_INTERNAL
fort_status_t fill_buffer_from_wstring(string_buffer_t *buffer, const wchar_t *str); fort_status_t fill_buffer_from_wstring(string_buffer_t *buffer, const wchar_t *str);
#endif /* FT_HAVE_WCHAR */ #endif /* FT_HAVE_WCHAR */
#ifdef FT_HAVE_UTF8
FT_INTERNAL FT_INTERNAL
size_t buffer_text_height(const string_buffer_t *buffer); fort_status_t fill_buffer_from_u8string(string_buffer_t *buffer, const void *str);
#endif /* FT_HAVE_UTF8 */
FT_INTERNAL FT_INTERNAL
size_t string_buffer_capacity(const string_buffer_t *buffer); size_t buffer_text_visible_width(const string_buffer_t *buffer);
FT_INTERNAL
size_t buffer_text_visible_height(const string_buffer_t *buffer);
FT_INTERNAL
size_t string_buffer_cod_width_capacity(const string_buffer_t *buffer);
FT_INTERNAL
size_t string_buffer_raw_capacity(const string_buffer_t *buffer);
FT_INTERNAL
size_t string_buffer_width_capacity(const string_buffer_t *buffer);
FT_INTERNAL FT_INTERNAL
void *buffer_get_data(string_buffer_t *buffer); void *buffer_get_data(string_buffer_t *buffer);
FT_INTERNAL FT_INTERNAL
size_t buffer_text_width(const string_buffer_t *buffer); int buffer_printf(string_buffer_t *buffer, size_t buffer_row, conv_context_t *cntx, size_t cod_width,
const char *content_style_tag, const char *reset_content_style_tag);
FT_INTERNAL
int buffer_printf(string_buffer_t *buffer, size_t buffer_row, char *buf, size_t total_buf_len,
const context_t *context, const char *content_style_tag, const char *reset_content_style_tag);
#ifdef FT_HAVE_WCHAR
FT_INTERNAL
int buffer_wprintf(string_buffer_t *buffer, size_t buffer_row, wchar_t *buf, size_t total_buf_len,
const context_t *context, const char *content_style_tag, const char *reset_content_style_tag);
#endif /* FT_HAVE_WCHAR */
#endif /* STRING_BUFFER_H */ #endif /* STRING_BUFFER_H */

View File

@ -294,3 +294,8 @@ fort_status_t table_geometry(const ft_table_t *table, size_t *height, size_t *wi
} }
FT_INTERNAL
fort_status_t table_internal_codepoints_geometry(const ft_table_t *table, size_t *height, size_t *width)
{
return table_geometry(table, height, width);
}

View File

@ -46,4 +46,11 @@ fort_status_t table_rows_and_cols_geometry(const ft_table_t *table,
FT_INTERNAL FT_INTERNAL
fort_status_t table_geometry(const ft_table_t *table, size_t *height, size_t *width); fort_status_t table_geometry(const ft_table_t *table, size_t *height, size_t *width);
/*
* Returns geometry in codepoints(characters) (include codepoints of invisible
* elements: e.g. styles tags).
*/
FT_INTERNAL
fort_status_t table_internal_codepoints_geometry(const ft_table_t *table, size_t *height, size_t *width);
#endif /* TABLE_H */ #endif /* TABLE_H */

View File

@ -125,12 +125,55 @@ void test_bug_fixes(void)
ft_destroy_table(table); ft_destroy_table(table);
} }
#endif #endif
#ifdef FT_HAVE_UTF8
SCENARIO("Issue 11 - https://github.com/seleznevae/libfort/issues/11 (utf-8 case)") {
ft_table_t *table = ft_create_table();
ft_set_border_style(table, FT_PLAIN_STYLE);
ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER);
ft_u8write_ln(table, "1", "2");
ft_u8write_ln(table, "3", "4");
const char *table_str = ft_to_u8string(table);
assert_true(table_str != NULL);
const char *table_str_etalon =
"-------\n"
" 1 2 \n"
"-------\n"
" 3 4 \n";
assert_str_equal(table_str, table_str_etalon);
ft_destroy_table(table);
}
#endif /* FT_HAVE_UTF8 */
} }
void test_table_basic(void) void test_table_basic(void)
{ {
ft_table_t *table = NULL; ft_table_t *table = NULL;
WHEN("Empty table") {
table = ft_create_table();
assert_true(table != NULL);
const char *table_str = ft_to_string(table);
assert_true(table_str != NULL);
const char *table_str_etalon = "";
assert_str_equal(table_str, table_str_etalon);
#ifdef FT_HAVE_WCHAR
const wchar_t *table_wstr = ft_to_wstring(table);
assert_true(table_wstr != NULL);
const wchar_t *table_wstr_etalon = L"";
assert_wcs_equal(table_wstr, table_wstr_etalon);
#endif
#ifdef FT_HAVE_UTF8
table_str = ft_to_u8string(table);
assert_true(table_str != NULL);
assert_str_equal(table_str, table_str_etalon);
#endif /* FT_HAVE_UTF8 */
ft_destroy_table(table);
}
WHEN("All columns are equal and not empty") { WHEN("All columns are equal and not empty") {
table = ft_create_table(); table = ft_create_table();
assert_true(table != NULL); assert_true(table != NULL);
@ -193,6 +236,39 @@ void test_table_basic(void)
} }
#endif #endif
#ifdef FT_HAVE_UTF8
WHEN("All columns are equal and not empty (utf8 strings)") {
table = ft_create_table();
assert_true(table != NULL);
assert_true(set_test_props_for_table(table) == FT_SUCCESS);
ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER);
assert_true(ft_u8write_ln(table, "3", "c", "234", "3.140000") == FT_SUCCESS);
assert_true(ft_u8write_ln(table, "3", "c", "234", "3.140000") == FT_SUCCESS);
assert_true(ft_u8write_ln(table, "3", "c", "234", "3.140000") == FT_SUCCESS);
const char *table_str = ft_to_u8string(table);
assert_true(table_str != NULL);
const char *table_str_etalon =
"+---+---+-----+----------+\n"
"| | | | |\n"
"| 3 | c | 234 | 3.140000 |\n"
"| | | | |\n"
"+---+---+-----+----------+\n"
"| | | | |\n"
"| 3 | c | 234 | 3.140000 |\n"
"| | | | |\n"
"+---+---+-----+----------+\n"
"| | | | |\n"
"| 3 | c | 234 | 3.140000 |\n"
"| | | | |\n"
"+---+---+-----+----------+\n";
assert_str_equal(table_str, table_str_etalon);
ft_destroy_table(table);
}
#endif /* FT_HAVE_UTF8 */
WHEN("All columns are not equal and not empty") { WHEN("All columns are not equal and not empty") {
table = ft_create_table(); table = ft_create_table();
assert_true(table != NULL); assert_true(table != NULL);
@ -255,6 +331,38 @@ void test_table_basic(void)
} }
#endif #endif
#ifdef FT_HAVE_UTF8
WHEN("All columns are not equal and not empty") {
table = ft_create_table();
assert_true(table != NULL);
assert_true(set_test_props_for_table(table) == FT_SUCCESS);
ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER);
assert_true(ft_u8write_ln(table, "3", "c", "234", "3.140000") == FT_SUCCESS);
assert_true(ft_u8write_ln(table, "c", "234", "3.140000", "3") == FT_SUCCESS);
assert_true(ft_u8write_ln(table, "234", "3.140000", "3", "c") == FT_SUCCESS);
const char *table_str = ft_to_u8string(table);
assert_true(table_str != NULL);
const char *table_str_etalon =
"+-----+----------+----------+----------+\n"
"| | | | |\n"
"| 3 | c | 234 | 3.140000 |\n"
"| | | | |\n"
"+-----+----------+----------+----------+\n"
"| | | | |\n"
"| c | 234 | 3.140000 | 3 |\n"
"| | | | |\n"
"+-----+----------+----------+----------+\n"
"| | | | |\n"
"| 234 | 3.140000 | 3 | c |\n"
"| | | | |\n"
"+-----+----------+----------+----------+\n";
assert_str_equal(table_str, table_str_etalon);
ft_destroy_table(table);
}
#endif /* FT_HAVE_UTF8 */
WHEN("All columns are not equal and some cells are empty") { WHEN("All columns are not equal and some cells are empty") {
table = ft_create_table(); table = ft_create_table();
assert_true(table != NULL); assert_true(table != NULL);
@ -317,6 +425,38 @@ void test_table_basic(void)
} }
#endif #endif
#ifdef FT_HAVE_UTF8
WHEN("All columns are not equal and some cells are empty (utf-8 strings)") {
table = ft_create_table();
assert_true(table != NULL);
assert_true(set_test_props_for_table(table) == FT_SUCCESS);
ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER);
assert_true(ft_u8write_ln(table, "", "", "234", "3.140000") == FT_SUCCESS);
assert_true(ft_u8write_ln(table, "c", "234", "3.140000", "") == FT_SUCCESS);
assert_true(ft_u8write_ln(table, "234", "3.140000", "", "") == FT_SUCCESS);
const char *table_str = ft_to_u8string(table);
assert_true(table_str != NULL);
const char *table_str_etalon =
"+-----+----------+----------+----------+\n"
"| | | | |\n"
"| | | 234 | 3.140000 |\n"
"| | | | |\n"
"+-----+----------+----------+----------+\n"
"| | | | |\n"
"| c | 234 | 3.140000 | |\n"
"| | | | |\n"
"+-----+----------+----------+----------+\n"
"| | | | |\n"
"| 234 | 3.140000 | | |\n"
"| | | | |\n"
"+-----+----------+----------+----------+\n";
assert_str_equal(table_str, table_str_etalon);
ft_destroy_table(table);
}
#endif /* FT_HAVE_UTF8 */
WHEN("All cells are empty") { WHEN("All cells are empty") {
table = ft_create_table(); table = ft_create_table();
assert_true(table != NULL); assert_true(table != NULL);
@ -378,6 +518,40 @@ void test_table_basic(void)
ft_destroy_table(table); ft_destroy_table(table);
} }
#endif #endif
WHEN("Multiline conten") {
table = ft_create_table();
assert_true(table != NULL);
assert_true(set_test_props_for_table(table) == FT_SUCCESS);
ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER);
assert_true(ft_write_ln(table, "3", "c", "234\n2", "3.140000") == FT_SUCCESS);
assert_true(ft_write_ln(table, "3", "c", "234", "3.140000\n123") == FT_SUCCESS);
assert_true(ft_write_ln(table, "3", "c", "234", "x") == FT_SUCCESS);
ft_set_cell_prop(table, FT_ANY_ROW, 3, FT_CPROP_TEXT_ALIGN, FT_ALIGNED_RIGHT);
const char *table_str = ft_to_string(table);
assert_true(table_str != NULL);
const char *table_str_etalon =
"+---+---+-----+----------+\n"
"| | | | |\n"
"| 3 | c | 234 | 3.140000 |\n"
"| | | 2 | |\n"
"| | | | |\n"
"+---+---+-----+----------+\n"
"| | | | |\n"
"| 3 | c | 234 | 3.140000 |\n"
"| | | | 123 |\n" /* todo: Fix strange alignment for multiline cells */
"| | | | |\n"
"+---+---+-----+----------+\n"
"| | | | |\n"
"| 3 | c | 234 | x |\n"
"| | | | |\n"
"+---+---+-----+----------+\n";
assert_str_equal(table_str, table_str_etalon);
ft_destroy_table(table);
}
} }
@ -419,6 +593,138 @@ void test_wcs_table_boundaries(void)
} }
#endif #endif
#ifdef FT_HAVE_UTF8
void test_utf8_table(void)
{
ft_table_t *table = NULL;
#define TEST_UTF8_SIMPLE(content) \
{ \
table = ft_create_table(); \
assert_true(table != NULL); \
assert(ft_set_border_style(table, FT_EMPTY_STYLE) == 0); \
assert_true(ft_u8write_ln(table, content) == FT_SUCCESS); \
const char *table_str = ft_to_u8string(table); \
assert_true(table_str != NULL); \
char table_str_etalon[1024] = {'\0'}; \
snprintf(table_str_etalon, 1024," %s \n", content); \
assert_str_equal(table_str, table_str_etalon); \
ft_destroy_table(table); \
}
TEST_UTF8_SIMPLE("");
TEST_UTF8_SIMPLE("1");
TEST_UTF8_SIMPLE("foo");
TEST_UTF8_SIMPLE("1234567890");
TEST_UTF8_SIMPLE("Xylophmsik");
TEST_UTF8_SIMPLE("ψημένηζειθ");
TEST_UTF8_SIMPLE("Dḟuascail");
TEST_UTF8_SIMPLE("Pójdźżełąć");
TEST_UTF8_SIMPLE("«braçõeshá");
TEST_UTF8_SIMPLE("французких");
TEST_UTF8_SIMPLE("Benjamínúñ");
TEST_UTF8_SIMPLE("görmüştüçğ");
TEST_UTF8_SIMPLE("視野無限廣窗外有藍天");
TEST_UTF8_SIMPLE("いろはにほへとちりぬ");
TEST_UTF8_SIMPLE("𠜎𠜱𠝹𠱓𠱸𠲖𠳏𠳕𠴕𠵼");
#undef TEST_UTF8_SIMPLE
#define TEST_UTF8_SIMPLE_STYLE(content) \
{ \
table = ft_create_table(); \
assert_true(table != NULL); \
assert(ft_set_border_style(table, FT_EMPTY_STYLE) == 0); \
assert_true(ft_u8write_ln(table, content) == FT_SUCCESS); \
assert(ft_set_cell_prop(table, 0, 0, FT_CPROP_CONT_FG_COLOR, FT_COLOR_YELLOW) == FT_SUCCESS); \
assert(ft_set_cell_prop(table, 0, 0, FT_CPROP_CELL_BG_COLOR, FT_COLOR_RED) == FT_SUCCESS); \
assert(ft_set_cell_prop(table, 0, 0, FT_CPROP_CONT_TEXT_STYLE, FT_TSTYLE_UNDERLINED) == FT_SUCCESS); \
const char *table_str = ft_to_u8string(table); \
assert_true(table_str != NULL); \
char table_str_etalon[1024] = {'\0'}; \
snprintf(table_str_etalon, 1024, \
"\033[41m \033[4m\033[33m%s\033[0m\033[41m \033[0m\n", content); \
assert_str_equal(table_str, table_str_etalon); \
ft_destroy_table(table); \
}
TEST_UTF8_SIMPLE_STYLE("1234567890");
TEST_UTF8_SIMPLE_STYLE("Xylophmsik");
TEST_UTF8_SIMPLE_STYLE("ψημένηζειθ");
TEST_UTF8_SIMPLE_STYLE("Dḟuascail");
TEST_UTF8_SIMPLE_STYLE("Pójdźżełąć");
TEST_UTF8_SIMPLE_STYLE("«braçõeshá");
TEST_UTF8_SIMPLE_STYLE("французких");
TEST_UTF8_SIMPLE_STYLE("Benjamínúñ");
TEST_UTF8_SIMPLE_STYLE("görmüştüçğ");
TEST_UTF8_SIMPLE_STYLE("視野無限廣窗外有藍天");
TEST_UTF8_SIMPLE_STYLE("いろはにほへとちりぬ");
TEST_UTF8_SIMPLE_STYLE("𠜎𠜱𠝹𠱓𠱸𠲖𠳏𠳕𠴕𠵼");
#undef TEST_UTF8_SIMPLE_STYLE
#define TEST_UTF8_BORDER(content) \
{ \
table = ft_create_table(); \
assert_true(table != NULL); \
assert(ft_set_border_style(table, FT_BASIC_STYLE) == 0); \
assert_true(ft_u8write_ln(table, content) == FT_SUCCESS); \
const char *table_str = ft_to_u8string(table); \
assert_true(table_str != NULL); \
char table_str_etalon[1024] = {'\0'}; \
snprintf(table_str_etalon, 1024, \
"+------------+\n" \
"| %s |\n" \
"+------------+\n", content); \
assert_str_equal(table_str, table_str_etalon); \
ft_destroy_table(table); \
}
TEST_UTF8_BORDER("1234567890");
TEST_UTF8_BORDER("Xylophmsik");
TEST_UTF8_BORDER("ψημένηζειθ");
TEST_UTF8_BORDER("Dḟuascail");
TEST_UTF8_BORDER("Pójdźżełąć");
TEST_UTF8_BORDER("«braçõeshá");
TEST_UTF8_BORDER("французких");
TEST_UTF8_BORDER("Benjamínúñ");
TEST_UTF8_BORDER("görmüştüçğ");
TEST_UTF8_BORDER("視野無限廣窗外有藍天");
TEST_UTF8_BORDER("いろはにほへとちりぬ");
TEST_UTF8_BORDER("𠜎𠜱𠝹𠱓𠱸𠲖𠳏𠳕𠴕𠵼");
#undef TEST_UTF8_BORDER
#define TEST_UTF8_STYLE(content) \
{ \
table = ft_create_table(); \
assert_true(table != NULL); \
assert(ft_set_border_style(table, FT_BASIC_STYLE) == 0); \
assert_true(ft_u8write_ln(table, content) == FT_SUCCESS); \
assert(ft_set_cell_prop(table, 0, 0, FT_CPROP_CONT_FG_COLOR, FT_COLOR_YELLOW) == FT_SUCCESS); \
assert(ft_set_cell_prop(table, 0, 0, FT_CPROP_CELL_BG_COLOR, FT_COLOR_RED) == FT_SUCCESS); \
assert(ft_set_cell_prop(table, 0, 0, FT_CPROP_CONT_TEXT_STYLE, FT_TSTYLE_UNDERLINED) == FT_SUCCESS); \
const char *table_str = ft_to_u8string(table); \
assert_true(table_str != NULL); \
char table_str_etalon[1024] = {'\0'}; \
snprintf(table_str_etalon, 1024, \
"+------------+\n" \
"|\033[41m \033[4m\033[33m%s\033[0m\033[41m \033[0m|\n" \
"+------------+\n", content); \
assert_str_equal(table_str, table_str_etalon); \
ft_destroy_table(table); \
}
TEST_UTF8_STYLE("1234567890");
TEST_UTF8_STYLE("Xylophmsik");
TEST_UTF8_STYLE("ψημένηζειθ");
TEST_UTF8_STYLE("Dḟuascail");
TEST_UTF8_STYLE("Pójdźżełąć");
TEST_UTF8_STYLE("«braçõeshá");
TEST_UTF8_STYLE("французких");
TEST_UTF8_STYLE("Benjamínúñ");
TEST_UTF8_STYLE("görmüştüçğ");
TEST_UTF8_STYLE("視野無限廣窗外有藍天");
TEST_UTF8_STYLE("いろはにほへとちりぬ");
TEST_UTF8_STYLE("𠜎𠜱𠝹𠱓𠱸𠲖𠳏𠳕𠴕𠵼");
#undef TEST_UTF8_STYLE
}
#endif /* FT_HAVE_UTF8 */
void test_table_write(void) void test_table_write(void)
{ {

View File

@ -22,6 +22,9 @@ void test_table_cell_properties(void);
void test_table_text_styles(void); void test_table_text_styles(void);
void test_table_tbl_properties(void); void test_table_tbl_properties(void);
void test_memory_errors(void); void test_memory_errors(void);
#ifdef FT_HAVE_UTF8
void test_utf8_table(void);
#endif
#ifdef FORT_WB_TESTING_ENABLED #ifdef FORT_WB_TESTING_ENABLED
@ -41,6 +44,9 @@ struct test_case bb_test_suite [] = {
{"test_table_basic", test_table_basic}, {"test_table_basic", test_table_basic},
#ifdef FT_HAVE_WCHAR #ifdef FT_HAVE_WCHAR
{"test_wcs_table_boundaries", test_wcs_table_boundaries}, {"test_wcs_table_boundaries", test_wcs_table_boundaries},
#endif
#ifdef FT_HAVE_UTF8
{"test_utf8_table", test_utf8_table},
#endif #endif
{"test_table_write", test_table_write}, {"test_table_write", test_table_write},
{"test_table_changing_cell", test_table_changing_cell}, {"test_table_changing_cell", test_table_changing_cell},

View File

@ -2,39 +2,53 @@
#include "string_buffer.h" #include "string_buffer.h"
#include "wcwidth.h" #include "wcwidth.h"
#include <wchar.h> #include <wchar.h>
#if defined(FT_HAVE_UTF8)
#include "utf8.h"
#endif
size_t strchr_count(const char *str, char ch); size_t strchr_count(const char *str, char ch);
size_t wstrchr_count(const wchar_t *str, wchar_t ch); size_t wstrchr_count(const wchar_t *str, wchar_t ch);
#if defined(FT_HAVE_UTF8)
size_t utf8chr_count(const void *str, utf8_int32_t ch);
#endif
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);
const wchar_t *wstr_n_substring_beg(const wchar_t *str, wchar_t ch_separator, size_t n); const wchar_t *wstr_n_substring_beg(const wchar_t *str, wchar_t ch_separator, size_t n);
#ifdef FT_HAVE_UTF8
const void *utf8_n_substring_beg(const void *str, utf8_int32_t ch_separator, size_t n);
#endif
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); void wstr_n_substring(const wchar_t *str, wchar_t ch_separator, size_t n, const wchar_t **begin, const wchar_t **end);
#ifdef FT_HAVE_UTF8
void utf8_n_substring(const void *str, utf8_int32_t ch_separator, size_t n, const void **begin, const void **end);
#endif
//size_t buffer_text_width(string_buffer_t *buffer);
void test_strchr_count(void); void test_strchr_count(void);
void test_str_n_substring(void); void test_str_n_substring(void);
void test_buffer_text_width(void); void test_buffer_text_visible_width(void);
void test_buffer_text_height(void); void test_buffer_text_visible_height(void);
#if defined(FT_HAVE_WCHAR) #if defined(FT_HAVE_WCHAR)
void test_wchar_basics(void); void test_wchar_basics(void);
#endif #endif
void test_print_n_strings(void);
void test_string_buffer(void) void test_string_buffer(void)
{ {
test_strchr_count(); test_strchr_count();
test_str_n_substring(); test_str_n_substring();
test_buffer_text_width(); test_buffer_text_visible_width();
test_buffer_text_height(); test_buffer_text_visible_height();
#if defined(FT_HAVE_WCHAR) #if defined(FT_HAVE_WCHAR)
test_wchar_basics(); test_wchar_basics();
#endif #endif
test_print_n_strings();
} }
@ -70,8 +84,60 @@ void test_strchr_count(void)
assert_true(wstrchr_count(L"\n123123\n123123\n\n\n123", L'\n') == 5); 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); assert_true(wstrchr_count(L"1\xffffy23123\xffffy123123\xffffy\xffffy\xffffy123", L'\xffff') == 5);
#ifdef FT_HAVE_UTF8
assert_true(utf8chr_count(NULL, '\n') == 0);
assert_true(utf8chr_count("", '\n') == 0);
assert_true(utf8chr_count("asbd", '\n') == 0);
assert_true(utf8chr_count("Chinese L視野無限廣窗外有藍天", '\n') == 0);
assert_true(utf8chr_count("Hindi ऋषियों को सताने वाले दुष्ट राक्षसों के राजा रावण का सर्वनाश करने वाले विष्णुवतार भगवान श्रीराम, अयोध्या के महाराज दशरथ के बड़े सपुत्र थे।", '\n') == 0);
assert_true(utf8chr_count("Portuguese Luís argüia à Júlia que «brações, fé, chá, óxido, pôr, zângão» eram palavras do português.", '\n') == 0);
assert_true(utf8chr_count("Russian В чащах юга жил бы цитрус? Да, но фальшивый экземпляръ!", '\n') == 0);
assert_true(utf8chr_count("Spanish La niña, viéndose atrapada en el áspero baúl índigo y sintiendo asfixia, lloró de vergüenza; mientras que la frustrada madre llamaba a su hija diciendo: ¿Dónde estás Waleska?", '\n') == 0);
assert_true(utf8chr_count("asbd\n", '\n') == 1);
assert_true(utf8chr_count("\nasbd", '\n') == 1);
assert_true(utf8chr_count("a\nsbd", '\n') == 1);
assert_true(utf8chr_count("Chinese L視野無限\n廣,窗外有藍天", '\n') == 1);
assert_true(utf8chr_count("Hindi ऋषियों को सताने वा\nले दुष्ट राक्षसों के राजा रावण का सर्वनाश करने वाले विष्णुवतार भगवान श्रीराम, अयोध्या के महाराज दशरथ के बड़े सपुत्र थे।", '\n') == 1);
assert_true(utf8chr_count("Portuguese Luís argüi\na à Júlia que «brações, fé, chá, óxido, pôr, zângão» eram palavras do português.", '\n') == 1);
assert_true(utf8chr_count("Russian В чащах \nюга жил бы цитрус? Да, но фальшивый экземпляръ!", '\n') == 1);
assert_true(utf8chr_count("Spanish La niña, vié\nndose atrapada en el áspero baúl índigo y sintiendo asfixia, lloró de vergüenza; mientras que la frustrada madre llamaba a su hija diciendo: ¿Dónde estás Waleska?", '\n') == 1);
assert_true(utf8chr_count("\n12\n123", '\n') == 2);
assert_true(utf8chr_count("\n12\n123\n", '\n') == 3);
assert_true(utf8chr_count("\n\n\n", '\n') == 3);
assert_true(utf8chr_count("\n123123\n123123\n\n\n123", '\n') == 5);
assert_true(utf8chr_count("Chinese L視野無限\n廣,窗外有\n藍天", '\n') == 2);
assert_true(utf8chr_count("Hindi ऋषियों को सताने वा\nले दुष्ट राक्षसों के राजा\n रावण का सर्वना\nश करने वाले विष्णुवतार भगवान श्रीराम, अयोध्या के महाराज दशरथ के बड़े सपुत्र थे।", '\n') == 3);
assert_true(utf8chr_count("Portuguese Luís argüi\na à Júlia que «brações, fé, chá, óxido, \npôr, zângão» eram pal\navras do portu\nguês.", '\n') == 4);
assert_true(utf8chr_count("Russian В чащах \nюга жил бы ц\nитрус? Да, но фальшивый экземпляръ!", '\n') == 2);
assert_true(utf8chr_count("Spanish La niña, vié\nndose atrapada en el \n\n\náspero baúl índigo y \nsintiendo asfixia, lloró de vergüenza; mientras que la frustrada madre llamaba a su hija diciendo: ¿Dónde estás Waleska?", '\n') == 5);
assert_true(utf8chr_count("1a23123a123123aaa123", 'a') == 5);
#endif
} }
void assert_str_equal_strong(const char *str1, const char *str2,
const char *file,
int line,
const char *function)
{
if (!str1 && !str2)
return;
if ((str1 && !str2) || (!str1 && str2)) {
fprintf(stderr, "%s:%d(%s):Abort! Not equals strings:\n", file, line, function);
exit(EXIT_FAILURE);
} else if (strcmp(str1, str2) != 0) {
fprintf(stderr, "%s:%d(%s):Abort! Not equals strings:\n", file, line, function);
exit(EXIT_FAILURE);
}
}
#define ASSERT_STR_EQUAL_STRONG(str1, str2) assert_str_equal_strong(str1, str2, __FILE__,__LINE__, __func__)
void test_str_n_substring(void) void test_str_n_substring(void)
{ {
@ -86,6 +152,13 @@ void test_str_n_substring(void)
assert_true(wstr_n_substring_beg(empty_wstr, L'\n', 1) == NULL); assert_true(wstr_n_substring_beg(empty_wstr, L'\n', 1) == NULL);
assert_true(wstr_n_substring_beg(empty_wstr, L'\n', 2) == NULL); assert_true(wstr_n_substring_beg(empty_wstr, L'\n', 2) == NULL);
#endif #endif
#ifdef FT_HAVE_UTF8
const char *utf8_empty_str = "";
assert_true(utf8_n_substring_beg(utf8_empty_str, '\n', 0) == utf8_empty_str);
assert_true(utf8_n_substring_beg(utf8_empty_str, '\n', 1) == NULL);
assert_true(utf8_n_substring_beg(utf8_empty_str, '\n', 2) == NULL);
#endif
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);
@ -106,6 +179,16 @@ void test_str_n_substring(void)
assert_true(wstr_n_substring_beg(wstr, L'\n', 2) == wstr + 9); assert_true(wstr_n_substring_beg(wstr, L'\n', 2) == wstr + 9);
assert_true(wstr_n_substring_beg(wstr, L'\n', 3) == NULL); assert_true(wstr_n_substring_beg(wstr, L'\n', 3) == NULL);
#endif #endif
#ifdef FT_HAVE_UTF8
const char *utf8_str = "123\n5678\n9";
ASSERT_STR_EQUAL_STRONG(utf8_n_substring_beg(NULL, '\n', 0), NULL);
ASSERT_STR_EQUAL_STRONG(utf8_n_substring_beg(utf8_str, '\n', 0), utf8_str);
ASSERT_STR_EQUAL_STRONG(utf8_n_substring_beg(utf8_str, '1', 0), utf8_str);
ASSERT_STR_EQUAL_STRONG(utf8_n_substring_beg(utf8_str, '\n', 1), "5678\n9");
ASSERT_STR_EQUAL_STRONG(utf8_n_substring_beg(utf8_str, '\n', 2), "9");
ASSERT_STR_EQUAL_STRONG(utf8_n_substring_beg(utf8_str, '\n', 3), NULL);
#endif
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);
@ -126,6 +209,16 @@ void test_str_n_substring(void)
assert_true(wstr_n_substring_beg(wstr2, L'\xff0f', 5) == wstr2 + 11); assert_true(wstr_n_substring_beg(wstr2, L'\xff0f', 5) == wstr2 + 11);
assert_true(wstr_n_substring_beg(wstr2, L'\xff0f', 6) == NULL); assert_true(wstr_n_substring_beg(wstr2, L'\xff0f', 6) == NULL);
#endif #endif
#ifdef FT_HAVE_UTF8
const char *utf8_str2 = "\n123\n56\n\n9\n";
ASSERT_STR_EQUAL_STRONG(utf8_n_substring_beg(utf8_str2, '\n', 0), utf8_str2);
ASSERT_STR_EQUAL_STRONG(utf8_n_substring_beg(utf8_str2, '\n', 1), "123\n56\n\n9\n");
ASSERT_STR_EQUAL_STRONG(utf8_n_substring_beg(utf8_str2, '\n', 2), "56\n\n9\n");
ASSERT_STR_EQUAL_STRONG(utf8_n_substring_beg(utf8_str2, '\n', 3), "\n9\n");
ASSERT_STR_EQUAL_STRONG(utf8_n_substring_beg(utf8_str2, '\n', 4), "9\n");
ASSERT_STR_EQUAL_STRONG(utf8_n_substring_beg(utf8_str2, '\n', 5), "");
ASSERT_STR_EQUAL_STRONG(utf8_n_substring_beg(utf8_str2, '\n', 6), NULL);
#endif
const char *beg = NULL; const char *beg = NULL;
const char *end = NULL; const char *end = NULL;
@ -146,6 +239,16 @@ void test_str_n_substring(void)
wstr_n_substring(empty_wstr, L'\n', 2, &wbeg, &wend); wstr_n_substring(empty_wstr, L'\n', 2, &wbeg, &wend);
assert_true(wbeg == NULL && wend == NULL); assert_true(wbeg == NULL && wend == NULL);
#endif #endif
#ifdef FT_HAVE_UTF8
const void *utf8_beg = NULL;
const void *utf8_end = NULL;
utf8_n_substring(utf8_empty_str, '\n', 0, &utf8_beg, &utf8_end);
assert_true(utf8_beg == utf8_empty_str && utf8_end == utf8_empty_str + strlen(utf8_empty_str));
utf8_n_substring(utf8_empty_str, '\n', 1, &utf8_beg, &utf8_end);
assert_true(utf8_beg == NULL && utf8_end == NULL);
utf8_n_substring(utf8_empty_str, '\n', 2, &utf8_beg, &utf8_end);
assert_true(utf8_beg == NULL && utf8_end == NULL);
#endif
str_n_substring(NULL, '\n', 0, &beg, &end); str_n_substring(NULL, '\n', 0, &beg, &end);
@ -163,6 +266,14 @@ void test_str_n_substring(void)
wstr_n_substring(wstr, L'2', 0, &wbeg, &wend); wstr_n_substring(wstr, L'2', 0, &wbeg, &wend);
assert_true(wbeg == wstr && wend == wstr + 1); assert_true(wbeg == wstr && wend == wstr + 1);
#endif #endif
#ifdef FT_HAVE_UTF8
utf8_n_substring(NULL, '\n', 0, &utf8_beg, &utf8_end);
assert_true(utf8_beg == NULL && utf8_end == NULL);
utf8_n_substring(utf8_str, '\n', 0, &utf8_beg, &utf8_end);
assert_true(utf8_beg == utf8_str && utf8_end == utf8_str + 3);
utf8_n_substring(utf8_str, '2', 0, &utf8_beg, &utf8_end);
assert_true(utf8_beg == utf8_str && utf8_end == utf8_str + 1);
#endif
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);
@ -179,6 +290,14 @@ void test_str_n_substring(void)
wstr_n_substring(wstr, L'\n', 3, &wbeg, &wend); wstr_n_substring(wstr, L'\n', 3, &wbeg, &wend);
assert_true(wbeg == NULL && wend == NULL); assert_true(wbeg == NULL && wend == NULL);
#endif #endif
#ifdef FT_HAVE_UTF8
utf8_n_substring(utf8_str, '\n', 1, &utf8_beg, &utf8_end);
assert_true(utf8_beg == utf8_str + 4 && utf8_end == utf8_str + 8);
utf8_n_substring(utf8_str, '\n', 2, &utf8_beg, &utf8_end);
assert_true(utf8_beg == utf8_str + 9 && utf8_end == utf8_str + strlen(utf8_str));
utf8_n_substring(utf8_str, '\n', 3, &utf8_beg, &utf8_end);
assert_true(utf8_beg == NULL && end == NULL);
#endif
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);
@ -211,113 +330,226 @@ void test_str_n_substring(void)
wstr_n_substring(wstr2, L'\xff0f', 6, &wbeg, &wend); wstr_n_substring(wstr2, L'\xff0f', 6, &wbeg, &wend);
assert_true(wbeg == NULL && wend == NULL); assert_true(wbeg == NULL && wend == NULL);
#endif #endif
#if defined(FT_HAVE_WCHAR)
utf8_n_substring(utf8_str2, '\n', 0, &utf8_beg, &utf8_end);
assert_true(utf8_beg == utf8_str2 && utf8_end == utf8_str2);
utf8_n_substring(utf8_str2, '\n', 1, &utf8_beg, &utf8_end);
assert_true(utf8_beg == utf8_str2 + 1 && utf8_end == utf8_str2 + 4);
utf8_n_substring(utf8_str2, '\n', 2, &utf8_beg, &utf8_end);
assert_true(utf8_beg == utf8_str2 + 5 && utf8_end == utf8_str2 + 7);
utf8_n_substring(utf8_str2, '\n', 3, &utf8_beg, &utf8_end);
assert_true(utf8_beg == utf8_str2 + 8 && utf8_end == utf8_str2 + 8);
utf8_n_substring(utf8_str2, '\n', 4, &utf8_beg, &utf8_end);
assert_true(utf8_beg == utf8_str2 + 9 && utf8_end == utf8_str2 + 10);
utf8_n_substring(utf8_str2, '\n', 5, &utf8_beg, &utf8_end);
assert_true(utf8_beg == utf8_str2 + 11 && utf8_end == utf8_str2 + 11);
utf8_n_substring(utf8_str2, '\n', 6, &utf8_beg, &utf8_end);
assert_true(utf8_beg == NULL && utf8_end == NULL);
#endif
} }
void test_buffer_text_width(void) void test_buffer_text_visible_width(void)
{ {
string_buffer_t *buffer = create_string_buffer(200, CharBuf); string_buffer_t *buffer = create_string_buffer(200, CHAR_BUF);
buffer->type = CharBuf; buffer->type = CHAR_BUF;
char *old_value = buffer->str.cstr; char *old_value = buffer->str.cstr;
buffer->str.cstr = (char *)""; buffer->str.cstr = (char *)"";
assert_true(buffer_text_width(buffer) == 0); assert_true(buffer_text_visible_width(buffer) == 0);
buffer->str.cstr = (char *)"\n\n\n\n"; buffer->str.cstr = (char *)"\n\n\n\n";
assert_true(buffer_text_width(buffer) == 0); assert_true(buffer_text_visible_width(buffer) == 0);
buffer->str.cstr = (char *)"12345"; buffer->str.cstr = (char *)"12345";
assert_true(buffer_text_width(buffer) == 5); assert_true(buffer_text_visible_width(buffer) == 5);
buffer->str.cstr = (char *)"12345\n1234567"; buffer->str.cstr = (char *)"12345\n1234567";
assert_true(buffer_text_width(buffer) == 7); assert_true(buffer_text_visible_width(buffer) == 7);
buffer->str.cstr = (char *)"12345\n1234567\n"; buffer->str.cstr = (char *)"12345\n1234567\n";
assert_true(buffer_text_width(buffer) == 7); assert_true(buffer_text_visible_width(buffer) == 7);
buffer->str.cstr = (char *)"12345\n1234567\n123"; buffer->str.cstr = (char *)"12345\n1234567\n123";
assert_true(buffer_text_width(buffer) == 7); assert_true(buffer_text_visible_width(buffer) == 7);
#if defined(FT_HAVE_WCHAR) #if defined(FT_HAVE_WCHAR)
buffer->type = WCharBuf; buffer->type = W_CHAR_BUF;
buffer->str.wstr = (wchar_t *)L""; buffer->str.wstr = (wchar_t *)L"";
assert_true(buffer_text_width(buffer) == 0); assert_true(buffer_text_visible_width(buffer) == 0);
buffer->str.wstr = (wchar_t *)L"\n\n\n\n"; buffer->str.wstr = (wchar_t *)L"\n\n\n\n";
assert_true(buffer_text_width(buffer) == 0); assert_true(buffer_text_visible_width(buffer) == 0);
buffer->str.wstr = (wchar_t *)L"12345"; buffer->str.wstr = (wchar_t *)L"12345";
assert_true(buffer_text_width(buffer) == 5); assert_true(buffer_text_visible_width(buffer) == 5);
buffer->str.wstr = (wchar_t *)L"12345\n1234567"; buffer->str.wstr = (wchar_t *)L"12345\n1234567";
assert_true(buffer_text_width(buffer) == 7); assert_true(buffer_text_visible_width(buffer) == 7);
buffer->str.wstr = (wchar_t *)L"12345\n1234567\n"; buffer->str.wstr = (wchar_t *)L"12345\n1234567\n";
assert_true(buffer_text_width(buffer) == 7); assert_true(buffer_text_visible_width(buffer) == 7);
buffer->str.wstr = (wchar_t *)L"12345\n1234567\n123"; buffer->str.wstr = (wchar_t *)L"12345\n1234567\n123";
assert_true(buffer_text_width(buffer) == 7); assert_true(buffer_text_visible_width(buffer) == 7);
#endif #endif
buffer->type = CharBuf; #if defined(FT_HAVE_UTF8)
buffer->type = UTF8_BUF;
buffer->str.u8str = (void *)"";
assert_true(buffer_text_visible_width(buffer) == 0);
buffer->str.u8str = (void *)"\n\n\n\n";
assert_true(buffer_text_visible_width(buffer) == 0);
buffer->str.u8str = (void *)"12345";
assert_true(buffer_text_visible_width(buffer) == 5);
buffer->str.u8str = (void *)"12345\n1234567";
assert_true(buffer_text_visible_width(buffer) == 7);
buffer->str.u8str = (void *)"12345\n1234567\n";
assert_true(buffer_text_visible_width(buffer) == 7);
buffer->str.u8str = (void *)"12345\n1234567\n123";
assert_true(buffer_text_visible_width(buffer) == 7);
/* panagrams from http://clagnut.com/blog/2380/ */
/* 10 20 30 40 50 60 70 80 90 100 110 */
buffer->str.u8str = (void *)"Numbers 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
assert_true(buffer_text_visible_width(buffer) == 110);
buffer->str.u8str = (void *)"Chinese 視野無限廣, 窗外有藍天";
assert_true(buffer_text_visible_width(buffer) == 22);
buffer->str.u8str = (void *)"German Falsches Üben von Xylophonmusik quält jeden größeren Zwerg";
assert_true(buffer_text_visible_width(buffer) == 68);
buffer->str.u8str = (void *)"Greek Ταχίστη αλώπηξ βαφής ψημένη γη, δρασκελίζει υπέρ νωθρού κυνός Takhístè";
assert_true(buffer_text_visible_width(buffer) == 80);
buffer->str.u8str = (void *)"Irish Dḟuascail Íosa Úrṁac na hÓiġe Beannaiṫe pór Éaḃa agus Áḋaiṁ";
assert_true(buffer_text_visible_width(buffer) == 70);
buffer->str.u8str = (void *)"Japanese いろはにほへと ちりぬるを わかよたれそ つねならむ うゐ";
assert_true(buffer_text_visible_width(buffer) == 39);
buffer->str.u8str = (void *)"Polish Pójdźże, kiń tę chmurność w głąb flaszy";
assert_true(buffer_text_visible_width(buffer) == 49);
buffer->str.u8str = (void *)"Portuguese Luís argüia à Júlia que «brações, fé, chá, óxido, pôr, zângão» eram palavras do português";
assert_true(buffer_text_visible_width(buffer) == 100);
buffer->str.u8str = (void *)"Russian Съешь же ещё этих мягких французских булок, да выпей чаю";
assert_true(buffer_text_visible_width(buffer) == 66);
buffer->str.u8str = (void *)"Spanish Benjamín pidió una bebida de kiwi y fresa; Noé, sin vergüenza, la más exquisita champaña del menú";
assert_true(buffer_text_visible_width(buffer) == 107);
buffer->str.u8str = (void *)"Turkish Vakfın çoğu bu huysuz genci plajda görmüştü";
assert_true(buffer_text_visible_width(buffer) == 53);
/* 10 20 30 40 50 60 70 80 90 100 110 */
buffer->str.u8str = (void *)"Numbers 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
assert_true(buffer_text_visible_width(buffer) == 110);
buffer->str.u8str = (void *)"Chinese 視野無限廣,\n 窗外有藍天";
assert_true(buffer_text_visible_width(buffer) == 16);
buffer->str.u8str = (void *)"German Falsches Üben von Xy\nlophonmusik quält \njeden größeren Zwerg";
assert_true(buffer_text_visible_width(buffer) == 30);
buffer->str.u8str = (void *)"Greek Ταχίστη αλώπηξ βαφής\n ψημένη γη, δρασκελίζει\n υπέρ νωθρού \nκυνός Takhístè";
assert_true(buffer_text_visible_width(buffer) == 30);
buffer->str.u8str = (void *)"Irish Dḟuascail Íosa Úrṁa\nc na hÓiġe Beannaiṫe\n pór Éaḃa agus Áḋaiṁ";
assert_true(buffer_text_visible_width(buffer) == 30);
buffer->str.u8str = (void *)"Japanese いろはにほへと ちり\nぬるを わかよたれそ つねならむ うゐ";
assert_true(buffer_text_visible_width(buffer) == 20);
buffer->str.u8str = (void *)"Polish Pójdźże, kiń tę chmu\nrność w głąb flaszy";
assert_true(buffer_text_visible_width(buffer) == 30);
buffer->str.u8str = (void *)"Portuguese Luís argüia à Júlia\n que «brações, fé, chá,\n óxido, pôr, \nzângão» eram palavras\n do português";
assert_true(buffer_text_visible_width(buffer) == 30);
buffer->str.u8str = (void *)"Russian Съешь же ещё этих мя\nгких французских булок,\n да выпей чаю";
assert_true(buffer_text_visible_width(buffer) == 30);
buffer->str.u8str = (void *)"Spanish Benjamín pidió una b\nebida de kiwi y fresa;\n Noé, sin vergüenza,\n la más exquisita\n champaña del menú";
assert_true(buffer_text_visible_width(buffer) == 30);
buffer->str.u8str = (void *)"Turkish Vakfın çoğu bu huysu\nz genci plajda gö\nrmüştü";
assert_true(buffer_text_visible_width(buffer) == 30);
#endif
buffer->type = CHAR_BUF;
buffer->str.cstr = old_value; buffer->str.cstr = old_value;
destroy_string_buffer(buffer); destroy_string_buffer(buffer);
} }
void test_buffer_text_height(void) void test_buffer_text_visible_height(void)
{ {
string_buffer_t *buffer = create_string_buffer(200, CharBuf); string_buffer_t *buffer = create_string_buffer(200, CHAR_BUF);
buffer->type = CharBuf; buffer->type = CHAR_BUF;
char *old_value = buffer->str.cstr; char *old_value = buffer->str.cstr;
buffer->str.cstr = (char *)""; buffer->str.cstr = (char *)"";
assert_true(buffer_text_height(buffer) == 0); assert_true(buffer_text_visible_height(buffer) == 0);
buffer->str.cstr = (char *)"\n"; buffer->str.cstr = (char *)"\n";
assert_true(buffer_text_height(buffer) == 2); assert_true(buffer_text_visible_height(buffer) == 2);
buffer->str.cstr = (char *)"\n\n"; buffer->str.cstr = (char *)"\n\n";
assert_true(buffer_text_height(buffer) == 3); assert_true(buffer_text_visible_height(buffer) == 3);
buffer->str.cstr = (char *)"\n\n\n\n"; buffer->str.cstr = (char *)"\n\n\n\n";
assert_true(buffer_text_height(buffer) == 5); assert_true(buffer_text_visible_height(buffer) == 5);
buffer->str.cstr = (char *)"12345"; buffer->str.cstr = (char *)"12345";
assert_true(buffer_text_height(buffer) == 1); assert_true(buffer_text_visible_height(buffer) == 1);
buffer->str.cstr = (char *)"\n12345"; buffer->str.cstr = (char *)"\n12345";
assert_true(buffer_text_height(buffer) == 2); assert_true(buffer_text_visible_height(buffer) == 2);
buffer->str.cstr = (char *)"\n12345\n\n2"; buffer->str.cstr = (char *)"\n12345\n\n2";
assert_true(buffer_text_height(buffer) == 4); assert_true(buffer_text_visible_height(buffer) == 4);
#if defined(FT_HAVE_WCHAR) #if defined(FT_HAVE_WCHAR)
buffer->type = WCharBuf; buffer->type = W_CHAR_BUF;
buffer->str.wstr = (wchar_t *)L""; buffer->str.wstr = (wchar_t *)L"";
assert_true(buffer_text_height(buffer) == 0); assert_true(buffer_text_visible_height(buffer) == 0);
buffer->str.wstr = (wchar_t *)L"\n"; buffer->str.wstr = (wchar_t *)L"\n";
assert_true(buffer_text_height(buffer) == 2); assert_true(buffer_text_visible_height(buffer) == 2);
buffer->str.wstr = (wchar_t *)L"\n\n"; buffer->str.wstr = (wchar_t *)L"\n\n";
assert_true(buffer_text_height(buffer) == 3); assert_true(buffer_text_visible_height(buffer) == 3);
buffer->str.wstr = (wchar_t *)L"\n\n\n\n"; buffer->str.wstr = (wchar_t *)L"\n\n\n\n";
assert_true(buffer_text_height(buffer) == 5); assert_true(buffer_text_visible_height(buffer) == 5);
buffer->str.wstr = (wchar_t *)L"\xff0fy2345\xff0f"; buffer->str.wstr = (wchar_t *)L"\xff0fy2345\xff0f";
assert_true(buffer_text_height(buffer) == 1); assert_true(buffer_text_visible_height(buffer) == 1);
buffer->str.wstr = (wchar_t *)L"\n12345"; buffer->str.wstr = (wchar_t *)L"\n12345";
assert_true(buffer_text_height(buffer) == 2); assert_true(buffer_text_visible_height(buffer) == 2);
buffer->str.wstr = (wchar_t *)L"\n12345\n\n2"; buffer->str.wstr = (wchar_t *)L"\n12345\n\n2";
assert_true(buffer_text_height(buffer) == 4); assert_true(buffer_text_visible_height(buffer) == 4);
#endif
#if defined(FT_HAVE_UTF8)
buffer->type = UTF8_BUF;
buffer->str.u8str = (void *)"";
assert_true(buffer_text_visible_height(buffer) == 0);
buffer->str.u8str = (void *)"\n";
assert_true(buffer_text_visible_height(buffer) == 2);
buffer->str.u8str = (void *)"\n\n";
assert_true(buffer_text_visible_height(buffer) == 3);
buffer->str.u8str = (void *)"\n\n\n\n";
assert_true(buffer_text_visible_height(buffer) == 5);
buffer->str.u8str = (void *)"12345";
assert_true(buffer_text_visible_height(buffer) == 1);
buffer->str.u8str = (void *)"\n12345";
assert_true(buffer_text_visible_height(buffer) == 2);
buffer->str.u8str = (void *)"\n12345\n\n2";
assert_true(buffer_text_visible_height(buffer) == 4);
#endif #endif
buffer->type = CharBuf; buffer->type = CHAR_BUF;
buffer->str.cstr = old_value; buffer->str.cstr = old_value;
destroy_string_buffer(buffer); destroy_string_buffer(buffer);
} }
@ -367,3 +599,59 @@ void test_wchar_basics(void)
#endif #endif
} }
#endif #endif
static void test_print_n_strings_(const char *str, size_t n)
{
int sz = n * strlen(str);
{
string_buffer_t *buffer = create_string_buffer(200, CHAR_BUF);
conv_context_t cntx;
cntx.buf = (char *)buffer_get_data(buffer);
cntx.buf_origin = (char *)buffer_get_data(buffer);
cntx.raw_avail = 200;
cntx.b_type = CHAR_BUF;
assert_true(print_n_strings(&cntx, n, str) == sz);
assert_true(cntx.buf - cntx.buf_origin == sz);
destroy_string_buffer(buffer);
}
{
string_buffer_t *buffer = create_string_buffer(200, W_CHAR_BUF);
conv_context_t cntx;
cntx.buf = (char *)buffer_get_data(buffer);
cntx.buf_origin = (char *)buffer_get_data(buffer);
cntx.raw_avail = 200;
cntx.b_type = W_CHAR_BUF;
assert_true(print_n_strings(&cntx, n, str) == /*sizeof(wchar_t) **/ sz);
assert_true(cntx.buf - cntx.buf_origin == sizeof(wchar_t) * sz);
destroy_string_buffer(buffer);
}
{
string_buffer_t *buffer = create_string_buffer(200, UTF8_BUF);
conv_context_t cntx;
cntx.buf = (char *)buffer_get_data(buffer);
cntx.buf_origin = (char *)buffer_get_data(buffer);
cntx.raw_avail = 200;
cntx.b_type = UTF8_BUF;
assert_true(print_n_strings(&cntx, n, str) == sz);
assert_true(cntx.buf - cntx.buf_origin == sz);
destroy_string_buffer(buffer);
}
}
void test_print_n_strings(void)
{
test_print_n_strings_("", 0);
test_print_n_strings_("", 1);
test_print_n_strings_("", 2);
test_print_n_strings_(" ", 0);
test_print_n_strings_(" ", 1);
test_print_n_strings_(" ", 2);
test_print_n_strings_("foo", 0);
test_print_n_strings_("foo", 1);
test_print_n_strings_("foo", 2);
}