[C] To string function returns non owning pointer

This commit is contained in:
seleznevae 2018-01-17 07:05:01 +03:00
parent b2ad87eb82
commit a4802cc737
4 changed files with 190 additions and 61 deletions

View File

@ -10,7 +10,7 @@ set(CMAKE_VERBOSE_MAKEFILE ON)
include_directories(include)
include_directories(src)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -g")

View File

@ -91,7 +91,16 @@ FORT_EXTERN int ft_hdr_printf(FTABLE *FORT_RESTRICT table, const char* FORT_REST
FORT_EXTERN int ft_row_printf(FTABLE *FORT_RESTRICT table, size_t row, const char* FORT_RESTRICT fmt, ...);
//FORT_EXTERN int ft_cell_printf(FTABLE *FORT_RESTRICT table, size_t row, size_t col, const char* FORT_RESTRICT fmt, ...);
FORT_EXTERN char* ft_to_string(const FTABLE *FORT_RESTRICT table);
FORT_EXTERN int ft_write(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT cell_content);
FORT_EXTERN int ft_write_ln(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT cell_content);
#define FT_HDR_PRINTF(table, ...) \
(( 0 ? fprintf(stderr, __VA_ARGS__) : 1), ft_hdr_printf(table, __VA_ARGS__))
#define FT_ROW_PRINTF(table, row, ...) \
(( 0 ? fprintf(stderr, __VA_ARGS__) : 1), ft_row_printf(table, row, __VA_ARGS__))
FORT_EXTERN const char* ft_to_string(const FTABLE *FORT_RESTRICT table);
//FORT_EXTERN ssize_t ft_n_to_string(const FTABLE *FORT_RESTRICT table, char *FORT_RESTRICT dst, size_t dst_len);
//FORT_EXTERN char* ft_header_to_string(const FTABLE *FORT_RESTRICT table);

View File

@ -48,6 +48,11 @@ SOFTWARE.
#define MAX(a,b) ((a) > (b) ? (a) : b)
#define MIN(a,b) ((a) < (b) ? (a) : b)
enum PolicyOnNull
{
Create,
DoNotCreate
};
enum F_BOOL
{
@ -503,23 +508,52 @@ static int columns_in_row(const fort_row_t *row)
return vector_size(row->cells);
}
static fort_cell_t *get_cell(fort_row_t *row, size_t col)
static fort_cell_t *get_cell_implementation(fort_row_t *row, size_t col, enum PolicyOnNull policy)
{
if (row == NULL || row->cells == NULL) {
return NULL;
}
if (col < columns_in_row(row)) {
return *(fort_cell_t**)vector_at(row->cells, col);
switch (policy) {
case DoNotCreate:
if (col < columns_in_row(row)) {
return *(fort_cell_t**)vector_at(row->cells, col);
}
return NULL;
break;
case Create:
while(col >= columns_in_row(row)) {
fort_cell_t *new_cell = create_cell();
if (new_cell == NULL)
return NULL;
if (IS_ERROR(vector_push(row->cells, &new_cell))) {
destroy_cell(new_cell);
return NULL;
}
}
return *(fort_cell_t**)vector_at(row->cells, col);
break;
}
return NULL;
}
static fort_cell_t *get_cell(fort_row_t *row, size_t col)
{
return get_cell_implementation(row, col, DoNotCreate);
}
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 fort_cell_t *get_cell_and_create_if_not_exists(fort_row_t *row, size_t col)
{
return get_cell_implementation(row, col, Create);
}
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,
@ -622,29 +656,81 @@ struct fort_table
{
vector_t *rows;
fort_table_options_t *options;
string_buffer_t *conv_buffer;
size_t cur_row;
size_t cur_col;
};
static fort_status_t get_table_sizes(const FTABLE *table, size_t *rows, size_t *cols);
static fort_row_t *get_row(fort_table_t *table, size_t row)
static fort_row_t *get_row_implementation(fort_table_t *table, size_t row, enum PolicyOnNull policy)
{
if (table == NULL || table->rows == NULL) {
return NULL;
}
size_t rows = vector_size(table->rows);
if (row < rows) {
return *(fort_row_t**)vector_at(table->rows, row);
switch (policy) {
case DoNotCreate:
if (row < vector_size(table->rows)) {
return *(fort_row_t**)vector_at(table->rows, row);
}
return NULL;
break;
case Create:
while(row >= vector_size(table->rows)) {
fort_row_t *new_row = create_row();
if (new_row == NULL)
return NULL;
if (IS_ERROR(vector_push(table->rows, &new_row))) {
destroy_row(new_row);
return NULL;
}
}
return *(fort_row_t**)vector_at(table->rows, row);
break;
}
return NULL;
}
static fort_row_t *get_row(fort_table_t *table, size_t row)
{
return get_row_implementation(table, row, DoNotCreate);
}
static const fort_row_t *get_row_c(const fort_table_t *table, size_t row)
{
return get_row((fort_table_t *)table, row);
}
static fort_row_t *get_row_and_create_if_not_exists(fort_table_t *table, size_t row)
{
return get_row_implementation(table, row, Create);
}
static string_buffer_t * get_cur_str_buffer_and_create_if_not_exists(FTABLE *FORT_RESTRICT table)
{
assert(table);
fort_row_t *row = get_row_and_create_if_not_exists(table, table->cur_row);
if (row == NULL)
return NULL;
fort_cell_t *cell = get_cell_and_create_if_not_exists(row, table->cur_col);
if (cell == NULL)
return NULL;
if (cell->str_buffer == NULL) {
cell->str_buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE);
if (cell->str_buffer == NULL)
return NULL;
}
return cell->str_buffer;
}
/*****************************************************************************
* LIBFORT helpers
*****************************************************************************/
@ -693,6 +779,9 @@ FTABLE * ft_create_table(void)
return NULL;
}
result->options = NULL;
result->conv_buffer = NULL;
result->cur_row = 0;
result->cur_col = 0;
return result;
}
@ -710,6 +799,7 @@ void ft_destroy_table(FTABLE *FORT_RESTRICT table)
destroy_vector(table->rows);
}
destroy_table_options(table->options);
destroy_string_buffer(table->conv_buffer);
F_FREE(table);
}
@ -748,6 +838,8 @@ static int ft_row_printf_impl(FTABLE *FORT_RESTRICT table, size_t row, const cha
destroy_row(*cur_row_p);
*cur_row_p = new_row;
table->cur_col = 0;
table->cur_row++;
return vector_size(new_row->cells);
clear:
@ -779,6 +871,29 @@ int ft_row_printf(FTABLE *FORT_RESTRICT table, size_t row, const char* FORT_REST
return result;
}
int ft_write(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT cell_content)
{
string_buffer_t *str_buffer = get_cur_str_buffer_and_create_if_not_exists(table);
if (str_buffer == NULL)
return F_ERROR;
int status = fill_buffer_from_string(str_buffer, cell_content);
if (IS_SUCCESS(status)) {
table->cur_col++;
}
return status;
}
int ft_write_ln(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT cell_content)
{
int status = ft_write(table, cell_content);
if (IS_SUCCESS(status)) {
table->cur_col = 0;
table->cur_row++;
}
return status;
}
int ft_set_default_options(const fort_table_options_t *options)
{
memcpy(&g_table_options, options, sizeof(fort_table_options_t));
@ -1316,6 +1431,7 @@ static fort_status_t table_geometry(const FTABLE *table, size_t *height, size_t
*width += col_width_arr[i];
}
/* todo: add check for non printable horizontal row separators */
*height = 1 + (rows == 0 ? 1 : rows); // for boundaries (that take 1 symbol)
for (size_t i = 0; i < rows; ++i) {
*height += row_height_arr[i];
@ -1328,7 +1444,7 @@ static fort_status_t table_geometry(const FTABLE *table, size_t *height, size_t
char* ft_to_string(const FTABLE *FORT_RESTRICT table)
const char* ft_to_string(const FTABLE *FORT_RESTRICT table)
{
#define CHECK_RESULT_AND_MOVE_DEV(statement) \
k = statement; \
@ -1339,6 +1455,7 @@ char* ft_to_string(const FTABLE *FORT_RESTRICT table)
assert(table);
/* Determing size of table string representation */
size_t height = 0;
size_t width = 0;
int status = table_geometry(table, &height, &width);
@ -1346,9 +1463,20 @@ char* ft_to_string(const FTABLE *FORT_RESTRICT table)
return NULL;
}
size_t sz = height * width + 1;
char *buffer = F_MALLOC(sz);
if (buffer == NULL)
return NULL;
/* Allocate string buffer for string representation */
if (table->conv_buffer == NULL) {
((FTABLE *)table)->conv_buffer = create_string_buffer(sz);
if (table->conv_buffer == NULL)
return NULL;
}
while (table->conv_buffer->str_sz < sz) {
if (IS_ERROR(realloc_string_buffer_without_copy(table->conv_buffer))) {
return NULL;
}
}
char *buffer = table->conv_buffer->str;
size_t cols = 0;
size_t rows = 0;

View File

@ -23,7 +23,7 @@ void test_table_sizes(void **state)
}
WHEN("Insert one cell") {
int n = ft_hdr_printf(table, "%c", 'c');
int n = FT_HDR_PRINTF(table, "%c", 'c');
assert_true( n == 1 );
status = get_table_sizes(table, &rows, &cols);
assert_true( IS_SUCCESS(status) );
@ -32,7 +32,7 @@ void test_table_sizes(void **state)
}
WHEN("Insert two cells in the next row") {
int n = ft_row_printf(table, 1, "%c|%c", 'c', 'd');
int n = FT_ROW_PRINTF(table, 1, "%c|%c", 'c', 'd');
assert_true( n == 2 );
status = get_table_sizes(table, &rows, &cols);
assert_true( IS_SUCCESS(status) );
@ -41,7 +41,7 @@ void test_table_sizes(void **state)
}
WHEN("Insert five cells in the next row") {
int n = ft_row_printf(table, 2, "%d|%d|%d|%d|%d", 1, 2, 3, 4, 5);
int n = FT_ROW_PRINTF(table, 2, "%d|%d|%d|%d|%d", 1, 2, 3, 4, 5);
assert_true( n == 5 );
status = get_table_sizes(table, &rows, &cols);
assert_true( IS_SUCCESS(status) );
@ -70,7 +70,7 @@ void test_table_geometry(void **state)
}
WHEN("Table has one cell") {
int n = ft_hdr_printf(table, "%c", 'c');
int n = FT_HDR_PRINTF(table, "%c", 'c');
assert_true( n == 1 );
status = table_geometry(table, &height, &width);
assert_true( IS_SUCCESS(status) );
@ -79,7 +79,7 @@ void test_table_geometry(void **state)
}
WHEN("Inserting 3 cells in the next row") {
int n = ft_row_printf(table, 1, "%c|%s|%c", 'c', "as", 'e');
int n = FT_ROW_PRINTF(table, 1, "%c|%s|%c", 'c', "as", 'e');
assert_true( n == 3 );
status = table_geometry(table, &height, &width);
assert_true( IS_SUCCESS(status) );
@ -96,14 +96,14 @@ void test_table_basic(void **state)
FTABLE *table = ft_create_table();
WHEN("All columns are equal and not empty") {
int n = ft_hdr_printf(table, "%d|%c|%s|%f", 3, 'c', "234", 3.14);
int n = FT_HDR_PRINTF(table, "%d|%c|%s|%f", 3, 'c', "234", 3.14);
assert_true( n == 4 );
n = ft_row_printf(table, 1, "%d|%c|%s|%f", 3, 'c', "234", 3.14);
n = FT_ROW_PRINTF(table, 1, "%d|%c|%s|%f", 3, 'c', "234", 3.14);
assert_true( n == 4 );
n = ft_row_printf(table, 2, "%d|%c|%s|%f", 3, 'c', "234", 3.14);
n = FT_ROW_PRINTF(table, 2, "%d|%c|%s|%f", 3, 'c', "234", 3.14);
assert_true( n == 4 );
char *table_str = ft_to_string(table);
const char *table_str = ft_to_string(table);
assert_true( table_str != NULL );
const char *table_str_etalon =
"+---+---+-----+----------+\n"
@ -123,7 +123,6 @@ void test_table_basic(void **state)
assert_true( strcmp(table_str, table_str_etalon) == 0);
free(table_str);
ft_destroy_table(table);
}
@ -132,14 +131,14 @@ void test_table_basic(void **state)
WHEN("All columns are not equal and not empty") {
table = ft_create_table();
int n = ft_hdr_printf(table, "%d|%c|%s|%f", 3, 'c', "234", 3.14);
int n = FT_HDR_PRINTF(table, "%d|%c|%s|%f", 3, 'c', "234", 3.14);
assert_true( n == 4 );
n = ft_row_printf(table, 1, "%c|%s|%f|%d", 'c', "234", 3.14, 3);
n = FT_ROW_PRINTF(table, 1, "%c|%s|%f|%d", 'c', "234", 3.14, 3);
assert_true( n == 4 );
n = ft_row_printf(table, 2, "%s|%f|%d|%c", "234", 3.14, 3, 'c');
n = FT_ROW_PRINTF(table, 2, "%s|%f|%d|%c", "234", 3.14, 3, 'c');
assert_true( n == 4 );
char *table_str = ft_to_string(table);
const char *table_str = ft_to_string(table);
assert_true( table_str != NULL );
const char *table_str_etalon =
"+-----+----------+----------+----------+\n"
@ -159,21 +158,20 @@ void test_table_basic(void **state)
// fprintf(stderr, "content:\n%s", table_str);
assert_true( strcmp(table_str, table_str_etalon) == 0);
free(table_str);
ft_destroy_table(table);
}
WHEN("All columns are not equal and some cells are empty") {
table = ft_create_table();
int n = ft_hdr_printf(table, "||%s|%f", "234", 3.14);
int n = FT_HDR_PRINTF(table, "||%s|%f", "234", 3.14);
assert_true( n == 4 );
n = ft_row_printf(table, 1, "%c|%s|%f", 'c', "234", 3.14);
n = FT_ROW_PRINTF(table, 1, "%c|%s|%f", 'c', "234", 3.14);
assert_true( n == 3 );
n = ft_row_printf(table, 2, "%s|%f||", "234", 3.14);
n = FT_ROW_PRINTF(table, 2, "%s|%f||", "234", 3.14);
assert_true( n == 4 );
char *table_str = ft_to_string(table);
const char *table_str = ft_to_string(table);
assert_true( table_str != NULL );
const char *table_str_etalon =
"+-----+----------+----------+----------+\n"
@ -193,21 +191,20 @@ void test_table_basic(void **state)
// fprintf(stderr, "content:\n%s", table_str);
assert_true( strcmp(table_str, table_str_etalon) == 0);
free(table_str);
ft_destroy_table(table);
}
WHEN("All cells are empty") {
table = ft_create_table();
int n = ft_hdr_printf(table, "|||");
int n = FT_HDR_PRINTF(table, "|||");
assert_true( n == 4 );
n = ft_row_printf(table, 1, "|||");
n = FT_ROW_PRINTF(table, 1, "|||");
assert_true( n == 4 );
n = ft_row_printf(table, 2, "|||");
n = FT_ROW_PRINTF(table, 2, "|||");
assert_true( n == 4 );
char *table_str = ft_to_string(table);
const char *table_str = ft_to_string(table);
assert_true( table_str != NULL );
const char *table_str_etalon =
"+--+--+--+--+\n"
@ -228,7 +225,6 @@ void test_table_basic(void **state)
// fprintf(stderr, "content:\n%s", table_str);
assert_true( strcmp(table_str, table_str_etalon) == 0);
free(table_str);
ft_destroy_table(table);
}
}
@ -243,13 +239,19 @@ FTABLE *create_test_int_table()
assert_true (table != NULL);
int n = ft_hdr_printf(table, "%d|%d|%d|%d", 3, 4, 55, 67);
assert_true( n == 4 );
n = ft_row_printf(table, 1, "%d|%d|%d|%d", 3, 4, 55, 67);
assert_true( n == 4 );
n = ft_row_printf(table, 2, "%d|%d|%d|%d", 3, 4, 55, 67);
int n = FT_HDR_PRINTF(table, "%d|%d|%d|%d", 3, 4, 55, 67);
assert_true( n == 4 );
assert(ft_write(table, "3") == F_SUCCESS);
assert(ft_write(table, "4") == F_SUCCESS);
assert(ft_write(table, "55") == F_SUCCESS);
assert(ft_write_ln(table, "67") == F_SUCCESS);
assert(ft_write(table, "3") == F_SUCCESS);
assert(ft_write(table, "4") == F_SUCCESS);
assert(ft_write(table, "55") == F_SUCCESS);
assert(ft_write_ln(table, "67") == F_SUCCESS);
return table;
}
@ -273,7 +275,7 @@ void test_table_options(void **state)
table = create_test_int_table();
char *table_str = ft_to_string(table);
const char *table_str = ft_to_string(table);
assert_true( table_str != NULL );
const char *table_str_etalon =
"+---+---+----+----+\n"
@ -293,7 +295,6 @@ void test_table_options(void **state)
assert_true( strcmp(table_str, table_str_etalon) == 0);
free(table_str);
ft_destroy_table(table);
}
@ -308,7 +309,7 @@ void test_table_options(void **state)
table = create_test_int_table();
char *table_str = ft_to_string(table);
const char *table_str = ft_to_string(table);
assert_true( table_str != NULL );
const char *table_str_etalon =
"+---+---+----+----+\n"
@ -322,7 +323,6 @@ void test_table_options(void **state)
assert_true( strcmp(table_str, table_str_etalon) == 0);
free(table_str);
ft_destroy_table(table);
}
@ -337,7 +337,7 @@ void test_table_options(void **state)
table = create_test_int_table();
char *table_str = ft_to_string(table);
const char *table_str = ft_to_string(table);
assert_true( table_str != NULL );
const char *table_str_etalon =
"+-+-+--+--+\n"
@ -357,7 +357,6 @@ void test_table_options(void **state)
assert_true( strcmp(table_str, table_str_etalon) == 0);
free(table_str);
ft_destroy_table(table);
}
@ -372,7 +371,7 @@ void test_table_options(void **state)
table = create_test_int_table();
char *table_str = ft_to_string(table);
const char *table_str = ft_to_string(table);
assert_true( table_str != NULL );
const char *table_str_etalon =
"+-+-+--+--+\n"
@ -386,7 +385,6 @@ void test_table_options(void **state)
assert_true( strcmp(table_str, table_str_etalon) == 0);
free(table_str);
ft_destroy_table(table);
}
@ -404,7 +402,7 @@ void test_table_options(void **state)
int n = ft_row_printf(table, 3, "|||");
assert_true( n == 4 );
char *table_str = ft_to_string(table);
const char *table_str = ft_to_string(table);
assert_true( table_str != NULL );
const char *table_str_etalon =
"+---+---+----+----+\n"
@ -427,7 +425,6 @@ void test_table_options(void **state)
assert_true( strcmp(table_str, table_str_etalon) == 0);
free(table_str);
ft_destroy_table(table);
}
@ -455,7 +452,7 @@ void test_table_options(void **state)
ft_set_default_options(&table_options);
table = create_test_int_table();
char *table_str = ft_to_string(table);
const char *table_str = ft_to_string(table);
assert_true( table_str != NULL );
const char *table_str_etalon =
"*******************\n"
@ -475,7 +472,6 @@ void test_table_options(void **state)
assert_true( strcmp(table_str, table_str_etalon) == 0);
free(table_str);
ft_destroy_table(table);
@ -518,7 +514,6 @@ void test_table_options(void **state)
assert_true( strcmp(table_str, table_str_etalon) == 0);
free(table_str);
ft_destroy_table(table);
}
@ -533,7 +528,7 @@ void test_table_options(void **state)
table = create_test_int_table();
char *table_str = ft_to_string(table);
const char *table_str = ft_to_string(table);
assert_true( table_str != NULL );
const char *table_str_etalon =
"+-+-+--+--+\n"
@ -546,7 +541,6 @@ void test_table_options(void **state)
// fprintf(stderr, "content:\n%s", table_str);
assert_true( strcmp(table_str, table_str_etalon) == 0);
free(table_str);
table_options.cell_padding_bottom = 1;
table_options.cell_padding_top = 1;
@ -572,7 +566,6 @@ void test_table_options(void **state)
// fprintf(stderr, "content:\n%s", table_str);
assert_true( strcmp(table_str, table_str_etalon) == 0);
free(table_str);
ft_destroy_table(table);
}
@ -595,7 +588,7 @@ void test_table_options(void **state)
ft_set_column_alignment(table, 2, CenterAligned);
char *table_str = ft_to_string(table);
const char *table_str = ft_to_string(table);
assert_true( table_str != NULL );
const char *table_str_etalon =
"+---+-------+--------+----+\n"
@ -615,7 +608,6 @@ void test_table_options(void **state)
assert_true( strcmp(table_str, table_str_etalon) == 0);
free(table_str);
ft_destroy_table(table);
}
}