[A] Added column alignment
This commit is contained in:
parent
58bd522e7c
commit
7f8dd23101
@ -102,6 +102,13 @@ FORT_EXTERN char* ft_to_string(const FTABLE *FORT_RESTRICT table);
|
||||
|
||||
|
||||
|
||||
enum TextAlignment
|
||||
{
|
||||
LeftAligned,
|
||||
CenterAligned,
|
||||
RightAligned
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* TABLE BORDER
|
||||
@ -148,6 +155,14 @@ enum BorderItemPos
|
||||
|
||||
struct vector;
|
||||
typedef struct vector vector_t;
|
||||
|
||||
struct fort_column_options
|
||||
{
|
||||
int col_min_width;
|
||||
enum TextAlignment align;
|
||||
};
|
||||
typedef struct fort_column_options fort_column_options_t;
|
||||
|
||||
struct fort_table_options
|
||||
{
|
||||
int cell_padding_top;
|
||||
@ -158,14 +173,17 @@ struct fort_table_options
|
||||
|
||||
char border_chars[BorderItemPosSize];
|
||||
char header_border_chars[BorderItemPosSize];
|
||||
vector_t *col_min_widths;
|
||||
vector_t *col_options;
|
||||
|
||||
};
|
||||
typedef struct fort_table_options fort_table_options_t;
|
||||
typedef fort_table_options_t context_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);
|
||||
FORT_EXTERN int ft_set_column_alignment(FTABLE * FORT_RESTRICT table, size_t column, enum TextAlignment align);
|
||||
|
||||
|
||||
|
||||
|
315
src/fort.c
315
src/fort.c
@ -108,6 +108,157 @@ static int snprint_n_chars(char *buf, size_t length, size_t n, char ch)
|
||||
return n;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* VECTOR
|
||||
* ***************************************************************************/
|
||||
|
||||
struct vector;
|
||||
typedef struct vector vector_t;
|
||||
|
||||
#define INVALID_VEC_INDEX ((size_t) -1)
|
||||
|
||||
static vector_t* create_vector(size_t item_size, size_t capacity);
|
||||
static void destroy_vector(vector_t*);
|
||||
|
||||
static size_t vector_size(const vector_t*);
|
||||
static size_t vector_capacity(const vector_t*);
|
||||
static size_t vector_index_of(const vector_t*, const void *item);
|
||||
|
||||
static int vector_push(vector_t*, const void *item);
|
||||
static int vector_erase(vector_t*, size_t index);
|
||||
static void vector_clear(vector_t*);
|
||||
static void* vector_at(vector_t*, size_t index);
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* COLUMN OPTIONS
|
||||
* ***************************************************************************/
|
||||
|
||||
static fort_column_options_t g_column_options =
|
||||
{
|
||||
0, /* col_min_width*/
|
||||
RightAligned, /* align */
|
||||
};
|
||||
|
||||
static fort_column_options_t create_column_options()
|
||||
{
|
||||
fort_column_options_t result;
|
||||
memset(&result, '\0', sizeof(result));
|
||||
memcpy(&result, &g_column_options, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* OPTIONS
|
||||
* ***************************************************************************/
|
||||
|
||||
static fort_table_options_t g_table_options = {
|
||||
1, /* cell_padding_top */
|
||||
1, /* cell_padding_bottom */
|
||||
1, /* cell_padding_left */
|
||||
1, /* cell_padding_right */
|
||||
1, /* cell_empty_string_height */
|
||||
|
||||
/* border_chars */
|
||||
{
|
||||
'=', '=', '=', '=',
|
||||
'|', '|', '|',
|
||||
'=', '=', '=', '=',
|
||||
'=', '=', '=', '='
|
||||
},
|
||||
|
||||
/* header_border_chars */
|
||||
{
|
||||
'=', '=', '=', '=',
|
||||
'|', '|', '|',
|
||||
'=', '=', '=', '=',
|
||||
'=', '=', '=', '='
|
||||
},
|
||||
|
||||
NULL, /* col_options */
|
||||
|
||||
};
|
||||
|
||||
|
||||
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_options != NULL) {
|
||||
destroy_vector(options->col_options);
|
||||
}
|
||||
F_FREE(options);
|
||||
}
|
||||
|
||||
|
||||
#define FORT_OPTIONS_SET_COLUMN_OPTION(options, column, opt_name, opt_value) \
|
||||
assert(options);\
|
||||
\
|
||||
if (options->col_options == NULL) {\
|
||||
options->col_options = create_vector(sizeof(fort_column_options_t), DEFAULT_VECTOR_CAPACITY);\
|
||||
if (options->col_options == NULL) \
|
||||
return F_MEMORY_ERROR; \
|
||||
} \
|
||||
\
|
||||
while (vector_size(options->col_options) <= column) {\
|
||||
fort_column_options_t def_option = create_column_options();\
|
||||
vector_push(options->col_options, &def_option);\
|
||||
}\
|
||||
\
|
||||
fort_column_options_t *col_option = (fort_column_options_t*)vector_at(options->col_options, column);\
|
||||
col_option->opt_name = opt_value;\
|
||||
\
|
||||
return F_SUCCESS;
|
||||
|
||||
static fort_status_t fort_options_set_column_min_width(fort_table_options_t *options, size_t column, size_t width)
|
||||
{
|
||||
FORT_OPTIONS_SET_COLUMN_OPTION(options, column, col_min_width, width);
|
||||
}
|
||||
|
||||
static fort_status_t fort_options_set_column_alignment(fort_table_options_t *options, size_t column, enum TextAlignment al)
|
||||
{
|
||||
FORT_OPTIONS_SET_COLUMN_OPTION(options, column, align, al);
|
||||
}
|
||||
|
||||
static int fort_options_column_width(const fort_table_options_t *options, size_t column)
|
||||
{
|
||||
assert(options);
|
||||
if (options->col_options == NULL)
|
||||
return -1;
|
||||
|
||||
if (vector_size(options->col_options) <= column)
|
||||
return -1;
|
||||
|
||||
return ((fort_column_options_t*)vector_at(options->col_options, column))->col_min_width;
|
||||
}
|
||||
|
||||
static int fort_options_column_alignment(const fort_table_options_t *options, size_t column)
|
||||
{
|
||||
assert(options);
|
||||
|
||||
enum TextAlignment align = g_column_options.align;
|
||||
if (options->col_options == NULL)
|
||||
return align;
|
||||
|
||||
if (vector_size(options->col_options) <= column)
|
||||
return align;
|
||||
|
||||
return ((fort_column_options_t*)vector_at(options->col_options, column))->align;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* STRING BUFFER
|
||||
@ -141,123 +292,52 @@ static size_t buffer_text_width(string_buffer_t *buffer)
|
||||
return strlen(buffer->str);
|
||||
}
|
||||
|
||||
static int buffer_printf(string_buffer_t *buffer, size_t row, char *buf, size_t buf_len)
|
||||
static int buffer_printf(string_buffer_t *buffer, size_t buffer_row, size_t table_column, char *buf, size_t buf_len, const context_t *context)
|
||||
{
|
||||
if (buffer == NULL || buffer->str == NULL
|
||||
|| row >= buffer_text_height(buffer) || buf_len == 0) {
|
||||
|| buffer_row >= buffer_text_height(buffer) || buf_len == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return snprintf(buf, buf_len, "%*s", (int)(buf_len - 1), buffer->str);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* VECTOR
|
||||
* ***************************************************************************/
|
||||
|
||||
struct vector;
|
||||
typedef struct vector vector_t;
|
||||
|
||||
#define INVALID_VEC_INDEX ((size_t) -1)
|
||||
|
||||
static vector_t* create_vector(size_t item_size, size_t capacity);
|
||||
static void destroy_vector(vector_t*);
|
||||
|
||||
static size_t vector_size(const vector_t*);
|
||||
static size_t vector_capacity(const vector_t*);
|
||||
static size_t vector_index_of(const vector_t*, const void *item);
|
||||
|
||||
static int vector_push(vector_t*, const void *item);
|
||||
static int vector_erase(vector_t*, size_t index);
|
||||
static void vector_clear(vector_t*);
|
||||
static void* vector_at(vector_t*, size_t index);
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* OPTIONS
|
||||
* ***************************************************************************/
|
||||
|
||||
typedef fort_table_options_t context_t;
|
||||
static fort_table_options_t g_table_options = {
|
||||
1, /* cell_padding_top */
|
||||
1, /* cell_padding_bottom */
|
||||
1, /* cell_padding_left */
|
||||
1, /* cell_padding_right */
|
||||
1, /* cell_empty_string_height */
|
||||
|
||||
/* border_chars */
|
||||
{
|
||||
'=', '=', '=', '=',
|
||||
'|', '|', '|',
|
||||
'=', '=', '=', '=',
|
||||
'=', '=', '=', '='
|
||||
},
|
||||
|
||||
/* header_border_chars */
|
||||
{
|
||||
'=', '=', '=', '=',
|
||||
'|', '|', '|',
|
||||
'=', '=', '=', '=',
|
||||
'=', '=', '=', '='
|
||||
},
|
||||
|
||||
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)
|
||||
size_t content_width = buffer_text_width(buffer);
|
||||
if ((buf_len - 1) < content_width)
|
||||
return -1;
|
||||
|
||||
if (vector_size(options->col_min_widths) <= column)
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
|
||||
switch (fort_options_column_alignment(context, table_column)) {
|
||||
case LeftAligned:
|
||||
left = 0;
|
||||
right = (buf_len - 1) - content_width;
|
||||
break;
|
||||
case CenterAligned:
|
||||
left = ((buf_len - 1) - content_width) / 2;
|
||||
right = ((buf_len - 1) - content_width) - left;
|
||||
break;
|
||||
case RightAligned:
|
||||
left = (buf_len - 1) - content_width;
|
||||
right = 0;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
if (left < 0 || right < 0)
|
||||
return -1;
|
||||
|
||||
return *(int*)vector_at(options->col_min_widths, column);
|
||||
|
||||
int written = 0;
|
||||
written += snprint_n_chars(buf + written, buf_len - written, left, ' ');
|
||||
if (written < 0)
|
||||
return written;
|
||||
|
||||
written += snprintf(buf + written, buf_len - written, "%*s", (int)content_width, buffer->str);
|
||||
if (written < 0)
|
||||
return written;
|
||||
|
||||
written += snprint_n_chars(buf + written, buf_len - written, right, ' ');
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
@ -340,7 +420,7 @@ static int hint_height_cell(const fort_cell_t *cell, const context_t *context)
|
||||
// return result + 1;
|
||||
//}
|
||||
|
||||
static int cell_printf(fort_cell_t *cell, size_t row, char *buf, size_t buf_len, const context_t *context)
|
||||
static int cell_printf(fort_cell_t *cell, size_t row, size_t column, char *buf, size_t buf_len, const context_t *context)
|
||||
{
|
||||
if (cell == NULL || buf_len == 0 || row >= hint_height_cell(cell, context)
|
||||
|| (buf_len <= hint_width_cell(cell, context))) {
|
||||
@ -359,7 +439,7 @@ static int cell_printf(fort_cell_t *cell, size_t row, char *buf, size_t buf_len,
|
||||
written += snprint_n_chars(buf + written, buf_len - written, left, ' ');
|
||||
|
||||
if (cell->str_buffer)
|
||||
written += buffer_printf(cell->str_buffer, row - context->cell_padding_top, buf + written, buf_len - written - right);
|
||||
written += buffer_printf(cell->str_buffer, row - context->cell_padding_top, column, buf + written, buf_len - written - right, context);
|
||||
else
|
||||
written += snprint_n_chars(buf + written, buf_len - written, buf_len - written - right, ' ');
|
||||
written += snprint_n_chars(buf + written, buf_len - written, right, ' ');
|
||||
@ -740,6 +820,19 @@ int ft_set_column_min_width(FTABLE *table, size_t column, size_t width)
|
||||
return status;
|
||||
}
|
||||
|
||||
int ft_set_column_alignment(FTABLE * FORT_RESTRICT table, size_t column, enum TextAlignment align)
|
||||
{
|
||||
if (table->options == NULL) {
|
||||
table->options = create_table_options();
|
||||
if (table->options == NULL)
|
||||
return F_MEMORY_ERROR;
|
||||
}
|
||||
|
||||
int status = fort_options_set_column_alignment(table->options, column, align);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* STRING BUFFER
|
||||
@ -1103,7 +1196,7 @@ static int snprintf_row(const fort_row_t *row, char *buffer, size_t buf_sz, size
|
||||
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);
|
||||
dev += cell_printf(cell, i, buffer + dev, col_width_arr[j] + 1, context);
|
||||
dev += cell_printf(cell, i, j, buffer + dev, col_width_arr[j] + 1, context);
|
||||
} else {
|
||||
dev += snprint_n_chars(buffer + dev, buf_sz - dev, col_width_arr[j], ' ');
|
||||
}
|
||||
|
@ -528,6 +528,7 @@ void test_table_options(void **state)
|
||||
"|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);
|
||||
@ -536,7 +537,7 @@ void test_table_options(void **state)
|
||||
|
||||
|
||||
|
||||
WHEN("Set table width") {
|
||||
WHEN("Set table width and column alignment") {
|
||||
fort_table_options_t table_options;
|
||||
memcpy(&table_options, &def_options, sizeof(fort_table_options_t));
|
||||
table_options.cell_padding_bottom = 1;
|
||||
@ -548,21 +549,22 @@ void test_table_options(void **state)
|
||||
|
||||
table = create_test_int_table();
|
||||
ft_set_column_min_width(table, 1, 7);
|
||||
ft_set_column_alignment(table, 1, LeftAligned);
|
||||
|
||||
char *table_str = ft_to_string(table);
|
||||
assert_true( table_str != NULL );
|
||||
const char *table_str_etalon =
|
||||
"=======================\n"
|
||||
"| | | | |\n"
|
||||
"| 3 | 4 | 55 | 67 |\n"
|
||||
"| 3 | 4 | 55 | 67 |\n"
|
||||
"| | | | |\n"
|
||||
"=======================\n"
|
||||
"| | | | |\n"
|
||||
"| 3 | 4 | 55 | 67 |\n"
|
||||
"| 3 | 4 | 55 | 67 |\n"
|
||||
"| | | | |\n"
|
||||
"=======================\n"
|
||||
"| | | | |\n"
|
||||
"| 3 | 4 | 55 | 67 |\n"
|
||||
"| 3 | 4 | 55 | 67 |\n"
|
||||
"| | | | |\n"
|
||||
"=======================\n";
|
||||
// fprintf(stderr, "content:\n%s", table_str);
|
||||
|
Loading…
Reference in New Issue
Block a user