From a4802cc737a453070442e16d1fbc252e29ebd895 Mon Sep 17 00:00:00 2001 From: seleznevae Date: Wed, 17 Jan 2018 07:05:01 +0300 Subject: [PATCH] [C] To string function returns non owning pointer --- CMakeLists.txt | 2 +- include/fort.h | 11 +++- src/fort.c | 150 +++++++++++++++++++++++++++++++++++++++++---- tests/test_table.c | 88 ++++++++++++-------------- 4 files changed, 190 insertions(+), 61 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b06a43..741da3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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") diff --git a/include/fort.h b/include/fort.h index be9482d..02eb32b 100644 --- a/include/fort.h +++ b/include/fort.h @@ -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); diff --git a/src/fort.c b/src/fort.c index f6b3818..8c95ca6 100644 --- a/src/fort.c +++ b/src/fort.c @@ -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; diff --git a/tests/test_table.c b/tests/test_table.c index 9fa2062..572b59b 100644 --- a/tests/test_table.c +++ b/tests/test_table.c @@ -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); } }