[C] Refactoring for utf-8
This commit is contained in:
parent
d3d3e1821c
commit
3e961b053a
@ -99,6 +99,7 @@ def main():
|
||||
"fort_utils.h",
|
||||
"vector.h",
|
||||
"wcwidth.h",
|
||||
"utf8.h",
|
||||
"string_buffer.h",
|
||||
"properties.h",
|
||||
"cell.h",
|
||||
|
@ -231,6 +231,65 @@ void colorfull_table(void)
|
||||
|
||||
ft_destroy_table(table);
|
||||
#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
2891
lib/fort.c
File diff suppressed because it is too large
Load Diff
18
lib/fort.h
18
lib/fort.h
@ -63,6 +63,10 @@ SOFTWARE.
|
||||
#define FT_HAVE_WCHAR
|
||||
#endif
|
||||
|
||||
#define FT_CONGIG_HAVE_UTF8
|
||||
#if defined(FT_CONGIG_HAVE_UTF8)
|
||||
#define FT_HAVE_UTF8
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* 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.
|
||||
*
|
||||
@ -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
|
||||
|
||||
#endif /* LIBFORT_H */
|
||||
|
134
src/cell.c
134
src/cell.c
@ -14,7 +14,7 @@ fort_cell_t *create_cell(void)
|
||||
fort_cell_t *cell = (fort_cell_t *)F_CALLOC(sizeof(fort_cell_t), 1);
|
||||
if (cell == 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) {
|
||||
F_FREE(cell);
|
||||
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 result = cell_padding_left + cell_padding_right;
|
||||
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));
|
||||
|
||||
@ -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 result = cell_padding_top + cell_padding_bottom;
|
||||
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;
|
||||
}
|
||||
return result;
|
||||
@ -121,14 +121,12 @@ size_t hint_height_cell(const fort_cell_t *cell, const context_t *context)
|
||||
|
||||
|
||||
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 = " ";
|
||||
int (*buffer_printf_)(string_buffer_t *, size_t, char *, size_t, const context_t *, const char *, const char *) = buffer_printf;
|
||||
int (*snprint_n_strings_)(char *, size_t, size_t, const char *) = snprint_n_strings;
|
||||
const context_t *context = cntx->cntx;
|
||||
size_t buf_len = vis_width;
|
||||
|
||||
if (cell == NULL || buf_len == 0
|
||||
|| (buf_len <= hint_width_cell(cell, context, VISIBLE_GEOMETRY))) {
|
||||
if (cell == NULL || (vis_width < hint_width_cell(cell, context, VISIBLE_GEOMETRY))) {
|
||||
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 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_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))
|
||||
#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(print_n_strings(cntx, 1, reset_cell_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(print_n_strings(cntx, 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))) {
|
||||
|| row >= (cell_padding_top + buffer_text_visible_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));
|
||||
CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, buf_len - TOTAL_WRITTEN - R3, FT_SPACE));
|
||||
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));
|
||||
CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, L2, FT_SPACE));
|
||||
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 {
|
||||
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_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;
|
||||
|
||||
return (int)TOTAL_WRITTEN;
|
||||
@ -213,101 +214,6 @@ clear:
|
||||
#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
|
||||
fort_status_t fill_cell_from_string(fort_cell_t *cell, const char *str)
|
||||
{
|
||||
|
@ -25,15 +25,12 @@ FT_INTERNAL
|
||||
enum CellType get_cell_type(const fort_cell_t *cell);
|
||||
|
||||
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
|
||||
fort_status_t fill_cell_from_string(fort_cell_t *cell, const char *str);
|
||||
|
||||
#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
|
||||
fort_status_t fill_cell_from_wstring(fort_cell_t *cell, const wchar_t *str);
|
||||
#endif
|
||||
|
18
src/fort.h
18
src/fort.h
@ -63,6 +63,10 @@ SOFTWARE.
|
||||
#define FT_HAVE_WCHAR
|
||||
#endif
|
||||
|
||||
#define FT_CONGIG_HAVE_UTF8
|
||||
#if defined(FT_CONGIG_HAVE_UTF8)
|
||||
#define FT_HAVE_UTF8
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* 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.
|
||||
*
|
||||
@ -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
|
||||
|
||||
#endif /* LIBFORT_H */
|
||||
|
366
src/fort_impl.c
366
src/fort_impl.c
@ -344,6 +344,23 @@ static int ft_write_impl(ft_table_t *table, const char *cell_content)
|
||||
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
|
||||
|
||||
@ -412,6 +429,9 @@ int ft_nwrite_ln(ft_table_t *table, size_t count, const char *cell_content, ...)
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef FT_HAVE_WCHAR
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
{
|
||||
typedef char char_type;
|
||||
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;
|
||||
return ft_to_string_impl(table, CHAR_BUF);
|
||||
}
|
||||
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
|
||||
|
||||
const wchar_t *ft_to_wstring(const ft_table_t *table)
|
||||
{
|
||||
typedef wchar_t char_type;
|
||||
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;
|
||||
return (const wchar_t *)ft_to_string_impl(table, W_CHAR_BUF);
|
||||
}
|
||||
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
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
#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 */
|
||||
|
164
src/fort_utils.c
164
src/fort_utils.c
@ -2,6 +2,9 @@
|
||||
#ifdef FT_HAVE_WCHAR
|
||||
#include <wchar.h>
|
||||
#endif
|
||||
#if defined(FT_HAVE_UTF8)
|
||||
#include "utf8.h"
|
||||
#endif
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
#if defined(FT_HAVE_UTF8)
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
#define WCS_SIZE 64
|
||||
|
||||
FT_INTERNAL
|
||||
static
|
||||
int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *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).
|
||||
*/
|
||||
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);
|
||||
}
|
||||
#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
|
||||
|
@ -35,12 +35,16 @@ extern char g_col_separator;
|
||||
#define F_REALLOC fort_realloc
|
||||
#define F_STRDUP fort_strdup
|
||||
#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 MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#define FT_NEWLINE "\n"
|
||||
#define FT_SPACE " "
|
||||
|
||||
enum PolicyOnNull {
|
||||
Create,
|
||||
@ -53,6 +57,20 @@ enum F_BOOL {
|
||||
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) \
|
||||
arg1##arg2
|
||||
@ -117,6 +135,16 @@ enum request_geom_type {
|
||||
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
|
||||
*****************************************************************************/
|
||||
@ -144,18 +172,38 @@ size_t number_of_columns_in_format_wstring(const wchar_t *fmt);
|
||||
#endif
|
||||
|
||||
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
|
||||
int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *str);
|
||||
#endif
|
||||
int ft_nprint(conv_context_t *cntx, const char *str, size_t strlen);
|
||||
#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) \
|
||||
do { \
|
||||
tmp = statement; \
|
||||
if (tmp < 0) {\
|
||||
PRINT_DEBUG_INFO \
|
||||
goto clear; \
|
||||
} \
|
||||
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 { \
|
||||
tmp = statement; \
|
||||
if (tmp < 0) {\
|
||||
PRINT_DEBUG_INFO \
|
||||
goto clear; \
|
||||
} \
|
||||
invisible_written += (size_t)tmp; \
|
||||
|
353
src/row.c
353
src/row.c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
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 fort_row_t *upper_row, const fort_row_t *lower_row,
|
||||
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(buffer);
|
||||
assert(context);
|
||||
assert(cntx);
|
||||
|
||||
const char *space_char = " ";
|
||||
int status = -1;
|
||||
|
||||
const context_t *context = cntx->cntx;
|
||||
|
||||
/* Get cell types
|
||||
*
|
||||
* 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 */
|
||||
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) {
|
||||
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 {
|
||||
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));
|
||||
CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 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));
|
||||
CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *II));
|
||||
} 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 {
|
||||
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 */
|
||||
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;
|
||||
|
||||
@ -411,194 +409,15 @@ clear:
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef FT_HAVE_WCHAR
|
||||
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 fort_row_t *upper_row, const fort_row_t *lower_row,
|
||||
enum HorSeparatorPos separatorPos, const separator_t *sep,
|
||||
const context_t *context)
|
||||
enum HorSeparatorPos separatorPos, const separator_t *sep)
|
||||
{
|
||||
int (*snprint_n_strings_)(wchar_t *, size_t, size_t, const char *) = wsnprint_n_string;
|
||||
|
||||
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;
|
||||
return print_row_separator_impl(cntx, col_width_arr, cols, upper_row, lower_row,
|
||||
separatorPos, sep);
|
||||
}
|
||||
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
|
||||
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 NUMBER_OF_COLUMNS_IN_FORMAT_STRING number_of_columns_in_format_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);
|
||||
if (buffer == NULL)
|
||||
@ -796,14 +615,14 @@ fort_row_t *create_row_from_fmt_string(const char *fmt, va_list *va_args)
|
||||
while (1) {
|
||||
va_list va;
|
||||
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);
|
||||
/* If error encountered */
|
||||
if (virtual_sz < 0)
|
||||
goto clear;
|
||||
|
||||
/* Successful write */
|
||||
if ((size_t)virtual_sz < string_buffer_capacity(buffer))
|
||||
if ((size_t)virtual_sz < string_buffer_width_capacity(buffer))
|
||||
break;
|
||||
|
||||
/* 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 NUMBER_OF_COLUMNS_IN_FORMAT_STRING number_of_columns_in_format_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);
|
||||
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) {
|
||||
va_list va;
|
||||
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);
|
||||
/* If error encountered */
|
||||
if (virtual_sz < 0)
|
||||
goto clear;
|
||||
|
||||
/* Successful write */
|
||||
if ((size_t)virtual_sz < string_buffer_capacity(buffer))
|
||||
if ((size_t)virtual_sz < string_buffer_width_capacity(buffer))
|
||||
break;
|
||||
|
||||
/* Otherwise buffer was too small, so incr. buffer size ant try again. */
|
||||
@ -950,12 +769,10 @@ clear:
|
||||
|
||||
|
||||
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,
|
||||
size_t row_height, const context_t *context)
|
||||
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)
|
||||
{
|
||||
int (*snprint_n_strings_)(char *, size_t, size_t, const char *) = snprint_n_strings;
|
||||
int (*cell_printf_)(fort_cell_t *, size_t, char *, size_t, const context_t *) = cell_printf;
|
||||
|
||||
const context_t *context = cntx->cntx;
|
||||
assert(context);
|
||||
const char *space_char = " ";
|
||||
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;
|
||||
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));
|
||||
CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 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));
|
||||
CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 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 cell_vis_width = 0;
|
||||
|
||||
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 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;
|
||||
cell_vis_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));
|
||||
CHCK_RSLT_ADD_TO_WRITTEN(cell_printf(cell, i, cntx, cell_vis_width));
|
||||
} else {
|
||||
/* 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 */
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
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 */
|
||||
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;
|
||||
|
||||
clear:
|
||||
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
|
||||
|
||||
|
||||
|
20
src/row.h
20
src/row.h
@ -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);
|
||||
|
||||
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 fort_row_t *upper_row, const fort_row_t *lower_row,
|
||||
enum HorSeparatorPos separatorPos, const separator_t *sep,
|
||||
const context_t *context);
|
||||
enum HorSeparatorPos separatorPos, const separator_t *sep);
|
||||
|
||||
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,
|
||||
size_t row_height, const context_t *context);
|
||||
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);
|
||||
|
||||
#ifdef FT_HAVE_WCHAR
|
||||
FT_INTERNAL
|
||||
@ -66,17 +65,6 @@ fort_row_t *create_row_from_wstring(const wchar_t *str);
|
||||
|
||||
FT_INTERNAL
|
||||
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
|
||||
|
||||
|
||||
|
@ -3,8 +3,12 @@
|
||||
#include "wcwidth.h"
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#ifdef FT_HAVE_WCHAR
|
||||
#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)
|
||||
{
|
||||
@ -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)
|
||||
{
|
||||
assert(buf);
|
||||
if (buf->type == CharBuf) {
|
||||
|
||||
switch (buf->type) {
|
||||
case CHAR_BUF:
|
||||
return strlen(buf->str.cstr);
|
||||
} else {
|
||||
#ifdef FT_HAVE_WCHAR
|
||||
case W_CHAR_BUF:
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#ifdef FT_HAVE_WCHAR
|
||||
FT_INTERNAL
|
||||
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;
|
||||
}
|
||||
#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
|
||||
@ -112,6 +155,29 @@ const wchar_t *wstr_n_substring_beg(const wchar_t *str, wchar_t ch_separator, si
|
||||
}
|
||||
#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
|
||||
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 */
|
||||
|
||||
#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
|
||||
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));
|
||||
if (result == 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->type = type;
|
||||
|
||||
if (sz && type == CharBuf) {
|
||||
if (sz && type == CHAR_BUF) {
|
||||
result->str.cstr[0] = '\0';
|
||||
#ifdef FT_HAVE_WCHAR
|
||||
} else if (sz && type == WCharBuf) {
|
||||
} else if (sz && type == W_CHAR_BUF) {
|
||||
result->str.wstr[0] = L'\0';
|
||||
#endif /* FT_HAVE_WCHAR */
|
||||
}
|
||||
@ -202,14 +291,14 @@ string_buffer_t *copy_string_buffer(const string_buffer_t *buffer)
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
switch (buffer->type) {
|
||||
case CharBuf:
|
||||
case CHAR_BUF:
|
||||
if (FT_IS_ERROR(fill_buffer_from_string(result, buffer->str.cstr))) {
|
||||
destroy_string_buffer(result);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
#ifdef FT_HAVE_WCHAR
|
||||
case WCharBuf:
|
||||
case W_CHAR_BUF:
|
||||
if (FT_IS_ERROR(fill_buffer_from_wstring(result, buffer->str.wstr))) {
|
||||
destroy_string_buffer(result);
|
||||
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);
|
||||
buffer->str.cstr = copy;
|
||||
buffer->type = CharBuf;
|
||||
buffer->type = CHAR_BUF;
|
||||
|
||||
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);
|
||||
buffer->str.wstr = copy;
|
||||
buffer->type = WCharBuf;
|
||||
buffer->type = W_CHAR_BUF;
|
||||
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
#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
|
||||
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) {
|
||||
return 0;
|
||||
}
|
||||
if (buffer->type == CharBuf)
|
||||
if (buffer->type == CHAR_BUF)
|
||||
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');
|
||||
#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
|
||||
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;
|
||||
if (buffer->type == CharBuf) {
|
||||
if (buffer->type == CHAR_BUF) {
|
||||
size_t n = 0;
|
||||
while (1) {
|
||||
const char *beg = NULL;
|
||||
@ -306,7 +450,7 @@ size_t buffer_text_width(const string_buffer_t *buffer)
|
||||
++n;
|
||||
}
|
||||
#ifdef FT_HAVE_WCHAR
|
||||
} else {
|
||||
} else if (buffer->type == W_CHAR_BUF) {
|
||||
size_t n = 0;
|
||||
while (1) {
|
||||
const wchar_t *beg = NULL;
|
||||
@ -323,149 +467,110 @@ size_t buffer_text_width(const string_buffer_t *buffer)
|
||||
++n;
|
||||
}
|
||||
#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 */
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
static void
|
||||
buffer_substring(const string_buffer_t *buffer, size_t buffer_row, void **begin, void **end, ptrdiff_t *str_it_width)
|
||||
{
|
||||
#define CHAR_TYPE char
|
||||
#define NULL_CHAR '\0'
|
||||
#define NEWLINE_CHAR '\n'
|
||||
#define SPACE_CHAR " "
|
||||
#define SNPRINTF_FMT_STR "%*s"
|
||||
#define SNPRINTF snprintf
|
||||
#define BUFFER_STR 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;
|
||||
switch (buffer->type) {
|
||||
case CHAR_BUF:
|
||||
str_n_substring(buffer->str.cstr, '\n', buffer_row, (const char **)begin, (const char **)end);
|
||||
if ((*(const char **)begin) && (*(const char **)end))
|
||||
*str_it_width = str_iter_width(*(const char **)begin, *(const char **)end);
|
||||
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
|
||||
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)
|
||||
{
|
||||
#define CHAR_TYPE wchar_t
|
||||
#define NULL_CHAR L'\0'
|
||||
#define NEWLINE_CHAR L'\n'
|
||||
#define SPACE_CHAR " "
|
||||
#define SNPRINTF_FMT_STR L"%*ls"
|
||||
#define SNPRINTF swprintf
|
||||
#define BUFFER_STR str.wstr
|
||||
#define SNPRINT_N_STRINGS wsnprint_n_string
|
||||
#define STR_N_SUBSTRING wstr_n_substring
|
||||
#define STR_ITER_WIDTH wcs_iter_width
|
||||
case W_CHAR_BUF:
|
||||
wstr_n_substring(buffer->str.wstr, L'\n', buffer_row, (const wchar_t **)begin, (const wchar_t **)end);
|
||||
if ((*(const wchar_t **)begin) && (*(const wchar_t **)end))
|
||||
*str_it_width = wcs_iter_width(*(const wchar_t **)begin, *(const wchar_t **)end);
|
||||
break;
|
||||
#endif /* FT_HAVE_WCHAR */
|
||||
#ifdef FT_HAVE_UTF8
|
||||
case UTF8_BUF:
|
||||
utf8_n_substring(buffer->str.wstr, '\n', buffer_row, begin, end);
|
||||
if ((*(const char **)begin) && (*(const char **)end))
|
||||
*str_it_width = ut8_width(*begin, *end);
|
||||
break;
|
||||
#endif /* FT_HAVE_UTF8 */
|
||||
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
|
||||
|| buffer_row >= buffer_text_height(buffer) || buf_len == 0) {
|
||||
|| buffer_row >= buffer_text_visible_height(buffer)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t content_width = buffer_text_width(buffer);
|
||||
if ((buf_len - 1) < content_width)
|
||||
size_t content_width = buffer_text_visible_width(buffer);
|
||||
if (vis_width < 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)) {
|
||||
switch (get_cell_property_value_hierarcial(props, row, column, FT_CPROP_TEXT_ALIGN)) {
|
||||
case FT_ALIGNED_LEFT:
|
||||
left = 0;
|
||||
right = (buf_len - 1) - content_width;
|
||||
right = (vis_width) - content_width;
|
||||
break;
|
||||
case FT_ALIGNED_CENTER:
|
||||
left = ((buf_len - 1) - content_width) / 2;
|
||||
right = ((buf_len - 1) - content_width) - left;
|
||||
left = ((vis_width) - content_width) / 2;
|
||||
right = ((vis_width) - content_width) - left;
|
||||
break;
|
||||
case FT_ALIGNED_RIGHT:
|
||||
left = (buf_len - 1) - content_width;
|
||||
left = (vis_width) - content_width;
|
||||
right = 0;
|
||||
break;
|
||||
default:
|
||||
@ -473,64 +578,41 @@ int buffer_wprintf(string_buffer_t *buffer, size_t buffer_row, wchar_t *buf, siz
|
||||
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);
|
||||
const void *beg = NULL;
|
||||
const void *end = NULL;
|
||||
buffer_substring(buffer, buffer_row, (void **)&beg, (void **)&end, &str_it_width);
|
||||
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;
|
||||
return -1;
|
||||
|
||||
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));
|
||||
size_t padding = content_width - (size_t)str_it_width;
|
||||
|
||||
*(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));
|
||||
CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, left, FT_SPACE));
|
||||
CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, content_style_tag));
|
||||
CHCK_RSLT_ADD_TO_WRITTEN(buffer_print_range(cntx, beg, end));
|
||||
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;
|
||||
|
||||
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
|
||||
}
|
||||
#endif /* FT_HAVE_WCHAR */
|
||||
|
||||
|
||||
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);
|
||||
if (buffer->type == CharBuf)
|
||||
if (buffer->type == CHAR_BUF)
|
||||
return buffer->data_sz;
|
||||
else
|
||||
else if (buffer->type == W_CHAR_BUF)
|
||||
return buffer->data_sz / sizeof(wchar_t);
|
||||
else if (buffer->type == UTF8_BUF)
|
||||
return buffer->data_sz / 4;
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,17 +7,16 @@
|
||||
/*****************************************************************************
|
||||
* STRING BUFFER
|
||||
* ***************************************************************************/
|
||||
enum str_buf_type {
|
||||
CharBuf,
|
||||
#ifdef FT_HAVE_WCHAR
|
||||
WCharBuf
|
||||
#endif /* FT_HAVE_WCHAR */
|
||||
};
|
||||
|
||||
struct string_buffer {
|
||||
union {
|
||||
char *cstr;
|
||||
#ifdef FT_HAVE_WCHAR
|
||||
wchar_t *wstr;
|
||||
#endif
|
||||
#ifdef FT_HAVE_UTF8
|
||||
void *u8str;
|
||||
#endif
|
||||
void *data;
|
||||
} str;
|
||||
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);
|
||||
#endif /* FT_HAVE_WCHAR */
|
||||
|
||||
#ifdef FT_HAVE_UTF8
|
||||
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
|
||||
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
|
||||
void *buffer_get_data(string_buffer_t *buffer);
|
||||
|
||||
FT_INTERNAL
|
||||
size_t buffer_text_width(const string_buffer_t *buffer);
|
||||
|
||||
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 */
|
||||
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);
|
||||
|
||||
#endif /* STRING_BUFFER_H */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -46,4 +46,11 @@ fort_status_t table_rows_and_cols_geometry(const ft_table_t *table,
|
||||
FT_INTERNAL
|
||||
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 */
|
||||
|
@ -125,12 +125,55 @@ void test_bug_fixes(void)
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
#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)
|
||||
{
|
||||
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") {
|
||||
table = ft_create_table();
|
||||
assert_true(table != NULL);
|
||||
@ -193,6 +236,39 @@ void test_table_basic(void)
|
||||
}
|
||||
#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") {
|
||||
table = ft_create_table();
|
||||
assert_true(table != NULL);
|
||||
@ -255,6 +331,38 @@ void test_table_basic(void)
|
||||
}
|
||||
#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") {
|
||||
table = ft_create_table();
|
||||
assert_true(table != NULL);
|
||||
@ -317,6 +425,38 @@ void test_table_basic(void)
|
||||
}
|
||||
#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") {
|
||||
table = ft_create_table();
|
||||
assert_true(table != NULL);
|
||||
@ -378,6 +518,40 @@ void test_table_basic(void)
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
#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
|
||||
|
||||
#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)
|
||||
{
|
||||
|
@ -22,6 +22,9 @@ void test_table_cell_properties(void);
|
||||
void test_table_text_styles(void);
|
||||
void test_table_tbl_properties(void);
|
||||
void test_memory_errors(void);
|
||||
#ifdef FT_HAVE_UTF8
|
||||
void test_utf8_table(void);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef FORT_WB_TESTING_ENABLED
|
||||
@ -41,6 +44,9 @@ struct test_case bb_test_suite [] = {
|
||||
{"test_table_basic", test_table_basic},
|
||||
#ifdef FT_HAVE_WCHAR
|
||||
{"test_wcs_table_boundaries", test_wcs_table_boundaries},
|
||||
#endif
|
||||
#ifdef FT_HAVE_UTF8
|
||||
{"test_utf8_table", test_utf8_table},
|
||||
#endif
|
||||
{"test_table_write", test_table_write},
|
||||
{"test_table_changing_cell", test_table_changing_cell},
|
||||
|
@ -2,39 +2,53 @@
|
||||
#include "string_buffer.h"
|
||||
#include "wcwidth.h"
|
||||
#include <wchar.h>
|
||||
|
||||
#if defined(FT_HAVE_UTF8)
|
||||
#include "utf8.h"
|
||||
#endif
|
||||
|
||||
size_t strchr_count(const char *str, char 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 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);
|
||||
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_str_n_substring(void);
|
||||
void test_buffer_text_width(void);
|
||||
void test_buffer_text_height(void);
|
||||
void test_buffer_text_visible_width(void);
|
||||
void test_buffer_text_visible_height(void);
|
||||
#if defined(FT_HAVE_WCHAR)
|
||||
void test_wchar_basics(void);
|
||||
#endif
|
||||
void test_print_n_strings(void);
|
||||
|
||||
|
||||
|
||||
void test_string_buffer(void)
|
||||
{
|
||||
test_strchr_count();
|
||||
test_str_n_substring();
|
||||
test_buffer_text_width();
|
||||
test_buffer_text_height();
|
||||
test_buffer_text_visible_width();
|
||||
test_buffer_text_visible_height();
|
||||
#if defined(FT_HAVE_WCHAR)
|
||||
test_wchar_basics();
|
||||
#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"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)
|
||||
{
|
||||
@ -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', 2) == NULL);
|
||||
#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";
|
||||
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', 3) == NULL);
|
||||
#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";
|
||||
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', 6) == NULL);
|
||||
#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 *end = NULL;
|
||||
@ -146,6 +239,16 @@ void test_str_n_substring(void)
|
||||
wstr_n_substring(empty_wstr, L'\n', 2, &wbeg, &wend);
|
||||
assert_true(wbeg == NULL && wend == NULL);
|
||||
#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);
|
||||
@ -163,6 +266,14 @@ void test_str_n_substring(void)
|
||||
wstr_n_substring(wstr, L'2', 0, &wbeg, &wend);
|
||||
assert_true(wbeg == wstr && wend == wstr + 1);
|
||||
#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);
|
||||
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);
|
||||
assert_true(wbeg == NULL && wend == NULL);
|
||||
#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);
|
||||
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);
|
||||
assert_true(wbeg == NULL && wend == NULL);
|
||||
#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);
|
||||
buffer->type = CharBuf;
|
||||
string_buffer_t *buffer = create_string_buffer(200, CHAR_BUF);
|
||||
buffer->type = CHAR_BUF;
|
||||
char *old_value = buffer->str.cstr;
|
||||
|
||||
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";
|
||||
assert_true(buffer_text_width(buffer) == 0);
|
||||
assert_true(buffer_text_visible_width(buffer) == 0);
|
||||
|
||||
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";
|
||||
assert_true(buffer_text_width(buffer) == 7);
|
||||
assert_true(buffer_text_visible_width(buffer) == 7);
|
||||
|
||||
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";
|
||||
assert_true(buffer_text_width(buffer) == 7);
|
||||
assert_true(buffer_text_visible_width(buffer) == 7);
|
||||
|
||||
#if defined(FT_HAVE_WCHAR)
|
||||
buffer->type = WCharBuf;
|
||||
buffer->type = W_CHAR_BUF;
|
||||
|
||||
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";
|
||||
assert_true(buffer_text_width(buffer) == 0);
|
||||
assert_true(buffer_text_visible_width(buffer) == 0);
|
||||
|
||||
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";
|
||||
assert_true(buffer_text_width(buffer) == 7);
|
||||
assert_true(buffer_text_visible_width(buffer) == 7);
|
||||
|
||||
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";
|
||||
assert_true(buffer_text_width(buffer) == 7);
|
||||
assert_true(buffer_text_visible_width(buffer) == 7);
|
||||
#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;
|
||||
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);
|
||||
buffer->type = CharBuf;
|
||||
string_buffer_t *buffer = create_string_buffer(200, CHAR_BUF);
|
||||
buffer->type = CHAR_BUF;
|
||||
char *old_value = buffer->str.cstr;
|
||||
|
||||
buffer->str.cstr = (char *)"";
|
||||
assert_true(buffer_text_height(buffer) == 0);
|
||||
assert_true(buffer_text_visible_height(buffer) == 0);
|
||||
|
||||
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";
|
||||
assert_true(buffer_text_height(buffer) == 3);
|
||||
assert_true(buffer_text_visible_height(buffer) == 3);
|
||||
|
||||
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";
|
||||
assert_true(buffer_text_height(buffer) == 1);
|
||||
assert_true(buffer_text_visible_height(buffer) == 1);
|
||||
|
||||
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";
|
||||
assert_true(buffer_text_height(buffer) == 4);
|
||||
assert_true(buffer_text_visible_height(buffer) == 4);
|
||||
|
||||
#if defined(FT_HAVE_WCHAR)
|
||||
buffer->type = WCharBuf;
|
||||
buffer->type = W_CHAR_BUF;
|
||||
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";
|
||||
assert_true(buffer_text_height(buffer) == 2);
|
||||
assert_true(buffer_text_visible_height(buffer) == 2);
|
||||
|
||||
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";
|
||||
assert_true(buffer_text_height(buffer) == 5);
|
||||
assert_true(buffer_text_visible_height(buffer) == 5);
|
||||
|
||||
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";
|
||||
assert_true(buffer_text_height(buffer) == 2);
|
||||
assert_true(buffer_text_visible_height(buffer) == 2);
|
||||
|
||||
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
|
||||
|
||||
|
||||
buffer->type = CharBuf;
|
||||
buffer->type = CHAR_BUF;
|
||||
buffer->str.cstr = old_value;
|
||||
destroy_string_buffer(buffer);
|
||||
}
|
||||
@ -367,3 +599,59 @@ void test_wchar_basics(void)
|
||||
#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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user