From 033506e7a9b6ad51024a385b62bc2f28cbbe64f7 Mon Sep 17 00:00:00 2001 From: seleznevae Date: Tue, 2 Jan 2018 12:03:58 +0300 Subject: [PATCH] C --- src/fort.c | 464 ++++++++++++++++++++++----------------------- src/fort_impl.h | 11 ++ tests/test.c | 1 + tests/test_table.c | 29 ++- tests/tests.h | 2 + 5 files changed, 267 insertions(+), 240 deletions(-) create mode 100644 src/fort_impl.h diff --git a/src/fort.c b/src/fort.c index d1993f6..8df9d2a 100644 --- a/src/fort.c +++ b/src/fort.c @@ -49,6 +49,9 @@ typedef int fort_status_t; #define IS_SUCCESS(arg) ((arg) == F_SUCCESS) #define IS_ERROR(arg) (!IS_SUCCESS(arg)) +/***************************************************************************** + * UTILITIES + * ***************************************************************************/ @@ -68,6 +71,33 @@ static void destroy_string_buffer(string_buffer_t *buffer); static fort_status_t realloc_string_buffer_without_copy(string_buffer_t *buffer); static fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str); +static size_t buffer_text_height(string_buffer_t *buffer) +{ + if (buffer == NULL) { + return 0; + } + return 1; +} + +static size_t buffer_text_width(string_buffer_t *buffer) +{ + if (buffer == NULL || buffer->str == NULL) { + return 0; + } + return strlen(buffer->str); +} + +static int buffer_printf(string_buffer_t *buffer, size_t row, char *buf, size_t buf_len) +{ + if (buffer == NULL || buffer->str == NULL + || row >= buffer_text_height(buffer) || buf_len == 0) { + return -1; + } + + return snprintf(buf, buf_len, "%*s", (int)(buf_len - 1), buffer->str); +} + + /***************************************************************************** * VECTOR * ***************************************************************************/ @@ -102,7 +132,7 @@ struct cell_options }; typedef struct cell_options cell_options_t; -void init_cell_options(cell_options_t *options) +static void init_cell_options(cell_options_t *options) { assert(options); options->padding_top = 1; @@ -119,7 +149,7 @@ struct fort_cell cell_options_t options; }; -fort_cell_t * create_cell() +static fort_cell_t * create_cell() { fort_cell_t *cell = F_CALLOC(sizeof(fort_cell_t), 1); if (cell == NULL) @@ -133,7 +163,7 @@ fort_cell_t * create_cell() return cell; } -void destroy_cell(fort_cell_t *cell) +static void destroy_cell(fort_cell_t *cell) { if (cell == NULL) return; @@ -141,22 +171,22 @@ void destroy_cell(fort_cell_t *cell) F_FREE(cell); } -int hint_width_cell(fort_cell_t *cell) +static int hint_width_cell(const fort_cell_t *cell) { assert(cell); int result = cell->options.padding_left + cell->options.padding_right; if (cell->str_buffer && cell->str_buffer->str) { - result += strlen(cell->str_buffer->str); + result += buffer_text_width(cell->str_buffer); } return result; } -int hint_height_cell(fort_cell_t *cell) +static int hint_height_cell(const fort_cell_t *cell) { assert(cell); int result = cell->options.padding_top + cell->options.padding_bottom; if (cell->str_buffer && cell->str_buffer->str) { - result += 1; + result += buffer_text_height(cell->str_buffer); } return result; } @@ -166,7 +196,7 @@ int hint_height_cell(fort_cell_t *cell) * Returns number of lines in cell. If cell is empty or * contains empty string, then 0 is returned. */ -int lines_number_cell(fort_cell_t *cell) +static int lines_number_cell(fort_cell_t *cell) { assert(cell); if (cell->str_buffer == NULL || cell->str_buffer->str == NULL || cell->str_buffer->str[0] == '\0') { @@ -182,6 +212,38 @@ int lines_number_cell(fort_cell_t *cell) return result + 1; } +static int cell_printf(fort_cell_t *cell, size_t row, char *buf, size_t buf_len) +{ + if (cell == NULL || buf_len == 0 || row >= hint_height_cell(cell) + || (buf_len <= hint_width_cell(cell))) { + return -1; + } + + + if (row < cell->options.padding_top + || row >= (cell->options.padding_top + buffer_text_height(cell->str_buffer))) { + for (int i = 0; i < (buf_len - 1); ++i) { + snprintf(buf, buf_len, "%c", ' '); + } + return buf_len - 1; + } else { + int written = 0; + int left = cell->options.padding_left; + + for (int i = 0; i < left; ++i) { + written += snprintf(buf + written, buf_len - written, "%c", ' '); + } + + written += buffer_printf(cell->str_buffer, row - cell->options.padding_top, buf + written, buf_len - written); + while (written < (buf_len - 1)) { + written += snprintf(buf + written, buf_len - written, "%c", ' '); + } + + return written; + } + +} + /***************************************************************************** * ROW * ***************************************************************************/ @@ -226,7 +288,7 @@ static void destroy_row(fort_row_t *row) static fort_row_t * create_row_from_string(const char *str); static fort_row_t* create_row_from_fmt_string(const char* FORT_RESTRICT fmt, va_list *va_args); -int columns_in_row(const fort_row_t *row) +static int columns_in_row(const fort_row_t *row) { if (row == NULL || row->cells == NULL) return 0; @@ -234,21 +296,59 @@ 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) +{ + if (row == NULL || row->cells == NULL) { + return NULL; + } + + if (col < columns_in_row(row)) { + return vector_at(row->cells, col); + } + return NULL; +} + +static const fort_cell_t *get_cell_c(const fort_row_t *row, size_t col) +{ + return get_cell((fort_row_t *)row, col); +} + /***************************************************************************** * TABLE *****************************************************************************/ +struct fort_table; +typedef struct fort_table fort_table_t; struct fort_table { - fort_row_t *header; vector_t *rows; }; +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) +{ + if (table == NULL || table->rows == NULL) { + return NULL; + } + + size_t rows = vector_size(table->rows); + if (row < rows) { + return vector_at(table->rows, row); + } + return NULL; +} + +static const fort_row_t *get_row_c(const fort_table_t *table, size_t row) +{ + return get_row((fort_table_t *)table, row); +} /***************************************************************************** * LIBFORT helpers *****************************************************************************/ -char *fort_strdup(const char* str) +static char *fort_strdup(const char* str) { if (str == NULL) return NULL; @@ -262,7 +362,7 @@ char *fort_strdup(const char* str) return str_copy; } -size_t number_of_columns_in_format_string(const char *fmt) +static size_t number_of_columns_in_format_string(const char *fmt) { int separator_counter = 0; const char *pos = fmt; @@ -301,7 +401,6 @@ void ft_destroy_table(FTABLE *FORT_RESTRICT table) if (table == NULL) return; - destroy_row(table->header); if (table->rows) { size_t row_n = vector_size(table->rows); for (size_t i = 0; i < row_n; ++i) { @@ -312,221 +411,15 @@ void ft_destroy_table(FTABLE *FORT_RESTRICT table) F_FREE(table); } -//void forward_va_list(const char *fmt FORT_UNUSED, va_list *va) -//{ -// /* todo - do normal implementation */ -// va_arg(*va, int); -// va_arg(*va, int); - -// while (*fmt) { -// if (*fmt != '%') { -// ++fmt; -// continue; -// } - -// char argument_type[2] = { '\0', '\0'}; - -// check_format: -// ++fmt; -// /* todo: do normal checking for order of symbols. Don't think symbol checking can be in independent order. */ -// switch(*fmt) { -// case '\0': -// return; - -// /* flags */ -// case '-': -// case '+': -// case ' ': -// case '#': -// case '0': -// case '1': -// case '2': -// case '3': -// case '4': -// case '5': -// case '6': -// case '7': -// case '8': -// case '9': -// case '.': -// goto check_format; - - -// /* length modifiers */ -// case 'h': -// case 'l': -// if (argument_type[0] == '\0') -// argument_type[0] = *fmt; -// else -// argument_type[1] = *fmt; -// goto check_format; -// case 'j': -// case 'z': -// case 't': -// case 'L': -// argument_type[1] = *fmt; -// goto check_format; - -// /* specifiers */ -// case 'c': -// if (argument_type[0] == 'l' && argument_type[0] == '\0') -// va_arg(*va, wint_t); -// else -// va_arg(*va, int); -// break; - -// /* specifiers */ -// case 's': -// if (argument_type[0] == 'l' && argument_type[0] == '\0') -// va_arg(*va, wint_t); -// else -// va_arg(*va, int); -// break; - - -// } -// } -//} - -//int ft_hdr_printf(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT fmt, ...) -//{ -// int DUMMY_BUFFER_SZ = 1024; -// char dummy_buffer[DUMMY_BUFFER_SZ]; - -// char *fmt_copy = F_STRDUP(fmt); -// if (fmt_copy == NULL) -// return 0; - -// va_list va; -// va_start(va, fmt); - -// char *pos = fmt_copy; -// char *base_pos = fmt_copy; -// while (*pos) { -// pos = strchr(pos, FORT_COL_SEPARATOR); -// if (pos != NULL) { -// /* todo: do normal escape checking */ -// if (pos > base_pos && (*(pos - 1) == '\\')) { /* column separator is escaped */ -// ++pos; -// continue; -// } else { /* column separator is found and it is not escaped */ -// *(pos) = '\0'; -// ++pos; -// } -// } - -// while (1) { -// va_list va_arg; -// va_copy(va_arg, va); -// int n = vsnprintf(dummy_buffer, DUMMY_BUFFER_SZ, base_pos, va_arg); - -// /* successful write */ -// if (n < DUMMY_BUFFER_SZ) { -// forward_va_list(base_pos, &va); -// fprintf(stderr, "%s\n", dummy_buffer); -// break; -// } -// } - -// if (pos == NULL) -// break; -// base_pos = pos; -// } - -//// va_list va; -//// int written_cols = 0; -//// written_cols = vfprintf(stderr, fmt, va); - -//// va_end(va); -//// va_start(va, fmt); -//// written_cols |= vfprintf(stderr, fmt, va); - - -//// va_end(va); - -// F_FREE(fmt_copy); -// return 0; -//} - - - -//int ft_hdr_printf(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT fmt, ...) -//{ -// string_buffer_t *buffer = create_string_buffer(1024); -// if (buffer == NULL) -// return -1; - -// int cols_origin = number_of_columns_in_format_string(fmt); - -// while (1) { -// va_list va; -// va_start(va, fmt); -// int virtual_sz = vsnprintf(buffer->str, buffer->str_sz, fmt, va); -// va_end(va); -// /* If error encountered */ -// if (virtual_sz == -1) -// goto clear; - -// /* Successful write */ -// if (virtual_sz < buffer->str_sz) -// break; - -// /* Otherwise buffer was too small, so incr. buffer size ant try again. */ -// if (!IS_SUCCESS(realloc_string_buffer_without_copy(buffer))) -// goto clear; -// } - -// int cols = number_of_columns_in_format_string(buffer->str); -// if (cols == cols_origin) { - -// fort_row_t *row = create_row_from_string(buffer->str); -// if (row == NULL) { -// goto clear; -// } - -// table->header = row; -// return vector_size(row->cells); -// } - - -//clear: -// destroy_string_buffer(buffer); -// return -1; -//} - -int ft_hdr_printf(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT fmt, ...) +int ft_row_printf_impl(FTABLE *FORT_RESTRICT table, size_t row, const char* FORT_RESTRICT fmt, va_list *va) { if (table == NULL) return -1; - va_list va; - va_start(va, fmt); - fort_row_t *row = create_row_from_fmt_string(fmt, &va); - va_end(va); - - if (row == NULL) { - return -1; - } - - if (table->header) { - destroy_row(table->header); - } - table->header = row; - return vector_size(row->cells); -} - -int ft_row_printf(FTABLE *FORT_RESTRICT table, size_t row, const char* FORT_RESTRICT fmt, ...) -{ - if (table == NULL) - return -1; - - va_list va; - va_start(va, fmt); - fort_row_t *new_row = create_row_from_fmt_string(fmt, &va); - va_end(va); + fort_row_t *new_row = create_row_from_fmt_string(fmt, va); if (new_row == NULL) { return -1; @@ -560,6 +453,24 @@ clear: return -1; } +int ft_hdr_printf(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT fmt, ...) +{ + va_list va; + va_start(va, fmt); + int result = ft_row_printf_impl(table, 0, fmt, &va); + va_end(va); + return result; +} + +int ft_row_printf(FTABLE *FORT_RESTRICT table, size_t row, const char* FORT_RESTRICT fmt, ...) +{ + va_list va; + va_start(va, fmt); + int result = ft_row_printf_impl(table, row, fmt, &va); + va_end(va); + return result; +} + /***************************************************************************** @@ -766,7 +677,7 @@ static void *vector_at(vector_t *vector, size_t index) #define FOR_EACH_(type, item, vector, index_name) \ - for (size_t index_name = 0; (item = *(type*)vector_at(vector, index_name)), (index_name < vector_size(vector)); ++index_name) + for (size_t index_name = 0; (index_name < vector_size(vector)) ? ((item = *(type*)vector_at(vector, index_name)), 1) : 0; ++index_name) #define FOR_EACH(type, item, vector) \ FOR_EACH_(type, item, vector, UNIQUE_NAME(i)) @@ -894,7 +805,7 @@ static int print_row(char *buffer, const fort_row_t *row) /* * Returns number of cells (rows * cols) */ -static void table_body_sizes(const FTABLE *table, size_t *rows, size_t *cols) +static fort_status_t get_table_sizes(const FTABLE *table, size_t *rows, size_t *cols) { *rows = 0; *cols = 0; @@ -906,26 +817,82 @@ static void table_body_sizes(const FTABLE *table, size_t *rows, size_t *cols) *cols = cols_in_row; } } + return F_SUCCESS; } +static fort_status_t table_rows_and_cols_geometry(const FTABLE *table, + size_t **col_width_arr_p, size_t *col_width_arr_sz, + size_t **row_height_arr_p, size_t *row_height_arr_sz) +{ + if (table == NULL) { + return F_ERROR; + } + size_t cols = 0; + size_t rows = 0; + int status = get_table_sizes(table, &rows, &cols); + if (IS_ERROR(status)) + return status; + + size_t *col_width_arr = F_CALLOC(sizeof(size_t), cols); + size_t *row_height_arr = F_CALLOC(sizeof(size_t), rows); + if (col_width_arr == NULL || row_height_arr == NULL) { + F_FREE(col_width_arr); + F_FREE(row_height_arr); + return F_ERROR; + } + + for (size_t col = 0; col < cols; ++col) { + col_width_arr[col] = 0; + for (size_t row = 0; row < rows; ++row) { + const fort_row_t *row_p = get_row_c(table, row); + const fort_cell_t *cell = get_cell_c(row_p, col); + if (cell) { + col_width_arr[col] = MAX(col_width_arr[col], hint_width_cell(cell)); + row_height_arr[row] = MAX(row_height_arr[row], hint_height_cell(cell)); + } + } + } + + *col_width_arr_p = col_width_arr; + *col_width_arr_sz = cols; + *row_height_arr_p = row_height_arr; + *row_height_arr_sz = rows; + return F_SUCCESS; +} /* * Returns geometry in characters */ -static void table_geometry(const FTABLE *table, size_t *height, size_t *width) +static fort_status_t table_geometry(const FTABLE *table, size_t *height, size_t *width) { + if (table == NULL) + return F_ERROR; + *height = 0; *width = 0; - if (table) { - size_t cols = 0; - size_t rows = 0; - table_body_sizes(table, &rows, &cols); - if (table->header) { - cols = MAX(cols, columns_in_row(table->header)); - ++rows; - } + size_t cols = 0; + size_t rows = 0; + size_t *col_width_arr = NULL; + size_t *row_height_arr = NULL; + + int status = table_rows_and_cols_geometry(table, &col_width_arr, &cols, &row_height_arr, &rows); + if (IS_ERROR(status)) + return status; + + *width = 1 + (cols == 0 ? 1 : cols) + 1; // for boundaries (that take 1 symbol) + newline + for (size_t i = 0; i < cols; ++i) { + *width += col_width_arr[i]; } + + *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]; + } + F_FREE(col_width_arr); + F_FREE(row_height_arr); + return F_SUCCESS; + } char* ft_to_string(const FTABLE *FORT_RESTRICT table) @@ -933,12 +900,7 @@ char* ft_to_string(const FTABLE *FORT_RESTRICT table) assert(table); char *dummy = F_MALLOC(2056); - fort_row_t *header = table->header; - int dev = print_row(dummy, header); - - sprintf(dummy + dev , "\n"); - dev += 1; - + int dev = 0; size_t rows = vector_size(table->rows); for (size_t i = 0; i < rows; ++i) { fort_row_t *row = *(fort_row_t**)vector_at(table->rows, i); @@ -951,6 +913,32 @@ char* ft_to_string(const FTABLE *FORT_RESTRICT table) } +//char* ft_to_string(const FTABLE *FORT_RESTRICT table) +//{ +// assert(table); + +// size_t height = 0; +// size_t width = 0; +// int status = table_geometry(table, &height, &width); +// if (IS_ERROR(status)) { +// return NULL; +// } +// fprintf(stderr, "width = %d ; height = %d\n", (int)width, (int)height); +// size_t sz = height * width + 10; +// char *dummy = F_MALLOC(sz); + +// int dev = 0; +// size_t rows = vector_size(table->rows); +// for (size_t i = 0; i < rows; ++i) { +// fort_row_t *row = *(fort_row_t**)vector_at(table->rows, i); +// dev += print_row(dummy + dev, row); +// sprintf(dummy + dev , "\n"); +// dev += 1; +// } + +// return dummy; +//} + diff --git a/src/fort_impl.h b/src/fort_impl.h new file mode 100644 index 0000000..008274e --- /dev/null +++ b/src/fort_impl.h @@ -0,0 +1,11 @@ +#ifndef FORT_IMPL_H +#define FORT_IMPL_H + + +#include "fort.h" + + + + + +#endif // FORT_IMPL_H diff --git a/tests/test.c b/tests/test.c index 6e91f8a..f1c243e 100644 --- a/tests/test.c +++ b/tests/test.c @@ -4,6 +4,7 @@ int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_vector_basic), + cmocka_unit_test(test_table_geometry), cmocka_unit_test(test_table_basic) }; return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/tests/test_table.c b/tests/test_table.c index 98a4c4e..ee723b2 100644 --- a/tests/test_table.c +++ b/tests/test_table.c @@ -3,6 +3,25 @@ #include #include #include +#include "fort.c" + +void test_table_geometry(void **state) +{ + (void)state; + FTABLE *table = ft_create_table(); + + int n = ft_hdr_printf(table, "%c", 'c'); + assert_true( n == 1 ); + + size_t height = 0; + size_t width = 0; + int status = table_geometry(table, &height, &width); + assert_true( IS_SUCCESS(status) ); + + + ft_destroy_table(table); +} + void test_table_basic(void **state) { (void)state; @@ -11,17 +30,23 @@ void test_table_basic(void **state) int n = ft_hdr_printf(table, "%d , %c|| %s|%f", 3, 'c', "234", 3.14); assert_true( n == 4 ); - n = ft_row_printf(table, 0, "%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); assert_true( n == 4 ); + n = ft_row_printf(table, 2, "%d , %c|| %s|%f", 3, 'c', "234", 3.14); + assert_true( n == 4 ); + n = ft_row_printf(table, 4, "%d , %c|| %s|%f", 3, 'c', "234", 3.14); + assert_true( n == 4 ); + char *table_str = ft_to_string(table); const char *table_str_etalon = "| 3 , c| | 234| 3.140000\n" "| 3 , c| | 234| 3.140000\n" + "| 3 , c| | 234| 3.140000\n" + "\n" "| 3 , c| | 234| 3.140000\n"; + fprintf(stderr, "%s", table_str); assert_true( strcmp(table_str, table_str_etalon) == 0); diff --git a/tests/tests.h b/tests/tests.h index b3977d5..ca4205e 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -11,6 +11,8 @@ void test_vector_basic(void **state); + +void test_table_geometry(void **state); void test_table_basic(void **state);