diff --git a/include/fort.h b/include/fort.h index 94cfe96..40db98f 100644 --- a/include/fort.h +++ b/include/fort.h @@ -101,6 +101,51 @@ FORT_EXTERN char* ft_to_string(const FTABLE *FORT_RESTRICT table); //FORT_EXTERN ssize_t ft_n_row_to_string(const FTABLE *FORT_RESTRICT table, size_t row, char *FORT_RESTRICT dst, size_t dst_len); + + +/***************************************************************************** + * TABLE BORDER + *****************************************************************************/ + +/* + * TL TT TT TT TV TT TT TT TV TB TB TB TR <----- TopSeparator + * LL IV IV RR + * LH IH IH IH II IH IH IH II IH IH IH RH <----- InsideSeparator + * LL IV IV RR + * BL BB BB BB BV BB BB BB BV BB BB BB BR <----- BottomSeparator + */ + +enum HorSeparatorPos +{ + TopSeparator, + InsideSeparator, + BottomSeparator +}; + +enum BorderItemPos +{ + TL_bip = 0, + TT_bip = 1, + TV_bip = 2, + TR_bip = 3, + + LL_bip = 4, + IV_bip = 5, + RR_bip = 6, + + LH_bip = 7, + IH_bip = 8, + II_bip = 9, + RH_bip = 10, + + BL_bip = 11, + BB_bip = 12, + BV_bip = 13, + BR_bip = 14, + + BorderItemPosSize +}; + struct fort_table_options { int cell_padding_top; @@ -108,10 +153,9 @@ struct fort_table_options int cell_padding_left; int cell_padding_right; int cell_empty_string_height; - char hor_separator; - char ver_separator; - char header_hor_separator; - char header_ver_separator; + + char border_chars[BorderItemPosSize]; + char header_border_chars[BorderItemPosSize]; }; typedef struct fort_table_options fort_table_options_t; diff --git a/src/fort.c b/src/fort.c index 1cb2c33..b28a580 100644 --- a/src/fort.c +++ b/src/fort.c @@ -185,10 +185,23 @@ static fort_table_options_t g_table_options = { 1, /* cell_padding_left */ 1, /* cell_padding_right */ 1, /* cell_empty_string_height */ - '=', /* hor_separator */ - '|', /* ver_separator */ - '=', /* header_hor_separator */ - '|' /* header_ver_separator */ + + /* border_chars */ + { + '=', '=', '=', '=', + '|', '|', '|', + '=', '=', '=', '=', + '=', '=', '=', '=' + }, + + /* header_border_chars */ + { + '=', '=', '=', '=', + '|', '|', '|', + '=', '=', '=', '=', + '=', '=', '=', '=' + } + }; @@ -369,9 +382,10 @@ static const fort_cell_t *get_cell_c(const fort_row_t *row, size_t col) return get_cell((fort_row_t *)row, col); } -static int print_row_separator(char *buffer, size_t buffer_sz, size_t table_width, +static int print_row_separator(char *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, - const context_t *context) + enum HorSeparatorPos separatorPos, const context_t *context) { #define CHECK_RESULT_AND_MOVE_DEV(statement) \ k = statement; \ @@ -385,7 +399,6 @@ static int print_row_separator(char *buffer, size_t buffer_sz, size_t table_widt int dev = 0; int k = 0; - const char *hor_separator = NULL; const fort_row_t *main_row = NULL; if (upper_row != NULL && lower_row != NULL) { @@ -398,11 +411,55 @@ static int print_row_separator(char *buffer, size_t buffer_sz, size_t table_widt main_row = NULL; } - hor_separator = (main_row && main_row->is_header == F_TRUE) - ? &(context->header_hor_separator) - : &(context->hor_separator); + /* Row separator anatomy + * + * L I I I IV I I I R + */ + const char *L = NULL; + const char *I = NULL; + const char *IV = NULL; + const char *R = NULL; + + const char (*border_chars)[BorderItemPosSize] = NULL; + if (main_row && main_row->is_header == F_TRUE) { + border_chars = &context->header_border_chars; + } else { + border_chars = &context->border_chars; + } + + switch (separatorPos) { + case TopSeparator: + L = &(*border_chars)[TL_bip]; + I = &(*border_chars)[TT_bip]; + IV = &(*border_chars)[TV_bip]; + R = &(*border_chars)[TR_bip]; + break; + case InsideSeparator: + L = &(*border_chars)[LH_bip]; + I = &(*border_chars)[IH_bip]; + IV = &(*border_chars)[II_bip]; + R = &(*border_chars)[RH_bip]; + break; + case BottomSeparator: + L = &(*border_chars)[BL_bip]; + I = &(*border_chars)[BB_bip]; + IV = &(*border_chars)[BV_bip]; + R = &(*border_chars)[BR_bip]; + break; + default: + break; + } + + for (size_t i = 0; i < cols; ++i) { + if (i == 0) { + CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, 1, *L)); + } else { + CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, 1, *IV)); + } + CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, col_width_arr[i], *I)); + } + CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, 1, *R)); - CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, table_width - 1, *hor_separator)); CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, 1, '\n')); return dev; @@ -955,13 +1012,22 @@ static int snprintf_row(const fort_row_t *row, char *buffer, size_t buf_sz, size if (cols_in_row > col_width_arr_sz) return -1; - const char *ver_separator = (row->is_header == F_TRUE) - ? &(context->header_ver_separator) - : &(context->ver_separator); + /* Row separator anatomy + * + * L data IV data IV data R + */ + + const char (*bord_chars)[BorderItemPosSize] = (row->is_header) + ? (&context->header_border_chars) + : (&context->border_chars); + const char *L = &(*bord_chars)[LL_bip]; + const char *IV = &(*bord_chars)[IV_bip]; + const char *R = &(*bord_chars)[RR_bip]; + int dev = 0; for (size_t i = 0; i < row_height; ++i) { - dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, *ver_separator); + dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, *L); for (size_t j = 0; j < col_width_arr_sz; ++j) { if (j < cols_in_row) { fort_cell_t *cell = *(fort_cell_t**)vector_at(row->cells, j); @@ -969,7 +1035,11 @@ static int snprintf_row(const fort_row_t *row, char *buffer, size_t buf_sz, size } else { dev += snprint_n_chars(buffer + dev, buf_sz - dev, col_width_arr[j], ' '); } - dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, *ver_separator); + if (j == col_width_arr_sz - 1) { + dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, *R); + } else { + dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, *IV); + } } dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, '\n'); } @@ -1120,12 +1190,13 @@ char* ft_to_string(const FTABLE *FORT_RESTRICT table) fort_row_t *cur_row = NULL; for (size_t i = 0; i < rows; ++i) { cur_row = *(fort_row_t**)vector_at(table->rows, i); - CHECK_RESULT_AND_MOVE_DEV(print_row_separator(buffer + dev, sz - dev, width, prev_row, cur_row, context)); + enum HorSeparatorPos separatorPos = (i == 0) ? TopSeparator : InsideSeparator; + CHECK_RESULT_AND_MOVE_DEV(print_row_separator(buffer + dev, sz - dev, col_width_arr, cols, prev_row, cur_row, separatorPos, context)); CHECK_RESULT_AND_MOVE_DEV(snprintf_row(cur_row, buffer + dev, sz - dev, col_width_arr, cols, row_height_arr[i], context)); prev_row = cur_row; } cur_row = NULL; - CHECK_RESULT_AND_MOVE_DEV(print_row_separator(buffer + dev, sz - dev, width, prev_row, cur_row, context)); + CHECK_RESULT_AND_MOVE_DEV(print_row_separator(buffer + dev, sz - dev, col_width_arr, cols, prev_row, cur_row, BottomSeparator, context)); F_FREE(col_width_arr); diff --git a/tests/test_table.c b/tests/test_table.c index e20e212..99dfe46 100644 --- a/tests/test_table.c +++ b/tests/test_table.c @@ -434,10 +434,23 @@ void test_table_options(void **state) WHEN("Changing cell separators") { fort_table_options_t table_options; memcpy(&table_options, &def_options, sizeof(fort_table_options_t)); - table_options.hor_separator = '|'; - table_options.ver_separator = '='; - table_options.header_hor_separator = '*'; - table_options.header_ver_separator = 'v'; + +#define BOR_CHARS table_options.border_chars +#define H_BOR_CHARS table_options.header_border_chars + + BOR_CHARS[TL_bip] = BOR_CHARS[TT_bip] = BOR_CHARS[TV_bip] = BOR_CHARS[TR_bip] = '|'; + BOR_CHARS[LH_bip] = BOR_CHARS[IH_bip] = BOR_CHARS[II_bip] = BOR_CHARS[RH_bip] = '|'; + BOR_CHARS[BL_bip] = BOR_CHARS[BB_bip] = BOR_CHARS[BV_bip] = BOR_CHARS[BR_bip] = '|'; + BOR_CHARS[LL_bip] = BOR_CHARS[IV_bip] = BOR_CHARS[RR_bip] = '='; + + + H_BOR_CHARS[TL_bip] = H_BOR_CHARS[TT_bip] = H_BOR_CHARS[TV_bip] = H_BOR_CHARS[TR_bip] = '*'; + H_BOR_CHARS[LH_bip] = H_BOR_CHARS[IH_bip] = H_BOR_CHARS[II_bip] = H_BOR_CHARS[RH_bip] = '*'; + H_BOR_CHARS[BL_bip] = H_BOR_CHARS[BB_bip] = H_BOR_CHARS[BV_bip] = H_BOR_CHARS[BR_bip] = '*'; + H_BOR_CHARS[LL_bip] = H_BOR_CHARS[IV_bip] = H_BOR_CHARS[RR_bip] = 'v'; + +#undef BOR_CHARS +#undef H_BOR_CHARS ft_set_default_options(&table_options);