1
0
Fork 0
libfort/lib/fort.c

5070 lines
156 KiB
C
Raw Normal View History

2018-05-06 16:04:34 +02:00
/*
libfort
MIT License
Copyright (c) 2017 - 2018 Seleznev Anton
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
2018-05-06 15:21:45 +02:00
/* The file was GENERATED by an amalgamation script.*/
/* DO NOT EDIT BY HAND!!! */
2018-05-06 16:08:32 +02:00
2018-05-06 15:21:45 +02:00
/********************************************************
2018-05-06 15:36:53 +02:00
Begin of file "fort_utils.h"
2018-05-06 15:21:45 +02:00
********************************************************/
#ifndef FORT_IMPL_H
#define FORT_IMPL_H
#if defined(_MSC_VER)
#define _CRT_SECURE_NO_WARNINGS /* To disable warnings for unsafe functions */
#endif
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "fort.h"
#define FORT_COL_SEPARATOR '|'
#define FORT_COL_SEPARATOR_LENGTH 1
#define FORT_UNUSED __attribute__((unused))
#define F_MALLOC fort_malloc
#define F_FREE fort_free
#define F_CALLOC fort_calloc
#define F_REALLOC fort_realloc
#define F_STRDUP fort_strdup
#define F_WCSDUP fort_wcsdup
#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)
2018-05-06 16:04:34 +02:00
enum PolicyOnNull {
2018-05-06 15:21:45 +02:00
Create,
DoNotCreate
};
2018-05-06 16:04:34 +02:00
enum F_BOOL {
2018-05-06 15:21:45 +02:00
F_FALSE = 0,
F_TRUE = 1
};
#define FT_STR_2_CAT_(arg1, arg2) \
arg1##arg2
#define FT_STR_2_CAT(arg1, arg2) \
FT_STR_2_CAT_(arg1, arg2)
#define UNIQUE_NAME_(prefix) \
FT_STR_2_CAT(prefix,__COUNTER__)
#define UNIQUE_NAME(prefix) \
UNIQUE_NAME_(prefix)
/*****************************************************************************
* LOGGER
*****************************************************************************/
#define SYS_LOG_ERROR(...)
/*****************************************************************************
* 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;
2018-05-06 16:04:34 +02:00
struct separator {
2018-05-06 15:21:45 +02:00
int enabled;
};
typedef struct fort_table_options fort_table_options_t;
2018-05-06 16:04:34 +02:00
struct fort_context {
2018-05-06 15:21:45 +02:00
fort_table_options_t *table_options;
size_t row;
size_t column;
};
typedef struct fort_context 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 ft_table ft_table_t;
typedef struct separator separator_t;
2018-05-06 16:04:34 +02:00
enum CellType {
2018-05-06 15:21:45 +02:00
CommonCell,
GroupMasterCell,
GroupSlaveCell
};
/*****************************************************************************
* LIBFORT helpers
*****************************************************************************/
extern void *(*fort_malloc)(size_t size);
extern void (*fort_free)(void *ptr);
extern void *(*fort_calloc)(size_t nmemb, size_t size);
extern void *(*fort_realloc)(void *ptr, size_t size);
void set_memory_funcs(void *(*f_malloc)(size_t size), void (*f_free)(void *ptr));
2018-05-06 16:04:34 +02:00
char *fort_strdup(const char *str);
wchar_t *fort_wcsdup(const wchar_t *str);
2018-05-06 15:21:45 +02:00
size_t number_of_columns_in_format_string(const char *fmt);
size_t number_of_columns_in_format_wstring(const wchar_t *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);
int snprint_n_strings(char *buf, size_t length, size_t n, const char *str);
int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *str);
#define CHCK_RSLT_ADD_TO_WRITTEN(statement) \
do { \
tmp = statement; \
if (tmp < 0) {\
goto clear; \
} \
written += tmp; \
} while(0)
#define CHECK_NOT_NEGATIVE(x) \
do { if (x < 0) goto fort_fail; } while (0)
#endif /* FORT_IMPL_H */
/********************************************************
2018-05-06 15:36:53 +02:00
End of file "fort_utils.h"
2018-05-06 15:21:45 +02:00
********************************************************/
/********************************************************
Begin of file "vector.h"
********************************************************/
#ifndef VECTOR_H
#define VECTOR_H
2018-05-06 15:36:53 +02:00
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
2018-05-06 15:21:45 +02:00
/*****************************************************************************
* VECTOR
* ***************************************************************************/
struct vector;
typedef struct vector vector_t;
#define INVALID_VEC_INDEX ((size_t) -1)
2018-05-06 16:04:34 +02:00
extern vector_t *create_vector(size_t item_size, size_t capacity);
extern void destroy_vector(vector_t *);
extern vector_t *copy_vector(vector_t *);
2018-05-06 15:21:45 +02:00
2018-05-06 16:04:34 +02:00
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);
2018-05-06 15:21:45 +02:00
2018-05-06 16:04:34 +02:00
extern int vector_push(vector_t *, const void *item);
extern int vector_erase(vector_t *, size_t index);
extern void vector_clear(vector_t *);
2018-05-06 15:21:45 +02:00
extern const void *vector_at_c(const vector_t *vector, size_t index);
2018-05-06 16:04:34 +02:00
extern void *vector_at(vector_t *, size_t index);
2018-05-06 15:21:45 +02:00
extern fort_status_t vector_swap(vector_t *cur_vec, vector_t *mv_vec, size_t pos);
#define FOR_EACH_(type, item, vector, index_name) \
size_t index_name = 0; \
for (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 */
/********************************************************
End of file "vector.h"
********************************************************/
/********************************************************
Begin of file "wcwidth.h"
********************************************************/
#ifndef WCWIDTH_H
#define WCWIDTH_H
int mk_wcswidth(const wchar_t *pwcs, size_t n);
#endif // WCWIDTH_H
/********************************************************
End of file "wcwidth.h"
********************************************************/
/********************************************************
Begin of file "string_buffer.h"
********************************************************/
#ifndef STRING_BUFFER_H
#define STRING_BUFFER_H
2018-05-06 15:36:53 +02:00
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
2018-05-06 15:21:45 +02:00
/*****************************************************************************
* STRING BUFFER
* ***************************************************************************/
2018-05-06 16:04:34 +02:00
enum str_buf_type {
2018-05-06 15:21:45 +02:00
CharBuf,
WCharBuf
};
struct string_buffer;
typedef struct string_buffer string_buffer_t;
2018-05-06 16:04:34 +02:00
struct string_buffer {
2018-05-06 15:21:45 +02:00
union {
char *cstr;
wchar_t *wstr;
void *data;
2018-05-06 16:04:34 +02:00
} str;
2018-05-06 15:21:45 +02:00
size_t data_sz;
enum str_buf_type type;
};
2018-05-06 16:04:34 +02:00
string_buffer_t *create_string_buffer(size_t number_of_chars, enum str_buf_type type);
2018-05-06 15:21:45 +02:00
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, char *buf, size_t buf_len, const context_t *context);
int buffer_wprintf(string_buffer_t *buffer, size_t buffer_row, wchar_t *buf, size_t buf_len, const context_t *context);
#endif /* STRING_BUFFER_H */
/********************************************************
End of file "string_buffer.h"
********************************************************/
/********************************************************
Begin of file "options.h"
********************************************************/
#ifndef OPTIONS_H
#define OPTIONS_H
2018-05-06 15:36:53 +02:00
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
2018-05-06 15:21:45 +02:00
#include <stdint.h>
#include <limits.h>
2018-05-06 16:04:34 +02:00
struct fort_column_options {
2018-05-06 15:21:45 +02:00
int col_min_width;
enum ft_text_alignment 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(void);
struct vector;
typedef struct vector vector_t;
#define OPTION_IS_SET(ft_opts, option) ((ft_opts) & (option))
#define OPTION_SET(ft_opts, option) ((ft_opts) |=(option))
#define OPTION_UNSET(ft_opts, option) ((ft_opts) &= ~((uint32_t)option))
2018-05-06 16:04:34 +02:00
struct fort_cell_options {
2018-05-06 15:21:45 +02:00
size_t cell_row;
size_t cell_col;
uint32_t options;
unsigned int col_min_width;
enum ft_text_alignment align;
unsigned int cell_padding_top;
unsigned int cell_padding_bottom;
unsigned int cell_padding_left;
unsigned int cell_padding_right;
unsigned int cell_empty_string_height;
enum ft_row_type row_type;
};
typedef struct fort_cell_options fort_cell_options_t;
typedef vector_t fort_cell_opt_container_t;
fort_cell_opt_container_t *create_cell_opt_container(void);
void destroy_cell_opt_container(fort_cell_opt_container_t *cont);
2018-05-06 16:04:34 +02:00
const fort_cell_options_t *cget_cell_opt(const fort_cell_opt_container_t *cont, size_t row, size_t col);
fort_cell_options_t *get_cell_opt_and_create_if_not_exists(fort_cell_opt_container_t *cont, size_t row, size_t col);
2018-05-06 15:21:45 +02:00
fort_status_t set_cell_option(fort_cell_opt_container_t *cont, size_t row, size_t col, uint32_t option, int value);
fort_status_t unset_cell_option(fort_cell_opt_container_t *cont, unsigned row, unsigned col, uint32_t option);
int get_cell_opt_value_hierarcial(const fort_table_options_t *options, size_t row, size_t column, uint32_t option);
fort_status_t set_default_cell_option(uint32_t option, int value);
/*****************************************************************************
* 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
*/
2018-05-06 16:04:34 +02:00
enum HorSeparatorPos {
2018-05-06 15:21:45 +02:00
TopSeparator,
InsideSeparator,
BottomSeparator
};
2018-05-06 16:04:34 +02:00
enum BorderItemPos {
2018-05-06 15:21:45 +02:00
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
};
2018-05-06 16:04:34 +02:00
enum SeparatorItemPos {
2018-05-06 15:21:45 +02:00
LH_sip = 0,
IH_sip = 1,
II_sip = 2,
RH_sip = 3,
SepratorItemPosSize
};
2018-05-06 16:04:34 +02:00
struct fort_border_style {
2018-05-06 15:21:45 +02:00
const char *border_chars[BorderItemPosSize];
const char *header_border_chars[BorderItemPosSize];
const char *separator_chars[SepratorItemPosSize];
};
extern struct fort_border_style FORT_BASIC_STYLE;
extern struct fort_border_style FORT_SIMPLE_STYLE;
extern struct fort_border_style FORT_PLAIN_STYLE;
extern struct fort_border_style FORT_DOT_STYLE;
extern struct fort_border_style FORT_EMPTY_STYLE;
extern struct fort_border_style FORT_SOLID_STYLE;
extern struct fort_border_style FORT_SOLID_ROUND_STYLE;
extern struct fort_border_style FORT_DOUBLE_STYLE;
extern struct fort_border_style FORT_DOUBLE2_STYLE;
extern struct fort_border_style FORT_BOLD_STYLE;
extern struct fort_border_style FORT_BOLD2_STYLE;
extern struct fort_border_style FORT_FRAME_STYLE;
2018-05-06 16:04:34 +02:00
struct fort_entire_table_options {
2018-05-06 15:21:45 +02:00
unsigned int left_margin;
unsigned int top_margin;
unsigned int right_margin;
unsigned int bottom_margin;
};
typedef struct fort_entire_table_options fort_entire_table_options_t;
extern fort_entire_table_options_t g_entire_table_options;
fort_status_t set_entire_table_option(fort_table_options_t *table_options, uint32_t option, int value);
fort_status_t set_default_entire_table_option(uint32_t option, int value);
2018-05-06 16:04:34 +02:00
struct fort_table_options {
2018-05-06 15:21:45 +02:00
struct fort_border_style border_style;
2018-05-06 16:04:34 +02:00
fort_cell_opt_container_t *cell_options;
2018-05-06 15:21:45 +02:00
fort_entire_table_options_t entire_table_options;
};
typedef struct fort_table_options fort_table_options_t;
extern fort_table_options_t g_table_options;
2018-05-06 16:04:34 +02:00
size_t max_border_elem_strlen(struct fort_table_options *);
2018-05-06 15:21:45 +02:00
2018-05-06 16:04:34 +02:00
fort_table_options_t *create_table_options(void);
fort_table_options_t *copy_table_options(const fort_table_options_t *option);
void destroy_table_options(fort_table_options_t *options);
2018-05-06 15:21:45 +02:00
#endif /* OPTIONS_H */
/********************************************************
End of file "options.h"
********************************************************/
/********************************************************
Begin of file "cell.h"
********************************************************/
#ifndef CELL_H
#define CELL_H
2018-05-06 15:36:53 +02:00
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
2018-05-06 15:21:45 +02:00
/*****************************************************************************
* CELL
* ***************************************************************************/
2018-05-06 16:04:34 +02:00
fort_cell_t *create_cell(void);
2018-05-06 15:21:45 +02:00
void destroy_cell(fort_cell_t *cell);
size_t hint_width_cell(const fort_cell_t *cell, const context_t *context);
size_t hint_height_cell(const fort_cell_t *cell, const context_t *context);
void set_cell_type(fort_cell_t *cell, enum CellType type);
enum CellType get_cell_type(const fort_cell_t *cell);
/*
* 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, char *buf, size_t buf_len, const context_t *context);
fort_status_t fill_cell_from_string(fort_cell_t *cell, const char *str);
#ifdef FT_HAVE_WCHAR
int cell_wprintf(fort_cell_t *cell, size_t row, wchar_t *buf, size_t buf_len, const context_t *context);
fort_status_t fill_cell_from_wstring(fort_cell_t *cell, const wchar_t *str);
#endif
2018-05-06 16:04:34 +02:00
string_buffer_t *cell_get_string_buffer(fort_cell_t *cell);
2018-05-06 15:21:45 +02:00
#endif /* CELL_H */
/********************************************************
End of file "cell.h"
********************************************************/
/********************************************************
Begin of file "row.h"
********************************************************/
#ifndef ROW_H
#define ROW_H
2018-05-06 15:36:53 +02:00
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
2018-05-06 15:21:45 +02:00
#include "fort.h"
#include <stdarg.h>
/* #include "options.h" */ /* Commented by amalgamation script */
#ifdef FT_HAVE_WCHAR
#include <wchar.h>
#endif
struct fort_row;
typedef struct fort_row fort_row_t;
2018-05-06 16:04:34 +02:00
fort_row_t *create_row(void);
2018-05-06 15:21:45 +02:00
void destroy_row(fort_row_t *row);
2018-05-06 16:04:34 +02:00
fort_row_t *create_row_from_string(const char *str);
fort_row_t *create_row_from_fmt_string(const char *fmt, va_list *va_args);
2018-05-06 15:21:45 +02:00
size_t 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);
fort_status_t swap_row(fort_row_t *cur_row, fort_row_t *ins_row, size_t pos);
size_t group_cell_number(const fort_row_t *row, size_t master_cell_col);
int get_row_cell_types(const fort_row_t *row, enum CellType *types, size_t types_sz);
fort_status_t row_set_cell_span(fort_row_t *row, size_t cell_column, size_t hor_span);
int print_row_separator(char *buffer, size_t buffer_sz,
2018-05-06 16:04:34 +02:00
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);
2018-05-06 15:21:45 +02:00
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,
2018-05-06 16:04:34 +02:00
size_t row_height, const context_t *context);
2018-05-06 15:21:45 +02:00
#ifdef FT_HAVE_WCHAR
fort_row_t *create_row_from_wstring(const wchar_t *str);
2018-05-06 16:04:34 +02:00
fort_row_t *create_row_from_fmt_wstring(const wchar_t *fmt, va_list *va_args);
2018-05-06 15:21:45 +02:00
int wprint_row_separator(wchar_t *buffer, size_t buffer_sz,
2018-05-06 16:04:34 +02:00
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);
2018-05-06 15:21:45 +02:00
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,
2018-05-06 16:04:34 +02:00
size_t row_height, const context_t *context);
2018-05-06 15:21:45 +02:00
#endif
#endif /* ROW_H */
/********************************************************
End of file "row.h"
********************************************************/
/********************************************************
Begin of file "table.h"
********************************************************/
#ifndef TABLE_H
#define TABLE_H
2018-05-06 15:36:53 +02:00
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
2018-05-06 15:21:45 +02:00
struct ft_table;
typedef struct ft_table ft_table_t;
2018-05-06 16:04:34 +02:00
struct ft_table {
2018-05-06 15:21:45 +02:00
vector_t *rows;
fort_table_options_t *options;
string_buffer_t *conv_buffer;
size_t cur_row;
size_t cur_col;
vector_t *separators;
};
static FT_INLINE
separator_t *create_separator(int enabled)
{
separator_t *res = (separator_t *)F_CALLOC(1, sizeof(separator_t));
if (res == NULL)
return NULL;
res->enabled = enabled;
return res;
}
static FT_INLINE
void destroy_separator(separator_t *sep)
{
F_FREE(sep);
}
fort_status_t get_table_sizes(const ft_table_t *table, size_t *rows, size_t *cols);
fort_row_t *get_row_implementation(ft_table_t *table, size_t row, enum PolicyOnNull policy);
fort_row_t *get_row(ft_table_t *table, size_t row);
const fort_row_t *get_row_c(const ft_table_t *table, size_t row);
fort_row_t *get_row_and_create_if_not_exists(ft_table_t *table, size_t row);
2018-05-06 16:04:34 +02:00
string_buffer_t *get_cur_str_buffer_and_create_if_not_exists(ft_table_t *table);
2018-05-06 15:21:45 +02:00
fort_status_t table_rows_and_cols_geometry(const ft_table_t *table,
2018-05-06 16:04:34 +02:00
size_t **col_width_arr_p, size_t *col_width_arr_sz,
size_t **row_height_arr_p, size_t *row_height_arr_sz);
2018-05-06 15:21:45 +02:00
fort_status_t table_geometry(const ft_table_t *table, size_t *height, size_t *width);
#endif /* TABLE_H */
/********************************************************
End of file "table.h"
********************************************************/
/********************************************************
Begin of file "options.c"
********************************************************/
#include <assert.h>
/* #include "options.h" */ /* Commented by amalgamation script */
2018-05-06 15:36:53 +02:00
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
2018-05-06 15:21:45 +02:00
/* #include "vector.h" */ /* Commented by amalgamation script */
/*****************************************************************************
* COLUMN OPTIONS
* ***************************************************************************/
struct fort_cell_options g_default_cell_option = {
FT_ANY_ROW, /* cell_row */
FT_ANY_COLUMN, /* cell_col */
/* options */
FT_COPT_MIN_WIDTH | FT_COPT_TEXT_ALIGN | FT_COPT_TOP_PADDING
| FT_COPT_BOTTOM_PADDING | FT_COPT_LEFT_PADDING | FT_COPT_RIGHT_PADDING
| FT_COPT_EMPTY_STR_HEIGHT,
0, /* col_min_width */
FT_ALIGNED_RIGHT, /* align */
0, /* cell_padding_top */
0, /* cell_padding_bottom */
1, /* cell_padding_left */
1, /* cell_padding_right */
1, /* cell_empty_string_height */
FT_ROW_COMMON, /* row_type */
};
static int get_option_value_if_exists_otherwise_default(const struct fort_cell_options *cell_opts, uint32_t option)
{
if (cell_opts == NULL || !OPTION_IS_SET(cell_opts->options, option)) {
cell_opts = &g_default_cell_option;
}
switch (option) {
case FT_COPT_MIN_WIDTH:
return cell_opts->col_min_width;
case FT_COPT_TEXT_ALIGN:
return cell_opts->align;
case FT_COPT_TOP_PADDING:
return cell_opts->cell_padding_top;
case FT_COPT_BOTTOM_PADDING:
return cell_opts->cell_padding_bottom;
case FT_COPT_LEFT_PADDING:
return cell_opts->cell_padding_left;
case FT_COPT_RIGHT_PADDING:
return cell_opts->cell_padding_right;
case FT_COPT_EMPTY_STR_HEIGHT:
return cell_opts->cell_empty_string_height;
case FT_COPT_ROW_TYPE:
return cell_opts->row_type;
default:
/* todo: implement later */
exit(333);
}
}
fort_column_options_t g_column_options = {
0, /* col_min_width*/
FT_ALIGNED_RIGHT, /* align */
};
fort_column_options_t create_column_options(void)
{
fort_column_options_t result;
memset(&result, '\0', sizeof(result));
memcpy(&result, &g_column_options, sizeof(result));
return result;
}
//#define DEFAULT_CELL_OPTION {FT_ROW_UNSPEC, FT_COLUMN_UNSPEC, 0, 0, 0}
fort_cell_opt_container_t *create_cell_opt_container(void)
{
fort_cell_opt_container_t *ret = create_vector(sizeof(fort_cell_options_t), DEFAULT_VECTOR_CAPACITY);
return ret;
}
void destroy_cell_opt_container(fort_cell_opt_container_t *cont)
{
if (cont)
destroy_vector(cont);
}
const fort_cell_options_t *cget_cell_opt(const fort_cell_opt_container_t *cont, size_t row, size_t col)
{
assert(cont);
size_t sz = vector_size(cont);
size_t i = 0;
for (i = 0; i < sz; ++i) {
const fort_cell_options_t *opt = (const fort_cell_options_t *)vector_at_c(cont, i);
if (opt->cell_row == row && opt->cell_col == col)
return opt;
}
return NULL;
}
fort_cell_options_t *get_cell_opt_and_create_if_not_exists(fort_cell_opt_container_t *cont, size_t row, size_t col)
{
assert(cont);
size_t sz = vector_size(cont);
size_t i = 0;
for (i = 0; i < sz; ++i) {
fort_cell_options_t *opt = (fort_cell_options_t *)vector_at(cont, i);
if (opt->cell_row == row && opt->cell_col == col)
return opt;
}
fort_cell_options_t opt = g_default_cell_option;// DEFAULT_CELL_OPTION;
opt.cell_row = row;
opt.cell_col = col;
if (FT_IS_SUCCESS(vector_push(cont, &opt))) {
return (fort_cell_options_t *)vector_at(cont, sz);
}
return NULL;
}
int get_cell_opt_value_hierarcial(const fort_table_options_t *options, size_t row, size_t column, uint32_t option)
{
assert(options);
const fort_cell_options_t *opt = NULL;
if (options->cell_options != NULL) {
while (1) {
opt = cget_cell_opt(options->cell_options, row, column);
if (opt != NULL)
break;
if (row != FT_ANY_ROW) {
row = FT_ANY_ROW;
continue;
}
if (column != FT_ANY_COLUMN) {
column = FT_ANY_COLUMN;
continue;
}
opt = NULL;
break;
}
}
return get_option_value_if_exists_otherwise_default(opt, option);
}
static fort_status_t set_cell_option_impl(fort_cell_options_t *opt, uint32_t option, int value)
{
assert(opt);
OPTION_SET(opt->options, option);
if (OPTION_IS_SET(option, FT_COPT_MIN_WIDTH)) {
CHECK_NOT_NEGATIVE(value);
opt->col_min_width = value;
} else if (OPTION_IS_SET(option, FT_COPT_TEXT_ALIGN)) {
opt->align = (enum ft_text_alignment)value;
} else if (OPTION_IS_SET(option, FT_COPT_TOP_PADDING)) {
CHECK_NOT_NEGATIVE(value);
opt->cell_padding_top = value;
} else if (OPTION_IS_SET(option, FT_COPT_BOTTOM_PADDING)) {
CHECK_NOT_NEGATIVE(value);
opt->cell_padding_bottom = value;
} else if (OPTION_IS_SET(option, FT_COPT_LEFT_PADDING)) {
CHECK_NOT_NEGATIVE(value);
opt->cell_padding_left = value;
} else if (OPTION_IS_SET(option, FT_COPT_RIGHT_PADDING)) {
CHECK_NOT_NEGATIVE(value);
opt->cell_padding_right = value;
} else if (OPTION_IS_SET(option, FT_COPT_EMPTY_STR_HEIGHT)) {
CHECK_NOT_NEGATIVE(value);
opt->cell_empty_string_height = value;
} else if (OPTION_IS_SET(option, FT_COPT_ROW_TYPE)) {
opt->row_type = (enum ft_row_type)value;
}
return FT_SUCCESS;
fort_fail:
return FT_EINVAL;
}
fort_status_t set_cell_option(fort_cell_opt_container_t *cont, size_t row, size_t col, uint32_t option, int value)
{
fort_cell_options_t *opt = get_cell_opt_and_create_if_not_exists(cont, row, col);
if (opt == NULL)
return FT_ERROR;
return set_cell_option_impl(opt, option, value);
/*
OPTION_SET(opt->options, option);
if (OPTION_IS_SET(option, FT_COPT_MIN_WIDTH)) {
opt->col_min_width = value;
} else if (OPTION_IS_SET(option, FT_COPT_TEXT_ALIGN)) {
opt->align = value;
}
return FT_SUCCESS;
*/
}
fort_status_t set_default_cell_option(uint32_t option, int value)
{
return set_cell_option_impl(&g_default_cell_option, option, value);
}
/*****************************************************************************
* OPTIONS
* ***************************************************************************/
#define BASIC_STYLE { \
/* border_chars */ \
{ \
"+", "-", "+", "+", \
"|", "|", "|", \
"\0", "\0", "\0", "\0", \
"+", "-", "+", "+" \
}, \
/* header_border_chars */ \
{ \
"+", "-", "+", "+", \
"|", "|", "|", \
"+", "-", "+", "+", \
"+", "-", "+", "+" \
}, \
/* separator_chars */ \
{ \
"+", "-", "+", "+", \
}, \
}
#define SIMPLE_STYLE { \
/* border_chars */ \
{ \
" ", " ", " ", " ", \
" ", " ", " ", \
"\0", "\0", "\0", "\0", \
" ", " ", " ", " " \
}, \
/* header_border_chars */ \
{ \
" ", " ", " ", " ", \
" ", " ", " ", \
" ", "-", " ", " ", \
" ", " ", " ", " " \
}, \
/* separator_chars */ \
{ \
" ", "-", " ", " ", \
}, \
}
#define PLAIN_STYLE { \
/* border_chars */ \
{ \
" ", " ", " ", " ", \
" ", " ", " ", \
"\0", "\0", "\0", "\0", \
" ", " ", " ", " " \
}, \
/* header_border_chars */ \
{ \
" ", "-", "-", " ", \
" ", " ", " ", \
" ", "-", "-", " ", \
" ", "-", "-", " " \
}, \
/* separator_chars */ \
{ \
" ", "-", "-", " ", \
}, \
}
#define DOT_STYLE { \
/* border_chars */ \
{ \
".", ".", ".", ".", \
":", ":", ":", \
"\0", "\0", "\0", "\0", \
":", ".", ":", ":" \
}, \
/* header_border_chars */ \
{ \
".", ".", ".", ".", \
":", ":", ":", \
":", ".", ":", ":", \
":", ".", ":", ":" \
}, \
/* separator_chars */ \
{ \
":", ".", ":", ":", \
}, \
}
#define EMPTY_STYLE { \
/* border_chars */ \
{ \
" ", " ", " ", " ", \
" ", " ", " ", \
"\0", "\0", "\0", "\0", \
" ", " ", " ", " " \
}, \
/* header_border_chars */ \
{ \
" ", " ", " ", " ", \
" ", " ", " ", \
"\0", "\0", "\0", "\0", \
" ", " ", " ", " " \
}, \
/* separator_chars */ \
{ \
" ", " ", " ", " ", \
}, \
}
#define SOLID_STYLE { \
/* border_chars */ \
{ \
"", "", "", "", \
"", "", "", \
"", "", "", "", \
"", "", "", "" \
}, \
/* header_border_chars */ \
{ \
"", "", "", "", \
"", "", "", \
"", "", "", "", \
"", "", "", "" \
}, \
/* separator_chars */ \
{ \
"", "", "", "", \
}, \
}
#define SOLID_ROUND_STYLE { \
/* border_chars */ \
{ \
"", "", "", "", \
"", "", "", \
"", "", "", "", \
"", "", "", "" \
}, \
/* header_border_chars */ \
{ \
"", "", "", "", \
"", "", "", \
"", "", "", "", \
"", "", "", "" \
}, \
/* separator_chars */ \
{ \
"", "", "", "", \
}, \
}
#define DOUBLE_STYLE { \
/* border_chars */ \
{ \
"", "", "", "", \
"", "", "", \
"", "", "", "", \
"", "", "", "" \
}, \
/* header_border_chars */ \
{ \
"", "", "", "", \
"", "", "", \
"", "", "", "", \
"", "", "", "" \
}, \
/* separator_chars */ \
{ \
"", "", "", "", \
}, \
}
#define DOUBLE2_STYLE { \
/* border_chars */ \
{ \
"", "", "", "", \
"", "", "", \
"", "", "", "", \
"", "", "", "" \
}, \
/* header_border_chars */ \
{ \
"", "", "", "", \
"", "", "", \
"", "", "", "", \
"", "", "", "" \
}, \
/* separator_chars */ \
{ \
"", "", "", "", \
}, \
}
#define BOLD_STYLE { \
/* border_chars */ \
{ \
"", "", "", "", \
"", "", "", \
"", "", "", "", \
"", "", "", "" \
}, \
/* header_border_chars */ \
{ \
"", "", "", "", \
"", "", "", \
"", "", "", "", \
"", "", "", "" \
}, \
/* separator_chars */ \
{ \
"", "", "", "", \
}, \
}
#define BOLD2_STYLE { \
/* border_chars */ \
{ \
"", "", "", "", \
"", "", "", \
"", "", "", "", \
"", "", "", "" \
}, \
/* header_border_chars */ \
{ \
"", "", "", "", \
"", "", "", \
"", "", "", "", \
"", "", "", "" \
}, \
/* separator_chars */ \
{ \
"", "", "", "", \
}, \
}
#define FRAME_STYLE { \
/* border_chars */ \
{ \
"", "", "", "", \
"", "", "", \
"", "", "", "", \
"", "", "", "" \
}, \
/* header_border_chars */ \
{ \
"", "", "", "", \
"", "", "", \
"", "", "", "", \
"", "", "", "" \
}, \
/* separator_chars */ \
{ \
"", "", "", "", \
}, \
}
struct fort_border_style FORT_BASIC_STYLE = BASIC_STYLE;
struct fort_border_style FORT_SIMPLE_STYLE = SIMPLE_STYLE;
struct fort_border_style FORT_PLAIN_STYLE = PLAIN_STYLE;
struct fort_border_style FORT_DOT_STYLE = DOT_STYLE;
struct fort_border_style FORT_EMPTY_STYLE = EMPTY_STYLE;
struct fort_border_style FORT_SOLID_STYLE = SOLID_STYLE;
struct fort_border_style FORT_SOLID_ROUND_STYLE = SOLID_ROUND_STYLE;
struct fort_border_style FORT_DOUBLE_STYLE = DOUBLE_STYLE;
struct fort_border_style FORT_DOUBLE2_STYLE = DOUBLE2_STYLE;
struct fort_border_style FORT_BOLD_STYLE = BOLD_STYLE;
struct fort_border_style FORT_BOLD2_STYLE = BOLD2_STYLE;
struct fort_border_style FORT_FRAME_STYLE = FRAME_STYLE;
fort_entire_table_options_t g_entire_table_options = {
0, /* left_margin */
0, /* top_margin */
0, /* right_margin */
0, /* bottom_margin */
};
static fort_status_t set_entire_table_option_internal(fort_entire_table_options_t *options, uint32_t option, int value)
{
assert(options);
CHECK_NOT_NEGATIVE(value);
if (OPTION_IS_SET(option, FT_TOPT_LEFT_MARGIN)) {
options->left_margin = value;
} else if (OPTION_IS_SET(option, FT_TOPT_TOP_MARGIN)) {
options->top_margin = value;
} else if (OPTION_IS_SET(option, FT_TOPT_RIGHT_MARGIN)) {
options->right_margin = value;
} else if (OPTION_IS_SET(option, FT_TOPT_BOTTOM_MARGIN)) {
options->bottom_margin = value;
} else {
return FT_EINVAL;
}
return FT_SUCCESS;
fort_fail:
return FT_EINVAL;
}
fort_status_t set_entire_table_option(fort_table_options_t *table_options, uint32_t option, int value)
{
assert(table_options);
return set_entire_table_option_internal(&table_options->entire_table_options, option, value);
}
fort_status_t set_default_entire_table_option(uint32_t option, int value)
{
return set_entire_table_option_internal(&g_entire_table_options, option, value);
}
size_t max_border_elem_strlen(struct fort_table_options *options)
{
assert(options);
size_t result = 1;
int i = 0;
for (i = 0; i < BorderItemPosSize; ++i) {
result = MAX(result, strlen(options->border_style.border_chars[i]));
}
i = 0;
for (i = 0; i < BorderItemPosSize; ++i) {
result = MAX(result, strlen(options->border_style.header_border_chars[i]));
}
i = 0;
for (i = 0; i < SepratorItemPosSize; ++i) {
result = MAX(result, strlen(options->border_style.separator_chars[i]));
}
return result;
}
fort_table_options_t g_table_options = {
/* border_style */
BASIC_STYLE,
NULL, /* cell_options */
/* entire_table_options */
{
0, /* left_margin */
0, /* top_margin */
0, /* right_margin */
0 /* bottom_margin */
}
};
fort_table_options_t *create_table_options(void)
{
fort_table_options_t *options = (fort_table_options_t *)F_CALLOC(sizeof(fort_table_options_t), 1);
if (options == NULL) {
return NULL;
}
memcpy(options, &g_table_options, sizeof(fort_table_options_t));
options->cell_options = create_cell_opt_container();
if (options->cell_options == NULL) {
destroy_table_options(options);
return NULL;
}
memcpy(&options->entire_table_options, &g_entire_table_options, sizeof(fort_entire_table_options_t));
return options;
}
fort_table_options_t *copy_table_options(const fort_table_options_t *option)
{
/* todo: normal implementation, do deep copy of col options */
fort_table_options_t *new_opt = create_table_options();
if (new_opt == NULL)
return NULL;
memcpy(new_opt, option, sizeof(fort_table_options_t));
if (option->cell_options) {
destroy_cell_opt_container(new_opt->cell_options);
new_opt->cell_options = copy_vector(option->cell_options);
if (new_opt->cell_options == NULL) {
destroy_table_options(new_opt);
new_opt = NULL;
}
}
return new_opt;
}
void destroy_table_options(fort_table_options_t *options)
{
if (options == NULL)
return;
if (options->cell_options != NULL) {
destroy_cell_opt_container(options->cell_options);
}
F_FREE(options);
}
/********************************************************
End of file "options.c"
********************************************************/
/********************************************************
Begin of file "table.c"
********************************************************/
/* #include "table.h" */ /* Commented by amalgamation script */
/* #include "string_buffer.h" */ /* Commented by amalgamation script */
/* #include "cell.h" */ /* Commented by amalgamation script */
/* #include "vector.h" */ /* Commented by amalgamation script */
/* #include "row.h" */ /* Commented by amalgamation script */
fort_status_t get_table_sizes(const ft_table_t *table, size_t *rows, size_t *cols);
fort_row_t *get_row_implementation(ft_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 (FT_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(ft_table_t *table, size_t row)
{
return get_row_implementation(table, row, DoNotCreate);
}
const fort_row_t *get_row_c(const ft_table_t *table, size_t row)
{
return get_row((ft_table_t *)table, row);
}
fort_row_t *get_row_and_create_if_not_exists(ft_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(ft_table_t *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;
return cell_get_string_buffer(cell);
}
/*
* Returns number of cells (rows * cols)
*/
fort_status_t get_table_sizes(const ft_table_t *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 FT_SUCCESS;
}
fort_status_t table_rows_and_cols_geometry(const ft_table_t *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 FT_ERROR;
}
size_t cols = 0;
size_t rows = 0;
int status = get_table_sizes(table, &rows, &cols);
if (FT_IS_ERROR(status))
return status;
size_t *col_width_arr = (size_t *)F_CALLOC(sizeof(size_t), cols);
size_t *row_height_arr = (size_t *)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 FT_ERROR;
}
int combined_cells_found = 0;
context_t context;
context.table_options = (table->options ? table->options : &g_table_options);
size_t col = 0;
for (col = 0; col < cols; ++col) {
col_width_arr[col] = 0;
size_t row = 0;
for (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);
context.column = col;
context.row = row;
if (cell) {
switch (get_cell_type(cell)) {
case CommonCell:
col_width_arr[col] = MAX(col_width_arr[col], hint_width_cell(cell, &context));
break;
case GroupMasterCell:
combined_cells_found = 1;
break;
case GroupSlaveCell:
; /* Do nothing */
break;
}
row_height_arr[row] = MAX(row_height_arr[row], hint_height_cell(cell, &context));
}
}
}
if (combined_cells_found) {
col = 0;
for (col = 0; col < cols; ++col) {
size_t row = 0;
for (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);
context.column = col;
context.row = row;
if (cell) {
if (get_cell_type(cell) == GroupMasterCell) {
size_t hint_width = hint_width_cell(cell, &context);
size_t slave_col = col + group_cell_number(row_p, col);
size_t cur_adj_col = col;
size_t group_width = col_width_arr[col];
size_t i;
for (i = col + 1; i < slave_col; ++i)
group_width += col_width_arr[i] + FORT_COL_SEPARATOR_LENGTH;
/* adjust col. widths */
while (1) {
if (group_width >= hint_width)
break;
col_width_arr[cur_adj_col] += 1;
group_width++;
cur_adj_col++;
if (cur_adj_col == slave_col)
cur_adj_col = col;
}
}
}
}
}
}
/* 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 FT_SUCCESS;
}
/*
* Returns geometry in characters
*/
fort_status_t table_geometry(const ft_table_t *table, size_t *height, size_t *width)
{
if (table == NULL)
return FT_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 (FT_IS_ERROR(status))
return status;
*width = 1 + (cols == 0 ? 1 : cols) + 1; /* for boundaries (that take 1 symbol) + newline */
size_t i = 0;
for (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 (i = 0; i < rows; ++i) {
*height += row_height_arr[i];
}
F_FREE(col_width_arr);
F_FREE(row_height_arr);
if (table->options) {
*height += table->options->entire_table_options.top_margin;
*height += table->options->entire_table_options.bottom_margin;
*width += table->options->entire_table_options.left_margin;
*width += table->options->entire_table_options.right_margin;
}
/* Take into account that border elements can be more than one byte long */
fort_table_options_t *table_options = table->options ? table->options : &g_table_options;
size_t max_border_elem_len = max_border_elem_strlen(table_options);
*width *= max_border_elem_len;
return FT_SUCCESS;
}
/********************************************************
End of file "table.c"
********************************************************/
/********************************************************
Begin of file "fort_impl.c"
********************************************************/
2018-05-06 15:36:53 +02:00
/*
libfort
MIT License
Copyright (c) 2017 - 2018 Seleznev Anton
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include "fort.h"
#include <assert.h>
#include <string.h>
2018-05-06 15:21:45 +02:00
#include <wchar.h>
2018-05-06 15:36:53 +02:00
#include <ctype.h>
/* #include "vector.h" */ /* Commented by amalgamation script */
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
/* #include "string_buffer.h" */ /* Commented by amalgamation script */
/* #include "table.h" */ /* Commented by amalgamation script */
/* #include "row.h" */ /* Commented by amalgamation script */
/* #include "options.h" */ /* Commented by amalgamation script */
2018-05-06 15:21:45 +02:00
/*****************************************************************************
2018-05-06 15:36:53 +02:00
* LIBFORT
* ***************************************************************************/
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
ft_table_t *ft_create_table(void)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
ft_table_t *result = (ft_table_t *)F_CALLOC(1, sizeof(ft_table_t));
if (result == NULL)
return NULL;
result->rows = create_vector(sizeof(fort_row_t *), DEFAULT_VECTOR_CAPACITY);
if (result->rows == NULL) {
F_FREE(result);
return NULL;
}
result->separators = create_vector(sizeof(separator_t *), DEFAULT_VECTOR_CAPACITY);
if (result->separators == NULL) {
destroy_vector(result->rows);
F_FREE(result);
return NULL;
}
result->options = NULL;
result->conv_buffer = NULL;
result->cur_row = 0;
result->cur_col = 0;
return result;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
void ft_destroy_table(ft_table_t *table)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
size_t i = 0;
if (table == NULL)
return;
if (table->rows) {
size_t row_n = vector_size(table->rows);
for (i = 0; i < row_n; ++i) {
destroy_row(*(fort_row_t **)vector_at(table->rows, i));
}
destroy_vector(table->rows);
}
if (table->separators) {
size_t row_n = vector_size(table->separators);
for (i = 0; i < row_n; ++i) {
destroy_separator(*(separator_t **)vector_at(table->separators, i));
}
destroy_vector(table->separators);
}
destroy_table_options(table->options);
destroy_string_buffer(table->conv_buffer);
F_FREE(table);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
void ft_ln(ft_table_t *table)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(table);
table->cur_col = 0;
table->cur_row++;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
size_t ft_cur_row(ft_table_t *table)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(table);
return table->cur_row;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
size_t ft_cur_col(ft_table_t *table)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(table);
return table->cur_col;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
void ft_set_cur_cell(ft_table_t *table, size_t row, size_t col)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(table);
table->cur_row = row;
table->cur_col = col;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
static int ft_row_printf_impl(ft_table_t *table, size_t row, const char *fmt, va_list *va)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
#define CREATE_ROW_FROM_FMT_STRING create_row_from_fmt_string
size_t i = 0;
size_t new_cols = 0;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
if (table == NULL)
return -1;
fort_row_t *new_row = CREATE_ROW_FROM_FMT_STRING(fmt, va);
if (new_row == NULL) {
return -1;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
fort_row_t **cur_row_p = NULL;
size_t sz = vector_size(table->rows);
if (row >= sz) {
size_t push_n = row - sz + 1;
for (i = 0; i < push_n; ++i) {
fort_row_t *padding_row = create_row();
if (padding_row == NULL)
goto clear;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
if (FT_IS_ERROR(vector_push(table->rows, &padding_row))) {
destroy_row(padding_row);
goto clear;
}
}
}
/* todo: clearing pushed items in case of error ?? */
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
new_cols = columns_in_row(new_row);
cur_row_p = (fort_row_t **)vector_at(table->rows, row);
swap_row(*cur_row_p, new_row, table->cur_col);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
table->cur_col += new_cols;
destroy_row(new_row);
return new_cols;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
clear:
destroy_row(new_row);
return -1;
#undef CREATE_ROW_FROM_FMT_STRING
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
#ifdef FT_HAVE_WCHAR
static int ft_row_wprintf_impl(ft_table_t *table, size_t row, const wchar_t *fmt, va_list *va)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
#define CREATE_ROW_FROM_FMT_STRING create_row_from_fmt_wstring
size_t i = 0;
size_t new_cols = 0;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
if (table == NULL)
return -1;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
fort_row_t *new_row = CREATE_ROW_FROM_FMT_STRING(fmt, va);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
if (new_row == NULL) {
return -1;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
fort_row_t **cur_row_p = NULL;
size_t sz = vector_size(table->rows);
if (row >= sz) {
size_t push_n = row - sz + 1;
for (i = 0; i < push_n; ++i) {
fort_row_t *padding_row = create_row();
if (padding_row == NULL)
goto clear;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
if (FT_IS_ERROR(vector_push(table->rows, &padding_row))) {
destroy_row(padding_row);
goto clear;
}
}
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
/* todo: clearing pushed items in case of error ?? */
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
new_cols = columns_in_row(new_row);
cur_row_p = (fort_row_t **)vector_at(table->rows, row);
swap_row(*cur_row_p, new_row, table->cur_col);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
table->cur_col += new_cols;
destroy_row(new_row);
return new_cols;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
clear:
destroy_row(new_row);
return -1;
#undef CREATE_ROW_FROM_FMT_STRING
}
#endif
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
#if defined(FT_CLANG_COMPILER) || defined(FT_GCC_COMPILER)
#define FT_PRINTF ft_printf
#define FT_PRINTF_LN ft_printf_ln
#else
#define FT_PRINTF ft_printf_impl
#define FT_PRINTF_LN ft_printf_ln_impl
#endif
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int FT_PRINTF(ft_table_t *table, const char *fmt, ...)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(table);
va_list va;
va_start(va, fmt);
int result = ft_row_printf_impl(table, table->cur_row, fmt, &va);
va_end(va);
return result;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int FT_PRINTF_LN(ft_table_t *table, const char *fmt, ...)
{
assert(table);
va_list va;
va_start(va, fmt);
int result = ft_row_printf_impl(table, table->cur_row, fmt, &va);
if (result >= 0) {
ft_ln(table);
}
va_end(va);
return result;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
#undef FT_PRINTF
#undef FT_PRINTF_LN
#undef FT_HDR_PRINTF
#undef FT_HDR_PRINTF_LN
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
#ifdef FT_HAVE_WCHAR
int ft_wprintf(ft_table_t *table, const wchar_t *fmt, ...)
{
assert(table);
va_list va;
va_start(va, fmt);
int result = ft_row_wprintf_impl(table, table->cur_row, fmt, &va);
va_end(va);
return result;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int ft_wprintf_ln(ft_table_t *table, const wchar_t *fmt, ...)
{
assert(table);
va_list va;
va_start(va, fmt);
int result = ft_row_wprintf_impl(table, table->cur_row, fmt, &va);
if (result >= 0) {
ft_ln(table);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
va_end(va);
return result;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
#endif
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
static int ft_write_impl(ft_table_t *table, const char *cell_content)
{
assert(table);
string_buffer_t *str_buffer = get_cur_str_buffer_and_create_if_not_exists(table);
if (str_buffer == NULL)
return FT_ERROR;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int status = fill_buffer_from_string(str_buffer, cell_content);
if (FT_IS_SUCCESS(status)) {
table->cur_col++;
}
return status;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
#ifdef FT_HAVE_WCHAR
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
static int ft_wwrite_impl(ft_table_t *table, const wchar_t *cell_content)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(table);
string_buffer_t *str_buffer = get_cur_str_buffer_and_create_if_not_exists(table);
if (str_buffer == NULL)
return FT_ERROR;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int status = fill_buffer_from_wstring(str_buffer, cell_content);
if (FT_IS_SUCCESS(status)) {
table->cur_col++;
}
return status;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
#endif
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int ft_nwrite(ft_table_t *table, size_t count, const char *cell_content, ...)
{
size_t i = 0;
assert(table);
int status = ft_write_impl(table, cell_content);
if (FT_IS_ERROR(status))
2018-05-06 15:21:45 +02:00
return status;
2018-05-06 15:36:53 +02:00
va_list va;
va_start(va, cell_content);
--count;
for (i = 0; i < count; ++i) {
const char *cell = va_arg(va, const char *);
status = ft_write_impl(table, cell);
if (FT_IS_ERROR(status))
return status;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
va_end(va);
return status;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
int ft_nwrite_ln(ft_table_t *table, size_t count, const char *cell_content, ...)
{
size_t i = 0;
assert(table);
int status = ft_write_impl(table, cell_content);
if (FT_IS_ERROR(status))
return status;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
va_list va;
va_start(va, cell_content);
--count;
for (i = 0; i < count; ++i) {
const char *cell = va_arg(va, const char *);
status = ft_write_impl(table, cell);
if (FT_IS_ERROR(status)) {
va_end(va);
return status;
}
}
va_end(va);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
ft_ln(table);
return status;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
#ifdef FT_HAVE_WCHAR
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int ft_nwwrite(ft_table_t *table, size_t n, const wchar_t *cell_content, ...)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
size_t i = 0;
assert(table);
int status = ft_wwrite_impl(table, cell_content);
if (FT_IS_ERROR(status))
return status;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
va_list va;
va_start(va, cell_content);
--n;
for (i = 0; i < n; ++i) {
const wchar_t *cell = va_arg(va, const wchar_t *);
status = ft_wwrite_impl(table, cell);
if (FT_IS_ERROR(status))
return status;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
va_end(va);
return status;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
int ft_nwwrite_ln(ft_table_t *table, size_t n, const wchar_t *cell_content, ...)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
size_t i = 0;
assert(table);
int status = ft_wwrite_impl(table, cell_content);
if (FT_IS_ERROR(status))
return status;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
va_list va;
va_start(va, cell_content);
--n;
for (i = 0; i < n; ++i) {
const wchar_t *cell = va_arg(va, const wchar_t *);
status = ft_wwrite_impl(table, cell);
if (FT_IS_ERROR(status)) {
va_end(va);
return status;
}
}
va_end(va);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
ft_ln(table);
return status;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
#endif
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int ft_row_write(ft_table_t *table, size_t cols, const char *cells[])
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
size_t i = 0;
assert(table);
for (i = 0; i < cols; ++i) {
int status = ft_write_impl(table, cells[i]);
if (FT_IS_ERROR(status)) {
/* todo: maybe current pos in case of error should be equal to the one before function call? */
return status;
}
}
return FT_SUCCESS;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
int ft_row_write_ln(ft_table_t *table, size_t cols, const char *cells[])
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(table);
int status = ft_row_write(table, cols, cells);
if (FT_IS_SUCCESS(status)) {
ft_ln(table);
}
return status;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
#ifdef FT_HAVE_WCHAR
int ft_row_wwrite(ft_table_t *table, size_t cols, const wchar_t *cells[])
2018-05-06 15:21:45 +02:00
{
size_t i = 0;
2018-05-06 15:36:53 +02:00
assert(table);
for (i = 0; i < cols; ++i) {
int status = ft_wwrite_impl(table, cells[i]);
if (FT_IS_ERROR(status)) {
/* todo: maybe current pos in case of error should be equal to the one before function call? */
return status;
2018-05-06 15:21:45 +02:00
}
}
2018-05-06 15:36:53 +02:00
return FT_SUCCESS;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
int ft_row_wwrite_ln(ft_table_t *table, size_t cols, const wchar_t *cells[])
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(table);
int status = ft_row_wwrite(table, cols, cells);
if (FT_IS_SUCCESS(status)) {
ft_ln(table);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
return status;
}
#endif
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int ft_table_write(ft_table_t *table, size_t rows, size_t cols, const char *table_cells[])
{
size_t i = 0;
assert(table);
for (i = 0; i < rows; ++i) {
int status = ft_row_write(table, cols, (const char **)&table_cells[i * cols]);
if (FT_IS_ERROR(status)) {
/* todo: maybe current pos in case of error should be equal to the one before function call? */
return status;
}
if (i != rows - 1)
ft_ln(table);
}
2018-05-06 15:21:45 +02:00
return FT_SUCCESS;
}
2018-05-06 15:36:53 +02:00
int ft_table_write_ln(ft_table_t *table, size_t rows, size_t cols, const char *table_cells[])
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(table);
int status = ft_table_write(table, rows, cols, table_cells);
if (FT_IS_SUCCESS(status)) {
ft_ln(table);
}
return status;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
#ifdef FT_HAVE_WCHAR
int ft_table_wwrite(ft_table_t *table, size_t rows, size_t cols, const wchar_t *table_cells[])
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
size_t i = 0;
assert(table);
for (i = 0; i < rows; ++i) {
int status = ft_row_wwrite(table, cols, (const wchar_t **)&table_cells[i * cols]);
if (FT_IS_ERROR(status)) {
/* todo: maybe current pos in case of error should be equal to the one before function call? */
return status;
}
if (i != rows - 1)
ft_ln(table);
}
return FT_SUCCESS;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
int ft_table_wwrite_ln(ft_table_t *table, size_t rows, size_t cols, const wchar_t *table_cells[])
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(table);
int status = ft_table_wwrite(table, rows, cols, table_cells);
if (FT_IS_SUCCESS(status)) {
ft_ln(table);
}
return status;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
#endif
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/*****************************************************************************
* TABLE
* ***************************************************************************/
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
const char *ft_to_string(const ft_table_t *table)
{
typedef char char_type;
const enum str_buf_type buf_type = CharBuf;
const char *space_char = " ";
const char *new_line_char = "\n";
2018-05-06 17:25:53 +02:00
#define EMPTY_STRING ""
2018-05-06 15:36:53 +02:00
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;
// int (*snprint_n_chars_)(char *, size_t, size_t, char) = snprint_n_chars;
int (*snprint_n_strings_)(char *, size_t, size_t, const char *) = snprint_n_strings;
assert(table);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/* Determing size of table string representation */
size_t height = 0;
size_t width = 0;
int status = table_geometry(table, &height, &width);
if (FT_IS_ERROR(status)) {
return NULL;
}
size_t sz = height * width + 1;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/* Allocate string buffer for string representation */
if (table->conv_buffer == NULL) {
((ft_table_t *)table)->conv_buffer = create_string_buffer(sz, buf_type);
if (table->conv_buffer == NULL)
return NULL;
}
while (string_buffer_capacity(table->conv_buffer) < sz) {
if (FT_IS_ERROR(realloc_string_buffer_without_copy(table->conv_buffer))) {
return NULL;
}
}
char_type *buffer = (char_type *)buffer_get_data(table->conv_buffer);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
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 (FT_IS_ERROR(status))
return NULL;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
if (rows == 0)
2018-05-06 17:25:53 +02:00
return EMPTY_STRING;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int written = 0;
int tmp = 0;
size_t i = 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);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/* Print top margin */
for (i = 0; i < context.table_options->entire_table_options.top_margin; ++i) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, width - 1/* minus new_line*/, space_char));
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, 1, new_line_char));
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
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;
CHCK_RSLT_ADD_TO_WRITTEN(print_row_separator_(buffer + written, sz - written, col_width_arr, cols, prev_row, cur_row, separatorPos, cur_sep, &context));
CHCK_RSLT_ADD_TO_WRITTEN(snprintf_row_(cur_row, buffer + written, sz - written, 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;
CHCK_RSLT_ADD_TO_WRITTEN(print_row_separator_(buffer + written, sz - written, col_width_arr, cols, prev_row, cur_row, BottomSeparator, cur_sep, &context));
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/* Print bottom margin */
for (i = 0; i < context.table_options->entire_table_options.bottom_margin; ++i) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, width - 1/* minus new_line*/, space_char));
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, 1, new_line_char));
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
F_FREE(col_width_arr);
F_FREE(row_height_arr);
return buffer;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
clear:
F_FREE(col_width_arr);
F_FREE(row_height_arr);
// F_FREE(buffer);
return NULL;
2018-05-06 17:25:53 +02:00
#undef EMPTY_STRING
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
#ifdef FT_HAVE_WCHAR
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
const wchar_t *ft_to_wstring(const ft_table_t *table)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
typedef wchar_t char_type;
const enum str_buf_type buf_type = WCharBuf;
const char *space_char = " ";
const char *new_line_char = "\n";
2018-05-06 17:25:53 +02:00
#define EMPTY_STRING L""
2018-05-06 15:36:53 +02:00
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;
// int (*snprint_n_chars_)(wchar_t *, size_t, size_t, wchar_t) = wsnprint_n_chars;
int (*snprint_n_strings_)(wchar_t *, size_t, size_t, const char *) = wsnprint_n_string;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
assert(table);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/* Determing size of table string representation */
size_t height = 0;
size_t width = 0;
int status = table_geometry(table, &height, &width);
if (FT_IS_ERROR(status)) {
return NULL;
}
size_t sz = height * width + 1;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/* Allocate string buffer for string representation */
if (table->conv_buffer == NULL) {
((ft_table_t *)table)->conv_buffer = create_string_buffer(sz, buf_type);
if (table->conv_buffer == NULL)
2018-05-06 15:21:45 +02:00
return NULL;
}
2018-05-06 15:36:53 +02:00
while (string_buffer_capacity(table->conv_buffer) < sz) {
if (FT_IS_ERROR(realloc_string_buffer_without_copy(table->conv_buffer))) {
return NULL;
}
}
char_type *buffer = (char_type *)buffer_get_data(table->conv_buffer);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
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)
2018-05-06 17:25:53 +02:00
return EMPTY_STRING;
2018-05-06 15:36:53 +02:00
if (FT_IS_ERROR(status))
2018-05-06 15:21:45 +02:00
return NULL;
2018-05-06 15:36:53 +02:00
int written = 0;
int tmp = 0;
size_t i = 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);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/* Print top margin */
for (i = 0; i < context.table_options->entire_table_options.top_margin; ++i) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, width - 1/* minus new_line*/, space_char));
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, 1, new_line_char));
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
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;
CHCK_RSLT_ADD_TO_WRITTEN(print_row_separator_(buffer + written, sz - written, col_width_arr, cols, prev_row, cur_row, separatorPos, cur_sep, &context));
CHCK_RSLT_ADD_TO_WRITTEN(snprintf_row_(cur_row, buffer + written, sz - written, col_width_arr, cols, row_height_arr[i], &context));
prev_row = cur_row;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
cur_row = NULL;
cur_sep = (i < sep_size) ? (*(separator_t **)vector_at(table->separators, i)) : NULL;
CHCK_RSLT_ADD_TO_WRITTEN(print_row_separator_(buffer + written, sz - written, col_width_arr, cols, prev_row, cur_row, BottomSeparator, cur_sep, &context));
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/* Print bottom margin */
for (i = 0; i < context.table_options->entire_table_options.bottom_margin; ++i) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, width - 1/* minus new_line*/, space_char));
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, sz - written, 1, new_line_char));
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
F_FREE(col_width_arr);
F_FREE(row_height_arr);
return buffer;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
clear:
F_FREE(col_width_arr);
F_FREE(row_height_arr);
// F_FREE(buffer);
return NULL;
2018-05-06 17:25:53 +02:00
#undef EMPTY_STRING
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
#endif
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/*
* TMP
*/
//static int dummy_function(void)
//#if defined(FT_CLANG_COMPILER) || defined(FT_GCC_COMPILER)
//__attribute__ ((unused))
//#endif
//;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
//static int dummy_function(void)
//{
// if (0) {
// vector_t *v = create_vector(1, DEFAULT_VECTOR_CAPACITY);
// vector_clear(v);
// vector_erase(v, 0);
// vector_index_of(v, NULL);
// vector_capacity(v);
// }
// return 0;
//}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int ft_add_separator(ft_table_t *table)
{
assert(table);
assert(table->separators);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
while (vector_size(table->separators) <= table->cur_row) {
separator_t *sep_p = create_separator(F_FALSE);
if (sep_p == NULL)
return FT_MEMORY_ERROR;
int status = vector_push(table->separators, &sep_p);
if (FT_IS_ERROR(status))
2018-05-06 15:21:45 +02:00
return status;
}
2018-05-06 15:36:53 +02:00
separator_t **sep_p = (separator_t **)vector_at(table->separators, table->cur_row);
if (*sep_p == NULL)
*sep_p = create_separator(F_TRUE);
else
(*sep_p)->enabled = F_TRUE;
if (*sep_p == NULL)
return FT_ERROR;
2018-05-06 15:21:45 +02:00
return FT_SUCCESS;
}
2018-05-06 15:36:53 +02:00
/* ******************************************************************************* */
struct ft_border_style *FT_BASIC_STYLE = (struct ft_border_style *) &FORT_BASIC_STYLE;
struct ft_border_style *FT_SIMPLE_STYLE = (struct ft_border_style *) &FORT_SIMPLE_STYLE;
struct ft_border_style *FT_PLAIN_STYLE = (struct ft_border_style *) &FORT_PLAIN_STYLE;
struct ft_border_style *FT_DOT_STYLE = (struct ft_border_style *) &FORT_DOT_STYLE;
struct ft_border_style *FT_EMPTY_STYLE = (struct ft_border_style *) &FORT_EMPTY_STYLE;
struct ft_border_style *FT_SOLID_STYLE = (struct ft_border_style *) &FORT_SOLID_STYLE;
struct ft_border_style *FT_SOLID_ROUND_STYLE = (struct ft_border_style *) &FORT_SOLID_ROUND_STYLE;
struct ft_border_style *FT_DOUBLE_STYLE = (struct ft_border_style *) &FORT_DOUBLE_STYLE;
struct ft_border_style *FT_DOUBLE2_STYLE = (struct ft_border_style *) &FORT_DOUBLE2_STYLE;
struct ft_border_style *FT_BOLD_STYLE = (struct ft_border_style *) &FORT_BOLD_STYLE;
struct ft_border_style *FT_BOLD2_STYLE = (struct ft_border_style *) &FORT_BOLD2_STYLE;
struct ft_border_style *FT_FRAME_STYLE = (struct ft_border_style *) &FORT_FRAME_STYLE;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
static void set_border_options_for_options(fort_table_options_t *options, struct ft_border_style *style)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
if ((struct fort_border_style *)style == &FORT_BASIC_STYLE
|| (struct fort_border_style *)style == &FORT_SIMPLE_STYLE
|| (struct fort_border_style *)style == &FORT_DOT_STYLE
|| (struct fort_border_style *)style == &FORT_PLAIN_STYLE
|| (struct fort_border_style *)style == &FORT_EMPTY_STYLE
|| (struct fort_border_style *)style == &FORT_SOLID_STYLE
|| (struct fort_border_style *)style == &FORT_SOLID_ROUND_STYLE
|| (struct fort_border_style *)style == &FORT_DOUBLE_STYLE
|| (struct fort_border_style *)style == &FORT_DOUBLE2_STYLE
|| (struct fort_border_style *)style == &FORT_BOLD_STYLE
|| (struct fort_border_style *)style == &FORT_BOLD2_STYLE
|| (struct fort_border_style *)style == &FORT_FRAME_STYLE) {
memcpy(&(options->border_style), (struct fort_border_style *)style, sizeof(struct fort_border_style));
return;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
struct ft_border_chars *border_chs = &(style->border_chs);
struct ft_border_chars *header_border_chs = &(style->header_border_chs);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
#define BOR_CHARS options->border_style.border_chars
#define H_BOR_CHARS options->border_style.header_border_chars
#define SEP_CHARS options->border_style.separator_chars
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/*
BOR_CHARS[TL_bip] = BOR_CHARS[TT_bip] = BOR_CHARS[TV_bip] = BOR_CHARS[TR_bip] = border_chs->top_border_ch;
BOR_CHARS[LH_bip] = BOR_CHARS[IH_bip] = BOR_CHARS[II_bip] = BOR_CHARS[RH_bip] = border_chs->separator_ch;
BOR_CHARS[BL_bip] = BOR_CHARS[BB_bip] = BOR_CHARS[BV_bip] = BOR_CHARS[BR_bip] = border_chs->bottom_border_ch;
BOR_CHARS[LL_bip] = BOR_CHARS[IV_bip] = BOR_CHARS[RR_bip] = border_chs->side_border_ch;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
H_BOR_CHARS[TL_bip] = H_BOR_CHARS[TT_bip] = H_BOR_CHARS[TV_bip] = H_BOR_CHARS[TR_bip] = header_border_chs->top_border_ch;
H_BOR_CHARS[LH_bip] = H_BOR_CHARS[IH_bip] = H_BOR_CHARS[II_bip] = H_BOR_CHARS[RH_bip] = header_border_chs->separator_ch;
H_BOR_CHARS[BL_bip] = H_BOR_CHARS[BB_bip] = H_BOR_CHARS[BV_bip] = H_BOR_CHARS[BR_bip] = header_border_chs->bottom_border_ch;
H_BOR_CHARS[LL_bip] = H_BOR_CHARS[IV_bip] = H_BOR_CHARS[RR_bip] = header_border_chs->side_border_ch;
*/
BOR_CHARS[TT_bip] = border_chs->top_border_ch;
BOR_CHARS[IH_bip] = border_chs->separator_ch;
BOR_CHARS[BB_bip] = border_chs->bottom_border_ch;
BOR_CHARS[LL_bip] = BOR_CHARS[IV_bip] = BOR_CHARS[RR_bip] = border_chs->side_border_ch;
BOR_CHARS[TL_bip] = BOR_CHARS[TV_bip] = BOR_CHARS[TR_bip] = border_chs->out_intersect_ch;
BOR_CHARS[LH_bip] = BOR_CHARS[RH_bip] = border_chs->out_intersect_ch;
BOR_CHARS[BL_bip] = BOR_CHARS[BV_bip] = BOR_CHARS[BR_bip] = border_chs->out_intersect_ch;
BOR_CHARS[II_bip] = border_chs->in_intersect_ch;
// if (border_chs->separator_ch == '\0' && border_chs->in_intersect_ch == '\0') {
// BOR_CHARS[LH_bip] = BOR_CHARS[RH_bip] = '\0';
// }
if (strlen(border_chs->separator_ch) == 0 && strlen(border_chs->in_intersect_ch) == 0) {
BOR_CHARS[LH_bip] = BOR_CHARS[RH_bip] = "\0";
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
H_BOR_CHARS[TT_bip] = header_border_chs->top_border_ch;
H_BOR_CHARS[IH_bip] = header_border_chs->separator_ch;
H_BOR_CHARS[BB_bip] = header_border_chs->bottom_border_ch;
H_BOR_CHARS[LL_bip] = H_BOR_CHARS[IV_bip] = H_BOR_CHARS[RR_bip] = header_border_chs->side_border_ch;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
H_BOR_CHARS[TL_bip] = H_BOR_CHARS[TV_bip] = H_BOR_CHARS[TR_bip] = header_border_chs->out_intersect_ch;
H_BOR_CHARS[LH_bip] = H_BOR_CHARS[RH_bip] = header_border_chs->out_intersect_ch;
H_BOR_CHARS[BL_bip] = H_BOR_CHARS[BV_bip] = H_BOR_CHARS[BR_bip] = header_border_chs->out_intersect_ch;
H_BOR_CHARS[II_bip] = header_border_chs->in_intersect_ch;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
// if (header_border_chs->separator_ch == '\0' && header_border_chs->in_intersect_ch == '\0') {
// H_BOR_CHARS[LH_bip] = H_BOR_CHARS[RH_bip] = '\0';
// }
if (strlen(header_border_chs->separator_ch) == 0 && strlen(header_border_chs->in_intersect_ch) == 0) {
BOR_CHARS[LH_bip] = BOR_CHARS[RH_bip] = "\0";
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
SEP_CHARS[LH_sip] = SEP_CHARS[RH_sip] = SEP_CHARS[II_sip] = header_border_chs->out_intersect_ch;
SEP_CHARS[IH_sip] = style->hor_separator_char;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
#undef BOR_CHARS
#undef H_BOR_CHARS
#undef SEP_CHARS
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
int ft_set_default_border_style(struct ft_border_style *style)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
set_border_options_for_options(&g_table_options, style);
return FT_SUCCESS;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int ft_set_border_style(ft_table_t *table, struct ft_border_style *style)
{
assert(table);
if (table->options == NULL) {
table->options = create_table_options();
if (table->options == NULL)
return FT_MEMORY_ERROR;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
set_border_options_for_options(table->options, style);
return FT_SUCCESS;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int ft_set_cell_option(ft_table_t *table, size_t row, size_t col, uint32_t option, int value)
{
assert(table);
if (table->options == NULL) {
table->options = create_table_options();
if (table->options == NULL)
return FT_MEMORY_ERROR;
}
if (table->options->cell_options == NULL) {
table->options->cell_options = create_cell_opt_container();
if (table->options->cell_options == NULL) {
return FT_ERROR;
}
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
if (row == FT_CUR_ROW)
row = table->cur_row;
if (row == FT_CUR_COLUMN)
col = table->cur_col;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
return set_cell_option(table->options->cell_options, row, col, option, value);
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int ft_set_default_cell_option(uint32_t option, int value)
{
return set_default_cell_option(option, value);
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int ft_set_default_tbl_option(uint32_t option, int value)
{
return set_default_entire_table_option(option, value);
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int ft_set_tbl_option(ft_table_t *table, uint32_t option, int value)
{
assert(table);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
if (table->options == NULL) {
table->options = create_table_options();
if (table->options == NULL)
return FT_MEMORY_ERROR;
}
return set_entire_table_option(table->options, option, value);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
void ft_set_memory_funcs(void *(*f_malloc)(size_t size), void (*f_free)(void *ptr))
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
set_memory_funcs(f_malloc, f_free);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
int ft_set_cell_span(ft_table_t *table, size_t row, size_t col, size_t hor_span)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(table);
if (hor_span < 2)
return FT_EINVAL;
if (row == FT_CUR_ROW)
row = table->cur_row;
if (row == FT_CUR_COLUMN)
col = table->cur_col;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
fort_row_t *row_p = get_row_and_create_if_not_exists(table, row);
if (row_p == NULL)
return FT_ERROR;
return row_set_cell_span(row_p, col, hor_span);
}
2018-05-06 15:21:45 +02:00
/********************************************************
2018-05-06 15:36:53 +02:00
End of file "fort_impl.c"
2018-05-06 15:21:45 +02:00
********************************************************/
/********************************************************
2018-05-06 15:36:53 +02:00
Begin of file "vector.c"
2018-05-06 15:21:45 +02:00
********************************************************/
2018-05-06 15:36:53 +02:00
/* #include "vector.h" */ /* Commented by amalgamation script */
#include <assert.h>
#include <string.h>
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/*****************************************************************************
* VECTOR IMPLEMENTATIONS
* ***************************************************************************/
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
struct vector {
size_t m_size;
void *m_data;
size_t m_capacity;
size_t m_item_size;
};
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
static int vector_reallocate_(vector_t *vector, size_t new_capacity)
{
assert(vector);
assert(new_capacity > vector->m_capacity);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
size_t new_size = new_capacity * vector->m_item_size;
vector->m_data = F_REALLOC(vector->m_data, new_size);
if (vector->m_data == NULL)
return -1;
return 0;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/* ------------ Constructors & Destructors ----------------------------- */
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
vector_t *create_vector(size_t item_size, size_t capacity)
{
vector_t *vector = (vector_t *)F_MALLOC(sizeof(vector_t));
if (vector == NULL) {
SYS_LOG_ERROR("Failed to allocate memory for asock vector");
return NULL;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
size_t init_size = MAX(item_size * capacity, 1);
vector->m_data = F_MALLOC(init_size);
if (vector->m_data == NULL) {
SYS_LOG_ERROR("Failed to allocate memory for asock vector inern. buffer");
F_FREE(vector);
return NULL;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
vector->m_size = 0;
vector->m_capacity = capacity;
vector->m_item_size = item_size;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
return vector;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
void destroy_vector(vector_t *vector)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(vector);
F_FREE(vector->m_data);
F_FREE(vector);
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
vector_t *copy_vector(vector_t *v)
{
if (v == NULL)
2018-05-06 15:21:45 +02:00
return NULL;
2018-05-06 15:36:53 +02:00
vector_t *new_vector = create_vector(v->m_item_size, v->m_capacity);
if (new_vector == NULL)
2018-05-06 15:21:45 +02:00
return NULL;
2018-05-06 15:36:53 +02:00
memcpy(new_vector->m_data, v->m_data, v->m_item_size * v->m_size);
new_vector->m_size = v->m_size ;
new_vector->m_item_size = v->m_item_size ;
return new_vector;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
/* ----------- Nonmodifying functions --------------------------------- */
size_t vector_size(const vector_t *vector)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(vector);
return vector->m_size;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
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);
size_t i = 0;
for (i = 0; i < vector->m_size; ++i) {
void *data_pos = (char *)vector->m_data + i * vector->m_item_size;
if (memcmp(data_pos, item, vector->m_item_size) == 0) {
return i;
2018-05-06 15:21:45 +02:00
}
}
2018-05-06 15:36:53 +02:00
return INVALID_VEC_INDEX;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
/* ----------- Modifying functions ------------------------------------- */
int vector_push(vector_t *vector, const void *item)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(vector);
assert(item);
if (vector->m_size == vector->m_capacity) {
if (vector_reallocate_(vector, vector->m_capacity * 2) == -1)
return FT_ERROR;
vector->m_capacity = vector->m_capacity * 2;
}
ptrdiff_t deviation = vector->m_size * vector->m_item_size;
memcpy((char *)vector->m_data + deviation, item, vector->m_item_size);
++(vector->m_size);
return FT_SUCCESS;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
int vector_erase(vector_t *vector, size_t index)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(vector);
if (vector->m_size == 0 || index >= vector->m_size)
return FT_ERROR;
memmove((char *)vector->m_data + vector->m_item_size * index,
(char *)vector->m_data + vector->m_item_size * (index + 1),
(vector->m_size - 1 - index) * vector->m_item_size);
vector->m_size--;
return FT_SUCCESS;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
void vector_clear(vector_t *vector)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
vector->m_size = 0;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
const void *vector_at_c(const vector_t *vector, size_t index)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
if (index >= vector->m_size)
return NULL;
return (char *)vector->m_data + index * vector->m_item_size;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
void *vector_at(vector_t *vector, size_t index)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
if (index >= vector->m_size)
return NULL;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
return (char *)vector->m_data + index * vector->m_item_size;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
fort_status_t vector_swap(vector_t *cur_vec, vector_t *mv_vec, size_t pos)
{
assert(cur_vec);
assert(mv_vec);
assert(cur_vec != mv_vec);
assert(cur_vec->m_item_size == mv_vec->m_item_size);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
size_t cur_sz = vector_size(cur_vec);
size_t mv_sz = vector_size(mv_vec);
if (mv_sz == 0) {
return FT_SUCCESS;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
size_t min_targ_size = pos + mv_sz;
if (cur_sz < min_targ_size) {
if (vector_reallocate_(cur_vec, min_targ_size) == -1)
return FT_ERROR;
cur_vec->m_capacity = min_targ_size;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
ptrdiff_t deviation = pos * cur_vec->m_item_size;
void *tmp = NULL;
size_t new_mv_sz = 0;
if (cur_sz > pos) {
new_mv_sz = MIN(cur_sz - pos, mv_sz);
tmp = F_MALLOC(cur_vec->m_item_size * new_mv_sz);
if (tmp == NULL) {
return FT_MEMORY_ERROR;
2018-05-06 15:21:45 +02:00
}
}
2018-05-06 15:36:53 +02:00
memcpy(tmp,
(char *)cur_vec->m_data + deviation,
cur_vec->m_item_size * (cur_sz - pos));
memcpy((char *)cur_vec->m_data + deviation,
mv_vec->m_data,
cur_vec->m_item_size * mv_sz);
memcpy(mv_vec->m_data,
tmp,
cur_vec->m_item_size * new_mv_sz);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
mv_vec->m_size = new_mv_sz;
F_FREE(tmp);
return FT_SUCCESS;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/********************************************************
End of file "vector.c"
********************************************************/
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/********************************************************
Begin of file "string_buffer.c"
********************************************************/
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/* #include "string_buffer.h" */ /* Commented by amalgamation script */
/* #include "options.h" */ /* Commented by amalgamation script */
/* #include "wcwidth.h" */ /* Commented by amalgamation script */
#include <assert.h>
#include <stddef.h>
#include <wchar.h>
/*****************************************************************************
* STRING BUFFER
* ***************************************************************************/
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
static ptrdiff_t str_iter_width(const char *beg, const char *end)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(end >= beg);
return (end - beg);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
static ptrdiff_t wcs_iter_width(const wchar_t *beg, const wchar_t *end)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(end >= beg);
return mk_wcswidth(beg, (end - beg));
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
static size_t buf_str_len(const string_buffer_t *buf)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(buf);
if (buf->type == CharBuf) {
return strlen(buf->str.cstr);
} else {
return wcslen(buf->str.wstr);
}
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
size_t strchr_count(const char *str, char ch)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
if (str == NULL)
return 0;
size_t count = 0;
str = strchr(str, ch);
while (str) {
count++;
str++;
str = strchr(str, ch);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
return count;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
size_t wstrchr_count(const wchar_t *str, wchar_t ch)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
if (str == NULL)
return 0;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
size_t count = 0;
str = wcschr(str, ch);
while (str) {
count++;
str++;
str = wcschr(str, ch);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
return count;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
const char *str_n_substring_beg(const char *str, char ch_separator, size_t n)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
if (str == NULL)
return NULL;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
if (n == 0)
return str;
str = strchr(str, ch_separator);
--n;
while (n > 0) {
if (str == NULL)
return NULL;
--n;
str++;
str = strchr(str, ch_separator);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
return str ? (str + 1) : NULL;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
const wchar_t *wstr_n_substring_beg(const wchar_t *str, wchar_t ch_separator, size_t n)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
if (str == NULL)
return NULL;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
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);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
return str ? (str + 1) : NULL;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
void str_n_substring(const char *str, char ch_separator, size_t n, const char **begin, const char **end)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
const char *beg = str_n_substring_beg(str, ch_separator, n);
if (beg == NULL) {
*begin = NULL;
*end = NULL;
return;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
const char *en = strchr(beg, ch_separator);
if (en == NULL) {
en = str + strlen(str);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
*begin = beg;
*end = en;
return;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
void wstr_n_substring(const wchar_t *str, wchar_t ch_separator, size_t n, const wchar_t **begin, const wchar_t **end)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
const wchar_t *beg = wstr_n_substring_beg(str, ch_separator, n);
if (beg == NULL) {
*begin = NULL;
*end = NULL;
return;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
const wchar_t *en = wcschr(beg, ch_separator);
if (en == NULL) {
en = str + wcslen(str);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
*begin = beg;
*end = en;
return;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
string_buffer_t *create_string_buffer(size_t number_of_chars, enum str_buf_type type)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
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.data = F_MALLOC(sz);
if (result->str.data == NULL) {
F_FREE(result);
return NULL;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
result->data_sz = sz;
result->type = type;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
if (sz && type == CharBuf) {
result->str.cstr[0] = '\0';
} else if (sz && type == WCharBuf) {
result->str.wstr[0] = L'\0';
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
return result;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
void destroy_string_buffer(string_buffer_t *buffer)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
if (buffer == NULL)
return;
F_FREE(buffer->str.data);
buffer->str.data = NULL;
F_FREE(buffer);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
fort_status_t realloc_string_buffer_without_copy(string_buffer_t *buffer)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(buffer);
char *new_str = (char *)F_MALLOC(buffer->data_sz * 2);
if (new_str == NULL) {
return FT_MEMORY_ERROR;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
F_FREE(buffer->str.data);
buffer->str.data = new_str;
buffer->data_sz *= 2;
return FT_SUCCESS;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str)
{
assert(buffer);
assert(str);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
size_t sz = strlen(str);
char *copy = F_STRDUP(str);
if (copy == NULL)
return FT_MEMORY_ERROR;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
while (sz >= string_buffer_capacity(buffer)) {
int status = realloc_string_buffer_without_copy(buffer);
if (!FT_IS_SUCCESS(status)) {
2018-05-06 15:21:45 +02:00
return status;
}
}
2018-05-06 15:36:53 +02:00
F_FREE(buffer->str.data);
buffer->str.cstr = copy;
buffer->type = CharBuf;
2018-05-06 15:21:45 +02:00
return FT_SUCCESS;
}
2018-05-06 15:36:53 +02:00
fort_status_t fill_buffer_from_wstring(string_buffer_t *buffer, const wchar_t *str)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
assert(buffer);
assert(str);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
size_t sz = wcslen(str);
wchar_t *copy = F_WCSDUP(str);
if (copy == NULL)
return FT_MEMORY_ERROR;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
while (sz >= string_buffer_capacity(buffer)) {
int status = realloc_string_buffer_without_copy(buffer);
if (!FT_IS_SUCCESS(status)) {
2018-05-06 15:21:45 +02:00
return status;
}
}
2018-05-06 15:36:53 +02:00
F_FREE(buffer->str.data);
buffer->str.wstr = copy;
buffer->type = WCharBuf;
2018-05-06 15:21:45 +02:00
return FT_SUCCESS;
}
2018-05-06 15:36:53 +02:00
size_t buffer_text_height(string_buffer_t *buffer)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
if (buffer == NULL || buffer->str.data == NULL || buf_str_len(buffer) == 0) {
return 0;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
if (buffer->type == CharBuf)
return 1 + strchr_count(buffer->str.cstr, '\n');
else
return 1 + wstrchr_count(buffer->str.wstr, L'\n');
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
size_t buffer_text_width(string_buffer_t *buffer)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
size_t max_length = 0;
int n = 0;
if (buffer->type == CharBuf) {
while (1) {
const char *beg = NULL;
const char *end = NULL;
str_n_substring(buffer->str.cstr, '\n', n, &beg, &end);
if (beg == NULL || end == NULL)
return max_length;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
max_length = MAX(max_length, (size_t)(end - beg));
++n;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
} else {
while (1) {
const wchar_t *beg = NULL;
const wchar_t *end = NULL;
wstr_n_substring(buffer->str.wstr, L'\n', n, &beg, &end);
if (beg == NULL || end == NULL)
return max_length;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int line_width = mk_wcswidth(beg, end - beg);
if (line_width < 0) /* For safety */
line_width = 0;
max_length = MAX(max_length, (size_t)line_width);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
++n;
}
2018-05-06 15:21:45 +02:00
}
}
2018-05-06 15:36:53 +02:00
int buffer_printf(string_buffer_t *buffer, size_t buffer_row, char *buf, size_t buf_len, const context_t *context)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
#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 str.cstr
//#define SNPRINT_N_CHARS snprint_n_chars
#define SNPRINT_N_STRINGS snprint_n_strings
#define STR_N_SUBSTRING str_n_substring
#define STR_ITER_WIDTH str_iter_width
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
if (buffer == NULL || buffer->str.data == NULL
|| buffer_row >= buffer_text_height(buffer) || buf_len == 0) {
return -1;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
size_t content_width = buffer_text_width(buffer);
if ((buf_len - 1) < content_width)
return -1;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
size_t left = 0;
size_t right = 0;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
switch (get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_TEXT_ALIGN)) {
case FT_ALIGNED_LEFT:
left = 0;
right = (buf_len - 1) - content_width;
break;
case FT_ALIGNED_CENTER:
left = ((buf_len - 1) - content_width) / 2;
right = ((buf_len - 1) - content_width) - left;
break;
case FT_ALIGNED_RIGHT:
left = (buf_len - 1) - content_width;
right = 0;
break;
default:
assert(0);
break;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
int written = 0;
int tmp = 0;
const CHAR_TYPE *beg = NULL;
const CHAR_TYPE *end = NULL;
CHAR_TYPE old_value;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, buf_len - written, left, SPACE_CHAR));
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
STR_N_SUBSTRING(buffer->BUFFER_STR, NEWLINE_CHAR, buffer_row, &beg, &end);
if (beg == NULL || end == NULL)
return -1;
old_value = *end;
*(CHAR_TYPE *)end = NULL_CHAR;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
ptrdiff_t str_it_width = STR_ITER_WIDTH(beg, end);
if (str_it_width < 0 || content_width < (size_t)str_it_width)
return - 1;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINTF(buf + written, buf_len - written, SNPRINTF_FMT_STR, (int)(end - beg), beg));
*(CHAR_TYPE *)end = old_value;
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, buf_len - written, (content_width - (size_t)str_it_width), SPACE_CHAR));
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, buf_len - written, right, SPACE_CHAR));
return written;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
clear:
return -1;
#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 SNPRINT_N_STRINGS
#undef STR_N_SUBSTRING
#undef STR_ITER_WIDTH
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int buffer_wprintf(string_buffer_t *buffer, size_t buffer_row, 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 " "
#define SNPRINTF_FMT_STR L"%*ls"
#define SNPRINTF swprintf
#define BUFFER_STR str.wstr
//#define SNPRINT_N_CHARS wsnprint_n_chars
#define SNPRINT_N_STRINGS wsnprint_n_string
#define STR_N_SUBSTRING wstr_n_substring
#define STR_ITER_WIDTH wcs_iter_width
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
if (buffer == NULL || buffer->str.data == NULL
|| buffer_row >= buffer_text_height(buffer) || buf_len == 0) {
return -1;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
size_t content_width = buffer_text_width(buffer);
if ((buf_len - 1) < content_width)
return -1;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
size_t left = 0;
size_t right = 0;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
switch (get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_TEXT_ALIGN)) {
case FT_ALIGNED_LEFT:
left = 0;
right = (buf_len - 1) - content_width;
break;
case FT_ALIGNED_CENTER:
left = ((buf_len - 1) - content_width) / 2;
right = ((buf_len - 1) - content_width) - left;
break;
case FT_ALIGNED_RIGHT:
left = (buf_len - 1) - content_width;
right = 0;
break;
default:
assert(0);
break;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int written = 0;
int tmp = 0;
const CHAR_TYPE *beg = NULL;
const CHAR_TYPE *end = NULL;
CHAR_TYPE old_value;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, buf_len - written, left, SPACE_CHAR));
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
STR_N_SUBSTRING(buffer->BUFFER_STR, NEWLINE_CHAR, buffer_row, &beg, &end);
if (beg == NULL || end == NULL)
return -1;
old_value = *end;
*(CHAR_TYPE *)end = NULL_CHAR;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
ptrdiff_t str_it_width = STR_ITER_WIDTH(beg, end);
if (str_it_width < 0 || content_width < (size_t)str_it_width)
return - 1;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINTF(buf + written, buf_len - written, SNPRINTF_FMT_STR, (int)(end - beg), beg));
*(CHAR_TYPE *)end = old_value;
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, buf_len - written, (content_width - (size_t)str_it_width), SPACE_CHAR));
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, buf_len - written, right, SPACE_CHAR));
return written;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
clear:
return -1;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
#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 SNPRINT_N_STRINGS
#undef STR_N_SUBSTRING
#undef STR_ITER_WIDTH
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
size_t string_buffer_capacity(const string_buffer_t *buffer)
{
assert(buffer);
if (buffer->type == CharBuf)
return buffer->data_sz;
2018-05-06 15:21:45 +02:00
else
2018-05-06 15:36:53 +02:00
return buffer->data_sz / sizeof(wchar_t);
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
void *buffer_get_data(string_buffer_t *buffer)
{
assert(buffer);
return buffer->str.data;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
/********************************************************
End of file "string_buffer.c"
********************************************************/
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/********************************************************
Begin of file "fort_utils.c"
********************************************************/
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
#ifdef FT_HAVE_WCHAR
#include <wchar.h>
#endif
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/*****************************************************************************
* LIBFORT helpers
*****************************************************************************/
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
#ifndef FT_MICROSOFT_COMPILER
void *(*fort_malloc)(size_t size) = &malloc;
void (*fort_free)(void *ptr) = &free;
void *(*fort_calloc)(size_t nmemb, size_t size) = &calloc;
void *(*fort_realloc)(void *ptr, size_t size) = &realloc;
#else
static void *local_malloc(size_t size)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
return malloc(size);
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
static void local_free(void *ptr)
{
free(ptr);
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
static void *local_calloc(size_t nmemb, size_t size)
{
return calloc(nmemb, size);
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
static void *local_realloc(void *ptr, size_t size)
{
return realloc(ptr, size);
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
void *(*fort_malloc)(size_t size) = &local_malloc;
void (*fort_free)(void *ptr) = &local_free;
void *(*fort_calloc)(size_t nmemb, size_t size) = &local_calloc;
void *(*fort_realloc)(void *ptr, size_t size) = &local_realloc;
#endif
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
static void *custom_fort_calloc(size_t nmemb, size_t size)
{
size_t total_size = nmemb * size;
void *result = F_MALLOC(total_size);
if (result != NULL)
memset(result, 0, total_size);
return result;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
static void *custom_fort_realloc(void *ptr, size_t size)
{
if (ptr == NULL)
return F_MALLOC(size);
if (size == 0) {
F_FREE(ptr);
return NULL;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
void *new_chunk = F_MALLOC(size);
if (new_chunk == NULL)
return NULL;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/*
* In theory we should copy MIN(size, size allocated for ptr) bytes,
* but this is rather dummy implementation so we don't care about it
*/
memcpy(new_chunk, ptr, size);
F_FREE(ptr);
return new_chunk;
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
void set_memory_funcs(void *(*f_malloc)(size_t size), void (*f_free)(void *ptr))
{
assert((f_malloc == NULL && f_free == NULL) /* Use std functions */
|| (f_malloc != NULL && f_free != NULL) /* Use custom functions */);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
if (f_malloc == NULL && f_free == NULL) {
#ifndef FT_MICROSOFT_COMPILER
fort_malloc = &malloc;
fort_free = &free;
fort_calloc = &calloc;
fort_realloc = &realloc;
#else
fort_malloc = &local_malloc;
fort_free = &local_free;
fort_calloc = &local_calloc;
fort_realloc = &local_realloc;
#endif
} else {
fort_malloc = f_malloc;
fort_free = f_free;
fort_calloc = &custom_fort_calloc;
fort_realloc = &custom_fort_realloc;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
char *fort_strdup(const char *str)
{
if (str == NULL)
return NULL;
size_t sz = strlen(str);
char *str_copy = (char *)F_MALLOC((sz + 1) * sizeof(char));
if (str_copy == NULL)
return NULL;
strcpy(str_copy, str);
return str_copy;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
wchar_t *fort_wcsdup(const wchar_t *str)
{
if (str == NULL)
return NULL;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
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)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
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;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
size_t number_of_columns_in_format_wstring(const wchar_t *fmt)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
int separator_counter = 0;
const wchar_t *pos = fmt;
while (1) {
pos = wcschr(pos, FORT_COL_SEPARATOR);
if (pos == NULL)
break;
separator_counter++;
++pos;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
return separator_counter + 1;
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
//int snprint_n_chars(char *buf, size_t length, size_t n, char ch)
//{
// if (length <= n)
// return -1;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
// if (n == 0)
// return 0;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
// /* To ensure valid return value it is safely not print such big strings */
// if (n > INT_MAX)
// return -1;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
// int status = snprintf(buf, length, "%0*d", (int)n, 0);
// if (status < 0)
// return status;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
// size_t i = 0;
// for (i = 0; i < n; ++i) {
// *buf = ch;
// buf++;
// }
// return (int)n;
//}
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int snprint_n_strings(char *buf, size_t length, size_t n, const char *str)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
size_t str_len = strlen(str);
if (length <= n * str_len)
return -1;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
if (n == 0)
return 0;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/* To ensure valid return value it is safely not print such big strings */
if (n * str_len > INT_MAX)
return -1;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
int status = snprintf(buf, length, "%0*d", (int)(n * str_len), 0);
if (status < 0)
return status;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
size_t i = 0;
for (i = 0; i < n; ++i) {
const char *str_p = str;
while (*str_p)
*(buf++) = *(str_p++);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
return (int)(n * str_len);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
//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;
// /* To ensure valid return value it is safely not print such big strings */
// if (n > INT_MAX)
// return -1;
// int status = swprintf(buf, length, L"%0*d", (int)n, 0);
// if (status < 0)
// return status;
// size_t i = 0;
// for (i = 0; i < n; ++i) {
// *buf = ch;
// buf++;
// }
// return (int)n;
//}
int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *str)
2018-05-06 15:21:45 +02:00
{
2018-05-06 15:36:53 +02:00
size_t str_len = strlen(str);
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
/* This function doesn't work properly with multibyte characters
* so it is better return an error in this case
*/
if (str_len > 1)
return -1;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
if (length <= n * str_len)
return -1;
2018-05-06 15:21:45 +02:00
2018-05-06 15:36:53 +02:00
if (n == 0)
return 0;
/* To ensure valid return value it is safely not print such big strings */
if (n * str_len > INT_MAX)
return -1;
int status = swprintf(buf, length, L"%0*d", (int)(n * str_len), 0);
if (status < 0)
return status;
size_t i = 0;
for (i = 0; i < n; ++i) {
const char *str_p = str;
while (*str_p)
*(buf++) = (wchar_t) * (str_p++);
}
return (int)(n * str_len);
2018-05-06 15:21:45 +02:00
}
2018-05-06 15:36:53 +02:00
2018-05-06 15:21:45 +02:00
/********************************************************
2018-05-06 15:36:53 +02:00
End of file "fort_utils.c"
2018-05-06 15:21:45 +02:00
********************************************************/
/********************************************************
Begin of file "row.c"
********************************************************/
/* #include "row.h" */ /* Commented by amalgamation script */
/* #include "cell.h" */ /* Commented by amalgamation script */
/* #include "string_buffer.h" */ /* Commented by amalgamation script */
#include "assert.h"
/* #include "vector.h" */ /* Commented by amalgamation script */
#include "ctype.h"
struct fort_row {
vector_t *cells;
/*enum ft_row_type type;*/
};
fort_row_t *create_row(void)
{
fort_row_t *row = (fort_row_t *)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;
row->type = FT_ROW_COMMON;
*/
return row;
}
void destroy_row(fort_row_t *row)
{
size_t i = 0;
if (row == NULL)
return;
if (row->cells) {
size_t cells_n = vector_size(row->cells);
for (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);
}
size_t 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 (FT_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);
}
fort_status_t swap_row(fort_row_t *cur_row, fort_row_t *ins_row, size_t pos)
{
assert(cur_row);
assert(ins_row);
size_t cur_sz = vector_size(cur_row->cells);
if (cur_sz == 0 && pos == 0) {
fort_row_t tmp;
memcpy(&tmp, cur_row, sizeof(fort_row_t));
memcpy(cur_row, ins_row, sizeof(fort_row_t));
memcpy(ins_row, &tmp, sizeof(fort_row_t));
return FT_SUCCESS;
}
return vector_swap(cur_row->cells, ins_row->cells, pos);
}
size_t group_cell_number(const fort_row_t *row, size_t master_cell_col)
{
assert(row);
const fort_cell_t *cell = get_cell_c(row, master_cell_col);
if (cell == NULL)
return 0;
size_t total_cols = vector_size(row->cells);
size_t slave_col = master_cell_col + 1;
while (slave_col < total_cols) {
const fort_cell_t *cell = get_cell_c(row, slave_col);
if (cell && get_cell_type(cell) == GroupSlaveCell) {
++slave_col;
} else {
break;
}
}
return slave_col - master_cell_col;
}
int get_row_cell_types(const fort_row_t *row, enum CellType *types, size_t types_sz)
{
assert(row);
assert(types);
size_t i = 0;
for (i = 0; i < types_sz; ++i) {
const fort_cell_t *cell = get_cell_c(row, i);
if (cell) {
types[i] = get_cell_type(cell);
} else {
types[i] = CommonCell;
}
}
return FT_SUCCESS;
}
fort_status_t row_set_cell_span(fort_row_t *row, size_t cell_column, size_t hor_span)
{
assert(row);
if (hor_span < 2)
return FT_EINVAL;
fort_cell_t *main_cell = get_cell_and_create_if_not_exists(row, cell_column);
if (main_cell == NULL) {
return FT_ERROR;
}
set_cell_type(main_cell, GroupMasterCell);
--hor_span;
++cell_column;
while (hor_span) {
fort_cell_t *slave_cell = get_cell_and_create_if_not_exists(row, cell_column);
if (slave_cell == NULL) {
return FT_ERROR;
}
set_cell_type(slave_cell, GroupSlaveCell);
--hor_span;
++cell_column;
}
return FT_SUCCESS;
}
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 separator_t *sep, const context_t *context)
{
// int (*snprint_n_chars_)(char *, size_t, size_t, char) = snprint_n_chars;
int (*snprint_n_strings_)(char *, size_t, size_t, const char *) = snprint_n_strings;
assert(buffer);
assert(context);
const char *space_char = " ";
int status = -1;
/* Get cell types
*
* Regions above top row and below bottom row areconsidered full of virtual
* GroupSlaveCell cells
*/
enum CellType *top_row_types = F_MALLOC(sizeof(enum CellType) * cols * 2);
if (top_row_types == NULL) {
return FT_MEMORY_ERROR;
}
enum CellType *bottom_row_types = top_row_types + cols;
if (upper_row) {
get_row_cell_types(upper_row, top_row_types, cols);
} else {
size_t i = 0;
for (i = 0; i < cols; ++i)
top_row_types[i] = GroupSlaveCell;
}
if (lower_row) {
get_row_cell_types(lower_row, bottom_row_types, cols);
} else {
size_t i = 0;
for (i = 0; i < cols; ++i)
bottom_row_types[i] = GroupSlaveCell;
}
int written = 0;
int tmp = 0;
enum ft_row_type lower_row_type = FT_ROW_COMMON;
if (lower_row != NULL) {
lower_row_type = (enum ft_row_type)get_cell_opt_value_hierarcial(context->table_options, context->row, FT_ANY_COLUMN, FT_COPT_ROW_TYPE);
}
enum ft_row_type upper_row_type = FT_ROW_COMMON;
if (upper_row != NULL) {
upper_row_type = (enum ft_row_type)get_cell_opt_value_hierarcial(context->table_options, context->row - 1, FT_ANY_COLUMN, FT_COPT_ROW_TYPE);
}
/* Row separator anatomy
*
* | C11 | C12 C13 | C14 C15 |
* L I I I IV I I IT I I I IB I I II I I R
* | C21 | C22 | C23 C24 C25 |
*/
const char **L = NULL;
const char **I = NULL;
const char **IV = NULL;
const char **R = NULL;
const char **IT = NULL;
const char **IB = NULL;
const char **II = NULL;
typedef const char *(*border_chars_point_t)[BorderItemPosSize];
const char *(*border_chars)[BorderItemPosSize] = NULL;
border_chars = (border_chars_point_t)&context->table_options->border_style.border_chars;
if (upper_row_type == FT_ROW_HEADER || lower_row_type == FT_ROW_HEADER) {
border_chars = (border_chars_point_t)&context->table_options->border_style.header_border_chars;
}
if (sep && sep->enabled) {
L = &(context->table_options->border_style.separator_chars[LH_sip]);
I = &(context->table_options->border_style.separator_chars[IH_sip]);
IV = &(context->table_options->border_style.separator_chars[II_sip]);
R = &(context->table_options->border_style.separator_chars[RH_sip]);
IT = &(context->table_options->border_style.separator_chars[II_sip]);
IB = &(context->table_options->border_style.separator_chars[II_sip]);
II = &(context->table_options->border_style.separator_chars[IH_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];
IT = &(*border_chars)[TV_bip];
IB = &(*border_chars)[TV_bip];
II = &(*border_chars)[TT_bip];
break;
case InsideSeparator:
L = &(*border_chars)[LH_bip];
I = &(*border_chars)[IH_bip];
IV = &(*border_chars)[II_bip];
R = &(*border_chars)[RH_bip];
IT = &(*border_chars)[TV_bip];
IB = &(*border_chars)[BV_bip];
II = &(*border_chars)[IH_bip];
break;
case BottomSeparator:
L = &(*border_chars)[BL_bip];
I = &(*border_chars)[BB_bip];
IV = &(*border_chars)[BV_bip];
R = &(*border_chars)[BR_bip];
IT = &(*border_chars)[BV_bip];
IB = &(*border_chars)[BV_bip];
II = &(*border_chars)[BB_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)) {
// status = 0;
// goto clear;
// }
if ((strlen(*L) == 0 || (strlen(*L) == 1 && !isprint(**L)))
&& (strlen(*I) == 0 || (strlen(*I) == 1 && !isprint(**I)))
&& (strlen(*IV) == 0 || (strlen(*IV) == 1 && !isprint(**IV)))
&& (strlen(*R) == 0 || (strlen(*R) == 1 && !isprint(**R)))) {
status = 0;
goto clear;
}
size_t i = 0;
/* Print left margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, context->table_options->entire_table_options.left_margin, space_char));
for (i = 0; i < cols; ++i) {
if (i == 0) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *L));
} else {
if ((top_row_types[i] == CommonCell || top_row_types[i] == GroupMasterCell)
&& (bottom_row_types[i] == CommonCell || bottom_row_types[i] == GroupMasterCell)) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *IV));
} else if (top_row_types[i] == GroupSlaveCell && bottom_row_types[i] == GroupSlaveCell) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *II));
} else if (top_row_types[i] == GroupSlaveCell) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *IT));
} else {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *IB));
}
}
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, col_width_arr[i], *I));
}
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *R));
/* Print right margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, context->table_options->entire_table_options.right_margin, space_char));
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, "\n"));
status = written;
clear:
F_FREE(top_row_types);
return status;
}
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)
{
// int (*snprint_n_chars_)(wchar_t *, size_t, size_t, wchar_t) = wsnprint_n_chars;
int (*snprint_n_strings_)(wchar_t *, size_t, size_t, const char *) = wsnprint_n_string;
assert(buffer);
assert(context);
const char *space_char = " ";
int status = -1;
/* Get cell types
*
* Regions above top row and below bottom row areconsidered full of virtual
* GroupSlaveCell cells
*/
enum CellType *top_row_types = F_MALLOC(sizeof(enum CellType) * cols * 2);
if (top_row_types == NULL) {
return FT_MEMORY_ERROR;
}
enum CellType *bottom_row_types = top_row_types + cols;
if (upper_row) {
get_row_cell_types(upper_row, top_row_types, cols);
} else {
size_t i = 0;
for (i = 0; i < cols; ++i)
top_row_types[i] = GroupSlaveCell;
}
if (lower_row) {
get_row_cell_types(lower_row, bottom_row_types, cols);
} else {
size_t i = 0;
for (i = 0; i < cols; ++i)
bottom_row_types[i] = GroupSlaveCell;
}
int written = 0;
int tmp = 0;
enum ft_row_type lower_row_type = FT_ROW_COMMON;
if (lower_row != NULL) {
lower_row_type = (enum ft_row_type)get_cell_opt_value_hierarcial(context->table_options, context->row, FT_ANY_COLUMN, FT_COPT_ROW_TYPE);
}
enum ft_row_type upper_row_type = FT_ROW_COMMON;
if (upper_row != NULL) {
upper_row_type = (enum ft_row_type)get_cell_opt_value_hierarcial(context->table_options, context->row - 1, FT_ANY_COLUMN, FT_COPT_ROW_TYPE);
}
/* Row separator anatomy
*
* | C11 | C12 C13 | C14 C15 |
* L I I I IV I I IT I I I IB I I II I I R
* | C21 | C22 | C23 C24 C25 |
*/
const char **L = NULL;
const char **I = NULL;
const char **IV = NULL;
const char **R = NULL;
const char **IT = NULL;
const char **IB = NULL;
const char **II = NULL;
typedef const char *(*border_chars_point_t)[BorderItemPosSize];
const char *(*border_chars)[BorderItemPosSize] = NULL;
border_chars = (border_chars_point_t)&context->table_options->border_style.border_chars;
if (upper_row_type == FT_ROW_HEADER || lower_row_type == FT_ROW_HEADER) {
border_chars = (border_chars_point_t)&context->table_options->border_style.header_border_chars;
}
if (sep && sep->enabled) {
L = &(context->table_options->border_style.separator_chars[LH_sip]);
I = &(context->table_options->border_style.separator_chars[IH_sip]);
IV = &(context->table_options->border_style.separator_chars[II_sip]);
R = &(context->table_options->border_style.separator_chars[RH_sip]);
IT = &(context->table_options->border_style.separator_chars[II_sip]);
IB = &(context->table_options->border_style.separator_chars[II_sip]);
II = &(context->table_options->border_style.separator_chars[IH_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];
IT = &(*border_chars)[TV_bip];
IB = &(*border_chars)[TV_bip];
II = &(*border_chars)[TT_bip];
break;
case InsideSeparator:
L = &(*border_chars)[LH_bip];
I = &(*border_chars)[IH_bip];
IV = &(*border_chars)[II_bip];
R = &(*border_chars)[RH_bip];
IT = &(*border_chars)[TV_bip];
IB = &(*border_chars)[BV_bip];
II = &(*border_chars)[IH_bip];
break;
case BottomSeparator:
L = &(*border_chars)[BL_bip];
I = &(*border_chars)[BB_bip];
IV = &(*border_chars)[BV_bip];
R = &(*border_chars)[BR_bip];
IT = &(*border_chars)[BV_bip];
IB = &(*border_chars)[BV_bip];
II = &(*border_chars)[BB_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)) {
// status = 0;
// goto clear;
// }
if ((strlen(*L) == 0 || (strlen(*L) == 1 && !isprint(**L)))
&& (strlen(*I) == 0 || (strlen(*I) == 1 && !isprint(**I)))
&& (strlen(*IV) == 0 || (strlen(*IV) == 1 && !isprint(**IV)))
&& (strlen(*R) == 0 || (strlen(*R) == 1 && !isprint(**R)))) {
status = 0;
goto clear;
}
size_t i = 0;
/* Print left margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, context->table_options->entire_table_options.left_margin, space_char));
for (i = 0; i < cols; ++i) {
if (i == 0) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *L));
} else {
if ((top_row_types[i] == CommonCell || top_row_types[i] == GroupMasterCell)
&& (bottom_row_types[i] == CommonCell || bottom_row_types[i] == GroupMasterCell)) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *IV));
} else if (top_row_types[i] == GroupSlaveCell && bottom_row_types[i] == GroupSlaveCell) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *II));
} else if (top_row_types[i] == GroupSlaveCell) {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *IT));
} else {
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *IB));
}
}
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, col_width_arr[i], *I));
}
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, *R));
/* Print right margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, context->table_options->entire_table_options.right_margin, space_char));
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, 1, "\n"));
status = written;
clear:
F_FREE(top_row_types);
return status;
}
fort_row_t *create_row_from_string(const char *str)
{
typedef char char_type;
char_type *(*strdup_)(const char_type * str) = F_STRDUP;
const char_type zero_char = '\0';
fort_status_t (*fill_cell_from_string_)(fort_cell_t *cell, const char *str) = fill_cell_from_string;
const char_type *const zero_string = "";
#define STRCHR strchr
char_type *pos = NULL;
char_type *base_pos = NULL;
unsigned int number_of_separators = 0;
fort_row_t *row = create_row();
if (row == NULL)
return NULL;
if (str == NULL)
return row;
char_type *str_copy = strdup_(str);
if (str_copy == NULL)
goto clear;
pos = str_copy;
base_pos = str_copy;
number_of_separators = 0;
while (*pos) {
pos = STRCHR(pos, FORT_COL_SEPARATOR);
if (pos != NULL) {
*(pos) = zero_char;
++pos;
number_of_separators++;
}
fort_cell_t *cell = create_cell();
if (cell == NULL)
goto clear;
int status = fill_cell_from_string_(cell, base_pos);
if (FT_IS_ERROR(status)) {
destroy_cell(cell);
goto clear;
}
status = vector_push(row->cells, &cell);
if (FT_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_cell_from_string_(cell, zero_string);
if (FT_IS_ERROR(status)) {
destroy_cell(cell);
goto clear;
}
status = vector_push(row->cells, &cell);
if (FT_IS_ERROR(status)) {
destroy_cell(cell);
goto clear;
}
}
F_FREE(str_copy);
return row;
clear:
destroy_row(row);
F_FREE(str_copy);
return NULL;
#undef STRCHR
}
#ifdef FT_HAVE_WCHAR
fort_row_t *create_row_from_wstring(const wchar_t *str)
{
typedef wchar_t char_type;
char_type *(*strdup_)(const char_type * str) = F_WCSDUP;
const char_type zero_char = L'\0';
fort_status_t (*fill_cell_from_string_)(fort_cell_t *cell, const wchar_t *str) = fill_cell_from_wstring;
const char_type *const zero_string = L"";
#define STRCHR wcschr
char_type *pos = NULL;
char_type *base_pos = NULL;
unsigned int number_of_separators = 0;
fort_row_t *row = create_row();
if (row == NULL)
return NULL;
if (str == NULL)
return row;
char_type *str_copy = strdup_(str);
if (str_copy == NULL)
goto clear;
pos = str_copy;
base_pos = str_copy;
number_of_separators = 0;
while (*pos) {
pos = STRCHR(pos, FORT_COL_SEPARATOR);
if (pos != NULL) {
*(pos) = zero_char;
++pos;
number_of_separators++;
}
fort_cell_t *cell = create_cell();
if (cell == NULL)
goto clear;
int status = fill_cell_from_string_(cell, base_pos);
if (FT_IS_ERROR(status)) {
destroy_cell(cell);
goto clear;
}
status = vector_push(row->cells, &cell);
if (FT_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_cell_from_string_(cell, zero_string);
if (FT_IS_ERROR(status)) {
destroy_cell(cell);
goto clear;
}
status = vector_push(row->cells, &cell);
if (FT_IS_ERROR(status)) {
destroy_cell(cell);
goto clear;
}
}
F_FREE(str_copy);
return row;
clear:
destroy_row(row);
F_FREE(str_copy);
return NULL;
#undef STRCHR
}
#endif
fort_row_t *create_row_from_fmt_string(const char *fmt, va_list *va_args)
{
#define VSNPRINTF vsnprintf
#define STR_FILED cstr
#define CREATE_ROW_FROM_STRING create_row_from_string
#define NUMBER_OF_COLUMNS_IN_FORMAT_STRING number_of_columns_in_format_string
string_buffer_t *buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, CharBuf);
if (buffer == NULL)
return NULL;
size_t cols_origin = NUMBER_OF_COLUMNS_IN_FORMAT_STRING(fmt);
size_t cols = 0;
while (1) {
va_list va;
va_copy(va, *va_args);
int virtual_sz = VSNPRINTF(buffer->str.STR_FILED, string_buffer_capacity(buffer), fmt, va);
va_end(va);
/* If error encountered */
if (virtual_sz < 0)
goto clear;
/* Successful write */
if ((size_t)virtual_sz < string_buffer_capacity(buffer))
break;
/* Otherwise buffer was too small, so incr. buffer size ant try again. */
if (!FT_IS_SUCCESS(realloc_string_buffer_without_copy(buffer)))
goto clear;
}
cols = NUMBER_OF_COLUMNS_IN_FORMAT_STRING(buffer->str.STR_FILED);
if (cols == cols_origin) {
fort_row_t *row = CREATE_ROW_FROM_STRING(buffer->str.STR_FILED);
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;
#undef VSNPRINTF
#undef STR_FILED
#undef CREATE_ROW_FROM_STRING
#undef NUMBER_OF_COLUMNS_IN_FORMAT_STRING
}
#ifdef FT_HAVE_WCHAR
fort_row_t *create_row_from_fmt_wstring(const wchar_t *fmt, va_list *va_args)
{
#define VSNPRINTF vswprintf
#define STR_FILED wstr
#define CREATE_ROW_FROM_STRING create_row_from_wstring
#define NUMBER_OF_COLUMNS_IN_FORMAT_STRING number_of_columns_in_format_wstring
string_buffer_t *buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, CharBuf);
if (buffer == NULL)
return NULL;
size_t cols_origin = NUMBER_OF_COLUMNS_IN_FORMAT_STRING(fmt);
size_t cols = 0;
while (1) {
va_list va;
va_copy(va, *va_args);
int virtual_sz = VSNPRINTF(buffer->str.STR_FILED, string_buffer_capacity(buffer), fmt, va);
va_end(va);
/* If error encountered */
if (virtual_sz < 0)
goto clear;
/* Successful write */
if ((size_t)virtual_sz < string_buffer_capacity(buffer))
break;
/* Otherwise buffer was too small, so incr. buffer size ant try again. */
if (!FT_IS_SUCCESS(realloc_string_buffer_without_copy(buffer)))
goto clear;
}
cols = NUMBER_OF_COLUMNS_IN_FORMAT_STRING(buffer->str.STR_FILED);
if (cols == cols_origin) {
fort_row_t *row = CREATE_ROW_FROM_STRING(buffer->str.STR_FILED);
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;
#undef VSNPRINTF
#undef STR_FILED
#undef CREATE_ROW_FROM_STRING
#undef NUMBER_OF_COLUMNS_IN_FORMAT_STRING
}
#endif
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 (*snprint_n_chars_)(char *, size_t, size_t, char) = snprint_n_chars;
int (*snprint_n_strings_)(char *, size_t, size_t, const char *) = snprint_n_strings;
int (*cell_printf_)(fort_cell_t *, size_t, char *, size_t, const context_t *) = cell_printf;
assert(context);
const char *space_char = " ";
const char *new_line_char = "\n";
if (row == NULL)
return -1;
size_t 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
*/
typedef const char *(*border_chars_point_t)[BorderItemPosSize];
enum ft_row_type row_type = (enum ft_row_type)get_cell_opt_value_hierarcial(context->table_options, context->row, FT_ANY_COLUMN, FT_COPT_ROW_TYPE);
const char *(*bord_chars)[BorderItemPosSize] = (row_type == FT_ROW_HEADER)
? (border_chars_point_t)(&context->table_options->border_style.header_border_chars)
: (border_chars_point_t)(&context->table_options->border_style.border_chars);
const char **L = &(*bord_chars)[LL_bip];
const char **IV = &(*bord_chars)[IV_bip];
const char **R = &(*bord_chars)[RR_bip];
int written = 0;
int tmp = 0;
size_t i = 0;
for (i = 0; i < row_height; ++i) {
/* Print left margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, context->table_options->entire_table_options.left_margin, space_char));
/* Print left table boundary */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, *L));
size_t j = 0;
while (j < col_width_arr_sz) {
if (j < cols_in_row) {
((context_t *)context)->column = j;
fort_cell_t *cell = *(fort_cell_t **)vector_at(row->cells, j);
size_t cell_width = 0;
size_t group_slave_sz = group_cell_number(row, j);
cell_width = col_width_arr[j];
size_t slave_j = 0;
size_t master_j = j;
for (slave_j = master_j + 1; slave_j < (master_j + group_slave_sz); ++slave_j) {
cell_width += col_width_arr[slave_j] + FORT_COL_SEPARATOR_LENGTH;
++j;
}
CHCK_RSLT_ADD_TO_WRITTEN(cell_printf_(cell, i, buffer + written, cell_width + 1, context));
} else {
/* Print empty cell */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, col_width_arr[j], space_char));
}
/* Print boundary between cells */
if (j < col_width_arr_sz - 1)
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, *IV));
++j;
}
/* Print right table boundary */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, *R));
/* Print right margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, context->table_options->entire_table_options.right_margin, space_char));
/* Print new line character */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, new_line_char));
}
return written;
clear:
return -1;
}
#ifdef FT_HAVE_WCHAR
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)
{
// int (*snprint_n_chars_)(wchar_t *, size_t, size_t, wchar_t) = wsnprint_n_chars;
int (*snprint_n_strings_)(wchar_t *, size_t, size_t, const char *) = wsnprint_n_string;
int (*cell_printf_)(fort_cell_t *, size_t, wchar_t *, size_t, const context_t *) = cell_wprintf;
assert(context);
const char *space_char = " ";
const char *new_line_char = "\n";
if (row == NULL)
return -1;
size_t 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
*/
typedef const char *(*border_chars_point_t)[BorderItemPosSize];
enum ft_row_type row_type = (enum ft_row_type)get_cell_opt_value_hierarcial(context->table_options, context->row, FT_ANY_COLUMN, FT_COPT_ROW_TYPE);
const char *(*bord_chars)[BorderItemPosSize] = (row_type == FT_ROW_HEADER)
? (border_chars_point_t)(&context->table_options->border_style.header_border_chars)
: (border_chars_point_t)(&context->table_options->border_style.border_chars);
const char **L = &(*bord_chars)[LL_bip];
const char **IV = &(*bord_chars)[IV_bip];
const char **R = &(*bord_chars)[RR_bip];
int written = 0;
int tmp = 0;
size_t i = 0;
for (i = 0; i < row_height; ++i) {
/* Print left margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, context->table_options->entire_table_options.left_margin, space_char));
/* Print left table boundary */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, *L));
size_t j = 0;
while (j < col_width_arr_sz) {
if (j < cols_in_row) {
((context_t *)context)->column = j;
fort_cell_t *cell = *(fort_cell_t **)vector_at(row->cells, j);
size_t cell_width = 0;
size_t group_slave_sz = group_cell_number(row, j);
cell_width = col_width_arr[j];
size_t slave_j = 0;
size_t master_j = j;
for (slave_j = master_j + 1; slave_j < (master_j + group_slave_sz); ++slave_j) {
cell_width += col_width_arr[slave_j] + FORT_COL_SEPARATOR_LENGTH;
++j;
}
CHCK_RSLT_ADD_TO_WRITTEN(cell_printf_(cell, i, buffer + written, cell_width + 1, context));
} else {
/* Print empty cell */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, col_width_arr[j], space_char));
}
/* Print boundary between cells */
if (j < col_width_arr_sz - 1)
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, *IV));
++j;
}
/* Print right table boundary */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, *R));
/* Print right margin */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, context->table_options->entire_table_options.right_margin, space_char));
/* Print new line character */
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buf_sz - written, 1, new_line_char));
}
return written;
clear:
return -1;
}
#endif
/********************************************************
End of file "row.c"
********************************************************/
/********************************************************
Begin of file "wcwidth.c"
********************************************************/
/*
* This is an implementation of wcwidth() and wcswidth() (defined in
* IEEE Std 1002.1-2001) for Unicode.
*
* http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
* http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
*
* In fixed-width output devices, Latin characters all occupy a single
* "cell" position of equal width, whereas ideographic CJK characters
* occupy two such cells. Interoperability between terminal-line
* applications and (teletype-style) character terminals using the
* UTF-8 encoding requires agreement on which character should advance
* the cursor by how many cell positions. No established formal
* standards exist at present on which Unicode character shall occupy
* how many cell positions on character terminals. These routines are
* a first attempt of defining such behavior based on simple rules
* applied to data provided by the Unicode Consortium.
*
* For some graphical characters, the Unicode standard explicitly
* defines a character-cell width via the definition of the East Asian
* FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
* In all these cases, there is no ambiguity about which width a
* terminal shall use. For characters in the East Asian Ambiguous (A)
* class, the width choice depends purely on a preference of backward
* compatibility with either historic CJK or Western practice.
* Choosing single-width for these characters is easy to justify as
* the appropriate long-term solution, as the CJK practice of
* displaying these characters as double-width comes from historic
* implementation simplicity (8-bit encoded characters were displayed
* single-width and 16-bit ones double-width, even for Greek,
* Cyrillic, etc.) and not any typographic considerations.
*
* Much less clear is the choice of width for the Not East Asian
* (Neutral) class. Existing practice does not dictate a width for any
* of these characters. It would nevertheless make sense
* typographically to allocate two character cells to characters such
* as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
* represented adequately with a single-width glyph. The following
* routines at present merely assign a single-cell width to all
* neutral characters, in the interest of simplicity. This is not
* entirely satisfactory and should be reconsidered before
* establishing a formal standard in this area. At the moment, the
* decision which Not East Asian (Neutral) characters should be
* represented by double-width glyphs cannot yet be answered by
* applying a simple rule from the Unicode database content. Setting
* up a proper standard for the behavior of UTF-8 character terminals
* will require a careful analysis not only of each Unicode character,
* but also of each presentation form, something the author of these
* routines has avoided to do so far.
*
* http://www.unicode.org/unicode/reports/tr11/
*
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
*
* Permission to use, copy, modify, and distribute this software
* for any purpose and without fee is hereby granted. The author
* disclaims all warranties with regard to this software.
*
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
*/
#include <wchar.h>
struct interval {
int first;
int last;
};
/* auxiliary function for binary search in interval table */
static int bisearch(wchar_t ucs, const struct interval *table, int max)
{
int min = 0;
int mid;
if (ucs < table[0].first || ucs > table[max].last)
return 0;
while (max >= min) {
mid = (min + max) / 2;
if (ucs > table[mid].last)
min = mid + 1;
else if (ucs < table[mid].first)
max = mid - 1;
else
return 1;
}
return 0;
}
/* The following two functions define the column width of an ISO 10646
* character as follows:
*
* - The null character (U+0000) has a column width of 0.
*
* - Other C0/C1 control characters and DEL will lead to a return
* value of -1.
*
* - Non-spacing and enclosing combining characters (general
* category code Mn or Me in the Unicode database) have a
* column width of 0.
*
* - SOFT HYPHEN (U+00AD) has a column width of 1.
*
* - Other format characters (general category code Cf in the Unicode
* database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
*
* - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
* have a column width of 0.
*
* - Spacing characters in the East Asian Wide (W) or East Asian
* Full-width (F) category as defined in Unicode Technical
* Report #11 have a column width of 2.
*
* - All remaining characters (including all printable
* ISO 8859-1 and WGL4 characters, Unicode control characters,
* etc.) have a column width of 1.
*
* This implementation assumes that wchar_t characters are encoded
* in ISO 10646.
*/
int mk_wcwidth(wchar_t ucs)
{
/* sorted list of non-overlapping intervals of non-spacing characters */
/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
static const struct interval combining[] = {
{ 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
{ 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
{ 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
{ 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
{ 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
{ 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
{ 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
{ 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
{ 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
{ 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
{ 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
{ 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
{ 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
{ 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
{ 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
{ 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
{ 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
{ 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
{ 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
{ 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
{ 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
{ 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
{ 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
{ 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
{ 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
{ 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
{ 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
{ 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
{ 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
{ 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
{ 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
{ 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
{ 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
{ 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
{ 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
{ 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
{ 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
{ 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
{ 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
{ 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
{ 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
{ 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
{ 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
{ 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
{ 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
{ 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
{ 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
{ 0xE0100, 0xE01EF }
};
/* test for 8-bit control characters */
if (ucs == 0)
return 0;
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
return -1;
/* binary search in table of non-spacing characters */
if (bisearch(ucs, combining,
sizeof(combining) / sizeof(struct interval) - 1))
return 0;
/* if we arrive here, ucs is not a combining or C0/C1 control character */
return 1 +
(ucs >= 0x1100 &&
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
ucs == 0x2329 || ucs == 0x232a ||
(ucs >= 0x2e80 && ucs <= 0xa4cf &&
ucs != 0x303f) || /* CJK ... Yi */
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
(ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
(ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
(ucs >= 0xffe0 && ucs <= 0xffe6) ||
(ucs >= 0x20000 && ucs <= 0x2fffd) ||
(ucs >= 0x30000 && ucs <= 0x3fffd)));
}
int mk_wcswidth(const wchar_t *pwcs, size_t n)
{
int w, width = 0;
for (; *pwcs && n-- > 0; pwcs++)
if ((w = mk_wcwidth(*pwcs)) < 0)
return -1;
else
width += w;
return width;
}
/*
* The following functions are the same as mk_wcwidth() and
* mk_wcswidth(), except that spacing characters in the East Asian
* Ambiguous (A) category as defined in Unicode Technical Report #11
* have a column width of 2. This variant might be useful for users of
* CJK legacy encodings who want to migrate to UCS without changing
* the traditional terminal character-width behaviour. It is not
* otherwise recommended for general use.
*/
int mk_wcwidth_cjk(wchar_t ucs)
{
/* sorted list of non-overlapping intervals of East Asian Ambiguous
* characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
static const struct interval ambiguous[] = {
{ 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
{ 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 },
{ 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
{ 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
{ 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
{ 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
{ 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
{ 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
{ 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
{ 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
{ 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
{ 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
{ 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
{ 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
{ 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
{ 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB },
{ 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB },
{ 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 },
{ 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 },
{ 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 },
{ 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 },
{ 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 },
{ 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 },
{ 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 },
{ 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
{ 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
{ 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 },
{ 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 },
{ 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
{ 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 },
{ 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 },
{ 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B },
{ 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 },
{ 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 },
{ 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E },
{ 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 },
{ 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 },
{ 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F },
{ 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 },
{ 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF },
{ 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B },
{ 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 },
{ 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 },
{ 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 },
{ 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 },
{ 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 },
{ 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 },
{ 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 },
{ 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 },
{ 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F },
{ 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF },
{ 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD }
};
/* binary search in table of non-spacing characters */
if (bisearch(ucs, ambiguous,
sizeof(ambiguous) / sizeof(struct interval) - 1))
return 2;
return mk_wcwidth(ucs);
}
int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n)
{
int w, width = 0;
for (; *pwcs && n-- > 0; pwcs++)
if ((w = mk_wcwidth_cjk(*pwcs)) < 0)
return -1;
else
width += w;
return width;
}
/********************************************************
End of file "wcwidth.c"
********************************************************/
/********************************************************
Begin of file "cell.c"
********************************************************/
/* #include "cell.h" */ /* Commented by amalgamation script */
/* #include "options.h" */ /* Commented by amalgamation script */
/* #include "string_buffer.h" */ /* Commented by amalgamation script */
#include <assert.h>
/*****************************************************************************
* CELL
* ***************************************************************************/
struct fort_cell {
string_buffer_t *str_buffer;
enum CellType cell_type;
};
fort_cell_t *create_cell(void)
{
fort_cell_t *cell = (fort_cell_t *)F_CALLOC(sizeof(fort_cell_t), 1);
if (cell == NULL)
return NULL;
cell->str_buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, CharBuf);
if (cell->str_buffer == NULL) {
F_FREE(cell);
return NULL;
}
cell->cell_type = CommonCell;
return cell;
}
void destroy_cell(fort_cell_t *cell)
{
if (cell == NULL)
return;
destroy_string_buffer(cell->str_buffer);
F_FREE(cell);
}
void set_cell_type(fort_cell_t *cell, enum CellType type)
{
assert(cell);
cell->cell_type = type;
}
enum CellType get_cell_type(const fort_cell_t *cell)
{
assert(cell);
return cell->cell_type;
}
size_t hint_width_cell(const fort_cell_t *cell, const context_t *context)
{
/* todo:
* 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
*/
assert(cell);
assert(context);
size_t cell_padding_left = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_LEFT_PADDING);
size_t cell_padding_right = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_RIGHT_PADDING);
size_t result = cell_padding_left + cell_padding_right;
if (cell->str_buffer && cell->str_buffer->str.data) {
result += buffer_text_width(cell->str_buffer);
}
result = MAX(result, (size_t)get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_MIN_WIDTH));
return result;
}
size_t hint_height_cell(const fort_cell_t *cell, const context_t *context)
{
assert(cell);
assert(context);
size_t cell_padding_top = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_TOP_PADDING);
size_t cell_padding_bottom = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_BOTTOM_PADDING);
size_t cell_empty_string_height = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_EMPTY_STR_HEIGHT);
size_t result = cell_padding_top + cell_padding_bottom;
if (cell->str_buffer && cell->str_buffer->str.data) {
size_t text_height = buffer_text_height(cell->str_buffer);
result += text_height == 0 ? 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, char *buf, size_t buf_len, const context_t *context)
{
const char *space_char = " ";
int (*buffer_printf_)(string_buffer_t *, size_t, char *, size_t, const context_t *) = buffer_printf;
// int (*snprint_n_chars_)(char *, size_t, size_t, char) = snprint_n_chars;
int (*snprint_n_strings_)(char *, size_t, size_t, const char *) = snprint_n_strings;
if (cell == NULL || buf_len == 0
|| (buf_len <= hint_width_cell(cell, context))) {
return -1;
}
unsigned int cell_padding_top = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_TOP_PADDING);
unsigned int cell_padding_left = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_LEFT_PADDING);
unsigned int cell_padding_right = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_RIGHT_PADDING);
if (row >= hint_height_cell(cell, context)
|| row < cell_padding_top
|| row >= (cell_padding_top + buffer_text_height(cell->str_buffer))) {
return snprint_n_strings_(buf, buf_len, buf_len - 1, space_char);
}
int written = 0;
int tmp = 0;
int left = cell_padding_left;
int right = cell_padding_right;
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, left, space_char));
if (cell->str_buffer)
CHCK_RSLT_ADD_TO_WRITTEN(buffer_printf_(cell->str_buffer, row - cell_padding_top, buf + written, buf_len - written - right, context));
else
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, buf_len - written - right, space_char));
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, right, space_char));
return written;
clear:
return -1;
}
#ifdef FT_HAVE_WCHAR
int cell_wprintf(fort_cell_t *cell, size_t row, wchar_t *buf, size_t buf_len, const context_t *context)
{
const char *space_char = " ";
int (*buffer_printf_)(string_buffer_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;
int (*snprint_n_strings_)(wchar_t *, size_t, size_t, const char *) = wsnprint_n_string;
if (cell == NULL || buf_len == 0
|| (buf_len <= hint_width_cell(cell, context))) {
return -1;
}
unsigned int cell_padding_top = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_TOP_PADDING);
unsigned int cell_padding_left = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_LEFT_PADDING);
unsigned int cell_padding_right = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_RIGHT_PADDING);
if (row >= hint_height_cell(cell, context)
|| row < cell_padding_top
|| row >= (cell_padding_top + buffer_text_height(cell->str_buffer))) {
return snprint_n_strings_(buf, buf_len, buf_len - 1, space_char);
}
int written = 0;
int tmp = 0;
int left = cell_padding_left;
int right = cell_padding_right;
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, left, space_char));
if (cell->str_buffer)
CHCK_RSLT_ADD_TO_WRITTEN(buffer_printf_(cell->str_buffer, row - cell_padding_top, buf + written, buf_len - written - right, context));
else
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, buf_len - written - right, space_char));
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, right, space_char));
return written;
clear:
return -1;
}
#endif
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);
}
#ifdef FT_HAVE_WCHAR
fort_status_t fill_cell_from_wstring(fort_cell_t *cell, const wchar_t *str)
{
assert(str);
assert(cell);
return fill_buffer_from_wstring(cell->str_buffer, str);
}
#endif
string_buffer_t *cell_get_string_buffer(fort_cell_t *cell)
{
assert(cell);
assert(cell->str_buffer);
return cell->str_buffer;
}
/********************************************************
End of file "cell.c"
********************************************************/