[C] Refactoring of setting row type
This commit is contained in:
59
src/cell.c
59
src/cell.c
@@ -18,7 +18,7 @@ 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);
|
||||
cell->str_buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, CharBuf);
|
||||
if (cell->str_buffer == NULL) {
|
||||
F_FREE(cell);
|
||||
return NULL;
|
||||
@@ -49,7 +49,7 @@ int hint_width_cell(const fort_cell_t *cell, const context_t *context)
|
||||
int cell_padding_left = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_LEFT_PADDING);
|
||||
int cell_padding_right = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_RIGHT_PADDING);
|
||||
int result = cell_padding_left + cell_padding_right;
|
||||
if (cell->str_buffer && cell->str_buffer->str) {
|
||||
if (cell->str_buffer && cell->str_buffer->data) {
|
||||
result += buffer_text_width(cell->str_buffer);
|
||||
}
|
||||
result = MAX(result, get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_MIN_WIDTH));
|
||||
@@ -64,7 +64,7 @@ int hint_height_cell(const fort_cell_t *cell, const context_t *context)
|
||||
int cell_padding_bottom = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_BOTTOM_PADDING);
|
||||
int cell_empty_string_height = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_EMPTY_STR_HEIGHT);
|
||||
int result = cell_padding_top + cell_padding_bottom;
|
||||
if (cell->str_buffer && cell->str_buffer->str) {
|
||||
if (cell->str_buffer && cell->str_buffer->data) {
|
||||
size_t text_height = buffer_text_height(cell->str_buffer);
|
||||
result += text_height == 0 ? cell_empty_string_height : text_height;
|
||||
}
|
||||
@@ -94,6 +94,11 @@ int hint_height_cell(const fort_cell_t *cell, const context_t *context)
|
||||
|
||||
int cell_printf(fort_cell_t *cell, size_t row, size_t column, char *buf, size_t buf_len, const context_t *context)
|
||||
{
|
||||
char space_char = ' ';
|
||||
int (*buffer_printf_)(string_buffer_t *, size_t , size_t , char *, size_t , const context_t *) = buffer_printf;
|
||||
int (*snprint_n_chars_)(char *, size_t , size_t , char) = snprint_n_chars;
|
||||
|
||||
|
||||
if (cell == NULL || buf_len == 0
|
||||
|| (buf_len <= hint_width_cell(cell, context))) {
|
||||
return -1;
|
||||
@@ -106,26 +111,62 @@ int cell_printf(fort_cell_t *cell, size_t row, size_t column, char *buf, size_t
|
||||
if (row >= hint_height_cell(cell, context)
|
||||
|| row < cell_padding_top
|
||||
|| row >= (cell_padding_top + buffer_text_height(cell->str_buffer))) {
|
||||
int k = snprint_n_chars(buf, buf_len, buf_len - 1, ' ');
|
||||
int k = snprint_n_chars_(buf, buf_len, buf_len - 1, space_char);
|
||||
return k;
|
||||
} else {
|
||||
int written = 0;
|
||||
int left = cell_padding_left;
|
||||
int right = cell_padding_right;
|
||||
|
||||
written += snprint_n_chars(buf + written, buf_len - written, left, ' ');
|
||||
written += snprint_n_chars_(buf + written, buf_len - written, left, space_char);
|
||||
|
||||
if (cell->str_buffer)
|
||||
written += buffer_printf(cell->str_buffer, row - cell_padding_top, column, buf + written, buf_len - written - right, context);
|
||||
written += buffer_printf_(cell->str_buffer, row - 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, ' ');
|
||||
written += snprint_n_chars_(buf + written, buf_len - written, buf_len - written - right, space_char);
|
||||
written += snprint_n_chars_(buf + written, buf_len - written, right, space_char);
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int cell_wprintf(fort_cell_t *cell, size_t row, size_t column, wchar_t *buf, size_t buf_len, const context_t *context)
|
||||
{
|
||||
wchar_t space_char = L' ';
|
||||
int (*buffer_printf_)(string_buffer_t *, size_t , size_t , wchar_t *, size_t , const context_t *) = buffer_wprintf;
|
||||
int (*snprint_n_chars_)(wchar_t *, size_t , size_t , wchar_t) = wsnprint_n_chars;
|
||||
|
||||
|
||||
if (cell == NULL || buf_len == 0
|
||||
|| (buf_len <= hint_width_cell(cell, context))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cell_padding_top = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_TOP_PADDING);
|
||||
int cell_padding_left = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_LEFT_PADDING);
|
||||
int cell_padding_right = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_RIGHT_PADDING);
|
||||
|
||||
if (row >= hint_height_cell(cell, context)
|
||||
|| row < cell_padding_top
|
||||
|| row >= (cell_padding_top + buffer_text_height(cell->str_buffer))) {
|
||||
int k = snprint_n_chars_(buf, buf_len, buf_len - 1, space_char);
|
||||
return k;
|
||||
} else {
|
||||
int written = 0;
|
||||
int left = cell_padding_left;
|
||||
int right = cell_padding_right;
|
||||
|
||||
written += snprint_n_chars_(buf + written, buf_len - written, left, space_char);
|
||||
|
||||
if (cell->str_buffer)
|
||||
written += buffer_printf_(cell->str_buffer, row - 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, space_char);
|
||||
written += snprint_n_chars_(buf + written, buf_len - written, right, space_char);
|
||||
|
||||
return written;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fort_status_t fill_cell_from_string(fort_cell_t *cell, const char *str)
|
||||
|
@@ -25,6 +25,8 @@ int hint_height_cell(const fort_cell_t *cell, const context_t *context);
|
||||
//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);
|
||||
int cell_wprintf(fort_cell_t *cell, size_t row, size_t column, wchar_t *buf, size_t buf_len, const context_t *context);
|
||||
|
||||
|
||||
fort_status_t fill_cell_from_string(fort_cell_t *cell, const char *str);
|
||||
|
||||
|
203
src/fort.c
203
src/fort.c
@@ -171,7 +171,10 @@ int FT_HDR_PRINTF(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT fmt, ..
|
||||
if (result >= 0 && table->rows) {
|
||||
int sz = vector_size(table->rows);
|
||||
if (sz != 0) {
|
||||
set_row_type(*(fort_row_t**)vector_at(table->rows, sz - 1), Header);
|
||||
// set_row_type(*(fort_row_t**)vector_at(table->rows, sz - 1), Header);
|
||||
int ignore = ft_set_cell_option(table, sz - 1, FT_ANY_COLUMN, FT_OPT_ROW_TYPE, Header);
|
||||
(void)ignore;
|
||||
assert(ignore == F_SUCCESS);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -189,7 +192,10 @@ int FT_HDR_PRINTF_LN(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT fmt,
|
||||
if (result >= 0 && table->rows) {
|
||||
int sz = vector_size(table->rows);
|
||||
if (sz != 0) {
|
||||
set_row_type(*(fort_row_t**)vector_at(table->rows, sz - 1), Header);
|
||||
// set_row_type(*(fort_row_t**)vector_at(table->rows, sz - 1), Header);
|
||||
int ignore = ft_set_cell_option(table, sz - 1, FT_ANY_COLUMN, FT_OPT_ROW_TYPE, Header);
|
||||
(void)ignore;
|
||||
assert(ignore == F_SUCCESS);
|
||||
}
|
||||
}
|
||||
if (result >= 0) {
|
||||
@@ -251,7 +257,32 @@ int ft_write_ln(FTABLE *FORT_RESTRICT table, const char* FORT_RESTRICT cell_cont
|
||||
return status;
|
||||
}
|
||||
|
||||
FORT_EXTERN int ft_nwrite(FTABLE *FORT_RESTRICT table, size_t n, const char* FORT_RESTRICT cell_content, ...)
|
||||
int ft_wwrite(FTABLE *FORT_RESTRICT table, const wchar_t* FORT_RESTRICT cell_content)
|
||||
{
|
||||
assert(table);
|
||||
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_wstring(str_buffer, cell_content);
|
||||
if (IS_SUCCESS(status)) {
|
||||
table->cur_col++;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int ft_wwrite_ln(FTABLE *FORT_RESTRICT table, const wchar_t* FORT_RESTRICT cell_content)
|
||||
{
|
||||
assert(table);
|
||||
int status = ft_wwrite(table, cell_content);
|
||||
if (IS_SUCCESS(status)) {
|
||||
ft_ln(table);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int ft_nwrite(FTABLE *FORT_RESTRICT table, size_t n, const char* FORT_RESTRICT cell_content, ...)
|
||||
{
|
||||
assert(table);
|
||||
int status = ft_write(table, cell_content);
|
||||
@@ -271,7 +302,7 @@ FORT_EXTERN int ft_nwrite(FTABLE *FORT_RESTRICT table, size_t n, const char* FOR
|
||||
return status;
|
||||
}
|
||||
|
||||
FORT_EXTERN int ft_nwrite_ln(FTABLE *FORT_RESTRICT table, size_t n, const char* FORT_RESTRICT cell_content, ...)
|
||||
int ft_nwrite_ln(FTABLE *FORT_RESTRICT table, size_t n, const char* FORT_RESTRICT cell_content, ...)
|
||||
{
|
||||
assert(table);
|
||||
int status = ft_write(table, cell_content);
|
||||
@@ -296,6 +327,51 @@ FORT_EXTERN int ft_nwrite_ln(FTABLE *FORT_RESTRICT table, size_t n, const char*
|
||||
}
|
||||
|
||||
|
||||
int ft_nwwrite(FTABLE *FORT_RESTRICT table, size_t n, const wchar_t* FORT_RESTRICT cell_content, ...)
|
||||
{
|
||||
assert(table);
|
||||
int status = ft_wwrite(table, cell_content);
|
||||
if (IS_ERROR(status))
|
||||
return status;
|
||||
|
||||
va_list va;
|
||||
va_start(va, cell_content);
|
||||
--n;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
const wchar_t *cell = va_arg(va, const wchar_t*);
|
||||
status = ft_wwrite(table, cell);
|
||||
if (IS_ERROR(status))
|
||||
return status;
|
||||
}
|
||||
va_end(va);
|
||||
return status;
|
||||
}
|
||||
|
||||
int ft_nwwrite_ln(FTABLE *FORT_RESTRICT table, size_t n, const wchar_t* FORT_RESTRICT cell_content, ...)
|
||||
{
|
||||
assert(table);
|
||||
int status = ft_wwrite(table, cell_content);
|
||||
if (IS_ERROR(status))
|
||||
return status;
|
||||
|
||||
va_list va;
|
||||
va_start(va, cell_content);
|
||||
--n;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
const wchar_t *cell = va_arg(va, const wchar_t*);
|
||||
status = ft_wwrite(table, cell);
|
||||
if (IS_ERROR(status)) {
|
||||
va_end(va);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
ft_ln(table);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
FORT_EXTERN int ft_row_write(FTABLE *FORT_RESTRICT table, size_t cols, const char* FORT_RESTRICT cells[])
|
||||
{
|
||||
assert(table);
|
||||
@@ -396,6 +472,16 @@ const char* ft_to_string(const FTABLE *FORT_RESTRICT table)
|
||||
} \
|
||||
dev += k;
|
||||
|
||||
typedef char char_type;
|
||||
const char_type *empty_string = "";
|
||||
const enum str_buf_type buf_type = CharBuf;
|
||||
#define cur_F_STRDUP F_STRDUP
|
||||
int (*snprintf_row_)(const fort_row_t *, char *, size_t, size_t *, size_t, size_t, const context_t *) = snprintf_row;
|
||||
int (*print_row_separator_)(char *, size_t ,
|
||||
const size_t *, size_t ,
|
||||
const fort_row_t *, const fort_row_t *,
|
||||
enum HorSeparatorPos , const separator_t *,
|
||||
const context_t *) = print_row_separator;
|
||||
assert(table);
|
||||
|
||||
/* Determing size of table string representation */
|
||||
@@ -409,16 +495,16 @@ const char* ft_to_string(const FTABLE *FORT_RESTRICT table)
|
||||
|
||||
/* Allocate string buffer for string representation */
|
||||
if (table->conv_buffer == NULL) {
|
||||
((FTABLE *)table)->conv_buffer = create_string_buffer(sz);
|
||||
((FTABLE *)table)->conv_buffer = create_string_buffer(sz, buf_type);
|
||||
if (table->conv_buffer == NULL)
|
||||
return NULL;
|
||||
}
|
||||
while (table->conv_buffer->str_sz < sz) {
|
||||
while (string_buffer_capacity(table->conv_buffer) < sz) {// 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;
|
||||
char_type *buffer = buffer_get_data(table->conv_buffer);
|
||||
|
||||
|
||||
size_t cols = 0;
|
||||
@@ -428,7 +514,7 @@ const char* ft_to_string(const FTABLE *FORT_RESTRICT table)
|
||||
status = table_rows_and_cols_geometry(table, &col_width_arr, &cols, &row_height_arr, &rows);
|
||||
|
||||
if (rows == 0)
|
||||
return F_STRDUP("");
|
||||
return cur_F_STRDUP(empty_string);
|
||||
|
||||
if (IS_ERROR(status))
|
||||
return NULL;
|
||||
@@ -446,14 +532,108 @@ const char* ft_to_string(const FTABLE *FORT_RESTRICT table)
|
||||
cur_sep = (i < sep_size) ? (*(separator_t **)vector_at(table->separators, i)) : NULL;
|
||||
cur_row = *(fort_row_t**)vector_at(table->rows, i);
|
||||
enum HorSeparatorPos separatorPos = (i == 0) ? TopSeparator : InsideSeparator;
|
||||
CHECK_RESULT_AND_MOVE_DEV(print_row_separator(buffer + dev, sz - dev, col_width_arr, cols, prev_row, cur_row, separatorPos, cur_sep, &context));
|
||||
context.row = i;
|
||||
CHECK_RESULT_AND_MOVE_DEV(snprintf_row(cur_row, buffer + dev, sz - dev, col_width_arr, cols, row_height_arr[i], &context));
|
||||
CHECK_RESULT_AND_MOVE_DEV(print_row_separator_(buffer + dev, sz - dev, col_width_arr, cols, prev_row, cur_row, separatorPos, cur_sep, &context));
|
||||
CHECK_RESULT_AND_MOVE_DEV(snprintf_row_(cur_row, buffer + dev, sz - dev, col_width_arr, cols, row_height_arr[i], &context));
|
||||
prev_row = cur_row;
|
||||
}
|
||||
cur_row = NULL;
|
||||
cur_sep = (i < sep_size) ? (*(separator_t **)vector_at(table->separators, i)) : NULL;
|
||||
CHECK_RESULT_AND_MOVE_DEV(print_row_separator(buffer + dev, sz - dev, col_width_arr, cols, prev_row, cur_row, BottomSeparator, cur_sep, &context));
|
||||
CHECK_RESULT_AND_MOVE_DEV(print_row_separator_(buffer + dev, sz - dev, col_width_arr, cols, prev_row, cur_row, BottomSeparator, cur_sep, &context));
|
||||
|
||||
|
||||
F_FREE(col_width_arr);
|
||||
F_FREE(row_height_arr);
|
||||
return buffer;
|
||||
|
||||
clear:
|
||||
F_FREE(col_width_arr);
|
||||
F_FREE(row_height_arr);
|
||||
F_FREE(buffer);
|
||||
return NULL;
|
||||
|
||||
#undef cur_F_STRDUP
|
||||
#undef CHECK_RESULT_AND_MOVE_DEV
|
||||
}
|
||||
|
||||
|
||||
const wchar_t* ft_to_wstring(const FTABLE *FORT_RESTRICT table)
|
||||
{
|
||||
#define CHECK_RESULT_AND_MOVE_DEV(statement) \
|
||||
k = statement; \
|
||||
if (k < 0) {\
|
||||
goto clear; \
|
||||
} \
|
||||
dev += k;
|
||||
|
||||
typedef wchar_t char_type;
|
||||
const char_type *empty_string = L"";
|
||||
const enum str_buf_type buf_type = WCharBuf;
|
||||
#define cur_F_STRDUP F_WCSDUP
|
||||
int (*snprintf_row_)(const fort_row_t *, wchar_t *, size_t, size_t *, size_t, size_t, const context_t *) = wsnprintf_row;
|
||||
int (*print_row_separator_)(wchar_t *, size_t ,
|
||||
const size_t *, size_t ,
|
||||
const fort_row_t *, const fort_row_t *,
|
||||
enum HorSeparatorPos , const separator_t *,
|
||||
const context_t *) = wprint_row_separator;
|
||||
assert(table);
|
||||
|
||||
/* Determing size of table string representation */
|
||||
size_t height = 0;
|
||||
size_t width = 0;
|
||||
int status = table_geometry(table, &height, &width);
|
||||
if (IS_ERROR(status)) {
|
||||
return NULL;
|
||||
}
|
||||
size_t sz = height * width + 1;
|
||||
|
||||
/* Allocate string buffer for string representation */
|
||||
if (table->conv_buffer == NULL) {
|
||||
((FTABLE *)table)->conv_buffer = create_string_buffer(sz, buf_type);
|
||||
if (table->conv_buffer == NULL)
|
||||
return NULL;
|
||||
}
|
||||
while (string_buffer_capacity(table->conv_buffer) < sz) {// table->conv_buffer->str_sz < sz) {
|
||||
if (IS_ERROR(realloc_string_buffer_without_copy(table->conv_buffer))) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
char_type *buffer = buffer_get_data(table->conv_buffer);
|
||||
|
||||
|
||||
size_t cols = 0;
|
||||
size_t rows = 0;
|
||||
size_t *col_width_arr = NULL;
|
||||
size_t *row_height_arr = NULL;
|
||||
status = table_rows_and_cols_geometry(table, &col_width_arr, &cols, &row_height_arr, &rows);
|
||||
|
||||
if (rows == 0)
|
||||
return cur_F_STRDUP(empty_string);
|
||||
|
||||
if (IS_ERROR(status))
|
||||
return NULL;
|
||||
|
||||
int dev = 0;
|
||||
int k = 0;
|
||||
context_t context;
|
||||
context.table_options = (table->options ? table->options : &g_table_options);
|
||||
fort_row_t *prev_row = NULL;
|
||||
fort_row_t *cur_row = NULL;
|
||||
separator_t *cur_sep = NULL;
|
||||
size_t sep_size = vector_size(table->separators);
|
||||
size_t i = 0;
|
||||
for (i = 0; i < rows; ++i) {
|
||||
cur_sep = (i < sep_size) ? (*(separator_t **)vector_at(table->separators, i)) : NULL;
|
||||
cur_row = *(fort_row_t**)vector_at(table->rows, i);
|
||||
enum HorSeparatorPos separatorPos = (i == 0) ? TopSeparator : InsideSeparator;
|
||||
context.row = i;
|
||||
CHECK_RESULT_AND_MOVE_DEV(print_row_separator_(buffer + dev, sz - dev, col_width_arr, cols, prev_row, cur_row, separatorPos, cur_sep, &context));
|
||||
CHECK_RESULT_AND_MOVE_DEV(snprintf_row_(cur_row, buffer + dev, sz - dev, col_width_arr, cols, row_height_arr[i], &context));
|
||||
prev_row = cur_row;
|
||||
}
|
||||
cur_row = NULL;
|
||||
cur_sep = (i < sep_size) ? (*(separator_t **)vector_at(table->separators, i)) : NULL;
|
||||
CHECK_RESULT_AND_MOVE_DEV(print_row_separator_(buffer + dev, sz - dev, col_width_arr, cols, prev_row, cur_row, BottomSeparator, cur_sep, &context));
|
||||
|
||||
|
||||
F_FREE(col_width_arr);
|
||||
@@ -471,7 +651,6 @@ clear:
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* TMP
|
||||
*/
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#include "fort_impl.h"
|
||||
#include <wchar.h>
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +12,7 @@ char *fort_strdup(const char* str)
|
||||
return NULL;
|
||||
|
||||
size_t sz = strlen(str);
|
||||
char *str_copy = (char*)F_MALLOC(sz + 1);
|
||||
char *str_copy = (char*)F_MALLOC((sz + 1)*sizeof(char));
|
||||
if (str_copy == NULL)
|
||||
return NULL;
|
||||
|
||||
@@ -19,6 +20,20 @@ char *fort_strdup(const char* str)
|
||||
return str_copy;
|
||||
}
|
||||
|
||||
wchar_t *fort_wcsdup(const wchar_t* str)
|
||||
{
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
|
||||
size_t sz = wcslen(str);
|
||||
wchar_t *str_copy = (wchar_t*)F_MALLOC((sz + 1)*sizeof(wchar_t));
|
||||
if (str_copy == NULL)
|
||||
return NULL;
|
||||
|
||||
wcscpy(str_copy, str);
|
||||
return str_copy;
|
||||
}
|
||||
|
||||
size_t number_of_columns_in_format_string(const char *fmt)
|
||||
{
|
||||
int separator_counter = 0;
|
||||
@@ -39,6 +54,9 @@ int snprint_n_chars(char *buf, size_t length, size_t n, char ch)
|
||||
if (length <= n)
|
||||
return -1;
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
int status = snprintf(buf, length, "%0*d", (int)n, 0);
|
||||
if (status < 0)
|
||||
return status;
|
||||
@@ -49,3 +67,23 @@ int snprint_n_chars(char *buf, size_t length, size_t n, char ch)
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
int wsnprint_n_chars(wchar_t *buf, size_t length, size_t n, wchar_t ch)
|
||||
{
|
||||
if (length <= n)
|
||||
return -1;
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
int status = swprintf(buf, length, L"%0*d", (int)n, 0);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
*buf = ch;
|
||||
buf++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#define F_REALLOC realloc
|
||||
#define F_FREE free
|
||||
#define F_STRDUP fort_strdup
|
||||
#define F_WCSDUP fort_wcsdup
|
||||
|
||||
#define F_CREATE(type) ((type *)F_CALLOC(sizeof(type), 1))
|
||||
|
||||
@@ -107,7 +108,10 @@ typedef struct separator separator_t;
|
||||
* LIBFORT helpers
|
||||
*****************************************************************************/
|
||||
char *fort_strdup(const char* str);
|
||||
wchar_t *fort_wcsdup(const wchar_t* 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);
|
||||
int wsnprint_n_chars(wchar_t *buf, size_t length, size_t n, wchar_t ch);
|
||||
|
||||
|
||||
#endif // FORT_IMPL_H
|
||||
|
@@ -23,6 +23,8 @@ struct fort_cell_options g_default_cell_option =
|
||||
1, /* cell_padding_left */
|
||||
1, /* cell_padding_right */
|
||||
1, /* cell_empty_string_height */
|
||||
|
||||
Common, /* row_type */
|
||||
};
|
||||
|
||||
static int get_option_value_if_exists_otherwise_default(const struct fort_cell_options *cell_opts, uint32_t option)
|
||||
@@ -46,6 +48,8 @@ static int get_option_value_if_exists_otherwise_default(const struct fort_cell_o
|
||||
return cell_opts->cell_padding_right;
|
||||
case FT_OPT_EMPTY_STR_HEIGHT:
|
||||
return cell_opts->cell_empty_string_height;
|
||||
case FT_OPT_ROW_TYPE:
|
||||
return cell_opts->row_type;
|
||||
default:
|
||||
// todo: implement later
|
||||
exit(333);
|
||||
@@ -164,6 +168,8 @@ static fort_status_t set_cell_option_impl(fort_cell_options_t *opt, uint32_t opt
|
||||
opt->cell_padding_right = value;
|
||||
} else if (OPTION_IS_SET(option, FT_OPT_EMPTY_STR_HEIGHT)) {
|
||||
opt->cell_empty_string_height = value;
|
||||
} else if (OPTION_IS_SET(option, FT_OPT_ROW_TYPE)) {
|
||||
opt->row_type = value;
|
||||
}
|
||||
|
||||
return F_SUCCESS;
|
||||
|
@@ -12,6 +12,12 @@ enum TextAlignment
|
||||
RightAligned
|
||||
};
|
||||
|
||||
enum RowType
|
||||
{
|
||||
Common,
|
||||
Header
|
||||
};
|
||||
|
||||
|
||||
struct fort_column_options
|
||||
{
|
||||
@@ -41,6 +47,7 @@ typedef struct vector vector_t;
|
||||
#define FT_OPT_LEFT_PADDING ((uint32_t)(0x01U << (4)))
|
||||
#define FT_OPT_RIGHT_PADDING ((uint32_t)(0x01U << (5)))
|
||||
#define FT_OPT_EMPTY_STR_HEIGHT ((uint32_t)(0x01U << (6)))
|
||||
#define FT_OPT_ROW_TYPE ((uint32_t)(0x01U << (7)))
|
||||
|
||||
#define OPTION_IS_SET(ft_opts, option) ((ft_opts) & (option))
|
||||
#define OPTION_SET(ft_opts, option) ((ft_opts) |=(option))
|
||||
@@ -58,6 +65,7 @@ struct fort_cell_options
|
||||
int cell_padding_left;
|
||||
int cell_padding_right;
|
||||
int cell_empty_string_height;
|
||||
enum RowType row_type;
|
||||
};
|
||||
|
||||
typedef struct fort_cell_options fort_cell_options_t;
|
||||
|
239
src/row.c
239
src/row.c
@@ -24,7 +24,7 @@ fort_row_t * create_row()
|
||||
return NULL;
|
||||
}
|
||||
// row->is_header = F_FALSE;
|
||||
row->type = Common;
|
||||
// row->type = Common;
|
||||
return row;
|
||||
}
|
||||
|
||||
@@ -120,22 +120,26 @@ int print_row_separator(char *buffer, size_t buffer_sz,
|
||||
} \
|
||||
dev += k;
|
||||
|
||||
typedef char char_type;
|
||||
char new_line_char = '\n';
|
||||
int (*snprint_n_chars_)(char *, size_t , size_t , char) = snprint_n_chars;
|
||||
|
||||
|
||||
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->type == Header ? 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;
|
||||
enum RowType lower_row_type = Common;
|
||||
if (lower_row != NULL) {
|
||||
lower_row_type = get_cell_opt_value_hierarcial(context->table_options, context->row, FT_ANY_COLUMN, FT_OPT_ROW_TYPE);
|
||||
}
|
||||
enum RowType upper_row_type = Common;
|
||||
if (upper_row != NULL) {
|
||||
upper_row_type = get_cell_opt_value_hierarcial(context->table_options, context->row-1, FT_ANY_COLUMN, FT_OPT_ROW_TYPE);
|
||||
}
|
||||
|
||||
|
||||
/* Row separator anatomy
|
||||
*
|
||||
@@ -147,10 +151,9 @@ int print_row_separator(char *buffer, size_t buffer_sz,
|
||||
const char *R = NULL;
|
||||
|
||||
const char (*border_chars)[BorderItemPosSize] = NULL;
|
||||
if (main_row && main_row->type == Header) {
|
||||
border_chars = &context->table_options->border_chars;
|
||||
if (upper_row_type == Header || lower_row_type == Header) {
|
||||
border_chars = &context->table_options->header_border_chars;
|
||||
} else {
|
||||
border_chars = &context->table_options->border_chars;
|
||||
}
|
||||
|
||||
if (sep && sep->enabled) {
|
||||
@@ -183,21 +186,21 @@ int print_row_separator(char *buffer, size_t buffer_sz,
|
||||
}
|
||||
}
|
||||
|
||||
/* If all chars are not printable, skip line separator */
|
||||
/* If all chars are not printable, skip line separator */ /* todo: add processing for wchar_t */
|
||||
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));
|
||||
CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, 1, (char_type)*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, 1, (char_type)*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, col_width_arr[i], (char_type)*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, (char_type)*R));
|
||||
|
||||
CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars(buffer + dev, buffer_sz - dev, 1, '\n'));
|
||||
CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, 1, new_line_char));
|
||||
|
||||
return dev;
|
||||
|
||||
@@ -209,6 +212,110 @@ clear:
|
||||
|
||||
|
||||
|
||||
int wprint_row_separator(wchar_t *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 separator_t *sep,
|
||||
const context_t *context)
|
||||
{
|
||||
#define CHECK_RESULT_AND_MOVE_DEV(statement) \
|
||||
k = statement; \
|
||||
if (k < 0) {\
|
||||
goto clear; \
|
||||
} \
|
||||
dev += k;
|
||||
|
||||
typedef wchar_t char_type;
|
||||
char new_line_char = L'\n';
|
||||
int (*snprint_n_chars_)(wchar_t*, size_t , size_t , wchar_t) = wsnprint_n_chars;
|
||||
|
||||
|
||||
assert(buffer);
|
||||
assert(context);
|
||||
|
||||
int dev = 0;
|
||||
int k = 0;
|
||||
|
||||
enum RowType lower_row_type = Common;
|
||||
if (lower_row != NULL) {
|
||||
lower_row_type = get_cell_opt_value_hierarcial(context->table_options, context->row, FT_ANY_COLUMN, FT_OPT_ROW_TYPE);
|
||||
}
|
||||
enum RowType upper_row_type = Common;
|
||||
if (upper_row != NULL) {
|
||||
upper_row_type = get_cell_opt_value_hierarcial(context->table_options, context->row-1, FT_ANY_COLUMN, FT_OPT_ROW_TYPE);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
border_chars = &context->table_options->border_chars;
|
||||
if (upper_row_type == Header || lower_row_type == Header) {
|
||||
border_chars = &context->table_options->header_border_chars;
|
||||
}
|
||||
|
||||
|
||||
if (sep && sep->enabled) {
|
||||
L = &(context->table_options->separator_chars[LH_sip]);
|
||||
I = &(context->table_options->separator_chars[IH_sip]);
|
||||
IV = &(context->table_options->separator_chars[II_sip]);
|
||||
R = &(context->table_options->separator_chars[RH_sip]);
|
||||
} else {
|
||||
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 */ /* todo: add processing for wchar_t */
|
||||
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, (char_type)*L));
|
||||
} else {
|
||||
CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, 1, (char_type)*IV));
|
||||
}
|
||||
CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, col_width_arr[i], (char_type)*I));
|
||||
}
|
||||
CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, 1, (char_type)*R));
|
||||
|
||||
CHECK_RESULT_AND_MOVE_DEV(snprint_n_chars_(buffer + dev, buffer_sz - dev, 1, new_line_char));
|
||||
|
||||
return dev;
|
||||
|
||||
clear:
|
||||
return -1;
|
||||
|
||||
#undef CHECK_RESULT_AND_MOVE_DEV
|
||||
}
|
||||
|
||||
|
||||
|
||||
fort_row_t* create_row_from_string(const char *str)
|
||||
{
|
||||
@@ -290,7 +397,7 @@ clear:
|
||||
|
||||
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);
|
||||
string_buffer_t *buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, CharBuf);
|
||||
if (buffer == NULL)
|
||||
return NULL;
|
||||
|
||||
@@ -299,14 +406,14 @@ fort_row_t* create_row_from_fmt_string(const char* FORT_RESTRICT fmt, va_list *v
|
||||
while (1) {
|
||||
va_list va;
|
||||
va_copy(va, *va_args);
|
||||
int virtual_sz = vsnprintf(buffer->str, buffer->str_sz, fmt, va);
|
||||
int virtual_sz = vsnprintf(buffer->cstr, string_buffer_capacity(buffer)/*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)
|
||||
if (virtual_sz < string_buffer_capacity(buffer))// buffer->str_sz)
|
||||
break;
|
||||
|
||||
/* Otherwise buffer was too small, so incr. buffer size ant try again. */
|
||||
@@ -314,10 +421,10 @@ fort_row_t* create_row_from_fmt_string(const char* FORT_RESTRICT fmt, va_list *v
|
||||
goto clear;
|
||||
}
|
||||
|
||||
int cols = number_of_columns_in_format_string(buffer->str);
|
||||
int cols = number_of_columns_in_format_string(buffer->cstr);
|
||||
if (cols == cols_origin) {
|
||||
|
||||
fort_row_t *row = create_row_from_string(buffer->str);
|
||||
fort_row_t *row = create_row_from_string(buffer->cstr);
|
||||
if (row == NULL) {
|
||||
goto clear;
|
||||
}
|
||||
@@ -337,6 +444,13 @@ clear:
|
||||
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)
|
||||
{
|
||||
typedef char char_type;
|
||||
char space_char = ' ';
|
||||
char new_line_char = '\n';
|
||||
int (*snprint_n_chars_)(char *, size_t , size_t , char) = snprint_n_chars;
|
||||
int (*cell_printf_)(fort_cell_t *, size_t, size_t, char *, size_t, const context_t *) = cell_printf;
|
||||
|
||||
|
||||
assert(context);
|
||||
if (row == NULL)
|
||||
return -1;
|
||||
@@ -350,7 +464,8 @@ int snprintf_row(const fort_row_t *row, char *buffer, size_t buf_sz, size_t *col
|
||||
* L data IV data IV data R
|
||||
*/
|
||||
|
||||
const char (*bord_chars)[BorderItemPosSize] = (row->type == Header)
|
||||
enum RowType row_type = get_cell_opt_value_hierarcial(context->table_options, context->row, FT_ANY_COLUMN, FT_OPT_ROW_TYPE);
|
||||
const char (*bord_chars)[BorderItemPosSize] = (row_type == Header)
|
||||
? (&context->table_options->header_border_chars)
|
||||
: (&context->table_options->border_chars);
|
||||
const char *L = &(*bord_chars)[LL_bip];
|
||||
@@ -360,30 +475,86 @@ int snprintf_row(const fort_row_t *row, char *buffer, size_t buf_sz, size_t *col
|
||||
|
||||
int dev = 0;
|
||||
for (size_t i = 0; i < row_height; ++i) {
|
||||
dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, *L);
|
||||
dev += snprint_n_chars_(buffer + dev, buf_sz - dev, 1, (char_type)*L);
|
||||
for (size_t j = 0; j < col_width_arr_sz; ++j) {
|
||||
((context_t *)context)->column = 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);
|
||||
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], ' ');
|
||||
dev += snprint_n_chars_(buffer + dev, buf_sz - dev, col_width_arr[j], space_char);
|
||||
}
|
||||
if (j == col_width_arr_sz - 1) {
|
||||
dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, *R);
|
||||
dev += snprint_n_chars_(buffer + dev, buf_sz - dev, 1, (char_type)*R);
|
||||
} else {
|
||||
dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, *IV);
|
||||
dev += snprint_n_chars_(buffer + dev, buf_sz - dev, 1, (char_type)*IV);
|
||||
}
|
||||
}
|
||||
dev += snprint_n_chars(buffer + dev, buf_sz - dev, 1, '\n');
|
||||
dev += snprint_n_chars_(buffer + dev, buf_sz - dev, 1, new_line_char);
|
||||
}
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void set_row_type(fort_row_t *row, enum RowType type)
|
||||
int wsnprintf_row(const fort_row_t *row, wchar_t *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(row);
|
||||
row->type = type;
|
||||
typedef wchar_t char_type;
|
||||
char space_char = L' ';
|
||||
char new_line_char = L'\n';
|
||||
int (*snprint_n_chars_)(wchar_t *, size_t , size_t , wchar_t) = wsnprint_n_chars;
|
||||
int (*cell_printf_)(fort_cell_t *, size_t, size_t, wchar_t *, size_t, const context_t *) = cell_wprintf;
|
||||
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
enum RowType row_type = get_cell_opt_value_hierarcial(context->table_options, context->row, FT_ANY_COLUMN, FT_OPT_ROW_TYPE);
|
||||
const char (*bord_chars)[BorderItemPosSize] = (row_type)
|
||||
? (&context->table_options->header_border_chars)
|
||||
: (&context->table_options->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, (char_type)*L);
|
||||
for (size_t j = 0; j < col_width_arr_sz; ++j) {
|
||||
((context_t *)context)->column = 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], space_char);
|
||||
}
|
||||
if (j == col_width_arr_sz - 1) {
|
||||
dev += snprint_n_chars_(buffer + dev, buf_sz - dev, 1, (char_type)*R);
|
||||
} else {
|
||||
dev += snprint_n_chars_(buffer + dev, buf_sz - dev, 1, (char_type)*IV);
|
||||
}
|
||||
}
|
||||
dev += snprint_n_chars_(buffer + dev, buf_sz - dev, 1, new_line_char);
|
||||
}
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//void set_row_type(fort_row_t *row, enum RowType type)
|
||||
//{
|
||||
// assert(row);
|
||||
// row->type = type;
|
||||
//}
|
||||
|
20
src/row.h
20
src/row.h
@@ -8,11 +8,11 @@
|
||||
struct fort_row;
|
||||
typedef struct fort_row fort_row_t;
|
||||
|
||||
enum RowType
|
||||
{
|
||||
Common,
|
||||
Header
|
||||
};
|
||||
//enum RowType
|
||||
//{
|
||||
// Common,
|
||||
// Header
|
||||
//};
|
||||
|
||||
|
||||
fort_row_t * create_row();
|
||||
@@ -36,6 +36,12 @@ int print_row_separator(char *buffer, size_t buffer_sz,
|
||||
enum HorSeparatorPos separatorPos, const separator_t *sep,
|
||||
const context_t *context);
|
||||
|
||||
int wprint_row_separator(wchar_t *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 separator_t *sep,
|
||||
const context_t *context);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -44,7 +50,9 @@ fort_row_t* create_row_from_fmt_string(const char* FORT_RESTRICT fmt, va_list *v
|
||||
|
||||
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);
|
||||
int wsnprintf_row(const fort_row_t *row, wchar_t *buffer, size_t buf_sz, size_t *col_width_arr, size_t col_width_arr_sz,
|
||||
size_t row_height, const context_t *context);
|
||||
|
||||
void set_row_type(fort_row_t *row, enum RowType type);
|
||||
//void set_row_type(fort_row_t *row, enum RowType type);
|
||||
|
||||
#endif // ROW_H
|
||||
|
@@ -1,11 +1,22 @@
|
||||
#include "string_buffer.h"
|
||||
#include "options.h"
|
||||
#include "assert.h"
|
||||
#include "wchar.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* STRING BUFFER
|
||||
* ***************************************************************************/
|
||||
|
||||
static size_t buf_str_len(const string_buffer_t*buf)
|
||||
{
|
||||
assert(buf);
|
||||
if (buf->type == CharBuf) {
|
||||
return strlen(buf->cstr);
|
||||
} else {
|
||||
return wcslen(buf->wstr);
|
||||
}
|
||||
}
|
||||
|
||||
size_t strchr_count(const char* str, char ch)
|
||||
{
|
||||
if (str == NULL)
|
||||
@@ -21,6 +32,21 @@ size_t strchr_count(const char* str, char ch)
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t wstrchr_count(const wchar_t* str, wchar_t ch)
|
||||
{
|
||||
if (str == NULL)
|
||||
return 0;
|
||||
|
||||
size_t count = 0;
|
||||
str = wcschr(str, ch);
|
||||
while (str) {
|
||||
count++;
|
||||
str++;
|
||||
str = wcschr(str, ch);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
const char* str_n_substring_beg(const char* str, char ch_separator, size_t n)
|
||||
{
|
||||
if (str == NULL)
|
||||
@@ -41,6 +67,26 @@ const char* str_n_substring_beg(const char* str, char ch_separator, size_t n)
|
||||
return str ? (str + 1) : NULL;
|
||||
}
|
||||
|
||||
const wchar_t* wstr_n_substring_beg(const wchar_t* str, wchar_t ch_separator, size_t n)
|
||||
{
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
|
||||
if (n == 0)
|
||||
return str;
|
||||
|
||||
str = wcschr(str, ch_separator);
|
||||
--n;
|
||||
while (n > 0) {
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
--n;
|
||||
str++;
|
||||
str = wcschr(str, ch_separator);
|
||||
}
|
||||
return str ? (str + 1) : NULL;
|
||||
}
|
||||
|
||||
void str_n_substring(const char* str, char ch_separator, size_t n, const char **begin, const char **end)
|
||||
{
|
||||
const char *beg = str_n_substring_beg(str, ch_separator, n);
|
||||
@@ -60,18 +106,39 @@ void str_n_substring(const char* str, char ch_separator, size_t n, const char **
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
string_buffer_t* create_string_buffer(size_t sz)
|
||||
void wstr_n_substring(const wchar_t* str, wchar_t ch_separator, size_t n, const wchar_t **begin, const wchar_t **end)
|
||||
{
|
||||
const wchar_t *beg = wstr_n_substring_beg(str, ch_separator, n);
|
||||
if (beg == NULL) {
|
||||
*begin = NULL;
|
||||
*end = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
const wchar_t *en = wcschr(beg, ch_separator);
|
||||
if (en == NULL) {
|
||||
en = str + wcslen(str);
|
||||
}
|
||||
|
||||
*begin = beg;
|
||||
*end = en;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
string_buffer_t* create_string_buffer(size_t number_of_chars, enum str_buf_type type)
|
||||
{
|
||||
size_t sz = (number_of_chars) * (type == CharBuf ? sizeof(char) : sizeof(wchar_t));
|
||||
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) {
|
||||
result->data = F_MALLOC(sz);
|
||||
if (result->data == NULL) {
|
||||
F_FREE(result);
|
||||
return NULL;
|
||||
}
|
||||
result->str_sz = sz;
|
||||
result->data_sz = sz;
|
||||
result->type = type;
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -80,21 +147,21 @@ void destroy_string_buffer(string_buffer_t *buffer)
|
||||
{
|
||||
if (buffer == NULL)
|
||||
return;
|
||||
F_FREE(buffer->str);
|
||||
buffer->str = NULL;
|
||||
F_FREE(buffer->data);
|
||||
buffer->data = 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);
|
||||
char *new_str = (char*)F_MALLOC(buffer->data_sz * 2);
|
||||
if (new_str == NULL) {
|
||||
return F_MEMORY_ERROR;
|
||||
}
|
||||
F_FREE(buffer->str);
|
||||
buffer->str = new_str;
|
||||
buffer->str_sz *= 2;
|
||||
F_FREE(buffer->data);
|
||||
buffer->data = new_str;
|
||||
buffer->data_sz *= 2;
|
||||
return F_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -108,14 +175,38 @@ fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str)
|
||||
if (copy == NULL)
|
||||
return F_MEMORY_ERROR;
|
||||
|
||||
while (sz >= buffer->str_sz) {
|
||||
while (sz >= string_buffer_capacity(buffer)) {
|
||||
int status = realloc_string_buffer_without_copy(buffer);
|
||||
if (!IS_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
F_FREE(buffer->str);
|
||||
buffer->str = copy;
|
||||
F_FREE(buffer->data);
|
||||
buffer->cstr = copy;
|
||||
buffer->type = CharBuf;
|
||||
|
||||
return F_SUCCESS;
|
||||
}
|
||||
|
||||
fort_status_t fill_buffer_from_wstring(string_buffer_t *buffer, const wchar_t *str)
|
||||
{
|
||||
assert(buffer);
|
||||
assert(str);
|
||||
|
||||
size_t sz = wcslen(str);
|
||||
wchar_t * copy = F_WCSDUP(str);
|
||||
if (copy == NULL)
|
||||
return F_MEMORY_ERROR;
|
||||
|
||||
while (sz >= string_buffer_capacity(buffer)) {
|
||||
int status = realloc_string_buffer_without_copy(buffer);
|
||||
if (!IS_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
F_FREE(buffer->data);
|
||||
buffer->wstr = copy;
|
||||
buffer->type = WCharBuf;
|
||||
|
||||
return F_SUCCESS;
|
||||
}
|
||||
@@ -124,32 +215,59 @@ fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str)
|
||||
|
||||
size_t buffer_text_height(string_buffer_t *buffer)
|
||||
{
|
||||
if (buffer == NULL || buffer->str == NULL || strlen(buffer->str) == 0) {
|
||||
if (buffer == NULL || buffer->data == NULL || buf_str_len(buffer) == 0) {
|
||||
return 0;
|
||||
}
|
||||
return 1 + strchr_count(buffer->str, '\n');
|
||||
if (buffer->type == CharBuf)
|
||||
return 1 + strchr_count(buffer->cstr, '\n');
|
||||
else
|
||||
return 1 + wstrchr_count(buffer->wstr, L'\n');
|
||||
}
|
||||
|
||||
size_t buffer_text_width(string_buffer_t *buffer)
|
||||
{
|
||||
size_t max_length = 0;
|
||||
int n = 0;
|
||||
while (1) {
|
||||
const char *beg = NULL;
|
||||
const char *end = NULL;
|
||||
str_n_substring(buffer->str, '\n', n, &beg, &end);
|
||||
if (beg == NULL || end == NULL)
|
||||
return max_length;
|
||||
if (buffer->type == CharBuf) {
|
||||
while (1) {
|
||||
const char *beg = NULL;
|
||||
const char *end = NULL;
|
||||
str_n_substring(buffer->cstr, '\n', n, &beg, &end);
|
||||
if (beg == NULL || end == NULL)
|
||||
return max_length;
|
||||
|
||||
max_length = MAX(max_length, (end - beg));
|
||||
++n;
|
||||
max_length = MAX(max_length, (end - beg));
|
||||
++n;
|
||||
}
|
||||
} else {
|
||||
while (1) {
|
||||
const wchar_t *beg = NULL;
|
||||
const wchar_t *end = NULL;
|
||||
wstr_n_substring(buffer->wstr, L'\n', n, &beg, &end);
|
||||
if (beg == NULL || end == NULL)
|
||||
return max_length;
|
||||
|
||||
max_length = MAX(max_length, (end - beg));
|
||||
++n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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
|
||||
#define CHAR_TYPE char
|
||||
#define NULL_CHAR '\0'
|
||||
#define NEWLINE_CHAR '\n'
|
||||
#define SPACE_CHAR ' '
|
||||
#define SNPRINTF_FMT_STR "%*s"
|
||||
#define SNPRINTF snprintf
|
||||
#define BUFFER_STR cstr
|
||||
#define SNPRINT_N_CHARS snprint_n_chars
|
||||
#define STR_N_SUBSTRING str_n_substring
|
||||
|
||||
if (buffer == NULL || buffer->data == NULL
|
||||
|| buffer_row >= buffer_text_height(buffer) || buf_len == 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -161,7 +279,6 @@ int buffer_printf(string_buffer_t *buffer, size_t buffer_row, size_t table_colum
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
|
||||
// switch (fort_options_column_alignment(context, table_column)) {
|
||||
switch (get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_TEXT_ALIGN)) {
|
||||
case LeftAligned:
|
||||
left = 0;
|
||||
@@ -184,29 +301,134 @@ int buffer_printf(string_buffer_t *buffer, size_t buffer_row, size_t table_colum
|
||||
|
||||
|
||||
int written = 0;
|
||||
written += snprint_n_chars(buf + written, buf_len - written, left, ' ');
|
||||
written += SNPRINT_N_CHARS(buf + written, buf_len - written, left, SPACE_CHAR);
|
||||
if (written < 0)
|
||||
return written;
|
||||
|
||||
|
||||
const char *beg = NULL;
|
||||
const char *end = NULL;
|
||||
str_n_substring(buffer->str, '\n', buffer_row, &beg, &end);
|
||||
const CHAR_TYPE *beg = NULL;
|
||||
const CHAR_TYPE *end = NULL;
|
||||
STR_N_SUBSTRING(buffer->BUFFER_STR, NEWLINE_CHAR, buffer_row, &beg, &end);
|
||||
if (beg == NULL || end == NULL)
|
||||
return -1;
|
||||
char old_value = *end;
|
||||
*(char *)end = '\0';
|
||||
CHAR_TYPE old_value = *end;
|
||||
*(CHAR_TYPE *)end = NULL_CHAR;
|
||||
|
||||
written += snprintf(buf + written, buf_len - written, "%*s", (int)(end - beg), beg);
|
||||
*(char *)end = old_value;
|
||||
written += SNPRINTF(buf + written, buf_len - written, SNPRINTF_FMT_STR, (int)(end - beg), beg);
|
||||
*(CHAR_TYPE *)end = old_value;
|
||||
if (written < 0)
|
||||
return written;
|
||||
written += snprint_n_chars(buf + written, buf_len - written, (int)(content_width - (end - beg)), ' ');
|
||||
written += SNPRINT_N_CHARS(buf + written, buf_len - written, (int)(content_width - (end - beg)), SPACE_CHAR);
|
||||
if (written < 0)
|
||||
return written;
|
||||
|
||||
|
||||
written += snprint_n_chars(buf + written, buf_len - written, right, ' ');
|
||||
written += SNPRINT_N_CHARS(buf + written, buf_len - written, right, SPACE_CHAR);
|
||||
return written;
|
||||
|
||||
#undef CHAR_TYPE
|
||||
#undef NULL_CHAR
|
||||
#undef NEWLINE_CHAR
|
||||
#undef SPACE_CHAR
|
||||
#undef SNPRINTF_FMT_STR
|
||||
#undef SNPRINTF
|
||||
#undef BUFFER_STR
|
||||
#undef SNPRINT_N_CHARS
|
||||
#undef STR_N_SUBSTRING
|
||||
}
|
||||
|
||||
|
||||
int buffer_wprintf(string_buffer_t *buffer, size_t buffer_row, size_t table_column, wchar_t *buf, size_t buf_len, const context_t *context)
|
||||
{
|
||||
#define CHAR_TYPE wchar_t
|
||||
#define NULL_CHAR L'\0'
|
||||
#define NEWLINE_CHAR L'\n'
|
||||
#define SPACE_CHAR L' '
|
||||
#define SNPRINTF_FMT_STR L"%*ls"
|
||||
#define SNPRINTF swprintf
|
||||
#define BUFFER_STR wstr
|
||||
#define SNPRINT_N_CHARS wsnprint_n_chars
|
||||
#define STR_N_SUBSTRING wstr_n_substring
|
||||
|
||||
if (buffer == NULL || buffer->data == 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 (get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_OPT_TEXT_ALIGN)) {
|
||||
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, SPACE_CHAR);
|
||||
if (written < 0)
|
||||
return written;
|
||||
|
||||
const CHAR_TYPE *beg = NULL;
|
||||
const CHAR_TYPE *end = NULL;
|
||||
STR_N_SUBSTRING(buffer->BUFFER_STR, NEWLINE_CHAR, buffer_row, &beg, &end);
|
||||
if (beg == NULL || end == NULL)
|
||||
return -1;
|
||||
CHAR_TYPE old_value = *end;
|
||||
*(CHAR_TYPE *)end = NULL_CHAR;
|
||||
|
||||
written += SNPRINTF(buf + written, buf_len - written, SNPRINTF_FMT_STR, (int)(end - beg), beg);
|
||||
*(CHAR_TYPE *)end = old_value;
|
||||
if (written < 0)
|
||||
return written;
|
||||
written += SNPRINT_N_CHARS(buf + written, buf_len - written, (int)(content_width - (end - beg)), SPACE_CHAR);
|
||||
if (written < 0)
|
||||
return written;
|
||||
|
||||
|
||||
written += SNPRINT_N_CHARS(buf + written, buf_len - written, right, SPACE_CHAR);
|
||||
return written;
|
||||
|
||||
#undef CHAR_TYPE
|
||||
#undef NULL_CHAR
|
||||
#undef NEWLINE_CHAR
|
||||
#undef SPACE_CHAR
|
||||
#undef SNPRINTF_FMT_STR
|
||||
#undef SNPRINTF
|
||||
#undef BUFFER_STR
|
||||
#undef SNPRINT_N_CHARS
|
||||
#undef STR_N_SUBSTRING
|
||||
}
|
||||
|
||||
size_t string_buffer_capacity(const string_buffer_t *buffer)
|
||||
{
|
||||
assert(buffer);
|
||||
if (buffer->type == CharBuf)
|
||||
return buffer->data_sz;
|
||||
else
|
||||
return buffer->data_sz / sizeof(wchar_t);
|
||||
}
|
||||
|
||||
void *buffer_get_data(string_buffer_t *buffer)
|
||||
{
|
||||
assert(buffer);
|
||||
return buffer->data;
|
||||
}
|
||||
|
@@ -7,24 +7,42 @@
|
||||
/*****************************************************************************
|
||||
* STRING BUFFER
|
||||
* ***************************************************************************/
|
||||
enum str_buf_type
|
||||
{
|
||||
CharBuf,
|
||||
WCharBuf
|
||||
};
|
||||
|
||||
struct string_buffer;
|
||||
typedef struct string_buffer string_buffer_t;
|
||||
struct string_buffer
|
||||
{
|
||||
char *str;
|
||||
size_t str_sz;
|
||||
union {
|
||||
char *cstr;
|
||||
wchar_t *wstr;
|
||||
void *data;
|
||||
};
|
||||
size_t data_sz;
|
||||
enum str_buf_type type;
|
||||
};
|
||||
|
||||
string_buffer_t* create_string_buffer(size_t sz);
|
||||
string_buffer_t* create_string_buffer(size_t number_of_chars, enum str_buf_type type);
|
||||
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);
|
||||
fort_status_t fill_buffer_from_wstring(string_buffer_t *buffer, const wchar_t *str);
|
||||
|
||||
|
||||
size_t buffer_text_height(string_buffer_t *buffer);
|
||||
size_t string_buffer_capacity(const string_buffer_t *buffer);
|
||||
void *buffer_get_data(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);
|
||||
int buffer_wprintf(string_buffer_t *buffer, size_t buffer_row, size_t table_column, wchar_t *buf, size_t buf_len, const context_t *context);
|
||||
|
||||
|
||||
|
||||
#endif // STRING_BUFFER_H
|
||||
|
Reference in New Issue
Block a user