diff --git a/example/main.c b/example/main.c index fda7e99..da8b22c 100644 --- a/example/main.c +++ b/example/main.c @@ -123,9 +123,18 @@ int main(void) printf("Table:\n%s\n", ft_to_string(table)); ft_destroy_table(table); + ft_set_default_border_style(FT_SOLID_STYLE); + table = create_basic_table(); + printf("Table:\n%s\n", ft_to_string(table)); + ft_destroy_table(table); + + ft_set_default_border_style(FT_DOUBLE_STYLE); + table = create_basic_table(); + printf("Table:\n%s\n", ft_to_string(table)); + ft_destroy_table(table); /* Debug */ - ft_set_default_border_style(FT_DOT_STYLE); + ft_set_default_border_style(FT_SOLID_STYLE); table = create_basic_table(); ft_set_cell_option(table, FT_CUR_ROW, FT_ANY_COLUMN, FT_COPT_ROW_TYPE, FT_ROW_HEADER); ft_write_ln(table, "Summary", "", "", "8.7"); @@ -133,12 +142,14 @@ int main(void) ft_some_api(table, 0, 0, 3); printf("Table:\n%s\n", ft_to_string(table)); ft_destroy_table(table); - return 0; + fflush(stdout); /*-------------------------------------------------------------*/ #if defined(FT_HAVE_WCHAR) && !defined(FT_MICROSOFT_COMPILER) setlocale(LC_CTYPE, ""); + ft_set_default_border_style(FT_BASIC_STYLE); + table = ft_create_table(); ft_set_cell_option(table, FT_ANY_ROW, 0, FT_COPT_TEXT_ALIGN, FT_ALIGNED_CENTER); ft_set_cell_option(table, FT_ANY_ROW, 1, FT_COPT_TEXT_ALIGN, FT_ALIGNED_LEFT); diff --git a/include/fort.h b/include/fort.h index d65fd34..4411ade 100644 --- a/include/fort.h +++ b/include/fort.h @@ -418,12 +418,12 @@ FT_EXTERN const char *ft_to_string(const FTABLE *table); * Structure describing border appearance. */ struct ft_border_chars { - char top_border_ch; - char separator_ch; - char bottom_border_ch; - char side_border_ch; - char out_intersect_ch; - char in_intersect_ch; + const char *top_border_ch; + const char *separator_ch; + const char *bottom_border_ch; + const char *side_border_ch; + const char *out_intersect_ch; + const char *in_intersect_ch; }; /** @@ -432,7 +432,7 @@ struct ft_border_chars { struct ft_border_style { struct ft_border_chars border_chs; struct ft_border_chars header_border_chs; - char hor_separator_char; + const char *hor_separator_char; }; /** @@ -443,6 +443,8 @@ extern struct ft_border_style *FT_SIMPLE_STYLE; extern struct ft_border_style *FT_PLAIN_STYLE; extern struct ft_border_style *FT_DOT_STYLE; extern struct ft_border_style *FT_EMPTY_STYLE; +extern struct ft_border_style *FT_SOLID_STYLE; +extern struct ft_border_style *FT_DOUBLE_STYLE; /** * Set default border style for all new formatted tables. diff --git a/src/cell.c b/src/cell.c index b7133bd..60646f8 100644 --- a/src/cell.c +++ b/src/cell.c @@ -106,9 +106,11 @@ static int lines_number_cell(fort_cell_t *cell) int cell_printf(fort_cell_t *cell, size_t row, char *buf, size_t buf_len, const context_t *context) { - char space_char = ' '; + const char *space_char = " "; int (*buffer_printf_)(string_buffer_t *, size_t, char *, size_t, const context_t *) = buffer_printf; - int (*snprint_n_chars_)(char *, size_t, size_t, char) = snprint_n_chars; +// int (*snprint_n_chars_)(char *, size_t, size_t, char) = snprint_n_chars; + int (*snprint_n_strings_)(char *, size_t, size_t, const char *) = snprint_n_strings; + if (cell == NULL || buf_len == 0 @@ -123,7 +125,7 @@ int cell_printf(fort_cell_t *cell, size_t row, char *buf, size_t buf_len, const if (row >= hint_height_cell(cell, context) || row < cell_padding_top || row >= (cell_padding_top + buffer_text_height(cell->str_buffer))) { - return snprint_n_chars_(buf, buf_len, buf_len - 1, space_char); + return snprint_n_strings_(buf, buf_len, buf_len - 1, space_char); } @@ -132,13 +134,13 @@ int cell_printf(fort_cell_t *cell, size_t row, char *buf, size_t buf_len, const int left = cell_padding_left; int right = cell_padding_right; - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buf + written, buf_len - written, left, space_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, left, space_char)); if (cell->str_buffer) CHCK_RSLT_ADD_TO_WRITTEN(buffer_printf_(cell->str_buffer, row - cell_padding_top, buf + written, buf_len - written - right, context)); else - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buf + written, buf_len - written, buf_len - written - right, space_char)); - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buf + written, buf_len - written, right, space_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, buf_len - written - right, space_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, right, space_char)); return written; @@ -149,9 +151,11 @@ clear: #ifdef FT_HAVE_WCHAR int cell_wprintf(fort_cell_t *cell, size_t row, wchar_t *buf, size_t buf_len, const context_t *context) { - wchar_t space_char = L' '; + const char *space_char = " "; int (*buffer_printf_)(string_buffer_t *, size_t, wchar_t *, size_t, const context_t *) = buffer_wprintf; - int (*snprint_n_chars_)(wchar_t *, size_t, size_t, wchar_t) = wsnprint_n_chars; +// int (*snprint_n_chars_)(wchar_t *, size_t, size_t, wchar_t) = wsnprint_n_chars; + int (*snprint_n_strings_)(wchar_t *, size_t, size_t, const char *) = wsnprint_n_string; + if (cell == NULL || buf_len == 0 @@ -166,7 +170,7 @@ int cell_wprintf(fort_cell_t *cell, size_t row, wchar_t *buf, size_t buf_len, co if (row >= hint_height_cell(cell, context) || row < cell_padding_top || row >= (cell_padding_top + buffer_text_height(cell->str_buffer))) { - return snprint_n_chars_(buf, buf_len, buf_len - 1, space_char); + return snprint_n_strings_(buf, buf_len, buf_len - 1, space_char); } int written = 0; @@ -174,13 +178,13 @@ int cell_wprintf(fort_cell_t *cell, size_t row, wchar_t *buf, size_t buf_len, co int left = cell_padding_left; int right = cell_padding_right; - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buf + written, buf_len - written, left, space_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, left, space_char)); if (cell->str_buffer) CHCK_RSLT_ADD_TO_WRITTEN(buffer_printf_(cell->str_buffer, row - cell_padding_top, buf + written, buf_len - written - right, context)); else - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buf + written, buf_len - written, buf_len - written - right, space_char)); - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buf + written, buf_len - written, right, space_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, buf_len - written - right, space_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, right, space_char)); return written; diff --git a/src/fort.c b/src/fort.c index 834d295..4e7ee2f 100644 --- a/src/fort.c +++ b/src/fort.c @@ -537,8 +537,8 @@ const char *ft_to_string(const FTABLE *table) typedef char char_type; const char_type *empty_string = ""; const enum str_buf_type buf_type = CharBuf; - char space_char = ' '; - char new_line_char = '\n'; + const char *space_char = " "; + const char *new_line_char = "\n"; #define cur_F_STRDUP F_STRDUP int (*snprintf_row_)(const fort_row_t *, char *, size_t, size_t *, size_t, size_t, const context_t *) = snprintf_row; int (*print_row_separator_)(char *, size_t, @@ -546,7 +546,8 @@ const char *ft_to_string(const FTABLE *table) const fort_row_t *, const fort_row_t *, enum HorSeparatorPos, const separator_t *, const context_t *) = print_row_separator; - int (*snprint_n_chars_)(char *, size_t, size_t, char) = snprint_n_chars; +// int (*snprint_n_chars_)(char *, size_t, size_t, char) = snprint_n_chars; + int (*snprint_n_strings_)(char *, size_t, size_t, const char *) = snprint_n_strings; assert(table); /* Determing size of table string representation */ @@ -595,8 +596,8 @@ const char *ft_to_string(const FTABLE *table) /* Print top margin */ for (i = 0; i < context.table_options->entire_table_options.top_margin; ++i) { - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, sz - written, width - 1/* minus new_line*/, space_char)); - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, sz - written, 1, new_line_char)); + 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) { @@ -614,8 +615,8 @@ const char *ft_to_string(const FTABLE *table) /* Print bottom margin */ for (i = 0; i < context.table_options->entire_table_options.bottom_margin; ++i) { - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, sz - written, width - 1/* minus new_line*/, space_char)); - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, sz - written, 1, new_line_char)); + 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)); } @@ -637,8 +638,8 @@ const wchar_t *ft_to_wstring(const FTABLE *table) typedef wchar_t char_type; const char_type *empty_string = L""; const enum str_buf_type buf_type = WCharBuf; - wchar_t space_char = L' '; - wchar_t new_line_char = L'\n'; + const char *space_char = " "; + const char *new_line_char = "\n"; #define cur_F_STRDUP F_WCSDUP int (*snprintf_row_)(const fort_row_t *, wchar_t *, size_t, size_t *, size_t, size_t, const context_t *) = wsnprintf_row; int (*print_row_separator_)(wchar_t *, size_t, @@ -646,7 +647,9 @@ const wchar_t *ft_to_wstring(const FTABLE *table) const fort_row_t *, const fort_row_t *, enum HorSeparatorPos, const separator_t *, const context_t *) = wprint_row_separator; - int (*snprint_n_chars_)(wchar_t *, size_t, size_t, wchar_t) = wsnprint_n_chars; +// int (*snprint_n_chars_)(wchar_t *, size_t, size_t, wchar_t) = wsnprint_n_chars; + int (*snprint_n_strings_)(wchar_t *, size_t, size_t, const char *) = wsnprint_n_string; + assert(table); @@ -697,8 +700,8 @@ const wchar_t *ft_to_wstring(const FTABLE *table) /* Print top margin */ for (i = 0; i < context.table_options->entire_table_options.top_margin; ++i) { - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, sz - written, width - 1/* minus new_line*/, space_char)); - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, sz - written, 1, new_line_char)); + 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) { @@ -716,8 +719,8 @@ const wchar_t *ft_to_wstring(const FTABLE *table) /* Print bottom margin */ for (i = 0; i < context.table_options->entire_table_options.bottom_margin; ++i) { - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, sz - written, width - 1/* minus new_line*/, space_char)); - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, sz - written, 1, new_line_char)); + 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); @@ -794,6 +797,8 @@ struct ft_border_style *FT_SIMPLE_STYLE = (struct ft_border_style *) &FORT_SIMPL struct ft_border_style *FT_PLAIN_STYLE = (struct ft_border_style *) &FORT_PLAIN_STYLE; struct ft_border_style *FT_DOT_STYLE = (struct ft_border_style *) &FORT_DOT_STYLE; struct ft_border_style *FT_EMPTY_STYLE = (struct ft_border_style *) &FORT_EMPTY_STYLE; +struct ft_border_style *FT_SOLID_STYLE = (struct ft_border_style *) &FORT_SOLID_STYLE; +struct ft_border_style *FT_DOUBLE_STYLE = (struct ft_border_style *) &FORT_DOUBLE_STYLE; @@ -803,7 +808,9 @@ static void set_border_options_for_options(fort_table_options_t *options, struct || (struct fort_border_style *)style == &FORT_SIMPLE_STYLE || (struct fort_border_style *)style == &FORT_DOT_STYLE || (struct fort_border_style *)style == &FORT_PLAIN_STYLE - || (struct fort_border_style *)style == &FORT_EMPTY_STYLE) { + || (struct fort_border_style *)style == &FORT_EMPTY_STYLE + || (struct fort_border_style *)style == &FORT_SOLID_STYLE + || (struct fort_border_style *)style == &FORT_DOUBLE_STYLE) { memcpy(&(options->border_style), (struct fort_border_style *)style, sizeof(struct fort_border_style)); return; } @@ -837,8 +844,11 @@ static void set_border_options_for_options(fort_table_options_t *options, struct BOR_CHARS[BL_bip] = BOR_CHARS[BV_bip] = BOR_CHARS[BR_bip] = border_chs->out_intersect_ch; BOR_CHARS[II_bip] = border_chs->in_intersect_ch; - if (border_chs->separator_ch == '\0' && border_chs->in_intersect_ch == '\0') { - BOR_CHARS[LH_bip] = BOR_CHARS[RH_bip] = '\0'; +// if (border_chs->separator_ch == '\0' && border_chs->in_intersect_ch == '\0') { +// BOR_CHARS[LH_bip] = BOR_CHARS[RH_bip] = '\0'; +// } + if (strlen(border_chs->separator_ch) == 0 && strlen(border_chs->in_intersect_ch) == 0) { + BOR_CHARS[LH_bip] = BOR_CHARS[RH_bip] = "\0"; } @@ -852,8 +862,11 @@ static void set_border_options_for_options(fort_table_options_t *options, struct H_BOR_CHARS[BL_bip] = H_BOR_CHARS[BV_bip] = H_BOR_CHARS[BR_bip] = header_border_chs->out_intersect_ch; H_BOR_CHARS[II_bip] = header_border_chs->in_intersect_ch; - if (header_border_chs->separator_ch == '\0' && header_border_chs->in_intersect_ch == '\0') { - H_BOR_CHARS[LH_bip] = H_BOR_CHARS[RH_bip] = '\0'; +// if (header_border_chs->separator_ch == '\0' && header_border_chs->in_intersect_ch == '\0') { +// H_BOR_CHARS[LH_bip] = H_BOR_CHARS[RH_bip] = '\0'; +// } + if (strlen(header_border_chs->separator_ch) == 0 && strlen(header_border_chs->in_intersect_ch) == 0) { + BOR_CHARS[LH_bip] = BOR_CHARS[RH_bip] = "\0"; } SEP_CHARS[LH_sip] = SEP_CHARS[RH_sip] = SEP_CHARS[II_sip] = header_border_chs->out_intersect_ch; diff --git a/src/fort_impl.c b/src/fort_impl.c index 95f570e..74a73dd 100644 --- a/src/fort_impl.c +++ b/src/fort_impl.c @@ -156,51 +156,113 @@ size_t number_of_columns_in_format_wstring(const wchar_t *fmt) } -int snprint_n_chars(char *buf, size_t length, size_t n, char ch) +//int snprint_n_chars(char *buf, size_t length, size_t n, char ch) +//{ +// if (length <= n) +// return -1; + +// if (n == 0) +// return 0; + +// /* To ensure valid return value it is safely not print such big strings */ +// if (n > INT_MAX) +// return -1; + +// int status = snprintf(buf, length, "%0*d", (int)n, 0); +// if (status < 0) +// return status; + +// size_t i = 0; +// for (i = 0; i < n; ++i) { +// *buf = ch; +// buf++; +// } +// return (int)n; +//} + +int snprint_n_strings(char *buf, size_t length, size_t n, const char *str) { - if (length <= n) + size_t str_len = strlen(str); + if (length <= n * str_len) return -1; if (n == 0) return 0; /* To ensure valid return value it is safely not print such big strings */ - if (n > INT_MAX) + if (n * str_len > INT_MAX) return -1; - int status = snprintf(buf, length, "%0*d", (int)n, 0); + int status = snprintf(buf, length, "%0*d", (int)(n * str_len), 0); if (status < 0) return status; size_t i = 0; for (i = 0; i < n; ++i) { - *buf = ch; - buf++; + const char *str_p = str; + while (*str_p) + *(buf++) = *(str_p++); } - return (int)n; + return (int)(n * str_len); } -int wsnprint_n_chars(wchar_t *buf, size_t length, size_t n, wchar_t ch) +//int wsnprint_n_chars(wchar_t *buf, size_t length, size_t n, wchar_t ch) +//{ +// if (length <= n) +// return -1; + +// if (n == 0) +// return 0; + +// /* To ensure valid return value it is safely not print such big strings */ +// if (n > INT_MAX) +// return -1; + +// int status = swprintf(buf, length, L"%0*d", (int)n, 0); +// if (status < 0) +// return status; + +// size_t i = 0; +// for (i = 0; i < n; ++i) { +// *buf = ch; +// buf++; +// } +// return (int)n; +//} + +int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *str) { - if (length <= n) + size_t str_len = strlen(str); + + /* This function doesn't work properly with multibyte characters + * so it is better return an error in this case + */ + if (str_len > 1) + return -1; + + if (length <= n * str_len) return -1; if (n == 0) return 0; + + /* To ensure valid return value it is safely not print such big strings */ - if (n > INT_MAX) + if (n * str_len > INT_MAX) return -1; - int status = swprintf(buf, length, L"%0*d", (int)n, 0); + int status = swprintf(buf, length, L"%0*d", (int)(n * str_len), 0); if (status < 0) return status; size_t i = 0; for (i = 0; i < n; ++i) { - *buf = ch; - buf++; + const char *str_p = str; + while (*str_p) + *(buf++) = (wchar_t) * (str_p++); } - return (int)n; + return (int)(n * str_len); } + diff --git a/src/fort_impl.h b/src/fort_impl.h index af1583a..c00afc9 100644 --- a/src/fort_impl.h +++ b/src/fort_impl.h @@ -127,8 +127,10 @@ char *fort_strdup(const char* str); wchar_t *fort_wcsdup(const wchar_t* str); size_t number_of_columns_in_format_string(const char *fmt); size_t number_of_columns_in_format_wstring(const wchar_t *fmt); -int snprint_n_chars(char *buf, size_t length, size_t n, char ch); -int wsnprint_n_chars(wchar_t *buf, size_t length, size_t n, wchar_t ch); +//int snprint_n_chars(char *buf, size_t length, size_t n, char ch); +//int wsnprint_n_chars(wchar_t *buf, size_t length, size_t n, wchar_t ch); +int snprint_n_strings(char *buf, size_t length, size_t n, const char *str); +int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *str); #define CHCK_RSLT_ADD_TO_WRITTEN(statement) \ diff --git a/src/options.c b/src/options.c index 8a4d402..a1efb02 100644 --- a/src/options.c +++ b/src/options.c @@ -218,113 +218,159 @@ fort_status_t set_default_cell_option(uint32_t option, int value) #define BASIC_STYLE { \ /* border_chars */ \ { \ - '+', '-', '+', '+', \ - '|', '|', '|', \ - '\0', '\0', '\0', '\0', \ - '+', '-', '+', '+' \ + "+", "-", "+", "+", \ + "|", "|", "|", \ + "\0", "\0", "\0", "\0", \ + "+", "-", "+", "+" \ }, \ /* header_border_chars */ \ { \ - '+', '-', '+', '+', \ - '|', '|', '|', \ - '+', '-', '+', '+', \ - '+', '-', '+', '+' \ + "+", "-", "+", "+", \ + "|", "|", "|", \ + "+", "-", "+", "+", \ + "+", "-", "+", "+" \ }, \ /* separator_chars */ \ { \ - '+', '-', '+', '+', \ + "+", "-", "+", "+", \ }, \ } #define SIMPLE_STYLE { \ /* border_chars */ \ { \ - ' ', ' ', ' ', ' ', \ - ' ', ' ', ' ', \ - '\0', '\0', '\0', '\0', \ - ' ', ' ', ' ', ' ' \ + " ", " ", " ", " ", \ + " ", " ", " ", \ + "\0", "\0", "\0", "\0", \ + " ", " ", " ", " " \ }, \ /* header_border_chars */ \ { \ - ' ', ' ', ' ', ' ', \ - ' ', ' ', ' ', \ - ' ', '-', ' ', ' ', \ - ' ', ' ', ' ', ' ' \ + " ", " ", " ", " ", \ + " ", " ", " ", \ + " ", "-", " ", " ", \ + " ", " ", " ", " " \ }, \ /* separator_chars */ \ { \ - ' ', '-', ' ', ' ', \ + " ", "-", " ", " ", \ }, \ } #define PLAIN_STYLE { \ /* border_chars */ \ { \ - ' ', ' ', ' ', ' ', \ - ' ', ' ', ' ', \ - '\0', '\0', '\0', '\0', \ - ' ', ' ', ' ', ' ' \ + " ", " ", " ", " ", \ + " ", " ", " ", \ + "\0", "\0", "\0", "\0", \ + " ", " ", " ", " " \ }, \ /* header_border_chars */ \ { \ - ' ', '-', '-', ' ', \ - ' ', ' ', ' ', \ - ' ', '-', '-', ' ', \ - ' ', '-', '-', ' ' \ + " ", "-", "-", " ", \ + " ", " ", " ", \ + " ", "-", "-", " ", \ + " ", "-", "-", " " \ }, \ /* separator_chars */ \ { \ - ' ', '-', '-', ' ', \ + " ", "-", "-", " ", \ }, \ } #define DOT_STYLE { \ /* border_chars */ \ { \ - '.', '.', '.', '.', \ - ':', ':', ':', \ - '\0', '\0', '\0', '\0', \ - ':', '.', ':', ':' \ + ".", ".", ".", ".", \ + ":", ":", ":", \ + "\0", "\0", "\0", "\0", \ + ":", ".", ":", ":" \ }, \ /* header_border_chars */ \ { \ - '.', '.', '.', '.', \ - ':', ':', ':', \ - ':', '.', ':', ':', \ - ':', '.', ':', ':' \ + ".", ".", ".", ".", \ + ":", ":", ":", \ + ":", ".", ":", ":", \ + ":", ".", ":", ":" \ }, \ /* separator_chars */ \ { \ - ':', '.', ':', ':', \ + ":", ".", ":", ":", \ }, \ } #define EMPTY_STYLE { \ /* border_chars */ \ { \ - ' ', ' ', ' ', ' ', \ - ' ', ' ', ' ', \ - '\0', '\0', '\0', '\0', \ - ' ', ' ', ' ', ' ' \ + " ", " ", " ", " ", \ + " ", " ", " ", \ + "\0", "\0", "\0", "\0", \ + " ", " ", " ", " " \ }, \ /* header_border_chars */ \ { \ - ' ', ' ', ' ', ' ', \ - ' ', ' ', ' ', \ - '\0', '\0', '\0', '\0', \ - ' ', ' ', ' ', ' ' \ + " ", " ", " ", " ", \ + " ", " ", " ", \ + "\0", "\0", "\0", "\0", \ + " ", " ", " ", " " \ }, \ /* separator_chars */ \ { \ - ' ', ' ', ' ', ' ', \ + " ", " ", " ", " ", \ }, \ } + +#define SOLID_STYLE { \ + /* border_chars */ \ + { \ + "┏", "━", "┳", "┓", \ + "┃", "┃", "┃", \ + "", "", "", "", \ + "┗", "━", "┻", "┛" \ + }, \ + /* header_border_chars */ \ + { \ + "┏", "━", "┳", "┓", \ + "┃", "┃", "┃", \ + "┣", "━", "╋", "┫", \ + "┗", "━", "┻", "┛" \ + }, \ + /* separator_chars */ \ + { \ + "┣", "━", "╋", "┫", \ + }, \ +} + +#define DOUBLE_STYLE { \ + /* border_chars */ \ + { \ + "╔", "═", "╦", "╗", \ + "║", "║", "║", \ + "", "", "", "", \ + "╚", "═", "╩", "╝" \ + }, \ + /* header_border_chars */ \ + { \ + "╔", "═", "╦", "╗", \ + "║", "║", "║", \ + "╠", "═", "╬", "╣", \ + "╚", "═", "╩", "╝" \ + }, \ + /* separator_chars */ \ + { \ + "╠", "═", "╬", "╣", \ + }, \ +} + + struct fort_border_style FORT_BASIC_STYLE = BASIC_STYLE; struct fort_border_style FORT_SIMPLE_STYLE = SIMPLE_STYLE; struct fort_border_style FORT_PLAIN_STYLE = PLAIN_STYLE; struct fort_border_style FORT_DOT_STYLE = DOT_STYLE; struct fort_border_style FORT_EMPTY_STYLE = EMPTY_STYLE; +struct fort_border_style FORT_SOLID_STYLE = SOLID_STYLE; +struct fort_border_style FORT_DOUBLE_STYLE = DOUBLE_STYLE; @@ -367,7 +413,26 @@ fort_status_t set_default_entire_table_option(uint32_t option, int value) return set_entire_table_option_internal(&g_entire_table_options, option, value); } +size_t max_border_elem_strlen(struct fort_table_options *options) +{ + assert(options); + size_t result = 1; + int i = 0; + for (i = 0; i < BorderItemPosSize; ++i) { + result = MAX(result, strlen(options->border_style.border_chars[i])); + } + i = 0; + for (i = 0; i < BorderItemPosSize; ++i) { + result = MAX(result, strlen(options->border_style.header_border_chars[i])); + } + + i = 0; + for (i = 0; i < SepratorItemPosSize; ++i) { + result = MAX(result, strlen(options->border_style.separator_chars[i])); + } + return result; +} fort_table_options_t g_table_options = { diff --git a/src/options.h b/src/options.h index aab23a4..1f2b463 100644 --- a/src/options.h +++ b/src/options.h @@ -112,15 +112,17 @@ enum SeparatorItemPos struct fort_border_style { - char border_chars[BorderItemPosSize]; - char header_border_chars[BorderItemPosSize]; - char separator_chars[SepratorItemPosSize]; + const char *border_chars[BorderItemPosSize]; + const char *header_border_chars[BorderItemPosSize]; + const char *separator_chars[SepratorItemPosSize]; }; extern struct fort_border_style FORT_BASIC_STYLE; extern struct fort_border_style FORT_SIMPLE_STYLE; extern struct fort_border_style FORT_PLAIN_STYLE; extern struct fort_border_style FORT_DOT_STYLE; extern struct fort_border_style FORT_EMPTY_STYLE; +extern struct fort_border_style FORT_SOLID_STYLE; +extern struct fort_border_style FORT_DOUBLE_STYLE; struct fort_entire_table_options @@ -144,6 +146,7 @@ struct fort_table_options typedef struct fort_table_options fort_table_options_t; extern fort_table_options_t g_table_options; +size_t max_border_elem_strlen(struct fort_table_options*); fort_table_options_t* create_table_options(void); diff --git a/src/row.c b/src/row.c index 515d6a4..b5da372 100644 --- a/src/row.c +++ b/src/row.c @@ -167,14 +167,13 @@ int print_row_separator(char *buffer, size_t buffer_sz, enum HorSeparatorPos separatorPos, const separator_t *sep, const context_t *context) { - typedef char char_type; - char new_line_char = '\n'; - int (*snprint_n_chars_)(char *, size_t, size_t, char) = snprint_n_chars; - char space_char = ' '; +// int (*snprint_n_chars_)(char *, size_t, size_t, char) = snprint_n_chars; + int (*snprint_n_strings_)(char *, size_t, size_t, const char *) = snprint_n_strings; assert(buffer); assert(context); + const char *space_char = " "; int status = -1; /* Get cell types @@ -221,17 +220,17 @@ int print_row_separator(char *buffer, size_t buffer_sz, * 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; + 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; + typedef const char *(*border_chars_point_t)[BorderItemPosSize]; + const char *(*border_chars)[BorderItemPosSize] = NULL; border_chars = (border_chars_point_t)&context->table_options->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_options->border_style.header_border_chars; @@ -284,7 +283,14 @@ int print_row_separator(char *buffer, size_t buffer_sz, } /* If all chars are not printable, skip line separator */ /* todo: add processing for wchar_t */ - if (!isprint(*L) && !isprint(*I) && !isprint(*IV) && !isprint(*R)) { +// if (!isprint(*L) && !isprint(*I) && !isprint(*IV) && !isprint(*R)) { +// 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; } @@ -292,31 +298,31 @@ int print_row_separator(char *buffer, size_t buffer_sz, size_t i = 0; /* Print left margin */ - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buffer_sz - written, context->table_options->entire_table_options.left_margin, space_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, context->table_options->entire_table_options.left_margin, space_char)); for (i = 0; i < cols; ++i) { if (i == 0) { - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buffer_sz - written, 1, (char_type)*L)); + 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_chars_(buffer + written, buffer_sz - written, 1, (char_type)*IV)); + && (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_chars_(buffer + written, buffer_sz - written, 1, (char_type)*II)); + 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_chars_(buffer + written, buffer_sz - written, 1, (char_type)*IT)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *IT)); } else { - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buffer_sz - written, 1, (char_type)*IB)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *IB)); } } - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buffer_sz - written, col_width_arr[i], (char_type)*I)); + 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_chars_(buffer + written, buffer_sz - written, 1, (char_type)*R)); + 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_chars_(buffer + written, buffer_sz - written, context->table_options->entire_table_options.right_margin, space_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, context->table_options->entire_table_options.right_margin, space_char)); - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buffer_sz - written, 1, new_line_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, "\n")); status = written; @@ -333,14 +339,41 @@ int wprint_row_separator(wchar_t *buffer, size_t buffer_sz, enum HorSeparatorPos separatorPos, const separator_t *sep, const context_t *context) { - typedef wchar_t char_type; - char new_line_char = L'\n'; - int (*snprint_n_chars_)(wchar_t *, size_t, size_t, wchar_t) = wsnprint_n_chars; - wchar_t space_char = L' '; +// int (*snprint_n_chars_)(wchar_t *, size_t, size_t, wchar_t) = wsnprint_n_chars; + 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 = F_MALLOC(sizeof(enum CellType) * cols * 2); + if (top_row_types == NULL) { + return FT_MEMORY_ERROR; + } + enum CellType *bottom_row_types = top_row_types + cols; + if (upper_row) { + get_row_cell_types(upper_row, top_row_types, cols); + } else { + size_t i = 0; + for (i = 0; i < cols; ++i) + top_row_types[i] = GroupSlaveCell; + } + if (lower_row) { + get_row_cell_types(lower_row, bottom_row_types, cols); + } else { + size_t i = 0; + for (i = 0; i < cols; ++i) + bottom_row_types[i] = GroupSlaveCell; + } + + int written = 0; int tmp = 0; @@ -353,28 +386,37 @@ int wprint_row_separator(wchar_t *buffer, size_t buffer_sz, upper_row_type = (enum ft_row_type)get_cell_opt_value_hierarcial(context->table_options, context->row - 1, FT_ANY_COLUMN, FT_COPT_ROW_TYPE); } - /* Row separator anatomy + /* Row separator anatomy * - * L I I I IV I I I R - */ - const char *L = NULL; - const char *I = NULL; - const char *IV = NULL; - const char *R = NULL; + * | 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; + + typedef const char *(*border_chars_point_t)[BorderItemPosSize]; + const char *(*border_chars)[BorderItemPosSize] = NULL; border_chars = (border_chars_point_t)&context->table_options->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_options->border_style.header_border_chars; } - if (sep && sep->enabled) { L = &(context->table_options->border_style.separator_chars[LH_sip]); I = &(context->table_options->border_style.separator_chars[IH_sip]); IV = &(context->table_options->border_style.separator_chars[II_sip]); R = &(context->table_options->border_style.separator_chars[RH_sip]); + + IT = &(context->table_options->border_style.separator_chars[II_sip]); + IB = &(context->table_options->border_style.separator_chars[II_sip]); + II = &(context->table_options->border_style.separator_chars[IH_sip]); } else { switch (separatorPos) { case TopSeparator: @@ -382,18 +424,30 @@ int wprint_row_separator(wchar_t *buffer, size_t buffer_sz, 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]; + 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; @@ -401,33 +455,52 @@ int wprint_row_separator(wchar_t *buffer, size_t buffer_sz, } /* If all chars are not printable, skip line separator */ /* todo: add processing for wchar_t */ - if (!isprint(*L) && !isprint(*I) && !isprint(*IV) && !isprint(*R)) - return 0; +// 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; + } size_t i = 0; /* Print left margin */ - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buffer_sz - written, context->table_options->entire_table_options.left_margin, space_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, context->table_options->entire_table_options.left_margin, space_char)); for (i = 0; i < cols; ++i) { if (i == 0) { - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buffer_sz - written, 1, (char_type)*L)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *L)); } else { - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buffer_sz - written, 1, (char_type)*IV)); + 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_chars_(buffer + written, buffer_sz - written, col_width_arr[i], (char_type)*I)); + 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_chars_(buffer + written, buffer_sz - written, 1, (char_type)*R)); + 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_chars_(buffer + written, buffer_sz - written, context->table_options->entire_table_options.right_margin, space_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, context->table_options->entire_table_options.right_margin, space_char)); - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buffer_sz - written, 1, new_line_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, "\n")); - return written; + status = written; clear: - return -1; + F_FREE(top_row_types); + return status; } @@ -724,14 +797,15 @@ clear: int snprintf_row(const fort_row_t *row, char *buffer, size_t buf_sz, size_t *col_width_arr, size_t col_width_arr_sz, size_t row_height, const context_t *context) { - typedef char char_type; - char space_char = ' '; - char new_line_char = '\n'; - int (*snprint_n_chars_)(char *, size_t, size_t, char) = snprint_n_chars; +// int (*snprint_n_chars_)(char *, size_t, size_t, char) = snprint_n_chars; + 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; assert(context); + const char *space_char = " "; + const char *new_line_char = "\n"; + if (row == NULL) return -1; @@ -744,14 +818,14 @@ int snprintf_row(const fort_row_t *row, char *buffer, size_t buf_sz, size_t *col * L data IV data IV data R */ - typedef const char (*border_chars_point_t)[BorderItemPosSize]; + typedef const char *(*border_chars_point_t)[BorderItemPosSize]; enum ft_row_type row_type = (enum ft_row_type)get_cell_opt_value_hierarcial(context->table_options, context->row, FT_ANY_COLUMN, FT_COPT_ROW_TYPE); - const char (*bord_chars)[BorderItemPosSize] = (row_type == FT_ROW_HEADER) + const char *(*bord_chars)[BorderItemPosSize] = (row_type == FT_ROW_HEADER) ? (border_chars_point_t)(&context->table_options->border_style.header_border_chars) : (border_chars_point_t)(&context->table_options->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]; + const char **L = &(*bord_chars)[LL_bip]; + const char **IV = &(*bord_chars)[IV_bip]; + const char **R = &(*bord_chars)[RR_bip]; int written = 0; @@ -759,10 +833,10 @@ 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_chars_(buffer + written, buf_sz - written, context->table_options->entire_table_options.left_margin, space_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, context->table_options->entire_table_options.left_margin, space_char)); /* Print left table boundary */ - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buf_sz - written, 1, (char_type)*L)); + 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) { @@ -782,24 +856,24 @@ int snprintf_row(const fort_row_t *row, char *buffer, size_t buf_sz, size_t *col 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_chars_(buffer + written, buf_sz - written, col_width_arr[j], space_char)); + 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_chars_(buffer + written, buf_sz - written, 1, (char_type)*IV)); + 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_chars_(buffer + written, buf_sz - written, 1, (char_type)*R)); + 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_chars_(buffer + written, buf_sz - written, context->table_options->entire_table_options.right_margin, space_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, context->table_options->entire_table_options.right_margin, space_char)); /* Print new line character */ - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buf_sz - written, 1, new_line_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, new_line_char)); } return written; @@ -812,14 +886,15 @@ clear: 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) { - typedef wchar_t char_type; - char space_char = L' '; - char new_line_char = L'\n'; - int (*snprint_n_chars_)(wchar_t *, size_t, size_t, wchar_t) = wsnprint_n_chars; +// int (*snprint_n_chars_)(wchar_t *, size_t, size_t, wchar_t) = wsnprint_n_chars; + 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; @@ -832,14 +907,14 @@ int wsnprintf_row(const fort_row_t *row, wchar_t *buffer, size_t buf_sz, size_t * L data IV data IV data R */ - typedef const char (*border_chars_point_t)[BorderItemPosSize]; + typedef const char *(*border_chars_point_t)[BorderItemPosSize]; enum ft_row_type row_type = (enum ft_row_type)get_cell_opt_value_hierarcial(context->table_options, context->row, FT_ANY_COLUMN, FT_COPT_ROW_TYPE); - const char (*bord_chars)[BorderItemPosSize] = (row_type) + const char *(*bord_chars)[BorderItemPosSize] = (row_type == FT_ROW_HEADER) ? (border_chars_point_t)(&context->table_options->border_style.header_border_chars) : (border_chars_point_t)(&context->table_options->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]; + const char **L = &(*bord_chars)[LL_bip]; + const char **IV = &(*bord_chars)[IV_bip]; + const char **R = &(*bord_chars)[RR_bip]; int written = 0; @@ -847,29 +922,47 @@ int wsnprintf_row(const fort_row_t *row, wchar_t *buffer, size_t buf_sz, size_t size_t i = 0; for (i = 0; i < row_height; ++i) { /* Print left margin */ - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buf_sz - written, context->table_options->entire_table_options.left_margin, space_char)); + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, context->table_options->entire_table_options.left_margin, space_char)); - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buf_sz - written, 1, (char_type)*L)); + /* Print left table boundary */ + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, *L)); size_t j = 0; - for (j = 0; j < col_width_arr_sz; ++j) { - ((context_t *)context)->column = j; + 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); - CHCK_RSLT_ADD_TO_WRITTEN(cell_printf_(cell, i, buffer + written, col_width_arr[j] + 1, context)); + 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 { - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buf_sz - written, col_width_arr[j], space_char)); - } - if (j == col_width_arr_sz - 1) { - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buf_sz - written, 1, (char_type)*R)); - } else { - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buf_sz - written, 1, (char_type)*IV)); + /* 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 margin */ - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buf_sz - written, context->table_options->entire_table_options.right_margin, space_char)); + /* Print right table boundary */ + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, *R)); - CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_chars_(buffer + written, buf_sz - written, 1, new_line_char)); + /* Print right margin */ + CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, context->table_options->entire_table_options.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 written; diff --git a/src/string_buffer.c b/src/string_buffer.c index bb98bbf..bb359df 100644 --- a/src/string_buffer.c +++ b/src/string_buffer.c @@ -279,11 +279,12 @@ int buffer_printf(string_buffer_t *buffer, size_t buffer_row, char *buf, size_t #define CHAR_TYPE char #define NULL_CHAR '\0' #define NEWLINE_CHAR '\n' -#define SPACE_CHAR ' ' +#define SPACE_CHAR " " #define SNPRINTF_FMT_STR "%*s" #define SNPRINTF snprintf #define BUFFER_STR str.cstr -#define SNPRINT_N_CHARS snprint_n_chars +//#define SNPRINT_N_CHARS snprint_n_chars +#define SNPRINT_N_STRINGS snprint_n_strings #define STR_N_SUBSTRING str_n_substring #define STR_ITER_WIDTH str_iter_width @@ -323,7 +324,7 @@ int buffer_printf(string_buffer_t *buffer, size_t buffer_row, char *buf, size_t const CHAR_TYPE *end = NULL; CHAR_TYPE old_value; - CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_CHARS(buf + written, buf_len - written, left, SPACE_CHAR)); + CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, buf_len - written, left, SPACE_CHAR)); STR_N_SUBSTRING(buffer->BUFFER_STR, NEWLINE_CHAR, buffer_row, &beg, &end); if (beg == NULL || end == NULL) @@ -337,8 +338,8 @@ int buffer_printf(string_buffer_t *buffer, size_t buffer_row, char *buf, size_t CHCK_RSLT_ADD_TO_WRITTEN(SNPRINTF(buf + written, buf_len - written, SNPRINTF_FMT_STR, (int)(end - beg), beg)); *(CHAR_TYPE *)end = old_value; - CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_CHARS(buf + written, buf_len - written, (content_width - (size_t)str_it_width), SPACE_CHAR)); - CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_CHARS(buf + written, buf_len - written, right, SPACE_CHAR)); + CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, buf_len - written, (content_width - (size_t)str_it_width), SPACE_CHAR)); + CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, buf_len - written, right, SPACE_CHAR)); return written; clear: @@ -351,7 +352,8 @@ clear: #undef SNPRINTF_FMT_STR #undef SNPRINTF #undef BUFFER_STR -#undef SNPRINT_N_CHARS +//#undef SNPRINT_N_CHARS +#undef SNPRINT_N_STRINGS #undef STR_N_SUBSTRING #undef STR_ITER_WIDTH } @@ -362,11 +364,12 @@ int buffer_wprintf(string_buffer_t *buffer, size_t buffer_row, wchar_t *buf, siz #define CHAR_TYPE wchar_t #define NULL_CHAR L'\0' #define NEWLINE_CHAR L'\n' -#define SPACE_CHAR L' ' +#define SPACE_CHAR " " #define SNPRINTF_FMT_STR L"%*ls" #define SNPRINTF swprintf #define BUFFER_STR str.wstr -#define SNPRINT_N_CHARS wsnprint_n_chars +//#define SNPRINT_N_CHARS wsnprint_n_chars +#define SNPRINT_N_STRINGS wsnprint_n_string #define STR_N_SUBSTRING wstr_n_substring #define STR_ITER_WIDTH wcs_iter_width @@ -406,7 +409,7 @@ int buffer_wprintf(string_buffer_t *buffer, size_t buffer_row, wchar_t *buf, siz const CHAR_TYPE *end = NULL; CHAR_TYPE old_value; - CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_CHARS(buf + written, buf_len - written, left, SPACE_CHAR)); + CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, buf_len - written, left, SPACE_CHAR)); STR_N_SUBSTRING(buffer->BUFFER_STR, NEWLINE_CHAR, buffer_row, &beg, &end); if (beg == NULL || end == NULL) @@ -420,8 +423,8 @@ int buffer_wprintf(string_buffer_t *buffer, size_t buffer_row, wchar_t *buf, siz CHCK_RSLT_ADD_TO_WRITTEN(SNPRINTF(buf + written, buf_len - written, SNPRINTF_FMT_STR, (int)(end - beg), beg)); *(CHAR_TYPE *)end = old_value; - CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_CHARS(buf + written, buf_len - written, (content_width - (size_t)str_it_width), SPACE_CHAR)); - CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_CHARS(buf + written, buf_len - written, right, SPACE_CHAR)); + CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, buf_len - written, (content_width - (size_t)str_it_width), SPACE_CHAR)); + CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, buf_len - written, right, SPACE_CHAR)); return written; clear: @@ -434,7 +437,8 @@ clear: #undef SNPRINTF_FMT_STR #undef SNPRINTF #undef BUFFER_STR -#undef SNPRINT_N_CHARS +//#undef SNPRINT_N_CHARS +#undef SNPRINT_N_STRINGS #undef STR_N_SUBSTRING #undef STR_ITER_WIDTH } diff --git a/src/table.c b/src/table.c index 5a56505..71f8044 100644 --- a/src/table.c +++ b/src/table.c @@ -234,6 +234,11 @@ fort_status_t table_geometry(const FTABLE *table, size_t *height, size_t *width) *width += table->options->entire_table_options.right_margin; } + /* Take into account that border elements can be more than one byte long */ + fort_table_options_t *table_options = table->options ? table->options : &g_table_options; + size_t max_border_elem_len = max_border_elem_strlen(table_options); + *width *= max_border_elem_len; + return FT_SUCCESS; } diff --git a/tests/test_table_border_style.c b/tests/test_table_border_style.c index 869cbe4..49e891d 100644 --- a/tests/test_table_border_style.c +++ b/tests/test_table_border_style.c @@ -15,19 +15,21 @@ void test_table_border_style(void) WHEN("Changing cell separators") { struct ft_border_style brdr_style; - brdr_style.border_chs.top_border_ch = '|'; - brdr_style.border_chs.separator_ch = '|'; - brdr_style.border_chs.bottom_border_ch = '|'; - brdr_style.border_chs.side_border_ch = '='; - brdr_style.border_chs.out_intersect_ch = '+'; - brdr_style.border_chs.in_intersect_ch = '#'; + brdr_style.border_chs.top_border_ch = "|"; + brdr_style.border_chs.separator_ch = "|"; + brdr_style.border_chs.bottom_border_ch = "|"; + brdr_style.border_chs.side_border_ch = "="; + brdr_style.border_chs.out_intersect_ch = "+"; + brdr_style.border_chs.in_intersect_ch = "#"; - brdr_style.header_border_chs.top_border_ch = '*'; - brdr_style.header_border_chs.separator_ch = '*'; - brdr_style.header_border_chs.bottom_border_ch = '*'; - brdr_style.header_border_chs.side_border_ch = 'v'; - brdr_style.header_border_chs.out_intersect_ch = '+'; - brdr_style.header_border_chs.in_intersect_ch = '#'; + brdr_style.header_border_chs.top_border_ch = "*"; + brdr_style.header_border_chs.separator_ch = "*"; + brdr_style.header_border_chs.bottom_border_ch = "*"; + brdr_style.header_border_chs.side_border_ch = "v"; + brdr_style.header_border_chs.out_intersect_ch = "+"; + brdr_style.header_border_chs.in_intersect_ch = "#"; + + brdr_style.hor_separator_char = "|"; ft_set_default_border_style(&brdr_style); @@ -54,19 +56,21 @@ void test_table_border_style(void) - brdr_style.border_chs.top_border_ch = '|'; - brdr_style.border_chs.separator_ch = '\0'; - brdr_style.border_chs.bottom_border_ch = '|'; - brdr_style.border_chs.side_border_ch = '='; - brdr_style.border_chs.out_intersect_ch = '+'; - brdr_style.border_chs.in_intersect_ch = '\0'; + brdr_style.border_chs.top_border_ch = "|"; + brdr_style.border_chs.separator_ch = "\0"; + brdr_style.border_chs.bottom_border_ch = "|"; + brdr_style.border_chs.side_border_ch = "="; + brdr_style.border_chs.out_intersect_ch = "+"; + brdr_style.border_chs.in_intersect_ch = "\0"; - brdr_style.header_border_chs.top_border_ch = '*'; - brdr_style.header_border_chs.separator_ch = '*'; - brdr_style.header_border_chs.bottom_border_ch = '*'; - brdr_style.header_border_chs.side_border_ch = 'v'; - brdr_style.header_border_chs.out_intersect_ch = '+'; - brdr_style.header_border_chs.in_intersect_ch = '#'; + brdr_style.header_border_chs.top_border_ch = "*"; + brdr_style.header_border_chs.separator_ch = "*"; + brdr_style.header_border_chs.bottom_border_ch = "*"; + brdr_style.header_border_chs.side_border_ch = "v"; + brdr_style.header_border_chs.out_intersect_ch = "+"; + brdr_style.header_border_chs.in_intersect_ch = "#"; + + brdr_style.hor_separator_char = ""; ft_set_default_border_style(&brdr_style); diff --git a/tests/test_utility.c b/tests/test_utility.c index e6b4003..470d3cb 100644 --- a/tests/test_utility.c +++ b/tests/test_utility.c @@ -15,21 +15,21 @@ int set_test_options_for_table(FTABLE *table) struct ft_border_style brdr_style; - brdr_style.border_chs.top_border_ch = '-'; - brdr_style.border_chs.separator_ch = '-'; - brdr_style.border_chs.bottom_border_ch = '-'; - brdr_style.border_chs.side_border_ch = '|'; - brdr_style.border_chs.out_intersect_ch = '+'; - brdr_style.border_chs.in_intersect_ch = '+'; + brdr_style.border_chs.top_border_ch = "-"; + brdr_style.border_chs.separator_ch = "-"; + brdr_style.border_chs.bottom_border_ch = "-"; + brdr_style.border_chs.side_border_ch = "|"; + brdr_style.border_chs.out_intersect_ch = "+"; + brdr_style.border_chs.in_intersect_ch = "+"; - brdr_style.header_border_chs.top_border_ch = '-'; - brdr_style.header_border_chs.separator_ch = '-'; - brdr_style.header_border_chs.bottom_border_ch = '-'; - brdr_style.header_border_chs.side_border_ch = '|'; - brdr_style.header_border_chs.out_intersect_ch = '+'; - brdr_style.header_border_chs.in_intersect_ch = '+'; + brdr_style.header_border_chs.top_border_ch = "-"; + brdr_style.header_border_chs.separator_ch = "-"; + brdr_style.header_border_chs.bottom_border_ch = "-"; + brdr_style.header_border_chs.side_border_ch = "|"; + brdr_style.header_border_chs.out_intersect_ch = "+"; + brdr_style.header_border_chs.in_intersect_ch = "+"; - brdr_style.hor_separator_char = '='; + brdr_style.hor_separator_char = "="; return ft_set_border_style(table, &brdr_style); } @@ -50,21 +50,21 @@ int set_test_options_as_default(void) struct ft_border_style brdr_style; - brdr_style.border_chs.top_border_ch = '-'; - brdr_style.border_chs.separator_ch = '-'; - brdr_style.border_chs.bottom_border_ch = '-'; - brdr_style.border_chs.side_border_ch = '|'; - brdr_style.border_chs.out_intersect_ch = '+'; - brdr_style.border_chs.in_intersect_ch = '+'; + brdr_style.border_chs.top_border_ch = "-"; + brdr_style.border_chs.separator_ch = "-"; + brdr_style.border_chs.bottom_border_ch = "-"; + brdr_style.border_chs.side_border_ch = "|"; + brdr_style.border_chs.out_intersect_ch = "+"; + brdr_style.border_chs.in_intersect_ch = "+"; - brdr_style.header_border_chs.top_border_ch = '-'; - brdr_style.header_border_chs.separator_ch = '-'; - brdr_style.header_border_chs.bottom_border_ch = '-'; - brdr_style.header_border_chs.side_border_ch = '|'; - brdr_style.header_border_chs.out_intersect_ch = '+'; - brdr_style.header_border_chs.in_intersect_ch = '+'; + brdr_style.header_border_chs.top_border_ch = "-"; + brdr_style.header_border_chs.separator_ch = "-"; + brdr_style.header_border_chs.bottom_border_ch = "-"; + brdr_style.header_border_chs.side_border_ch = "|"; + brdr_style.header_border_chs.out_intersect_ch = "+"; + brdr_style.header_border_chs.in_intersect_ch = "+"; - brdr_style.hor_separator_char = '='; + brdr_style.hor_separator_char = "="; return ft_set_default_border_style(&brdr_style); }