[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
|
* TABLE BORDER
|
||||||
@ -148,6 +155,14 @@ enum BorderItemPos
|
|||||||
|
|
||||||
struct vector;
|
struct vector;
|
||||||
typedef struct vector vector_t;
|
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
|
struct fort_table_options
|
||||||
{
|
{
|
||||||
int cell_padding_top;
|
int cell_padding_top;
|
||||||
@ -158,14 +173,17 @@ struct fort_table_options
|
|||||||
|
|
||||||
char border_chars[BorderItemPosSize];
|
char border_chars[BorderItemPosSize];
|
||||||
char header_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 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_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_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_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_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;
|
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
|
* STRING BUFFER
|
||||||
@ -141,123 +292,52 @@ static size_t buffer_text_width(string_buffer_t *buffer)
|
|||||||
return strlen(buffer->str);
|
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
|
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 -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return snprintf(buf, buf_len, "%*s", (int)(buf_len - 1), buffer->str);
|
size_t content_width = buffer_text_width(buffer);
|
||||||
}
|
if ((buf_len - 1) < content_width)
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* 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)
|
|
||||||
return -1;
|
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 -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;
|
// 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)
|
if (cell == NULL || buf_len == 0 || row >= hint_height_cell(cell, context)
|
||||||
|| (buf_len <= hint_width_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, ' ');
|
written += snprint_n_chars(buf + written, buf_len - written, left, ' ');
|
||||||
|
|
||||||
if (cell->str_buffer)
|
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
|
else
|
||||||
written += snprint_n_chars(buf + written, buf_len - written, buf_len - written - right, ' ');
|
written += snprint_n_chars(buf + written, buf_len - written, buf_len - written - right, ' ');
|
||||||
written += snprint_n_chars(buf + 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;
|
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
|
* 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) {
|
for (size_t j = 0; j < col_width_arr_sz; ++j) {
|
||||||
if (j < cols_in_row) {
|
if (j < cols_in_row) {
|
||||||
fort_cell_t *cell = *(fort_cell_t**)vector_at(row->cells, j);
|
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 {
|
} else {
|
||||||
dev += snprint_n_chars(buffer + dev, buf_sz - dev, col_width_arr[j], ' ');
|
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"
|
"|3|4|55|67|\n"
|
||||||
"| | | | |\n"
|
"| | | | |\n"
|
||||||
"===========\n";
|
"===========\n";
|
||||||
|
// fprintf(stderr, "content:\n%s", table_str);
|
||||||
assert_true( strcmp(table_str, table_str_etalon) == 0);
|
assert_true( strcmp(table_str, table_str_etalon) == 0);
|
||||||
|
|
||||||
free(table_str);
|
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;
|
fort_table_options_t table_options;
|
||||||
memcpy(&table_options, &def_options, sizeof(fort_table_options_t));
|
memcpy(&table_options, &def_options, sizeof(fort_table_options_t));
|
||||||
table_options.cell_padding_bottom = 1;
|
table_options.cell_padding_bottom = 1;
|
||||||
@ -548,6 +549,7 @@ void test_table_options(void **state)
|
|||||||
|
|
||||||
table = create_test_int_table();
|
table = create_test_int_table();
|
||||||
ft_set_column_min_width(table, 1, 7);
|
ft_set_column_min_width(table, 1, 7);
|
||||||
|
ft_set_column_alignment(table, 1, LeftAligned);
|
||||||
|
|
||||||
char *table_str = ft_to_string(table);
|
char *table_str = ft_to_string(table);
|
||||||
assert_true( table_str != NULL );
|
assert_true( table_str != NULL );
|
||||||
|
Loading…
Reference in New Issue
Block a user