Merge pull request #29 from seleznevae/issue-28
[A] Added `adding_strategy` property to the tables
This commit is contained in:
commit
c81d23e468
@ -3,6 +3,8 @@
|
||||
### API
|
||||
|
||||
- Add functions to check if table is empty to the API.
|
||||
- `ft_ln` returns status of operation.
|
||||
- Add new table property `adding_strategy` (2 strategies available - replace(default) and insert).
|
||||
|
||||
## v0.3.2
|
||||
|
||||
|
314
lib/fort.c
314
lib/fort.c
@ -311,6 +311,12 @@ size_t vector_capacity(const f_vector_t *);
|
||||
FT_INTERNAL
|
||||
int vector_push(f_vector_t *, const void *item);
|
||||
|
||||
FT_INTERNAL
|
||||
int vector_insert(f_vector_t *, const void *item, size_t pos);
|
||||
|
||||
FT_INTERNAL
|
||||
f_vector_t *vector_split(f_vector_t *, size_t pos);
|
||||
|
||||
FT_INTERNAL
|
||||
const void *vector_at_c(const f_vector_t *vector, size_t index);
|
||||
|
||||
@ -320,12 +326,15 @@ void *vector_at(f_vector_t *, size_t index);
|
||||
FT_INTERNAL
|
||||
f_status vector_swap(f_vector_t *cur_vec, f_vector_t *mv_vec, size_t pos);
|
||||
|
||||
FT_INTERNAL
|
||||
void vector_clear(f_vector_t *);
|
||||
|
||||
FT_INTERNAL
|
||||
int vector_erase(f_vector_t *, size_t index);
|
||||
|
||||
#ifdef FT_TEST_BUILD
|
||||
f_vector_t *copy_vector(f_vector_t *);
|
||||
size_t vector_index_of(const f_vector_t *, const void *item);
|
||||
int vector_erase(f_vector_t *, size_t index);
|
||||
void vector_clear(f_vector_t *);
|
||||
#endif
|
||||
|
||||
#endif /* VECTOR_H */
|
||||
@ -2020,6 +2029,7 @@ struct fort_entire_table_properties {
|
||||
unsigned int top_margin;
|
||||
unsigned int right_margin;
|
||||
unsigned int bottom_margin;
|
||||
enum ft_adding_strategy add_strategy;
|
||||
};
|
||||
typedef struct fort_entire_table_properties fort_entire_table_properties_t;
|
||||
extern fort_entire_table_properties_t g_entire_table_properties;
|
||||
@ -2134,6 +2144,9 @@ void destroy_row(f_row_t *row);
|
||||
FT_INTERNAL
|
||||
f_row_t *copy_row(f_row_t *row);
|
||||
|
||||
FT_INTERNAL
|
||||
f_row_t *split_row(f_row_t *row, size_t pos);
|
||||
|
||||
FT_INTERNAL
|
||||
f_row_t *create_row_from_string(const char *str);
|
||||
|
||||
@ -2152,9 +2165,15 @@ const f_cell_t *get_cell_c(const f_row_t *row, size_t col);
|
||||
FT_INTERNAL
|
||||
f_cell_t *get_cell_and_create_if_not_exists(f_row_t *row, size_t col);
|
||||
|
||||
FT_INTERNAL
|
||||
f_cell_t *create_cell_in_position(f_row_t *row, size_t col);
|
||||
|
||||
FT_INTERNAL
|
||||
f_status swap_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos);
|
||||
|
||||
FT_INTERNAL
|
||||
f_status insert_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos);
|
||||
|
||||
FT_INTERNAL
|
||||
size_t group_cell_number(const f_row_t *row, size_t master_cell_col);
|
||||
|
||||
@ -2611,7 +2630,14 @@ ft_table_t *ft_create_table(void)
|
||||
F_FREE(result);
|
||||
return NULL;
|
||||
}
|
||||
result->properties = NULL;
|
||||
|
||||
result->properties = create_table_properties();
|
||||
if (result->properties == NULL) {
|
||||
destroy_vector(result->separators);
|
||||
destroy_vector(result->rows);
|
||||
F_FREE(result);
|
||||
return NULL;
|
||||
}
|
||||
result->conv_buffer = NULL;
|
||||
result->cur_row = 0;
|
||||
result->cur_col = 0;
|
||||
@ -2677,7 +2703,12 @@ ft_table_t *ft_copy_table(ft_table_t *table)
|
||||
vector_push(result->separators, &new_sep);
|
||||
}
|
||||
|
||||
|
||||
/* note: by default new table has allocated default properties, so we
|
||||
* have to destroy them first.
|
||||
*/
|
||||
if (result->properties) {
|
||||
destroy_table_properties(result->properties);
|
||||
}
|
||||
result->properties = copy_table_properties(table->properties);
|
||||
if (result->properties == NULL) {
|
||||
ft_destroy_table(result);
|
||||
@ -2691,12 +2722,57 @@ ft_table_t *ft_copy_table(ft_table_t *table)
|
||||
return result;
|
||||
}
|
||||
|
||||
static int split_cur_row(ft_table_t *table, f_row_t **tail_of_cur_row)
|
||||
{
|
||||
if (table->cur_row >= vector_size(table->rows)) {
|
||||
tail_of_cur_row = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ft_ln(ft_table_t *table)
|
||||
f_row_t *row = *(f_row_t **)vector_at(table->rows, table->cur_row);
|
||||
if (table->cur_col >= columns_in_row(row)) {
|
||||
tail_of_cur_row = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
f_row_t *tail = split_row(row, table->cur_col);
|
||||
if (!tail) {
|
||||
tail_of_cur_row = NULL;
|
||||
return FT_ERROR;
|
||||
}
|
||||
|
||||
*tail_of_cur_row = tail;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ft_ln(ft_table_t *table)
|
||||
{
|
||||
assert(table);
|
||||
fort_entire_table_properties_t *table_props = &table->properties->entire_table_properties;
|
||||
switch (table_props->add_strategy) {
|
||||
case FT_STRATEGY_INSERT: {
|
||||
f_row_t *new_row = NULL;
|
||||
if (FT_IS_ERROR(split_cur_row(table, &new_row))) {
|
||||
return FT_ERROR;
|
||||
}
|
||||
if (new_row) {
|
||||
if (FT_IS_ERROR(vector_insert(table->rows, &new_row, table->cur_row + 1))) {
|
||||
destroy_row(new_row);
|
||||
return FT_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FT_STRATEGY_REPLACE:
|
||||
// do nothing
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Unexpected situation inside libfort");
|
||||
break;
|
||||
}
|
||||
table->cur_col = 0;
|
||||
table->cur_row++;
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
|
||||
size_t ft_cur_row(const ft_table_t *table)
|
||||
@ -2760,7 +2836,22 @@ static int ft_row_printf_impl_(ft_table_t *table, size_t row, const struct f_str
|
||||
|
||||
new_cols = columns_in_row(new_row);
|
||||
cur_row_p = (f_row_t **)vector_at(table->rows, row);
|
||||
swap_row(*cur_row_p, new_row, table->cur_col);
|
||||
|
||||
switch (table->properties->entire_table_properties.add_strategy) {
|
||||
case FT_STRATEGY_INSERT: {
|
||||
if (FT_IS_ERROR(insert_row(*cur_row_p, new_row, table->cur_col)))
|
||||
goto clear;
|
||||
break;
|
||||
}
|
||||
case FT_STRATEGY_REPLACE: {
|
||||
if (FT_IS_ERROR(swap_row(*cur_row_p, new_row, table->cur_col)))
|
||||
goto clear;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0 && "Unexpected situation inside libfort");
|
||||
break;
|
||||
}
|
||||
|
||||
table->cur_col += new_cols;
|
||||
destroy_row(new_row);
|
||||
@ -4920,6 +5011,7 @@ fort_entire_table_properties_t g_entire_table_properties = {
|
||||
0, /* top_margin */
|
||||
0, /* right_margin */
|
||||
0, /* bottom_margin */
|
||||
FT_STRATEGY_REPLACE, /* add_strategy */
|
||||
};
|
||||
|
||||
static f_status set_entire_table_property_internal(fort_entire_table_properties_t *properties, uint32_t property, int value)
|
||||
@ -4934,6 +5026,8 @@ static f_status set_entire_table_property_internal(fort_entire_table_properties_
|
||||
properties->right_margin = value;
|
||||
} else if (PROP_IS_SET(property, FT_TPROP_BOTTOM_MARGIN)) {
|
||||
properties->bottom_margin = value;
|
||||
} else if (PROP_IS_SET(property, FT_TPROP_ADDING_STRATEGY)) {
|
||||
properties->add_strategy = (enum ft_adding_strategy)value;
|
||||
} else {
|
||||
return FT_EINVAL;
|
||||
}
|
||||
@ -4989,7 +5083,8 @@ f_table_properties_t g_table_properties = {
|
||||
0, /* left_margin */
|
||||
0, /* top_margin */
|
||||
0, /* right_margin */
|
||||
0 /* bottom_margin */
|
||||
0, /* bottom_margin */
|
||||
FT_STRATEGY_REPLACE, /* add_strategy */
|
||||
}
|
||||
};
|
||||
|
||||
@ -5084,21 +5179,41 @@ struct f_row {
|
||||
f_vector_t *cells;
|
||||
};
|
||||
|
||||
|
||||
FT_INTERNAL
|
||||
f_row_t *create_row(void)
|
||||
static
|
||||
f_row_t *create_row_impl(f_vector_t *cells)
|
||||
{
|
||||
f_row_t *row = (f_row_t *)F_CALLOC(1, sizeof(f_row_t));
|
||||
if (row == NULL)
|
||||
return NULL;
|
||||
if (cells) {
|
||||
row->cells = cells;
|
||||
} else {
|
||||
row->cells = create_vector(sizeof(f_cell_t *), DEFAULT_VECTOR_CAPACITY);
|
||||
if (row->cells == NULL) {
|
||||
F_FREE(row);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
f_row_t *create_row(void)
|
||||
{
|
||||
return create_row_impl(NULL);
|
||||
}
|
||||
|
||||
static
|
||||
void destroy_each_cell(f_vector_t *cells)
|
||||
{
|
||||
size_t i = 0;
|
||||
size_t cells_n = vector_size(cells);
|
||||
for (i = 0; i < cells_n; ++i) {
|
||||
f_cell_t *cell = *(f_cell_t **)vector_at(cells, i);
|
||||
destroy_cell(cell);
|
||||
}
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
void destroy_row(f_row_t *row)
|
||||
{
|
||||
@ -5106,12 +5221,7 @@ void destroy_row(f_row_t *row)
|
||||
return;
|
||||
|
||||
if (row->cells) {
|
||||
size_t i = 0;
|
||||
size_t cells_n = vector_size(row->cells);
|
||||
for (i = 0; i < cells_n; ++i) {
|
||||
f_cell_t *cell = *(f_cell_t **)vector_at(row->cells, i);
|
||||
destroy_cell(cell);
|
||||
}
|
||||
destroy_each_cell(row->cells);
|
||||
destroy_vector(row->cells);
|
||||
}
|
||||
|
||||
@ -5141,6 +5251,23 @@ f_row_t *copy_row(f_row_t *row)
|
||||
return result;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
f_row_t *split_row(f_row_t *row, size_t pos)
|
||||
{
|
||||
assert(row);
|
||||
|
||||
f_vector_t *cells = vector_split(row->cells, pos);
|
||||
if (!cells)
|
||||
return NULL;
|
||||
f_row_t *tail = create_row_impl(cells);
|
||||
if (!tail) {
|
||||
destroy_each_cell(cells);
|
||||
destroy_vector(cells);
|
||||
}
|
||||
return tail;
|
||||
}
|
||||
|
||||
|
||||
FT_INTERNAL
|
||||
size_t columns_in_row(const f_row_t *row)
|
||||
{
|
||||
@ -5202,6 +5329,23 @@ f_cell_t *get_cell_and_create_if_not_exists(f_row_t *row, size_t col)
|
||||
return get_cell_impl(row, col, CREATE_ON_NULL);
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
f_cell_t *create_cell_in_position(f_row_t *row, size_t col)
|
||||
{
|
||||
if (row == NULL || row->cells == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f_cell_t *new_cell = create_cell();
|
||||
if (new_cell == NULL)
|
||||
return NULL;
|
||||
if (FT_IS_ERROR(vector_insert(row->cells, &new_cell, col))) {
|
||||
destroy_cell(new_cell);
|
||||
return NULL;
|
||||
}
|
||||
return *(f_cell_t **)vector_at(row->cells, col);
|
||||
}
|
||||
|
||||
|
||||
FT_INTERNAL
|
||||
f_status swap_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos)
|
||||
@ -5220,6 +5364,37 @@ f_status swap_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos)
|
||||
return vector_swap(cur_row->cells, ins_row->cells, pos);
|
||||
}
|
||||
|
||||
/* Ownership of cells of `ins_row` is passed to `cur_row`. */
|
||||
FT_INTERNAL
|
||||
f_status insert_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos)
|
||||
{
|
||||
assert(cur_row);
|
||||
assert(ins_row);
|
||||
|
||||
while (vector_size(cur_row->cells) < pos) {
|
||||
f_cell_t *new_cell = create_cell();
|
||||
if (!new_cell)
|
||||
return FT_ERROR;
|
||||
vector_push(cur_row->cells, &new_cell);
|
||||
}
|
||||
|
||||
size_t sz = vector_size(ins_row->cells);
|
||||
size_t i = 0;
|
||||
for (i = 0; i < sz; ++i) {
|
||||
f_cell_t *cell = *(f_cell_t **)vector_at(ins_row->cells, i);
|
||||
if (FT_IS_ERROR(vector_insert(cur_row->cells, &cell, pos + i))) {
|
||||
/* clean up what we have inserted */
|
||||
while (i--) {
|
||||
vector_erase(cur_row->cells, pos);
|
||||
}
|
||||
return FT_ERROR;
|
||||
}
|
||||
}
|
||||
/* Clear cells so that it will be safe to destroy this row */
|
||||
vector_clear(ins_row->cells);
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
FT_INTERNAL
|
||||
size_t group_cell_number(const f_row_t *row, size_t master_cell_col)
|
||||
@ -6672,7 +6847,6 @@ f_row_t *get_row_and_create_if_not_exists(ft_table_t *table, size_t row)
|
||||
return get_row_impl(table, row, CREATE_ON_NULL);
|
||||
}
|
||||
|
||||
|
||||
FT_INTERNAL
|
||||
f_string_buffer_t *get_cur_str_buffer_and_create_if_not_exists(ft_table_t *table)
|
||||
{
|
||||
@ -6681,7 +6855,21 @@ f_string_buffer_t *get_cur_str_buffer_and_create_if_not_exists(ft_table_t *table
|
||||
f_row_t *row = get_row_and_create_if_not_exists(table, table->cur_row);
|
||||
if (row == NULL)
|
||||
return NULL;
|
||||
f_cell_t *cell = get_cell_and_create_if_not_exists(row, table->cur_col);
|
||||
|
||||
f_cell_t *cell = NULL;
|
||||
fort_entire_table_properties_t *table_props = &table->properties->entire_table_properties;
|
||||
switch (table_props->add_strategy) {
|
||||
case FT_STRATEGY_INSERT:
|
||||
cell = create_cell_in_position(row, table->cur_col);
|
||||
break;
|
||||
case FT_STRATEGY_REPLACE:
|
||||
cell = get_cell_and_create_if_not_exists(row, table->cur_col);
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Unexpected situation inside libfort");
|
||||
break;
|
||||
}
|
||||
|
||||
if (cell == NULL)
|
||||
return NULL;
|
||||
|
||||
@ -6983,6 +7171,56 @@ int vector_push(f_vector_t *vector, const void *item)
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
int vector_insert(f_vector_t *vector, const void *item, size_t pos)
|
||||
{
|
||||
assert(vector);
|
||||
assert(item);
|
||||
size_t needed_capacity = MAX(pos + 1, vector->m_size + 1);
|
||||
if (vector->m_capacity < needed_capacity) {
|
||||
if (vector_reallocate_(vector, needed_capacity) == -1)
|
||||
return FT_ERROR;
|
||||
vector->m_capacity = needed_capacity;
|
||||
}
|
||||
size_t offset = pos * vector->m_item_size;
|
||||
if (pos >= vector->m_size) {
|
||||
/* Data in the middle are not initialized */
|
||||
memcpy((char *)vector->m_data + offset, item, vector->m_item_size);
|
||||
vector->m_size = pos + 1;
|
||||
return FT_SUCCESS;
|
||||
} else {
|
||||
/* Shift following data by one position */
|
||||
memmove((char *)vector->m_data + offset + vector->m_item_size,
|
||||
(char *)vector->m_data + offset,
|
||||
vector->m_item_size * (vector->m_size - pos));
|
||||
memcpy((char *)vector->m_data + offset, item, vector->m_item_size);
|
||||
++(vector->m_size);
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
f_vector_t *vector_split(f_vector_t *vector, size_t pos)
|
||||
{
|
||||
size_t trailing_sz = vector->m_size > pos ? vector->m_size - pos : 0;
|
||||
f_vector_t *new_vector = create_vector(vector->m_item_size, trailing_sz);
|
||||
if (!new_vector)
|
||||
return new_vector;
|
||||
if (new_vector->m_capacity < trailing_sz) {
|
||||
destroy_vector(new_vector);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (trailing_sz == 0)
|
||||
return new_vector;
|
||||
|
||||
size_t offset = vector->m_item_size * pos;
|
||||
memcpy(new_vector->m_data, (char *)vector->m_data + offset,
|
||||
trailing_sz * vector->m_item_size);
|
||||
new_vector->m_size = trailing_sz;
|
||||
vector->m_size = pos;
|
||||
return new_vector;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
const void *vector_at_c(const f_vector_t *vector, size_t index)
|
||||
@ -7058,6 +7296,26 @@ f_status vector_swap(f_vector_t *cur_vec, f_vector_t *mv_vec, size_t pos)
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
void vector_clear(f_vector_t *vector)
|
||||
{
|
||||
vector->m_size = 0;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
int vector_erase(f_vector_t *vector, size_t index)
|
||||
{
|
||||
assert(vector);
|
||||
|
||||
if (vector->m_size == 0 || index >= vector->m_size)
|
||||
return FT_ERROR;
|
||||
|
||||
memmove((char *)vector->m_data + vector->m_item_size * index,
|
||||
(char *)vector->m_data + vector->m_item_size * (index + 1),
|
||||
(vector->m_size - 1 - index) * vector->m_item_size);
|
||||
vector->m_size--;
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef FT_TEST_BUILD
|
||||
|
||||
@ -7091,26 +7349,6 @@ size_t vector_index_of(const f_vector_t *vector, const void *item)
|
||||
return INVALID_VEC_INDEX;
|
||||
}
|
||||
|
||||
|
||||
int vector_erase(f_vector_t *vector, size_t index)
|
||||
{
|
||||
assert(vector);
|
||||
|
||||
if (vector->m_size == 0 || index >= vector->m_size)
|
||||
return FT_ERROR;
|
||||
|
||||
memmove((char *)vector->m_data + vector->m_item_size * index,
|
||||
(char *)vector->m_data + vector->m_item_size * (index + 1),
|
||||
(vector->m_size - 1 - index) * vector->m_item_size);
|
||||
vector->m_size--;
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void vector_clear(f_vector_t *vector)
|
||||
{
|
||||
vector->m_size = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/********************************************************
|
||||
|
19
lib/fort.h
19
lib/fort.h
@ -275,8 +275,14 @@ ft_table_t *ft_copy_table(ft_table_t *table);
|
||||
*
|
||||
* @param table
|
||||
* Pointer to formatted table.
|
||||
* @return
|
||||
* - 0: Success; data were written
|
||||
* - (<0): In case of error.
|
||||
* @note
|
||||
* This function can fail only in case FT_STRATEGY_INSERT adding strategy
|
||||
* was set for the table.
|
||||
*/
|
||||
void ft_ln(ft_table_t *table);
|
||||
int ft_ln(ft_table_t *table);
|
||||
|
||||
/**
|
||||
* Get row number of the current cell.
|
||||
@ -816,8 +822,19 @@ int ft_set_cell_prop(ft_table_t *table, size_t row, size_t col, uint32_t propert
|
||||
#define FT_TPROP_TOP_MARGIN (0x01U << 1)
|
||||
#define FT_TPROP_RIGHT_MARGIN (0x01U << 2)
|
||||
#define FT_TPROP_BOTTOM_MARGIN (0x01U << 3)
|
||||
#define FT_TPROP_ADDING_STRATEGY (0x01U << 4)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Adding strategy.
|
||||
*
|
||||
* Determines what happens with old content if current cell is not empty after
|
||||
* adding data to it. Default strategy is FT_STRATEGY_REPLACE.
|
||||
*/
|
||||
enum ft_adding_strategy {
|
||||
FT_STRATEGY_REPLACE = 0, /**< Replace old content. */
|
||||
FT_STRATEGY_INSERT /**< Insert new conten. Old content is shifted. */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
|
27
lib/fort.hpp
27
lib/fort.hpp
@ -60,6 +60,17 @@ enum class row_type {
|
||||
header = FT_ROW_HEADER
|
||||
};
|
||||
|
||||
/**
|
||||
* Adding strategy.
|
||||
*
|
||||
* Determines what happens with old content if current cell is not empty after
|
||||
* adding data to it. Default strategy is 'replace'.
|
||||
*/
|
||||
enum class add_strategy {
|
||||
replace = FT_STRATEGY_REPLACE,
|
||||
insert = FT_STRATEGY_INSERT
|
||||
};
|
||||
|
||||
/**
|
||||
* Colors.
|
||||
*/
|
||||
@ -893,6 +904,22 @@ public:
|
||||
{
|
||||
return FT_IS_SUCCESS(ft_set_tbl_prop(table_, FT_TPROP_BOTTOM_MARGIN, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set table adding strategy.
|
||||
*
|
||||
* @param value
|
||||
* Adding strategy.
|
||||
* @return
|
||||
* - true: Success; table property was changed.
|
||||
* - false: In case of error.
|
||||
*/
|
||||
bool set_adding_strategy(fort::add_strategy value)
|
||||
{
|
||||
return FT_IS_SUCCESS(ft_set_tbl_prop(table_,
|
||||
FT_TPROP_ADDING_STRATEGY,
|
||||
static_cast<int>(value)));
|
||||
}
|
||||
private:
|
||||
ft_table_t *table_;
|
||||
mutable std::stringstream stream_;
|
||||
|
19
src/fort.h
19
src/fort.h
@ -275,8 +275,14 @@ ft_table_t *ft_copy_table(ft_table_t *table);
|
||||
*
|
||||
* @param table
|
||||
* Pointer to formatted table.
|
||||
* @return
|
||||
* - 0: Success; data were written
|
||||
* - (<0): In case of error.
|
||||
* @note
|
||||
* This function can fail only in case FT_STRATEGY_INSERT adding strategy
|
||||
* was set for the table.
|
||||
*/
|
||||
void ft_ln(ft_table_t *table);
|
||||
int ft_ln(ft_table_t *table);
|
||||
|
||||
/**
|
||||
* Get row number of the current cell.
|
||||
@ -816,8 +822,19 @@ int ft_set_cell_prop(ft_table_t *table, size_t row, size_t col, uint32_t propert
|
||||
#define FT_TPROP_TOP_MARGIN (0x01U << 1)
|
||||
#define FT_TPROP_RIGHT_MARGIN (0x01U << 2)
|
||||
#define FT_TPROP_BOTTOM_MARGIN (0x01U << 3)
|
||||
#define FT_TPROP_ADDING_STRATEGY (0x01U << 4)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Adding strategy.
|
||||
*
|
||||
* Determines what happens with old content if current cell is not empty after
|
||||
* adding data to it. Default strategy is FT_STRATEGY_REPLACE.
|
||||
*/
|
||||
enum ft_adding_strategy {
|
||||
FT_STRATEGY_REPLACE = 0, /**< Replace old content. */
|
||||
FT_STRATEGY_INSERT /**< Insert new conten. Old content is shifted. */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
|
27
src/fort.hpp
27
src/fort.hpp
@ -60,6 +60,17 @@ enum class row_type {
|
||||
header = FT_ROW_HEADER
|
||||
};
|
||||
|
||||
/**
|
||||
* Adding strategy.
|
||||
*
|
||||
* Determines what happens with old content if current cell is not empty after
|
||||
* adding data to it. Default strategy is 'replace'.
|
||||
*/
|
||||
enum class add_strategy {
|
||||
replace = FT_STRATEGY_REPLACE,
|
||||
insert = FT_STRATEGY_INSERT
|
||||
};
|
||||
|
||||
/**
|
||||
* Colors.
|
||||
*/
|
||||
@ -893,6 +904,22 @@ public:
|
||||
{
|
||||
return FT_IS_SUCCESS(ft_set_tbl_prop(table_, FT_TPROP_BOTTOM_MARGIN, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set table adding strategy.
|
||||
*
|
||||
* @param value
|
||||
* Adding strategy.
|
||||
* @return
|
||||
* - true: Success; table property was changed.
|
||||
* - false: In case of error.
|
||||
*/
|
||||
bool set_adding_strategy(fort::add_strategy value)
|
||||
{
|
||||
return FT_IS_SUCCESS(ft_set_tbl_prop(table_,
|
||||
FT_TPROP_ADDING_STRATEGY,
|
||||
static_cast<int>(value)));
|
||||
}
|
||||
private:
|
||||
ft_table_t *table_;
|
||||
mutable std::stringstream stream_;
|
||||
|
@ -57,7 +57,14 @@ ft_table_t *ft_create_table(void)
|
||||
F_FREE(result);
|
||||
return NULL;
|
||||
}
|
||||
result->properties = NULL;
|
||||
|
||||
result->properties = create_table_properties();
|
||||
if (result->properties == NULL) {
|
||||
destroy_vector(result->separators);
|
||||
destroy_vector(result->rows);
|
||||
F_FREE(result);
|
||||
return NULL;
|
||||
}
|
||||
result->conv_buffer = NULL;
|
||||
result->cur_row = 0;
|
||||
result->cur_col = 0;
|
||||
@ -123,7 +130,12 @@ ft_table_t *ft_copy_table(ft_table_t *table)
|
||||
vector_push(result->separators, &new_sep);
|
||||
}
|
||||
|
||||
|
||||
/* note: by default new table has allocated default properties, so we
|
||||
* have to destroy them first.
|
||||
*/
|
||||
if (result->properties) {
|
||||
destroy_table_properties(result->properties);
|
||||
}
|
||||
result->properties = copy_table_properties(table->properties);
|
||||
if (result->properties == NULL) {
|
||||
ft_destroy_table(result);
|
||||
@ -137,12 +149,57 @@ ft_table_t *ft_copy_table(ft_table_t *table)
|
||||
return result;
|
||||
}
|
||||
|
||||
static int split_cur_row(ft_table_t *table, f_row_t **tail_of_cur_row)
|
||||
{
|
||||
if (table->cur_row >= vector_size(table->rows)) {
|
||||
tail_of_cur_row = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ft_ln(ft_table_t *table)
|
||||
f_row_t *row = *(f_row_t **)vector_at(table->rows, table->cur_row);
|
||||
if (table->cur_col >= columns_in_row(row)) {
|
||||
tail_of_cur_row = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
f_row_t *tail = split_row(row, table->cur_col);
|
||||
if (!tail) {
|
||||
tail_of_cur_row = NULL;
|
||||
return FT_ERROR;
|
||||
}
|
||||
|
||||
*tail_of_cur_row = tail;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ft_ln(ft_table_t *table)
|
||||
{
|
||||
assert(table);
|
||||
fort_entire_table_properties_t *table_props = &table->properties->entire_table_properties;
|
||||
switch (table_props->add_strategy) {
|
||||
case FT_STRATEGY_INSERT: {
|
||||
f_row_t *new_row = NULL;
|
||||
if (FT_IS_ERROR(split_cur_row(table, &new_row))) {
|
||||
return FT_ERROR;
|
||||
}
|
||||
if (new_row) {
|
||||
if (FT_IS_ERROR(vector_insert(table->rows, &new_row, table->cur_row + 1))) {
|
||||
destroy_row(new_row);
|
||||
return FT_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FT_STRATEGY_REPLACE:
|
||||
// do nothing
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Unexpected situation inside libfort");
|
||||
break;
|
||||
}
|
||||
table->cur_col = 0;
|
||||
table->cur_row++;
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
|
||||
size_t ft_cur_row(const ft_table_t *table)
|
||||
@ -206,7 +263,22 @@ static int ft_row_printf_impl_(ft_table_t *table, size_t row, const struct f_str
|
||||
|
||||
new_cols = columns_in_row(new_row);
|
||||
cur_row_p = (f_row_t **)vector_at(table->rows, row);
|
||||
swap_row(*cur_row_p, new_row, table->cur_col);
|
||||
|
||||
switch (table->properties->entire_table_properties.add_strategy) {
|
||||
case FT_STRATEGY_INSERT: {
|
||||
if (FT_IS_ERROR(insert_row(*cur_row_p, new_row, table->cur_col)))
|
||||
goto clear;
|
||||
break;
|
||||
}
|
||||
case FT_STRATEGY_REPLACE: {
|
||||
if (FT_IS_ERROR(swap_row(*cur_row_p, new_row, table->cur_col)))
|
||||
goto clear;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0 && "Unexpected situation inside libfort");
|
||||
break;
|
||||
}
|
||||
|
||||
table->cur_col += new_cols;
|
||||
destroy_row(new_row);
|
||||
|
@ -874,6 +874,7 @@ fort_entire_table_properties_t g_entire_table_properties = {
|
||||
0, /* top_margin */
|
||||
0, /* right_margin */
|
||||
0, /* bottom_margin */
|
||||
FT_STRATEGY_REPLACE, /* add_strategy */
|
||||
};
|
||||
|
||||
static f_status set_entire_table_property_internal(fort_entire_table_properties_t *properties, uint32_t property, int value)
|
||||
@ -888,6 +889,8 @@ static f_status set_entire_table_property_internal(fort_entire_table_properties_
|
||||
properties->right_margin = value;
|
||||
} else if (PROP_IS_SET(property, FT_TPROP_BOTTOM_MARGIN)) {
|
||||
properties->bottom_margin = value;
|
||||
} else if (PROP_IS_SET(property, FT_TPROP_ADDING_STRATEGY)) {
|
||||
properties->add_strategy = (enum ft_adding_strategy)value;
|
||||
} else {
|
||||
return FT_EINVAL;
|
||||
}
|
||||
@ -943,7 +946,8 @@ f_table_properties_t g_table_properties = {
|
||||
0, /* left_margin */
|
||||
0, /* top_margin */
|
||||
0, /* right_margin */
|
||||
0 /* bottom_margin */
|
||||
0, /* bottom_margin */
|
||||
FT_STRATEGY_REPLACE, /* add_strategy */
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -177,6 +177,7 @@ struct fort_entire_table_properties {
|
||||
unsigned int top_margin;
|
||||
unsigned int right_margin;
|
||||
unsigned int bottom_margin;
|
||||
enum ft_adding_strategy add_strategy;
|
||||
};
|
||||
typedef struct fort_entire_table_properties fort_entire_table_properties_t;
|
||||
extern fort_entire_table_properties_t g_entire_table_properties;
|
||||
|
98
src/row.c
98
src/row.c
@ -10,21 +10,41 @@ struct f_row {
|
||||
f_vector_t *cells;
|
||||
};
|
||||
|
||||
|
||||
FT_INTERNAL
|
||||
f_row_t *create_row(void)
|
||||
static
|
||||
f_row_t *create_row_impl(f_vector_t *cells)
|
||||
{
|
||||
f_row_t *row = (f_row_t *)F_CALLOC(1, sizeof(f_row_t));
|
||||
if (row == NULL)
|
||||
return NULL;
|
||||
if (cells) {
|
||||
row->cells = cells;
|
||||
} else {
|
||||
row->cells = create_vector(sizeof(f_cell_t *), DEFAULT_VECTOR_CAPACITY);
|
||||
if (row->cells == NULL) {
|
||||
F_FREE(row);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
f_row_t *create_row(void)
|
||||
{
|
||||
return create_row_impl(NULL);
|
||||
}
|
||||
|
||||
static
|
||||
void destroy_each_cell(f_vector_t *cells)
|
||||
{
|
||||
size_t i = 0;
|
||||
size_t cells_n = vector_size(cells);
|
||||
for (i = 0; i < cells_n; ++i) {
|
||||
f_cell_t *cell = *(f_cell_t **)vector_at(cells, i);
|
||||
destroy_cell(cell);
|
||||
}
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
void destroy_row(f_row_t *row)
|
||||
{
|
||||
@ -32,12 +52,7 @@ void destroy_row(f_row_t *row)
|
||||
return;
|
||||
|
||||
if (row->cells) {
|
||||
size_t i = 0;
|
||||
size_t cells_n = vector_size(row->cells);
|
||||
for (i = 0; i < cells_n; ++i) {
|
||||
f_cell_t *cell = *(f_cell_t **)vector_at(row->cells, i);
|
||||
destroy_cell(cell);
|
||||
}
|
||||
destroy_each_cell(row->cells);
|
||||
destroy_vector(row->cells);
|
||||
}
|
||||
|
||||
@ -67,6 +82,23 @@ f_row_t *copy_row(f_row_t *row)
|
||||
return result;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
f_row_t *split_row(f_row_t *row, size_t pos)
|
||||
{
|
||||
assert(row);
|
||||
|
||||
f_vector_t *cells = vector_split(row->cells, pos);
|
||||
if (!cells)
|
||||
return NULL;
|
||||
f_row_t *tail = create_row_impl(cells);
|
||||
if (!tail) {
|
||||
destroy_each_cell(cells);
|
||||
destroy_vector(cells);
|
||||
}
|
||||
return tail;
|
||||
}
|
||||
|
||||
|
||||
FT_INTERNAL
|
||||
size_t columns_in_row(const f_row_t *row)
|
||||
{
|
||||
@ -128,6 +160,23 @@ f_cell_t *get_cell_and_create_if_not_exists(f_row_t *row, size_t col)
|
||||
return get_cell_impl(row, col, CREATE_ON_NULL);
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
f_cell_t *create_cell_in_position(f_row_t *row, size_t col)
|
||||
{
|
||||
if (row == NULL || row->cells == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f_cell_t *new_cell = create_cell();
|
||||
if (new_cell == NULL)
|
||||
return NULL;
|
||||
if (FT_IS_ERROR(vector_insert(row->cells, &new_cell, col))) {
|
||||
destroy_cell(new_cell);
|
||||
return NULL;
|
||||
}
|
||||
return *(f_cell_t **)vector_at(row->cells, col);
|
||||
}
|
||||
|
||||
|
||||
FT_INTERNAL
|
||||
f_status swap_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos)
|
||||
@ -146,6 +195,37 @@ f_status swap_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos)
|
||||
return vector_swap(cur_row->cells, ins_row->cells, pos);
|
||||
}
|
||||
|
||||
/* Ownership of cells of `ins_row` is passed to `cur_row`. */
|
||||
FT_INTERNAL
|
||||
f_status insert_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos)
|
||||
{
|
||||
assert(cur_row);
|
||||
assert(ins_row);
|
||||
|
||||
while (vector_size(cur_row->cells) < pos) {
|
||||
f_cell_t *new_cell = create_cell();
|
||||
if (!new_cell)
|
||||
return FT_ERROR;
|
||||
vector_push(cur_row->cells, &new_cell);
|
||||
}
|
||||
|
||||
size_t sz = vector_size(ins_row->cells);
|
||||
size_t i = 0;
|
||||
for (i = 0; i < sz; ++i) {
|
||||
f_cell_t *cell = *(f_cell_t **)vector_at(ins_row->cells, i);
|
||||
if (FT_IS_ERROR(vector_insert(cur_row->cells, &cell, pos + i))) {
|
||||
/* clean up what we have inserted */
|
||||
while (i--) {
|
||||
vector_erase(cur_row->cells, pos);
|
||||
}
|
||||
return FT_ERROR;
|
||||
}
|
||||
}
|
||||
/* Clear cells so that it will be safe to destroy this row */
|
||||
vector_clear(ins_row->cells);
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
FT_INTERNAL
|
||||
size_t group_cell_number(const f_row_t *row, size_t master_cell_col)
|
||||
|
@ -18,6 +18,9 @@ void destroy_row(f_row_t *row);
|
||||
FT_INTERNAL
|
||||
f_row_t *copy_row(f_row_t *row);
|
||||
|
||||
FT_INTERNAL
|
||||
f_row_t *split_row(f_row_t *row, size_t pos);
|
||||
|
||||
FT_INTERNAL
|
||||
f_row_t *create_row_from_string(const char *str);
|
||||
|
||||
@ -36,9 +39,15 @@ const f_cell_t *get_cell_c(const f_row_t *row, size_t col);
|
||||
FT_INTERNAL
|
||||
f_cell_t *get_cell_and_create_if_not_exists(f_row_t *row, size_t col);
|
||||
|
||||
FT_INTERNAL
|
||||
f_cell_t *create_cell_in_position(f_row_t *row, size_t col);
|
||||
|
||||
FT_INTERNAL
|
||||
f_status swap_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos);
|
||||
|
||||
FT_INTERNAL
|
||||
f_status insert_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos);
|
||||
|
||||
FT_INTERNAL
|
||||
size_t group_cell_number(const f_row_t *row, size_t master_cell_col);
|
||||
|
||||
|
17
src/table.c
17
src/table.c
@ -81,7 +81,6 @@ f_row_t *get_row_and_create_if_not_exists(ft_table_t *table, size_t row)
|
||||
return get_row_impl(table, row, CREATE_ON_NULL);
|
||||
}
|
||||
|
||||
|
||||
FT_INTERNAL
|
||||
f_string_buffer_t *get_cur_str_buffer_and_create_if_not_exists(ft_table_t *table)
|
||||
{
|
||||
@ -90,7 +89,21 @@ f_string_buffer_t *get_cur_str_buffer_and_create_if_not_exists(ft_table_t *table
|
||||
f_row_t *row = get_row_and_create_if_not_exists(table, table->cur_row);
|
||||
if (row == NULL)
|
||||
return NULL;
|
||||
f_cell_t *cell = get_cell_and_create_if_not_exists(row, table->cur_col);
|
||||
|
||||
f_cell_t *cell = NULL;
|
||||
fort_entire_table_properties_t *table_props = &table->properties->entire_table_properties;
|
||||
switch (table_props->add_strategy) {
|
||||
case FT_STRATEGY_INSERT:
|
||||
cell = create_cell_in_position(row, table->cur_col);
|
||||
break;
|
||||
case FT_STRATEGY_REPLACE:
|
||||
cell = get_cell_and_create_if_not_exists(row, table->cur_col);
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Unexpected situation inside libfort");
|
||||
break;
|
||||
}
|
||||
|
||||
if (cell == NULL)
|
||||
return NULL;
|
||||
|
||||
|
90
src/vector.c
90
src/vector.c
@ -91,6 +91,56 @@ int vector_push(f_vector_t *vector, const void *item)
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
int vector_insert(f_vector_t *vector, const void *item, size_t pos)
|
||||
{
|
||||
assert(vector);
|
||||
assert(item);
|
||||
size_t needed_capacity = MAX(pos + 1, vector->m_size + 1);
|
||||
if (vector->m_capacity < needed_capacity) {
|
||||
if (vector_reallocate_(vector, needed_capacity) == -1)
|
||||
return FT_ERROR;
|
||||
vector->m_capacity = needed_capacity;
|
||||
}
|
||||
size_t offset = pos * vector->m_item_size;
|
||||
if (pos >= vector->m_size) {
|
||||
/* Data in the middle are not initialized */
|
||||
memcpy((char *)vector->m_data + offset, item, vector->m_item_size);
|
||||
vector->m_size = pos + 1;
|
||||
return FT_SUCCESS;
|
||||
} else {
|
||||
/* Shift following data by one position */
|
||||
memmove((char *)vector->m_data + offset + vector->m_item_size,
|
||||
(char *)vector->m_data + offset,
|
||||
vector->m_item_size * (vector->m_size - pos));
|
||||
memcpy((char *)vector->m_data + offset, item, vector->m_item_size);
|
||||
++(vector->m_size);
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
f_vector_t *vector_split(f_vector_t *vector, size_t pos)
|
||||
{
|
||||
size_t trailing_sz = vector->m_size > pos ? vector->m_size - pos : 0;
|
||||
f_vector_t *new_vector = create_vector(vector->m_item_size, trailing_sz);
|
||||
if (!new_vector)
|
||||
return new_vector;
|
||||
if (new_vector->m_capacity < trailing_sz) {
|
||||
destroy_vector(new_vector);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (trailing_sz == 0)
|
||||
return new_vector;
|
||||
|
||||
size_t offset = vector->m_item_size * pos;
|
||||
memcpy(new_vector->m_data, (char *)vector->m_data + offset,
|
||||
trailing_sz * vector->m_item_size);
|
||||
new_vector->m_size = trailing_sz;
|
||||
vector->m_size = pos;
|
||||
return new_vector;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
const void *vector_at_c(const f_vector_t *vector, size_t index)
|
||||
@ -166,6 +216,26 @@ f_status vector_swap(f_vector_t *cur_vec, f_vector_t *mv_vec, size_t pos)
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
void vector_clear(f_vector_t *vector)
|
||||
{
|
||||
vector->m_size = 0;
|
||||
}
|
||||
|
||||
FT_INTERNAL
|
||||
int vector_erase(f_vector_t *vector, size_t index)
|
||||
{
|
||||
assert(vector);
|
||||
|
||||
if (vector->m_size == 0 || index >= vector->m_size)
|
||||
return FT_ERROR;
|
||||
|
||||
memmove((char *)vector->m_data + vector->m_item_size * index,
|
||||
(char *)vector->m_data + vector->m_item_size * (index + 1),
|
||||
(vector->m_size - 1 - index) * vector->m_item_size);
|
||||
vector->m_size--;
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef FT_TEST_BUILD
|
||||
|
||||
@ -199,24 +269,4 @@ size_t vector_index_of(const f_vector_t *vector, const void *item)
|
||||
return INVALID_VEC_INDEX;
|
||||
}
|
||||
|
||||
|
||||
int vector_erase(f_vector_t *vector, size_t index)
|
||||
{
|
||||
assert(vector);
|
||||
|
||||
if (vector->m_size == 0 || index >= vector->m_size)
|
||||
return FT_ERROR;
|
||||
|
||||
memmove((char *)vector->m_data + vector->m_item_size * index,
|
||||
(char *)vector->m_data + vector->m_item_size * (index + 1),
|
||||
(vector->m_size - 1 - index) * vector->m_item_size);
|
||||
vector->m_size--;
|
||||
return FT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void vector_clear(f_vector_t *vector)
|
||||
{
|
||||
vector->m_size = 0;
|
||||
}
|
||||
#endif
|
||||
|
13
src/vector.h
13
src/vector.h
@ -21,6 +21,12 @@ size_t vector_capacity(const f_vector_t *);
|
||||
FT_INTERNAL
|
||||
int vector_push(f_vector_t *, const void *item);
|
||||
|
||||
FT_INTERNAL
|
||||
int vector_insert(f_vector_t *, const void *item, size_t pos);
|
||||
|
||||
FT_INTERNAL
|
||||
f_vector_t *vector_split(f_vector_t *, size_t pos);
|
||||
|
||||
FT_INTERNAL
|
||||
const void *vector_at_c(const f_vector_t *vector, size_t index);
|
||||
|
||||
@ -30,12 +36,15 @@ void *vector_at(f_vector_t *, size_t index);
|
||||
FT_INTERNAL
|
||||
f_status vector_swap(f_vector_t *cur_vec, f_vector_t *mv_vec, size_t pos);
|
||||
|
||||
FT_INTERNAL
|
||||
void vector_clear(f_vector_t *);
|
||||
|
||||
FT_INTERNAL
|
||||
int vector_erase(f_vector_t *, size_t index);
|
||||
|
||||
#ifdef FT_TEST_BUILD
|
||||
f_vector_t *copy_vector(f_vector_t *);
|
||||
size_t vector_index_of(const f_vector_t *, const void *item);
|
||||
int vector_erase(f_vector_t *, size_t index);
|
||||
void vector_clear(f_vector_t *);
|
||||
#endif
|
||||
|
||||
#endif /* VECTOR_H */
|
||||
|
@ -1608,8 +1608,95 @@ void test_table_write(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
SCENARIO("Test write and printf functions simultaneously") {
|
||||
table = ft_create_table();
|
||||
assert_true(table != NULL);
|
||||
assert_true(FT_IS_SUCCESS(ft_write(table, "0", "1")));
|
||||
assert_true(FT_IS_SUCCESS(ft_printf(table, "2|3")));
|
||||
assert_true(FT_IS_SUCCESS(ft_write(table, "5", "6")));
|
||||
|
||||
const char *table_str = ft_to_string(table);
|
||||
assert_true(table_str != NULL);
|
||||
const char *table_str_etalon =
|
||||
"+---+---+---+---+---+---+\n"
|
||||
"| 0 | 1 | 2 | 3 | 5 | 6 |\n"
|
||||
"+---+---+---+---+---+---+\n";
|
||||
assert_str_equal(table_str, table_str_etalon);
|
||||
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
}
|
||||
|
||||
void test_table_insert_strategy(void)
|
||||
{
|
||||
SCENARIO("Test ft_ln") {
|
||||
ft_table_t *table = ft_create_table();
|
||||
assert_true(table != NULL);
|
||||
ft_set_tbl_prop(table, FT_TPROP_ADDING_STRATEGY, FT_STRATEGY_INSERT);
|
||||
assert_true(FT_IS_SUCCESS(ft_write_ln(table, "0", "1", "2")));
|
||||
ft_set_cur_cell(table, 0, 2);
|
||||
assert_true(FT_IS_SUCCESS(ft_ln(table)));
|
||||
ft_set_cur_cell(table, 1, 1);
|
||||
assert_true(FT_IS_SUCCESS(ft_write(table, "3")));
|
||||
|
||||
const char *table_str = ft_to_string(table);
|
||||
assert_true(table_str != NULL);
|
||||
const char *table_str_etalon =
|
||||
"+---+---+\n"
|
||||
"| 0 | 1 |\n"
|
||||
"| 2 | 3 |\n"
|
||||
"+---+---+\n";
|
||||
assert_str_equal(table_str, table_str_etalon);
|
||||
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
|
||||
SCENARIO("Test write functions") {
|
||||
ft_table_t *table = ft_create_table();
|
||||
assert_true(table != NULL);
|
||||
ft_set_tbl_prop(table, FT_TPROP_ADDING_STRATEGY, FT_STRATEGY_INSERT);
|
||||
assert_true(FT_IS_SUCCESS(ft_write_ln(table, "0", "1", "2", "4", "5")));
|
||||
ft_set_cur_cell(table, 0, 2);
|
||||
assert_true(FT_IS_SUCCESS(ft_ln(table)));
|
||||
ft_set_cur_cell(table, 1, 1);
|
||||
assert_true(FT_IS_SUCCESS(ft_write_ln(table, "3")));
|
||||
|
||||
const char *table_str = ft_to_string(table);
|
||||
assert_true(table_str != NULL);
|
||||
const char *table_str_etalon =
|
||||
"+---+---+\n"
|
||||
"| 0 | 1 |\n"
|
||||
"| 2 | 3 |\n"
|
||||
"| 4 | 5 |\n"
|
||||
"+---+---+\n";
|
||||
assert_str_equal(table_str, table_str_etalon);
|
||||
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
|
||||
SCENARIO("Test printf functions") {
|
||||
ft_table_t *table = ft_create_table();
|
||||
assert_true(table != NULL);
|
||||
ft_set_tbl_prop(table, FT_TPROP_ADDING_STRATEGY, FT_STRATEGY_INSERT);
|
||||
assert_true(FT_IS_SUCCESS(ft_write_ln(table, "0", "1", "2", "5", "6")));
|
||||
ft_set_cur_cell(table, 0, 2);
|
||||
assert_true(FT_IS_SUCCESS(ft_ln(table)));
|
||||
ft_set_cur_cell(table, 1, 1);
|
||||
assert_true(FT_IS_SUCCESS(ft_printf_ln(table, "3|4")));
|
||||
|
||||
const char *table_str = ft_to_string(table);
|
||||
assert_true(table_str != NULL);
|
||||
const char *table_str_etalon =
|
||||
"+---+---+---+\n"
|
||||
"| 0 | 1 | |\n"
|
||||
"| 2 | 3 | 4 |\n"
|
||||
"| 5 | 6 | |\n"
|
||||
"+---+---+---+\n";
|
||||
assert_str_equal(table_str, table_str_etalon);
|
||||
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
}
|
||||
|
||||
void test_table_copy(void)
|
||||
{
|
||||
|
@ -300,6 +300,52 @@ void test_cpp_table_write(void)
|
||||
}
|
||||
}
|
||||
|
||||
void test_cpp_table_insert(void)
|
||||
{
|
||||
SCENARIO("Test insert into beginning") {
|
||||
fort::char_table table;
|
||||
table.set_adding_strategy(fort::add_strategy::insert);
|
||||
table.set_border_style(FT_BOLD_STYLE);
|
||||
table << "val1" << "val2" << fort::endr
|
||||
<< "val3" << "val4" << fort::endr;
|
||||
|
||||
table.set_cur_cell(0, 0);
|
||||
table << fort::header
|
||||
<< "hdr1" << "hdr2" << fort::endr;
|
||||
|
||||
std::string table_str = table.to_string();
|
||||
std::string table_str_etalon =
|
||||
"┏━━━━━━┳━━━━━━┓\n"
|
||||
"┃ hdr1 ┃ hdr2 ┃\n"
|
||||
"┣━━━━━━╋━━━━━━┫\n"
|
||||
"┃ val1 ┃ val2 ┃\n"
|
||||
"┃ val3 ┃ val4 ┃\n"
|
||||
"┗━━━━━━┻━━━━━━┛\n";
|
||||
assert_string_equal(table_str, table_str_etalon);
|
||||
}
|
||||
|
||||
SCENARIO("Test insert into the middle") {
|
||||
fort::char_table table;
|
||||
table.set_adding_strategy(fort::add_strategy::insert);
|
||||
table.set_border_style(FT_BOLD_STYLE);
|
||||
table << fort::header << "hdr1" << "hdr2" << fort::endr
|
||||
<< "val1" << "val4" << fort::endr;
|
||||
|
||||
table.set_cur_cell(1, 1);
|
||||
table << "val2" << fort::endr << "val3";
|
||||
|
||||
std::string table_str = table.to_string();
|
||||
std::string table_str_etalon =
|
||||
"┏━━━━━━┳━━━━━━┓\n"
|
||||
"┃ hdr1 ┃ hdr2 ┃\n"
|
||||
"┣━━━━━━╋━━━━━━┫\n"
|
||||
"┃ val1 ┃ val2 ┃\n"
|
||||
"┃ val3 ┃ val4 ┃\n"
|
||||
"┗━━━━━━┻━━━━━━┛\n";
|
||||
assert_string_equal(table_str, table_str_etalon);
|
||||
}
|
||||
}
|
||||
|
||||
void test_cpp_table_changing_cell(void)
|
||||
{
|
||||
WHEN("All columns are equal and not empty") {
|
||||
|
@ -16,6 +16,7 @@ void test_table_changing_cell(void);
|
||||
void test_wcs_table_boundaries(void);
|
||||
#endif
|
||||
void test_table_write(void);
|
||||
void test_table_insert_strategy(void);
|
||||
void test_table_border_style(void);
|
||||
void test_table_builtin_border_styles(void);
|
||||
void test_table_cell_properties(void);
|
||||
@ -49,6 +50,7 @@ struct test_case bb_test_suite [] = {
|
||||
{"test_utf8_table", test_utf8_table},
|
||||
#endif
|
||||
{"test_table_write", test_table_write},
|
||||
{"test_table_insert_strategy", test_table_insert_strategy},
|
||||
{"test_table_changing_cell", test_table_changing_cell},
|
||||
{"test_table_border_style", test_table_border_style},
|
||||
{"test_table_builtin_border_styles", test_table_builtin_border_styles},
|
||||
|
@ -5,6 +5,7 @@
|
||||
/* Test cases */
|
||||
void test_cpp_table_basic(void);
|
||||
void test_cpp_table_write(void);
|
||||
void test_cpp_table_insert(void);
|
||||
void test_cpp_table_changing_cell(void);
|
||||
void test_cpp_table_tbl_properties(void);
|
||||
void test_cpp_table_cell_properties(void);
|
||||
@ -15,6 +16,7 @@ void test_cpp_bug_fixes(void);
|
||||
struct test_case bb_test_suite [] = {
|
||||
{"test_cpp_table_basic", test_cpp_table_basic},
|
||||
{"test_cpp_table_write", test_cpp_table_write},
|
||||
{"test_cpp_table_insert", test_cpp_table_insert},
|
||||
{"test_cpp_table_changing_cell", test_cpp_table_changing_cell},
|
||||
{"test_cpp_table_tbl_properties", test_cpp_table_tbl_properties},
|
||||
{"test_cpp_table_cell_properties", test_cpp_table_cell_properties},
|
||||
|
@ -87,6 +87,30 @@ void test_vector_basic(void)
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("Testing insert method vector") {
|
||||
vector_clear(vector);
|
||||
|
||||
size_t capacity = 10 * init_capacity;
|
||||
for (i = 0; i < capacity; ++i) {
|
||||
item_t item = (item_t)i;
|
||||
vector_insert(vector, &item, 0);
|
||||
}
|
||||
assert_true(vector_size(vector) == capacity);
|
||||
for (i = 0; i < capacity; ++i) {
|
||||
assert_true(*(item_t *)vector_at(vector, i) == (item_t)(capacity - i) - 1);
|
||||
}
|
||||
|
||||
item_t item_666 = 666;
|
||||
vector_insert(vector, &item_666, 5 * capacity - 1);
|
||||
assert_true(vector_size(vector) == 5 * capacity);
|
||||
assert_true(*(item_t *)vector_at(vector, 5 * capacity - 1) == item_666);
|
||||
|
||||
item_t item_777 = 777;
|
||||
vector_insert(vector, &item_777, 10);
|
||||
assert_true(vector_size(vector) == 5 * capacity + 1);
|
||||
assert_true(*(item_t *)vector_at(vector, 10) == item_777);
|
||||
}
|
||||
|
||||
WHEN("Moving from another vector") {
|
||||
vector_clear(vector);
|
||||
for (i = 0; i < 10; ++i) {
|
||||
|
Loading…
Reference in New Issue
Block a user