[C] Separated code in different files
This commit is contained in:
parent
a4802cc737
commit
d2798da48d
@ -15,11 +15,19 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -g")
|
||||
|
||||
|
||||
|
||||
FILE(GLOB_RECURSE FortHeaders "include/*.h" "tests/*.h")
|
||||
FILE(GLOB_RECURSE FortHeaders "include/*.h" "tests/*.h" "src/*.h" "src/*.h" "src/*.h" "src/*.h" "src/*.h" "src/*.h")
|
||||
add_custom_target(headers SOURCES ${FortHeaders})
|
||||
|
||||
|
||||
set(FORT_SOURCES src/fort.c)
|
||||
set(FORT_SOURCES
|
||||
src/fort.c
|
||||
src/vector.c
|
||||
src/string_buffer.c
|
||||
src/options.c
|
||||
src/cell.c
|
||||
src/row.c
|
||||
src/table.c
|
||||
src/fort_impl.c)
|
||||
|
||||
|
||||
add_executable(${PROJECT_NAME}
|
||||
@ -31,6 +39,7 @@ include_directories(tests/cmocka-1.1.0/include)
|
||||
link_directories(${CMAKE_SOURCE_DIR}/tests/cmocka-1.1.0/build/src)
|
||||
|
||||
add_executable(TEST
|
||||
${FORT_SOURCES}
|
||||
tests/test.c
|
||||
tests/test_vector.c
|
||||
tests/test_table.c)
|
||||
|
@ -30,6 +30,9 @@ SOFTWARE.
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#include "options.h"
|
||||
|
||||
/*
|
||||
* Determine compiler
|
||||
*/
|
||||
@ -111,82 +114,8 @@ FORT_EXTERN const char* ft_to_string(const FTABLE *FORT_RESTRICT table);
|
||||
|
||||
|
||||
|
||||
enum TextAlignment
|
||||
{
|
||||
LeftAligned,
|
||||
CenterAligned,
|
||||
RightAligned
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* TABLE BORDER
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* TL TT TT TT TV TT TT TT TV TB TB TB TR <----- TopSeparator
|
||||
* LL IV IV RR
|
||||
* LH IH IH IH II IH IH IH II IH IH IH RH <----- InsideSeparator
|
||||
* LL IV IV RR
|
||||
* BL BB BB BB BV BB BB BB BV BB BB BB BR <----- BottomSeparator
|
||||
*/
|
||||
|
||||
enum HorSeparatorPos
|
||||
{
|
||||
TopSeparator,
|
||||
InsideSeparator,
|
||||
BottomSeparator
|
||||
};
|
||||
|
||||
enum BorderItemPos
|
||||
{
|
||||
TL_bip = 0,
|
||||
TT_bip = 1,
|
||||
TV_bip = 2,
|
||||
TR_bip = 3,
|
||||
|
||||
LL_bip = 4,
|
||||
IV_bip = 5,
|
||||
RR_bip = 6,
|
||||
|
||||
LH_bip = 7,
|
||||
IH_bip = 8,
|
||||
II_bip = 9,
|
||||
RH_bip = 10,
|
||||
|
||||
BL_bip = 11,
|
||||
BB_bip = 12,
|
||||
BV_bip = 13,
|
||||
BR_bip = 14,
|
||||
|
||||
BorderItemPosSize
|
||||
};
|
||||
|
||||
struct vector;
|
||||
typedef struct vector vector_t;
|
||||
|
||||
struct fort_column_options
|
||||
{
|
||||
int col_min_width;
|
||||
enum TextAlignment align;
|
||||
};
|
||||
typedef struct fort_column_options fort_column_options_t;
|
||||
|
||||
struct fort_table_options
|
||||
{
|
||||
int cell_padding_top;
|
||||
int cell_padding_bottom;
|
||||
int cell_padding_left;
|
||||
int cell_padding_right;
|
||||
int cell_empty_string_height;
|
||||
|
||||
char border_chars[BorderItemPosSize];
|
||||
char header_border_chars[BorderItemPosSize];
|
||||
vector_t *col_options;
|
||||
|
||||
};
|
||||
typedef struct fort_table_options fort_table_options_t;
|
||||
typedef fort_table_options_t context_t;
|
||||
|
||||
FORT_EXTERN int ft_set_default_options(const fort_table_options_t *options);
|
||||
FORT_EXTERN int ft_get_default_options(fort_table_options_t *options);
|
||||
|
128
src/cell.c
Normal file
128
src/cell.c
Normal file
@ -0,0 +1,128 @@
|
||||
#include "cell.h"
|
||||
#include "options.h"
|
||||
#include "string_buffer.h"
|
||||
#include "assert.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* CELL
|
||||
* ***************************************************************************/
|
||||
|
||||
struct fort_cell
|
||||
{
|
||||
string_buffer_t *str_buffer;
|
||||
fort_table_options_t *options;
|
||||
};
|
||||
|
||||
fort_cell_t * create_cell()
|
||||
{
|
||||
fort_cell_t *cell = F_CALLOC(sizeof(fort_cell_t), 1);
|
||||
if (cell == NULL)
|
||||
return NULL;
|
||||
cell->str_buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE);
|
||||
if (cell->str_buffer == NULL) {
|
||||
F_FREE(cell);
|
||||
return NULL;
|
||||
}
|
||||
cell->options = NULL;
|
||||
// init_cell_options(&(cell->options));
|
||||
return cell;
|
||||
}
|
||||
|
||||
void destroy_cell(fort_cell_t *cell)
|
||||
{
|
||||
if (cell == NULL)
|
||||
return;
|
||||
destroy_string_buffer(cell->str_buffer);
|
||||
F_FREE(cell->options);
|
||||
F_FREE(cell);
|
||||
}
|
||||
|
||||
int hint_width_cell(const fort_cell_t *cell, const context_t *context)
|
||||
{
|
||||
assert(cell);
|
||||
assert(context);
|
||||
int result = context->cell_padding_left + context->cell_padding_right;
|
||||
if (cell->str_buffer && cell->str_buffer->str) {
|
||||
result += buffer_text_width(cell->str_buffer);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int hint_height_cell(const fort_cell_t *cell, const context_t *context)
|
||||
{
|
||||
assert(cell);
|
||||
assert(context);
|
||||
int result = context->cell_padding_top + context->cell_padding_bottom;
|
||||
if (cell->str_buffer && cell->str_buffer->str) {
|
||||
size_t text_height = buffer_text_height(cell->str_buffer);
|
||||
result += text_height == 0 ? context->cell_empty_string_height : text_height;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns number of lines in cell. If cell is empty or
|
||||
* contains empty string, then 0 is returned.
|
||||
*/
|
||||
//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') {
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// int result = 0;
|
||||
// char *pos = cell->str_buffer->str;
|
||||
// while ((pos = strchr(pos, '\n')) != NULL) {
|
||||
// result++;
|
||||
// pos++;
|
||||
// }
|
||||
// return result + 1;
|
||||
//}
|
||||
|
||||
int cell_printf(fort_cell_t *cell, size_t row, size_t column, char *buf, size_t buf_len, const context_t *context)
|
||||
{
|
||||
if (cell == NULL || buf_len == 0 || row >= hint_height_cell(cell, context)
|
||||
|| (buf_len <= hint_width_cell(cell, context))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (row < context->cell_padding_top
|
||||
|| row >= (context->cell_padding_top + buffer_text_height(cell->str_buffer))) {
|
||||
int k = snprint_n_chars(buf, buf_len, buf_len - 1, ' ');
|
||||
return k;
|
||||
} else {
|
||||
int written = 0;
|
||||
int left = context->cell_padding_left;
|
||||
int right = context->cell_padding_right;
|
||||
|
||||
written += snprint_n_chars(buf + written, buf_len - written, left, ' ');
|
||||
|
||||
if (cell->str_buffer)
|
||||
written += buffer_printf(cell->str_buffer, row - context->cell_padding_top, column, buf + written, buf_len - written - right, context);
|
||||
else
|
||||
written += snprint_n_chars(buf + written, buf_len - written, buf_len - written - right, ' ');
|
||||
written += snprint_n_chars(buf + written, buf_len - written, right, ' ');
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
fort_status_t fill_cell_from_string(fort_cell_t *cell, const char *str)
|
||||
{
|
||||
assert(str);
|
||||
assert(cell);
|
||||
|
||||
return fill_buffer_from_string(cell->str_buffer, str);
|
||||
}
|
||||
|
||||
string_buffer_t *cell_get_string_buffer(fort_cell_t *cell)
|
||||
{
|
||||
assert(cell);
|
||||
assert(cell->str_buffer);
|
||||
return cell->str_buffer;
|
||||
}
|
38
src/cell.h
Normal file
38
src/cell.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef CELL_H
|
||||
#define CELL_H
|
||||
|
||||
#include "fort_impl.h"
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* CELL
|
||||
* ***************************************************************************/
|
||||
//struct fort_cell
|
||||
//{
|
||||
// string_buffer_t *str_buffer;
|
||||
// fort_table_options_t *options;
|
||||
//};
|
||||
|
||||
fort_cell_t * create_cell();
|
||||
|
||||
|
||||
void destroy_cell(fort_cell_t *cell);
|
||||
int hint_width_cell(const fort_cell_t *cell, const context_t *context);
|
||||
int hint_height_cell(const fort_cell_t *cell, const context_t *context);
|
||||
|
||||
|
||||
/*
|
||||
* Returns number of lines in cell. If cell is empty or
|
||||
* contains empty string, then 0 is returned.
|
||||
*/
|
||||
//static int lines_number_cell(fort_cell_t *cell);
|
||||
|
||||
int cell_printf(fort_cell_t *cell, size_t row, size_t column, char *buf, size_t buf_len, const context_t *context);
|
||||
|
||||
fort_status_t fill_cell_from_string(fort_cell_t *cell, const char *str);
|
||||
|
||||
string_buffer_t* cell_get_string_buffer(fort_cell_t *cell);
|
||||
|
||||
#endif // CELL_H
|
1201
src/fort.c
1201
src/fort.c
File diff suppressed because it is too large
Load Diff
51
src/fort_impl.c
Normal file
51
src/fort_impl.c
Normal file
@ -0,0 +1,51 @@
|
||||
#include "fort_impl.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* LIBFORT helpers
|
||||
*****************************************************************************/
|
||||
char *fort_strdup(const char* str)
|
||||
{
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
|
||||
size_t sz = strlen(str);
|
||||
char *str_copy = (char*)F_MALLOC(sz + 1);
|
||||
if (str_copy == NULL)
|
||||
return NULL;
|
||||
|
||||
strcpy(str_copy, str);
|
||||
return str_copy;
|
||||
}
|
||||
|
||||
size_t number_of_columns_in_format_string(const char *fmt)
|
||||
{
|
||||
int separator_counter = 0;
|
||||
const char *pos = fmt;
|
||||
while (1) {
|
||||
pos = strchr(pos, FORT_COL_SEPARATOR);
|
||||
if (pos == NULL)
|
||||
break;
|
||||
|
||||
separator_counter++;
|
||||
++pos;
|
||||
}
|
||||
return separator_counter + 1;
|
||||
}
|
||||
|
||||
int snprint_n_chars(char *buf, size_t length, size_t n, char ch)
|
||||
{
|
||||
if (length <= n)
|
||||
return -1;
|
||||
|
||||
int status = snprintf(buf, length, "%0*d", (int)n, 0);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
*buf = ch;
|
||||
buf++;
|
||||
}
|
||||
return n;
|
||||
}
|
104
src/fort_impl.h
Normal file
104
src/fort_impl.h
Normal file
@ -0,0 +1,104 @@
|
||||
#ifndef FORT_IMPL_H
|
||||
#define FORT_IMPL_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define FORT_COL_SEPARATOR '|'
|
||||
|
||||
#define FORT_UNUSED __attribute__((unused))
|
||||
|
||||
#define F_CALLOC calloc
|
||||
#define F_MALLOC malloc
|
||||
#define F_REALLOC realloc
|
||||
#define F_FREE free
|
||||
#define F_STRDUP fort_strdup
|
||||
|
||||
#define F_CREATE(type) ((type *)F_CALLOC(sizeof(type), 1))
|
||||
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : b)
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : b)
|
||||
|
||||
|
||||
enum PolicyOnNull
|
||||
{
|
||||
Create,
|
||||
DoNotCreate
|
||||
};
|
||||
|
||||
|
||||
enum F_BOOL
|
||||
{
|
||||
F_FALSE = 0,
|
||||
F_TRUE = 1
|
||||
};
|
||||
|
||||
|
||||
#define STR_2_CAT_(arg1, arg2) \
|
||||
arg1##arg2
|
||||
#define STR_2_CAT(arg1, arg2) \
|
||||
STR_2_CAT_(arg1, arg2)
|
||||
|
||||
#define UNIQUE_NAME_(prefix) \
|
||||
STR_2_CAT(prefix,__COUNTER__)
|
||||
#define UNIQUE_NAME(prefix) \
|
||||
UNIQUE_NAME_(prefix)
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* LOGGER
|
||||
*****************************************************************************/
|
||||
#define SYS_LOG_ERROR(...)
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* RETURN CODES
|
||||
* ***************************************************************************/
|
||||
typedef int fort_status_t;
|
||||
#define F_SUCCESS 0
|
||||
#define F_MEMORY_ERROR 1
|
||||
#define F_ERROR 2
|
||||
#define IS_SUCCESS(arg) ((arg) == F_SUCCESS)
|
||||
#define IS_ERROR(arg) (!IS_SUCCESS(arg))
|
||||
|
||||
/*****************************************************************************
|
||||
* DEFAULT_SIZES
|
||||
* ***************************************************************************/
|
||||
#define DEFAULT_STR_BUF_SIZE 1024
|
||||
#define DEFAULT_VECTOR_CAPACITY 10
|
||||
|
||||
|
||||
|
||||
struct fort_table_options;
|
||||
struct fort_column_options;
|
||||
struct fort_row;
|
||||
struct vector;
|
||||
struct fort_cell;
|
||||
struct string_buffer;
|
||||
|
||||
|
||||
typedef struct fort_table_options fort_table_options_t;
|
||||
typedef fort_table_options_t context_t;
|
||||
typedef struct fort_column_options fort_column_options_t;
|
||||
typedef struct vector vector_t;
|
||||
typedef struct fort_cell fort_cell_t;
|
||||
typedef struct string_buffer string_buffer_t;
|
||||
typedef struct fort_row fort_row_t;
|
||||
typedef struct fort_table FTABLE;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* LIBFORT helpers
|
||||
*****************************************************************************/
|
||||
char *fort_strdup(const char* str);
|
||||
size_t number_of_columns_in_format_string(const char *fmt);
|
||||
int snprint_n_chars(char *buf, size_t length, size_t n, char ch);
|
||||
|
||||
#endif // FORT_IMPL_H
|
132
src/options.c
Normal file
132
src/options.c
Normal file
@ -0,0 +1,132 @@
|
||||
#include "options.h"
|
||||
#include "fort_impl.h"
|
||||
#include "assert.h"
|
||||
#include "vector.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* COLUMN OPTIONS
|
||||
* ***************************************************************************/
|
||||
|
||||
fort_column_options_t g_column_options =
|
||||
{
|
||||
0, /* col_min_width*/
|
||||
RightAligned, /* align */
|
||||
};
|
||||
|
||||
fort_column_options_t create_column_options()
|
||||
{
|
||||
fort_column_options_t result;
|
||||
memset(&result, '\0', sizeof(result));
|
||||
memcpy(&result, &g_column_options, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* OPTIONS
|
||||
* ***************************************************************************/
|
||||
|
||||
|
||||
|
||||
fort_table_options_t g_table_options = {
|
||||
1, /* cell_padding_top */
|
||||
1, /* cell_padding_bottom */
|
||||
1, /* cell_padding_left */
|
||||
1, /* cell_padding_right */
|
||||
1, /* cell_empty_string_height */
|
||||
|
||||
/* border_chars */
|
||||
{
|
||||
'+', '-', '+', '+',
|
||||
'|', '|', '|',
|
||||
'+', '-', '+', '+',
|
||||
'+', '-', '+', '+'
|
||||
},
|
||||
|
||||
/* header_border_chars */
|
||||
{
|
||||
'+', '-', '+', '+',
|
||||
'|', '|', '|',
|
||||
'+', '-', '+', '+',
|
||||
'+', '-', '+', '+'
|
||||
},
|
||||
|
||||
NULL, /* col_options */
|
||||
};
|
||||
|
||||
|
||||
fort_table_options_t* create_table_options()
|
||||
{
|
||||
fort_table_options_t* options = F_CALLOC(sizeof(fort_table_options_t), 1);
|
||||
if (options == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(options, &g_table_options, sizeof(fort_table_options_t));
|
||||
return options;
|
||||
}
|
||||
|
||||
void destroy_table_options(fort_table_options_t* options)
|
||||
{
|
||||
if (options == NULL)
|
||||
return;
|
||||
|
||||
if (options->col_options != NULL) {
|
||||
destroy_vector(options->col_options);
|
||||
}
|
||||
F_FREE(options);
|
||||
}
|
||||
|
||||
|
||||
#define FORT_OPTIONS_SET_COLUMN_OPTION(options, column, opt_name, opt_value) \
|
||||
assert(options);\
|
||||
\
|
||||
if (options->col_options == NULL) {\
|
||||
options->col_options = create_vector(sizeof(fort_column_options_t), DEFAULT_VECTOR_CAPACITY);\
|
||||
if (options->col_options == NULL) \
|
||||
return F_MEMORY_ERROR; \
|
||||
} \
|
||||
\
|
||||
while (vector_size(options->col_options) <= column) {\
|
||||
fort_column_options_t def_option = create_column_options();\
|
||||
vector_push(options->col_options, &def_option);\
|
||||
}\
|
||||
\
|
||||
fort_column_options_t *col_option = (fort_column_options_t*)vector_at(options->col_options, column);\
|
||||
col_option->opt_name = opt_value;\
|
||||
\
|
||||
return F_SUCCESS;
|
||||
|
||||
fort_status_t fort_options_set_column_min_width(fort_table_options_t *options, size_t column, size_t width)
|
||||
{
|
||||
FORT_OPTIONS_SET_COLUMN_OPTION(options, column, col_min_width, width);
|
||||
}
|
||||
|
||||
fort_status_t fort_options_set_column_alignment(fort_table_options_t *options, size_t column, enum TextAlignment al)
|
||||
{
|
||||
FORT_OPTIONS_SET_COLUMN_OPTION(options, column, align, al);
|
||||
}
|
||||
|
||||
int fort_options_column_width(const fort_table_options_t *options, size_t column)
|
||||
{
|
||||
assert(options);
|
||||
if (options->col_options == NULL)
|
||||
return -1;
|
||||
|
||||
if (vector_size(options->col_options) <= column)
|
||||
return -1;
|
||||
|
||||
return ((fort_column_options_t*)vector_at(options->col_options, column))->col_min_width;
|
||||
}
|
||||
|
||||
int fort_options_column_alignment(const fort_table_options_t *options, size_t column)
|
||||
{
|
||||
assert(options);
|
||||
|
||||
enum TextAlignment align = g_column_options.align;
|
||||
if (options->col_options == NULL)
|
||||
return align;
|
||||
|
||||
if (vector_size(options->col_options) <= column)
|
||||
return align;
|
||||
|
||||
return ((fort_column_options_t*)vector_at(options->col_options, column))->align;
|
||||
}
|
105
src/options.h
Normal file
105
src/options.h
Normal file
@ -0,0 +1,105 @@
|
||||
#ifndef OPTIONS_H
|
||||
#define OPTIONS_H
|
||||
|
||||
#include "fort_impl.h"
|
||||
|
||||
enum TextAlignment
|
||||
{
|
||||
LeftAligned,
|
||||
CenterAligned,
|
||||
RightAligned
|
||||
};
|
||||
|
||||
|
||||
struct fort_column_options
|
||||
{
|
||||
int col_min_width;
|
||||
enum TextAlignment align;
|
||||
};
|
||||
typedef struct fort_column_options fort_column_options_t;
|
||||
|
||||
extern fort_column_options_t g_column_options;
|
||||
fort_column_options_t create_column_options();
|
||||
|
||||
|
||||
|
||||
struct vector;
|
||||
typedef struct vector vector_t;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* TABLE BORDER
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* TL TT TT TT TV TT TT TT TV TB TB TB TR <----- TopSeparator
|
||||
* LL IV IV RR
|
||||
* LH IH IH IH II IH IH IH II IH IH IH RH <----- InsideSeparator
|
||||
* LL IV IV RR
|
||||
* BL BB BB BB BV BB BB BB BV BB BB BB BR <----- BottomSeparator
|
||||
*/
|
||||
|
||||
enum HorSeparatorPos
|
||||
{
|
||||
TopSeparator,
|
||||
InsideSeparator,
|
||||
BottomSeparator
|
||||
};
|
||||
|
||||
enum BorderItemPos
|
||||
{
|
||||
TL_bip = 0,
|
||||
TT_bip = 1,
|
||||
TV_bip = 2,
|
||||
TR_bip = 3,
|
||||
|
||||
LL_bip = 4,
|
||||
IV_bip = 5,
|
||||
RR_bip = 6,
|
||||
|
||||
LH_bip = 7,
|
||||
IH_bip = 8,
|
||||
II_bip = 9,
|
||||
RH_bip = 10,
|
||||
|
||||
BL_bip = 11,
|
||||
BB_bip = 12,
|
||||
BV_bip = 13,
|
||||
BR_bip = 14,
|
||||
|
||||
BorderItemPosSize
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct fort_table_options
|
||||
{
|
||||
int cell_padding_top;
|
||||
int cell_padding_bottom;
|
||||
int cell_padding_left;
|
||||
int cell_padding_right;
|
||||
int cell_empty_string_height;
|
||||
|
||||
char border_chars[BorderItemPosSize];
|
||||
char header_border_chars[BorderItemPosSize];
|
||||
vector_t *col_options;
|
||||
|
||||
};
|
||||
typedef struct fort_table_options fort_table_options_t;
|
||||
typedef fort_table_options_t context_t;
|
||||
extern fort_table_options_t g_table_options;
|
||||
|
||||
|
||||
|
||||
fort_table_options_t* create_table_options();
|
||||
void destroy_table_options(fort_table_options_t* options);
|
||||
fort_status_t fort_options_set_column_min_width(fort_table_options_t *options, size_t column, size_t width);
|
||||
fort_status_t fort_options_set_column_alignment(fort_table_options_t *options, size_t column, enum TextAlignment al);
|
||||
int fort_options_column_width(const fort_table_options_t *options, size_t column);
|
||||
int fort_options_column_alignment(const fort_table_options_t *options, size_t column);
|
||||
|
||||
#endif // OPTIONS_H
|
363
src/row.c
Normal file
363
src/row.c
Normal file
@ -0,0 +1,363 @@
|
||||
#include "row.h"
|
||||
#include "cell.h"
|
||||
#include "string_buffer.h"
|
||||
#include "assert.h"
|
||||
#include "vector.h"
|
||||
#include "ctype.h"
|
||||
|
||||
fort_row_t * create_row()
|
||||
{
|
||||
fort_row_t * row = F_CALLOC(sizeof(fort_row_t), 1);
|
||||
if (row == NULL)
|
||||
return NULL;
|
||||
row->cells = create_vector(sizeof(fort_cell_t*), DEFAULT_VECTOR_CAPACITY);
|
||||
if (row->cells == NULL) {
|
||||
F_FREE(row);
|
||||
return NULL;
|
||||
}
|
||||
row->is_header = F_FALSE;
|
||||
return row;
|
||||
}
|
||||
|
||||
void destroy_row(fort_row_t *row)
|
||||
{
|
||||
if (row == NULL)
|
||||
return;
|
||||
|
||||
if (row->cells) {
|
||||
size_t cells_n = vector_size(row->cells);
|
||||
for (size_t i = 0; i < cells_n; ++i) {
|
||||
fort_cell_t *cell = *(fort_cell_t **)vector_at(row->cells, i);
|
||||
destroy_cell(cell);
|
||||
}
|
||||
destroy_vector(row->cells);
|
||||
}
|
||||
|
||||
F_FREE(row);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int columns_in_row(const fort_row_t *row)
|
||||
{
|
||||
if (row == NULL || row->cells == NULL)
|
||||
return 0;
|
||||
|
||||
return vector_size(row->cells);
|
||||
}
|
||||
|
||||
|
||||
fort_cell_t *get_cell_implementation(fort_row_t *row, size_t col, enum PolicyOnNull policy)
|
||||
{
|
||||
if (row == NULL || row->cells == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
fort_cell_t *get_cell(fort_row_t *row, size_t col)
|
||||
{
|
||||
return get_cell_implementation(row, col, DoNotCreate);
|
||||
}
|
||||
|
||||
const fort_cell_t *get_cell_c(const fort_row_t *row, size_t col)
|
||||
{
|
||||
return get_cell((fort_row_t *)row, col);
|
||||
}
|
||||
|
||||
fort_cell_t *get_cell_and_create_if_not_exists(fort_row_t *row, size_t col)
|
||||
{
|
||||
return get_cell_implementation(row, col, Create);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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,
|
||||
enum HorSeparatorPos separatorPos, const context_t *context)
|
||||
{
|
||||
#define CHECK_RESULT_AND_MOVE_DEV(statement) \
|
||||
k = statement; \
|
||||
if (k < 0) {\
|
||||
goto clear; \
|
||||
} \
|
||||
dev += k;
|
||||
|
||||
assert(buffer);
|
||||
assert(context);
|
||||
|
||||
int dev = 0;
|
||||
int k = 0;
|
||||
|
||||
const fort_row_t *main_row = NULL;
|
||||
if (upper_row != NULL && lower_row != NULL) {
|
||||
main_row = lower_row->is_header == F_TRUE ? lower_row : upper_row;
|
||||
} else if (upper_row != NULL && lower_row == NULL) {
|
||||
main_row = upper_row;
|
||||
} else if (upper_row == NULL && lower_row != NULL) {
|
||||
main_row = lower_row;
|
||||
} else if (upper_row == NULL && lower_row == NULL) {
|
||||
main_row = NULL;
|
||||
}
|
||||
|
||||
/* Row separator anatomy
|
||||
*
|
||||
* L I I I IV I I I R
|
||||
*/
|
||||
const char *L = NULL;
|
||||
const char *I = NULL;
|
||||
const char *IV = NULL;
|
||||
const char *R = NULL;
|
||||
|
||||
const char (*border_chars)[BorderItemPosSize] = NULL;
|
||||
if (main_row && main_row->is_header == F_TRUE) {
|
||||
border_chars = &context->header_border_chars;
|
||||
} else {
|
||||
border_chars = &context->border_chars;
|
||||
}
|
||||
|
||||
switch (separatorPos) {
|
||||
case TopSeparator:
|
||||
L = &(*border_chars)[TL_bip];
|
||||
I = &(*border_chars)[TT_bip];
|
||||
IV = &(*border_chars)[TV_bip];
|
||||
R = &(*border_chars)[TR_bip];
|
||||
break;
|
||||
case InsideSeparator:
|
||||
L = &(*border_chars)[LH_bip];
|
||||
I = &(*border_chars)[IH_bip];
|
||||
IV = &(*border_chars)[II_bip];
|
||||
R = &(*border_chars)[RH_bip];
|
||||
break;
|
||||
case BottomSeparator:
|
||||
L = &(*border_chars)[BL_bip];
|
||||
I = &(*border_chars)[BB_bip];
|
||||
IV = &(*border_chars)[BV_bip];
|
||||
R = &(*border_chars)[BR_bip];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* If all chars are not printable, skip line separator */
|
||||
if (!isprint(*L) && !isprint(*I) && !isprint(*IV) && !isprint(*R))
|
||||
return 0;
|
||||
|
||||
for (size_t i = 0; i < cols; ++i) {
|
||||
if (i == 0) {
|
||||
CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, 1, *L));
|
||||
} else {
|
||||
CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, 1, *IV));
|
||||
}
|
||||
CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, col_width_arr[i], *I));
|
||||
}
|
||||
CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, 1, *R));
|
||||
|
||||
CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, 1, '\n'));
|
||||
|
||||
return dev;
|
||||
|
||||
clear:
|
||||
return -1;
|
||||
|
||||
#undef CHECK_RESULT_AND_MOVE_DEV
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fort_row_t* create_row_from_string(const char *str)
|
||||
{
|
||||
fort_row_t * row = create_row();
|
||||
if (row == NULL)
|
||||
return NULL;
|
||||
|
||||
if (str == NULL)
|
||||
return row;
|
||||
|
||||
char *str_copy = F_STRDUP(str);
|
||||
if (str_copy == NULL)
|
||||
goto clear;
|
||||
|
||||
char *pos = str_copy;
|
||||
char *base_pos = str_copy;
|
||||
int number_of_separators = 0;
|
||||
while (*pos) {
|
||||
pos = strchr(pos, FORT_COL_SEPARATOR);
|
||||
if (pos != NULL) {
|
||||
*(pos) = '\0';
|
||||
++pos;
|
||||
number_of_separators++;
|
||||
}
|
||||
|
||||
fort_cell_t *cell = create_cell();
|
||||
if (cell == NULL)
|
||||
goto clear;
|
||||
|
||||
// int status = fill_buffer_from_string(cell->str_buffer, base_pos);
|
||||
int status = fill_cell_from_string(cell, base_pos);
|
||||
if (IS_ERROR(status)) {
|
||||
destroy_cell(cell);
|
||||
goto clear;
|
||||
}
|
||||
|
||||
status = vector_push(row->cells, &cell);
|
||||
if (IS_ERROR(status)) {
|
||||
destroy_cell(cell);
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (pos == NULL)
|
||||
break;
|
||||
base_pos = pos;
|
||||
}
|
||||
|
||||
/* special case if in format string last cell is empty */
|
||||
while (vector_size(row->cells) < (number_of_separators + 1)) {
|
||||
fort_cell_t *cell = create_cell();
|
||||
if (cell == NULL)
|
||||
goto clear;
|
||||
|
||||
// int status = fill_buffer_from_string(cell->str_buffer, "");
|
||||
int status = fill_cell_from_string(cell, "");
|
||||
if (IS_ERROR(status)) {
|
||||
destroy_cell(cell);
|
||||
goto clear;
|
||||
}
|
||||
|
||||
status = vector_push(row->cells, &cell);
|
||||
if (IS_ERROR(status)) {
|
||||
destroy_cell(cell);
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
F_FREE(str_copy);
|
||||
return row;
|
||||
|
||||
clear:
|
||||
destroy_row(row);
|
||||
F_FREE(str_copy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fort_row_t* create_row_from_fmt_string(const char* FORT_RESTRICT fmt, va_list *va_args)
|
||||
{
|
||||
string_buffer_t *buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE);
|
||||
if (buffer == NULL)
|
||||
return NULL;
|
||||
|
||||
int cols_origin = number_of_columns_in_format_string(fmt);
|
||||
|
||||
while (1) {
|
||||
va_list va;
|
||||
va_copy(va, *va_args);
|
||||
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;
|
||||
}
|
||||
|
||||
destroy_string_buffer(buffer);
|
||||
return row;
|
||||
}
|
||||
|
||||
/* todo: add processing of cols != cols_origin */
|
||||
|
||||
clear:
|
||||
destroy_string_buffer(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int snprintf_row(const fort_row_t *row, char *buffer, size_t buf_sz, size_t *col_width_arr, size_t col_width_arr_sz,
|
||||
size_t row_height, const context_t *context)
|
||||
{
|
||||
assert(context);
|
||||
if (row == NULL)
|
||||
return -1;
|
||||
|
||||
int cols_in_row = columns_in_row(row);
|
||||
if (cols_in_row > col_width_arr_sz)
|
||||
return -1;
|
||||
|
||||
/* Row separator anatomy
|
||||
*
|
||||
* L data IV data IV data R
|
||||
*/
|
||||
|
||||
const char (*bord_chars)[BorderItemPosSize] = (row->is_header)
|
||||
? (&context->header_border_chars)
|
||||
: (&context->border_chars);
|
||||
const char *L = &(*bord_chars)[LL_bip];
|
||||
const char *IV = &(*bord_chars)[IV_bip];
|
||||
const char *R = &(*bord_chars)[RR_bip];
|
||||
|
||||
|
||||
int dev = 0;
|
||||
for (size_t i = 0; i < row_height; ++i) {
|
||||
dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, *L);
|
||||
for (size_t j = 0; j < col_width_arr_sz; ++j) {
|
||||
if (j < cols_in_row) {
|
||||
fort_cell_t *cell = *(fort_cell_t**)vector_at(row->cells, j);
|
||||
dev += cell_printf(cell, i, j, buffer + dev, col_width_arr[j] + 1, context);
|
||||
} else {
|
||||
dev += snprint_n_chars(buffer + dev, buf_sz - dev, col_width_arr[j], ' ');
|
||||
}
|
||||
if (j == col_width_arr_sz - 1) {
|
||||
dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, *R);
|
||||
} else {
|
||||
dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, *IV);
|
||||
}
|
||||
}
|
||||
dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, '\n');
|
||||
}
|
||||
return dev;
|
||||
}
|
48
src/row.h
Normal file
48
src/row.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef ROW_H
|
||||
#define ROW_H
|
||||
|
||||
#include "fort_impl.h"
|
||||
#include "fort.h"
|
||||
#include "stdarg.h"
|
||||
|
||||
struct fort_row;
|
||||
typedef struct fort_row fort_row_t;
|
||||
struct fort_row
|
||||
{
|
||||
vector_t *cells;
|
||||
enum F_BOOL is_header;
|
||||
};
|
||||
|
||||
|
||||
|
||||
fort_row_t * create_row();
|
||||
void destroy_row(fort_row_t *row);
|
||||
fort_row_t * create_row_from_string(const char *str);
|
||||
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);
|
||||
|
||||
fort_cell_t *get_cell_implementation(fort_row_t *row, size_t col, enum PolicyOnNull policy);
|
||||
fort_cell_t *get_cell(fort_row_t *row, size_t col);
|
||||
const fort_cell_t *get_cell_c(const fort_row_t *row, size_t col);
|
||||
fort_cell_t *get_cell_and_create_if_not_exists(fort_row_t *row, size_t col);
|
||||
|
||||
|
||||
|
||||
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,
|
||||
enum HorSeparatorPos separatorPos, const context_t *context);
|
||||
|
||||
|
||||
|
||||
|
||||
fort_row_t* create_row_from_string(const char *str);
|
||||
fort_row_t* create_row_from_fmt_string(const char* FORT_RESTRICT fmt, va_list *va_args);
|
||||
|
||||
int snprintf_row(const fort_row_t *row, char *buffer, size_t buf_sz, size_t *col_width_arr, size_t col_width_arr_sz,
|
||||
size_t row_height, const context_t *context);
|
||||
|
||||
|
||||
#endif // ROW_H
|
132
src/string_buffer.c
Normal file
132
src/string_buffer.c
Normal file
@ -0,0 +1,132 @@
|
||||
#include "string_buffer.h"
|
||||
#include "options.h"
|
||||
#include "assert.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* STRING BUFFER
|
||||
* ***************************************************************************/
|
||||
string_buffer_t* create_string_buffer(size_t sz)
|
||||
{
|
||||
string_buffer_t *result = (string_buffer_t *)F_MALLOC(sizeof(string_buffer_t));
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
result->str = F_MALLOC(sz);
|
||||
if (result->str == NULL) {
|
||||
F_FREE(result);
|
||||
return NULL;
|
||||
}
|
||||
result->str_sz = sz;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void destroy_string_buffer(string_buffer_t *buffer)
|
||||
{
|
||||
if (buffer == NULL)
|
||||
return;
|
||||
F_FREE(buffer->str);
|
||||
buffer->str = NULL;
|
||||
F_FREE(buffer);
|
||||
}
|
||||
|
||||
fort_status_t realloc_string_buffer_without_copy(string_buffer_t *buffer)
|
||||
{
|
||||
assert(buffer);
|
||||
char *new_str = (char*)F_MALLOC(buffer->str_sz * 2);
|
||||
if (new_str == NULL) {
|
||||
return F_MEMORY_ERROR;
|
||||
}
|
||||
F_FREE(buffer->str);
|
||||
buffer->str = new_str;
|
||||
buffer->str_sz *= 2;
|
||||
return F_SUCCESS;
|
||||
}
|
||||
|
||||
fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str)
|
||||
{
|
||||
assert(buffer);
|
||||
assert(str);
|
||||
|
||||
size_t sz = strlen(str);
|
||||
char * copy = F_STRDUP(str);
|
||||
if (copy == NULL)
|
||||
return F_MEMORY_ERROR;
|
||||
|
||||
while (sz >= buffer->str_sz) {
|
||||
int status = realloc_string_buffer_without_copy(buffer);
|
||||
if (!IS_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
F_FREE(buffer->str);
|
||||
buffer->str = copy;
|
||||
|
||||
return F_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t buffer_text_height(string_buffer_t *buffer)
|
||||
{
|
||||
if (buffer == NULL || buffer->str == NULL || strlen(buffer->str) == 0) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t buffer_text_width(string_buffer_t *buffer)
|
||||
{
|
||||
if (buffer == NULL || buffer->str == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return strlen(buffer->str);
|
||||
}
|
||||
|
||||
|
||||
int buffer_printf(string_buffer_t *buffer, size_t buffer_row, size_t table_column, char *buf, size_t buf_len, const context_t *context)
|
||||
{
|
||||
if (buffer == NULL || buffer->str == NULL
|
||||
|| buffer_row >= buffer_text_height(buffer) || buf_len == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t content_width = buffer_text_width(buffer);
|
||||
if ((buf_len - 1) < content_width)
|
||||
return -1;
|
||||
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
|
||||
switch (fort_options_column_alignment(context, table_column)) {
|
||||
case LeftAligned:
|
||||
left = 0;
|
||||
right = (buf_len - 1) - content_width;
|
||||
break;
|
||||
case CenterAligned:
|
||||
left = ((buf_len - 1) - content_width) / 2;
|
||||
right = ((buf_len - 1) - content_width) - left;
|
||||
break;
|
||||
case RightAligned:
|
||||
left = (buf_len - 1) - content_width;
|
||||
right = 0;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
if (left < 0 || right < 0)
|
||||
return -1;
|
||||
|
||||
|
||||
int written = 0;
|
||||
written += snprint_n_chars(buf + written, buf_len - written, left, ' ');
|
||||
if (written < 0)
|
||||
return written;
|
||||
|
||||
written += snprintf(buf + written, buf_len - written, "%*s", (int)content_width, buffer->str);
|
||||
if (written < 0)
|
||||
return written;
|
||||
|
||||
written += snprint_n_chars(buf + written, buf_len - written, right, ' ');
|
||||
return written;
|
||||
}
|
30
src/string_buffer.h
Normal file
30
src/string_buffer.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef STRING_BUFFER_H
|
||||
#define STRING_BUFFER_H
|
||||
|
||||
#include "fort_impl.h"
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* STRING BUFFER
|
||||
* ***************************************************************************/
|
||||
struct string_buffer;
|
||||
typedef struct string_buffer string_buffer_t;
|
||||
struct string_buffer
|
||||
{
|
||||
char *str;
|
||||
size_t str_sz;
|
||||
};
|
||||
|
||||
string_buffer_t* create_string_buffer(size_t sz);
|
||||
void destroy_string_buffer(string_buffer_t *buffer);
|
||||
fort_status_t realloc_string_buffer_without_copy(string_buffer_t *buffer);
|
||||
fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str);
|
||||
|
||||
size_t buffer_text_height(string_buffer_t *buffer);
|
||||
|
||||
|
||||
size_t buffer_text_width(string_buffer_t *buffer);
|
||||
int buffer_printf(string_buffer_t *buffer, size_t buffer_row, size_t table_column, char *buf, size_t buf_len, const context_t *context);
|
||||
|
||||
|
||||
#endif // STRING_BUFFER_H
|
186
src/table.c
Normal file
186
src/table.c
Normal file
@ -0,0 +1,186 @@
|
||||
#include "table.h"
|
||||
#include "string_buffer.h"
|
||||
#include "cell.h"
|
||||
#include "vector.h"
|
||||
#include "row.h"
|
||||
fort_status_t get_table_sizes(const FTABLE *table, size_t *rows, size_t *cols);
|
||||
|
||||
|
||||
|
||||
fort_row_t *get_row_implementation(fort_table_t *table, size_t row, enum PolicyOnNull policy)
|
||||
{
|
||||
if (table == NULL || table->rows == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
fort_row_t *get_row(fort_table_t *table, size_t row)
|
||||
{
|
||||
return get_row_implementation(table, row, DoNotCreate);
|
||||
}
|
||||
|
||||
const fort_row_t *get_row_c(const fort_table_t *table, size_t row)
|
||||
{
|
||||
return get_row((fort_table_t *)table, row);
|
||||
}
|
||||
|
||||
fort_row_t *get_row_and_create_if_not_exists(fort_table_t *table, size_t row)
|
||||
{
|
||||
return get_row_implementation(table, row, Create);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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;
|
||||
|
||||
return cell_get_string_buffer(cell);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns number of cells (rows * cols)
|
||||
*/
|
||||
fort_status_t get_table_sizes(const FTABLE *table, size_t *rows, size_t *cols)
|
||||
{
|
||||
*rows = 0;
|
||||
*cols = 0;
|
||||
if (table && table->rows) {
|
||||
*rows = vector_size(table->rows);
|
||||
fort_row_t *row = NULL;
|
||||
FOR_EACH(fort_row_t*, row, table->rows) {
|
||||
size_t cols_in_row = columns_in_row(row);
|
||||
if (cols_in_row > *cols)
|
||||
*cols = cols_in_row;
|
||||
}
|
||||
}
|
||||
return F_SUCCESS;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
context_t *context = (table->options ? table->options : &g_table_options);
|
||||
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, context));
|
||||
row_height_arr[row] = MAX(row_height_arr[row], hint_height_cell(cell, context));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* todo: Maybe it is better to move min width checking to a particular cell width checking.
|
||||
* At the moment min width includes paddings. Maybe it is better that min width weren't include
|
||||
* paddings but be min width of the cell content without padding
|
||||
*/
|
||||
if (table->options) {
|
||||
for (size_t i = 0; i < cols; ++i) {
|
||||
col_width_arr[i] = MAX((int)col_width_arr[i], fort_options_column_width(table->options, i));
|
||||
}
|
||||
}
|
||||
|
||||
*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
|
||||
*/
|
||||
fort_status_t table_geometry(const FTABLE *table, size_t *height, size_t *width)
|
||||
{
|
||||
if (table == NULL)
|
||||
return F_ERROR;
|
||||
|
||||
*height = 0;
|
||||
*width = 0;
|
||||
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];
|
||||
}
|
||||
|
||||
/* 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];
|
||||
}
|
||||
F_FREE(col_width_arr);
|
||||
F_FREE(row_height_arr);
|
||||
return F_SUCCESS;
|
||||
|
||||
}
|
||||
|
33
src/table.h
Normal file
33
src/table.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef TABLE_H
|
||||
#define TABLE_H
|
||||
|
||||
#include "fort_impl.h"
|
||||
#include "fort.h"
|
||||
struct fort_table;
|
||||
typedef struct fort_table fort_table_t;
|
||||
struct fort_table
|
||||
{
|
||||
vector_t *rows;
|
||||
fort_table_options_t *options;
|
||||
string_buffer_t *conv_buffer;
|
||||
size_t cur_row;
|
||||
size_t cur_col;
|
||||
};
|
||||
|
||||
|
||||
fort_status_t get_table_sizes(const FTABLE *table, size_t *rows, size_t *cols);
|
||||
fort_row_t *get_row_implementation(fort_table_t *table, size_t row, enum PolicyOnNull policy);
|
||||
fort_row_t *get_row(fort_table_t *table, size_t row);
|
||||
const fort_row_t *get_row_c(const fort_table_t *table, size_t row);
|
||||
fort_row_t *get_row_and_create_if_not_exists(fort_table_t *table, size_t row);
|
||||
|
||||
string_buffer_t * get_cur_str_buffer_and_create_if_not_exists(FTABLE *FORT_RESTRICT table);
|
||||
|
||||
|
||||
|
||||
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);
|
||||
fort_status_t table_geometry(const FTABLE *table, size_t *height, size_t *width);
|
||||
|
||||
#endif // TABLE_H
|
144
src/vector.c
Normal file
144
src/vector.c
Normal file
@ -0,0 +1,144 @@
|
||||
#include "vector.h"
|
||||
#include <assert.h>
|
||||
|
||||
/*****************************************************************************
|
||||
* VECTOR IMPLEMENTATIONS
|
||||
* ***************************************************************************/
|
||||
|
||||
struct vector
|
||||
{
|
||||
size_t m_size;
|
||||
void *m_data;
|
||||
size_t m_capacity;
|
||||
size_t m_item_size;
|
||||
};
|
||||
|
||||
static int vector_reallocate_(vector_t *vector, size_t new_capacity)
|
||||
{
|
||||
assert(vector);
|
||||
assert(new_capacity > vector->m_capacity);
|
||||
|
||||
size_t new_size = new_capacity * vector->m_item_size;
|
||||
vector->m_data = realloc(vector->m_data, new_size);
|
||||
if (vector->m_data == NULL)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------ Constructors & Destructors ----------------------------- */
|
||||
|
||||
vector_t* create_vector(size_t item_size, size_t capacity)
|
||||
{
|
||||
vector_t *vector = malloc(sizeof(vector_t));
|
||||
if (vector == NULL) {
|
||||
SYS_LOG_ERROR("Failed to allocate memory for asock vector");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t init_size = MAX(item_size * capacity, 1);
|
||||
vector->m_data = malloc(init_size);
|
||||
if (vector->m_data == NULL) {
|
||||
SYS_LOG_ERROR("Failed to allocate memory for asock vector inern. buffer");
|
||||
free(vector);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vector->m_size = 0;
|
||||
vector->m_capacity = capacity;
|
||||
vector->m_item_size = item_size;
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
|
||||
void destroy_vector(vector_t* vector)
|
||||
{
|
||||
assert(vector);
|
||||
free(vector->m_data);
|
||||
free(vector);
|
||||
}
|
||||
|
||||
|
||||
/* ----------- Nonmodifying functions --------------------------------- */
|
||||
|
||||
size_t vector_size(const vector_t* vector)
|
||||
{
|
||||
assert(vector);
|
||||
return vector->m_size;
|
||||
}
|
||||
|
||||
|
||||
size_t vector_capacity(const vector_t* vector)
|
||||
{
|
||||
assert(vector);
|
||||
return vector->m_capacity;
|
||||
}
|
||||
|
||||
size_t vector_index_of(const vector_t* vector, const void *item)
|
||||
{
|
||||
assert(vector);
|
||||
assert(item);
|
||||
|
||||
for (size_t i = 0; i < vector->m_size; ++i) {
|
||||
void *data_pos = vector->m_data + i * vector->m_item_size;
|
||||
if (memcmp(data_pos, item, vector->m_item_size) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return INVALID_VEC_INDEX;
|
||||
}
|
||||
|
||||
|
||||
/* ----------- Modifying functions ------------------------------------- */
|
||||
|
||||
int vector_push (vector_t* vector, const void* item)
|
||||
{
|
||||
assert(vector);
|
||||
assert(item);
|
||||
|
||||
if (vector->m_size == vector->m_capacity) {
|
||||
if (vector_reallocate_(vector, vector->m_capacity * 2) == -1)
|
||||
return F_ERROR;
|
||||
vector->m_capacity = vector->m_capacity * 2;
|
||||
}
|
||||
|
||||
ptrdiff_t deviation = vector->m_size * vector->m_item_size;
|
||||
memcpy(vector->m_data + deviation, item, vector->m_item_size);
|
||||
|
||||
++(vector->m_size);
|
||||
|
||||
return F_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int vector_erase(vector_t *vector, size_t index)
|
||||
{
|
||||
assert(vector);
|
||||
|
||||
if (vector->m_size == 0 || index >= vector->m_size)
|
||||
return F_ERROR;
|
||||
|
||||
memmove(vector->m_data + vector->m_item_size * index,
|
||||
vector->m_data + vector->m_item_size * (index + 1),
|
||||
(vector->m_size - 1 - index) * vector->m_item_size);
|
||||
vector->m_size--;
|
||||
return F_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void vector_clear(vector_t *vector)
|
||||
{
|
||||
vector->m_size = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void *vector_at(vector_t *vector, size_t index)
|
||||
{
|
||||
if (index >= vector->m_size)
|
||||
return NULL;
|
||||
|
||||
return vector->m_data + index * vector->m_item_size;
|
||||
}
|
||||
|
||||
|
35
src/vector.h
Normal file
35
src/vector.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef VECTOR_H
|
||||
#define VECTOR_H
|
||||
|
||||
#include "fort_impl.h"
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* VECTOR
|
||||
* ***************************************************************************/
|
||||
|
||||
struct vector;
|
||||
typedef struct vector vector_t;
|
||||
|
||||
#define INVALID_VEC_INDEX ((size_t) -1)
|
||||
|
||||
extern vector_t* create_vector(size_t item_size, size_t capacity);
|
||||
extern void destroy_vector(vector_t*);
|
||||
|
||||
extern size_t vector_size(const vector_t*);
|
||||
extern size_t vector_capacity(const vector_t*);
|
||||
extern size_t vector_index_of(const vector_t*, const void *item);
|
||||
|
||||
extern int vector_push(vector_t*, const void *item);
|
||||
extern int vector_erase(vector_t*, size_t index);
|
||||
extern void vector_clear(vector_t*);
|
||||
extern void* vector_at(vector_t*, size_t index);
|
||||
|
||||
|
||||
#define FOR_EACH_(type, item, 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))
|
||||
|
||||
#endif // VECTOR_H
|
@ -1,10 +1,11 @@
|
||||
#define FORT_EXTERN static
|
||||
//#define FORT_EXTERN static
|
||||
#include "tests.h"
|
||||
#include "fort.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "fort.c"
|
||||
//#include "fort.c"
|
||||
#include "table.h"
|
||||
|
||||
void test_table_sizes(void **state)
|
||||
{
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "tests.h"
|
||||
#include "../src/fort.c"
|
||||
|
||||
#include "vector.h"
|
||||
//#include "../src/fort.c"
|
||||
|
||||
|
||||
void test_vector_basic(void **state)
|
||||
|
Loading…
Reference in New Issue
Block a user