diff --git a/include/fort.h b/include/fort.h index 40db98f..9ed336e 100644 --- a/include/fort.h +++ b/include/fort.h @@ -146,6 +146,8 @@ enum BorderItemPos BorderItemPosSize }; +struct vector; +typedef struct vector vector_t; struct fort_table_options { int cell_padding_top; @@ -156,12 +158,14 @@ struct fort_table_options char border_chars[BorderItemPosSize]; char header_border_chars[BorderItemPosSize]; + vector_t *col_min_widths; }; typedef struct fort_table_options fort_table_options_t; FORT_EXTERN int ft_set_default_options(const fort_table_options_t *options); FORT_EXTERN int ft_get_default_options(fort_table_options_t *options); FORT_EXTERN int ft_set_table_options(FTABLE * FORT_RESTRICT table, const fort_table_options_t * FORT_RESTRICT options); +FORT_EXTERN int ft_set_column_min_width(FTABLE * FORT_RESTRICT table, size_t column, size_t width); diff --git a/src/fort.c b/src/fort.c index b28a580..133d3be 100644 --- a/src/fort.c +++ b/src/fort.c @@ -175,7 +175,7 @@ static void* vector_at(vector_t*, size_t index); /***************************************************************************** - * CELL + * OPTIONS * ***************************************************************************/ typedef fort_table_options_t context_t; @@ -200,12 +200,70 @@ static fort_table_options_t g_table_options = { '|', '|', '|', '=', '=', '=', '=', '=', '=', '=', '=' - } + }, + NULL /* col_widths */ }; +static fort_table_options_t* create_table_options() +{ + fort_table_options_t* options = F_CALLOC(sizeof(fort_table_options_t), 1); + if (options == NULL) { + return NULL; + } + memcpy(options, &g_table_options, sizeof(fort_table_options_t)); + return options; +} +static void destroy_table_options(fort_table_options_t* options) +{ + if (options == NULL) + return; + + if (options->col_min_widths != NULL) { + destroy_vector(options->col_min_widths); + } + F_FREE(options); +} + +static fort_status_t fort_options_set_column_min_width(fort_table_options_t *options, size_t column, size_t width) +{ + assert(options); + + if (options->col_min_widths == NULL) { + options->col_min_widths = create_vector(sizeof(int), DEFAULT_VECTOR_CAPACITY); + if (options->col_min_widths == NULL) + return F_MEMORY_ERROR; + } + + while (vector_size(options->col_min_widths) <= column) { + int dummy = -1; + vector_push(options->col_min_widths, &dummy); + } + + int *wid = (int*)vector_at(options->col_min_widths, column); + *wid = width; + + return F_SUCCESS; +} + +static int fort_options_column_width(fort_table_options_t *options, size_t column) +{ + assert(options); + if (options->col_min_widths == NULL) + return -1; + + if (vector_size(options->col_min_widths) <= column) + return -1; + + return *(int*)vector_at(options->col_min_widths, column); +} + + +/***************************************************************************** + * CELL + * ***************************************************************************/ struct fort_cell; typedef struct fort_cell fort_cell_t; struct fort_cell @@ -567,7 +625,7 @@ void ft_destroy_table(FTABLE *FORT_RESTRICT table) } destroy_vector(table->rows); } - F_FREE(table->options); + destroy_table_options(table->options); F_FREE(table); } @@ -669,6 +727,20 @@ int ft_set_table_options(FTABLE * FORT_RESTRICT table, const fort_table_options_ } + +int ft_set_column_min_width(FTABLE *table, size_t column, size_t width) +{ + if (table->options == NULL) { + table->options = create_table_options(); + if (table->options == NULL) + return F_MEMORY_ERROR; + } + + int status = fort_options_set_column_min_width(table->options, column, width); + return status; +} + + /***************************************************************************** * STRING BUFFER * ***************************************************************************/ @@ -1106,6 +1178,16 @@ static fort_status_t table_rows_and_cols_geometry(const FTABLE *table, } } + /* todo: Maybe it is better to move min width checking to a particular cell width checking. + * At the moment min width includes paddings. Maybe it is better that min width weren't include + * paddings but be min width of the cell content without padding + */ + if (table->options) { + for (size_t i = 0; i < cols; ++i) { + col_width_arr[i] = MAX((int)col_width_arr[i], fort_options_column_width(table->options, i)); + } + } + *col_width_arr_p = col_width_arr; *col_width_arr_sz = cols; *row_height_arr_p = row_height_arr; diff --git a/tests/test_table.c b/tests/test_table.c index 99dfe46..a93e3c9 100644 --- a/tests/test_table.c +++ b/tests/test_table.c @@ -534,4 +534,42 @@ void test_table_options(void **state) ft_destroy_table(table); } + + + WHEN("Set table width") { + fort_table_options_t table_options; + memcpy(&table_options, &def_options, sizeof(fort_table_options_t)); + table_options.cell_padding_bottom = 1; + table_options.cell_padding_top = 1; + table_options.cell_padding_left = 1; + table_options.cell_padding_right = 1; + ft_set_default_options(&table_options); + + + table = create_test_int_table(); + ft_set_column_min_width(table, 1, 7); + + char *table_str = ft_to_string(table); + assert_true( table_str != NULL ); + const char *table_str_etalon = + "=======================\n" + "| | | | |\n" + "| 3 | 4 | 55 | 67 |\n" + "| | | | |\n" + "=======================\n" + "| | | | |\n" + "| 3 | 4 | 55 | 67 |\n" + "| | | | |\n" + "=======================\n" + "| | | | |\n" + "| 3 | 4 | 55 | 67 |\n" + "| | | | |\n" + "=======================\n"; +// fprintf(stderr, "content:\n%s", table_str); + + assert_true( strcmp(table_str, table_str_etalon) == 0); + + free(table_str); + ft_destroy_table(table); + } }