5904 lines
179 KiB
C
5904 lines
179 KiB
C
/*
|
|
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.
|
|
*/
|
|
|
|
/* The file was GENERATED by an amalgamation script.*/
|
|
/* DO NOT EDIT BY HAND!!! */
|
|
|
|
|
|
#define FT_AMALGAMED_SOURCE /* Macros to make internal libfort functions static */
|
|
|
|
|
|
/********************************************************
|
|
Begin of file "fort_utils.h"
|
|
********************************************************/
|
|
|
|
#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 FT_INTERNAL to make internal libfort functions static
|
|
* in the result amalgamed source file.
|
|
*/
|
|
#ifdef FT_AMALGAMED_SOURCE
|
|
#define FT_INTERNAL static
|
|
#else
|
|
#define FT_INTERNAL
|
|
#endif /* FT_AMALGAMED_SORCE */
|
|
|
|
|
|
#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)
|
|
|
|
|
|
enum PolicyOnNull {
|
|
Create,
|
|
DoNotCreate
|
|
};
|
|
|
|
|
|
enum F_BOOL {
|
|
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_properties;
|
|
struct fort_column_properties;
|
|
struct fort_row;
|
|
struct vector;
|
|
struct fort_cell;
|
|
struct string_buffer;
|
|
struct separator {
|
|
int enabled;
|
|
};
|
|
|
|
typedef struct fort_table_properties fort_table_properties_t;
|
|
struct fort_context {
|
|
fort_table_properties_t *table_properties;
|
|
size_t row;
|
|
size_t column;
|
|
};
|
|
typedef struct fort_context context_t;
|
|
typedef struct fort_column_properties fort_column_properties_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;
|
|
|
|
enum CellType {
|
|
CommonCell,
|
|
GroupMasterCell,
|
|
GroupSlaveCell
|
|
};
|
|
|
|
enum request_geom_type {
|
|
VISIBLE_GEOMETRY,
|
|
INTERN_REPR_GEOMETRY
|
|
};
|
|
|
|
/*****************************************************************************
|
|
* 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);
|
|
|
|
FT_INTERNAL
|
|
void set_memory_funcs(void *(*f_malloc)(size_t size), void (*f_free)(void *ptr));
|
|
|
|
FT_INTERNAL
|
|
char *fort_strdup(const char *str);
|
|
|
|
FT_INTERNAL
|
|
size_t number_of_columns_in_format_string(const char *fmt);
|
|
|
|
#if defined(FT_HAVE_WCHAR)
|
|
FT_INTERNAL
|
|
wchar_t *fort_wcsdup(const wchar_t *str);
|
|
|
|
FT_INTERNAL
|
|
size_t number_of_columns_in_format_wstring(const wchar_t *fmt);
|
|
#endif
|
|
|
|
FT_INTERNAL
|
|
int snprint_n_strings(char *buf, size_t length, size_t n, const char *str);
|
|
|
|
#if defined(FT_HAVE_WCHAR)
|
|
FT_INTERNAL
|
|
int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *str);
|
|
#endif
|
|
|
|
|
|
#define CHCK_RSLT_ADD_TO_WRITTEN(statement) \
|
|
do { \
|
|
tmp = statement; \
|
|
if (tmp < 0) {\
|
|
goto clear; \
|
|
} \
|
|
written += tmp; \
|
|
} while(0)
|
|
|
|
#define CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(statement) \
|
|
do { \
|
|
tmp = statement; \
|
|
if (tmp < 0) {\
|
|
goto clear; \
|
|
} \
|
|
invisible_written += tmp; \
|
|
} while(0)
|
|
|
|
|
|
#define CHECK_NOT_NEGATIVE(x) \
|
|
do { if (x < 0) goto fort_fail; } while (0)
|
|
|
|
#endif /* FORT_IMPL_H */
|
|
|
|
/********************************************************
|
|
End of file "fort_utils.h"
|
|
********************************************************/
|
|
|
|
|
|
/********************************************************
|
|
Begin of file "vector.h"
|
|
********************************************************/
|
|
|
|
#ifndef VECTOR_H
|
|
#define VECTOR_H
|
|
|
|
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
|
|
|
|
|
|
#define INVALID_VEC_INDEX ((size_t) -1)
|
|
|
|
FT_INTERNAL
|
|
vector_t *create_vector(size_t item_size, size_t capacity);
|
|
|
|
FT_INTERNAL
|
|
void destroy_vector(vector_t *);
|
|
|
|
FT_INTERNAL
|
|
size_t vector_size(const vector_t *);
|
|
|
|
FT_INTERNAL
|
|
size_t vector_capacity(const vector_t *);
|
|
|
|
FT_INTERNAL
|
|
int vector_push(vector_t *, const void *item);
|
|
|
|
FT_INTERNAL
|
|
const void *vector_at_c(const vector_t *vector, size_t index);
|
|
|
|
FT_INTERNAL
|
|
void *vector_at(vector_t *, size_t index);
|
|
|
|
FT_INTERNAL
|
|
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))
|
|
|
|
|
|
#ifdef FT_TEST_BUILD
|
|
vector_t *copy_vector(vector_t *);
|
|
size_t vector_index_of(const vector_t *, const void *item);
|
|
int vector_erase(vector_t *, size_t index);
|
|
void vector_clear(vector_t *);
|
|
#endif
|
|
|
|
#endif /* VECTOR_H */
|
|
|
|
/********************************************************
|
|
End of file "vector.h"
|
|
********************************************************/
|
|
|
|
|
|
/********************************************************
|
|
Begin of file "wcwidth.h"
|
|
********************************************************/
|
|
|
|
#ifndef WCWIDTH_H
|
|
#define WCWIDTH_H
|
|
|
|
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
#include <wchar.h>
|
|
|
|
FT_INTERNAL
|
|
int mk_wcswidth(const wchar_t *pwcs, size_t n);
|
|
|
|
#endif /* FT_HAVE_WCHAR */
|
|
|
|
#endif /* WCWIDTH_H */
|
|
|
|
/********************************************************
|
|
End of file "wcwidth.h"
|
|
********************************************************/
|
|
|
|
|
|
/********************************************************
|
|
Begin of file "string_buffer.h"
|
|
********************************************************/
|
|
|
|
#ifndef STRING_BUFFER_H
|
|
#define STRING_BUFFER_H
|
|
|
|
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
|
|
|
|
|
|
/*****************************************************************************
|
|
* STRING BUFFER
|
|
* ***************************************************************************/
|
|
enum str_buf_type {
|
|
CharBuf,
|
|
#ifdef FT_HAVE_WCHAR
|
|
WCharBuf
|
|
#endif /* FT_HAVE_WCHAR */
|
|
};
|
|
|
|
struct string_buffer {
|
|
union {
|
|
char *cstr;
|
|
wchar_t *wstr;
|
|
void *data;
|
|
} str;
|
|
size_t data_sz;
|
|
enum str_buf_type type;
|
|
};
|
|
|
|
FT_INTERNAL
|
|
string_buffer_t *create_string_buffer(size_t number_of_chars, enum str_buf_type type);
|
|
|
|
FT_INTERNAL
|
|
void destroy_string_buffer(string_buffer_t *buffer);
|
|
|
|
FT_INTERNAL
|
|
string_buffer_t *copy_string_buffer(string_buffer_t *buffer);
|
|
|
|
FT_INTERNAL
|
|
fort_status_t realloc_string_buffer_without_copy(string_buffer_t *buffer);
|
|
|
|
FT_INTERNAL
|
|
fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str);
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
FT_INTERNAL
|
|
fort_status_t fill_buffer_from_wstring(string_buffer_t *buffer, const wchar_t *str);
|
|
#endif /* FT_HAVE_WCHAR */
|
|
|
|
FT_INTERNAL
|
|
size_t buffer_text_height(string_buffer_t *buffer);
|
|
|
|
FT_INTERNAL
|
|
size_t string_buffer_capacity(const string_buffer_t *buffer);
|
|
|
|
FT_INTERNAL
|
|
void *buffer_get_data(string_buffer_t *buffer);
|
|
|
|
FT_INTERNAL
|
|
size_t buffer_text_width(const string_buffer_t *buffer);
|
|
|
|
FT_INTERNAL
|
|
int buffer_printf(string_buffer_t *buffer, size_t buffer_row, char *buf, size_t total_buf_len,
|
|
const context_t *context, const char *content_style_tag, const char *reset_content_style_tag);
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
FT_INTERNAL
|
|
int buffer_wprintf(string_buffer_t *buffer, size_t buffer_row, wchar_t *buf, size_t total_buf_len,
|
|
const context_t *context, const char *content_style_tag, const char *reset_content_style_tag);
|
|
#endif /* FT_HAVE_WCHAR */
|
|
|
|
#endif /* STRING_BUFFER_H */
|
|
|
|
/********************************************************
|
|
End of file "string_buffer.h"
|
|
********************************************************/
|
|
|
|
|
|
/********************************************************
|
|
Begin of file "properties.h"
|
|
********************************************************/
|
|
|
|
#ifndef PROPERTIES_H
|
|
#define PROPERTIES_H
|
|
|
|
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
|
|
#include <stdint.h>
|
|
#include <limits.h>
|
|
|
|
#define PROP_IS_SET(ft_props, property) ((ft_props) & (property))
|
|
#define PROP_SET(ft_props, property) ((ft_props) |=(property))
|
|
#define PROP_UNSET(ft_props, property) ((ft_props) &= ~((uint32_t)property))
|
|
|
|
#define TEXT_STYLE_TAG_MAX_SIZE 64
|
|
|
|
FT_INTERNAL
|
|
void get_style_tag_for_cell(const fort_table_properties_t *props,
|
|
size_t row, size_t col, char *style_tag, size_t sz);
|
|
|
|
FT_INTERNAL
|
|
void get_reset_style_tag_for_cell(const fort_table_properties_t *props,
|
|
size_t row, size_t col, char *style_tag, size_t sz);
|
|
|
|
FT_INTERNAL
|
|
void get_style_tag_for_content(const fort_table_properties_t *props,
|
|
size_t row, size_t col, char *style_tag, size_t sz);
|
|
|
|
FT_INTERNAL
|
|
void get_reset_style_tag_for_content(const fort_table_properties_t *props,
|
|
size_t row, size_t col, char *style_tag, size_t sz);
|
|
|
|
|
|
struct fort_cell_props {
|
|
size_t cell_row;
|
|
size_t cell_col;
|
|
uint32_t properties;
|
|
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;
|
|
unsigned int content_fg_color_number;
|
|
unsigned int content_bg_color_number;
|
|
unsigned int cell_bg_color_number;
|
|
enum ft_text_style cell_text_style;
|
|
enum ft_text_style content_text_style;
|
|
};
|
|
|
|
typedef struct fort_cell_props fort_cell_props_t;
|
|
typedef vector_t fort_cell_prop_container_t;
|
|
|
|
FT_INTERNAL
|
|
fort_cell_prop_container_t *create_cell_prop_container(void);
|
|
|
|
FT_INTERNAL
|
|
void destroy_cell_prop_container(fort_cell_prop_container_t *cont);
|
|
|
|
FT_INTERNAL
|
|
const fort_cell_props_t *cget_cell_prop(const fort_cell_prop_container_t *cont, size_t row, size_t col);
|
|
|
|
FT_INTERNAL
|
|
fort_cell_props_t *get_cell_prop_and_create_if_not_exists(fort_cell_prop_container_t *cont, size_t row, size_t col);
|
|
|
|
FT_INTERNAL
|
|
fort_status_t set_cell_property(fort_cell_prop_container_t *cont, size_t row, size_t col, uint32_t property, int value);
|
|
|
|
FT_INTERNAL
|
|
int get_cell_property_value_hierarcial(const fort_table_properties_t *properties, size_t row, size_t column, uint32_t property);
|
|
|
|
FT_INTERNAL
|
|
fort_status_t set_default_cell_property(uint32_t property, int value);
|
|
|
|
|
|
/* TABLE BORDER DESRIPTION
|
|
*
|
|
*
|
|
* TL TT TT TT TV TT TT TT TT TT TT TT TR
|
|
* LL IV RR
|
|
* LL IV RR
|
|
* LH IH IH IH II IH IH IH TI IH IH IH RH
|
|
* LL IV IV RR
|
|
* LL IV IV RR
|
|
* LL LI IH IH IH RI RH
|
|
* LL IV IV RR
|
|
* LL IV IV RR
|
|
* LH IH IH IH BI IH IH IH II IH IH IH RH
|
|
* LL IV RR
|
|
* LL IV RR
|
|
* BL BB BB BB BV BB BB BB BV BB BB BB BR
|
|
*/
|
|
|
|
|
|
/* HORIZONTAL SEPARATOR DESCRIPTION
|
|
*
|
|
*
|
|
* TL TT TT TT TV TT TT TT TV TT TT TT TR <----- TopSeparator
|
|
* LL IV IV RR
|
|
* LH IH IH IH II IH IH IH II IH IH IH RH <----- InsideSeparator
|
|
* LL IV IV RR
|
|
* BL BB BB BB BV BB BB BB BV BB BB BB BR <----- BottomSeparator
|
|
*/
|
|
|
|
enum HorSeparatorPos {
|
|
TopSeparator,
|
|
InsideSeparator,
|
|
BottomSeparator
|
|
};
|
|
|
|
enum BorderItemPos {
|
|
TL_bip = 0,
|
|
TT_bip = 1,
|
|
TV_bip = 2,
|
|
TR_bip = 3,
|
|
|
|
LL_bip = 4,
|
|
IV_bip = 5,
|
|
RR_bip = 6,
|
|
|
|
LH_bip = 7,
|
|
IH_bip = 8,
|
|
II_bip = 9,
|
|
RH_bip = 10,
|
|
|
|
BL_bip = 11,
|
|
BB_bip = 12,
|
|
BV_bip = 13,
|
|
BR_bip = 14,
|
|
|
|
LI_bip = 15,
|
|
TI_bip = 16,
|
|
RI_bip = 17,
|
|
BI_bip = 18,
|
|
|
|
BorderItemPosSize
|
|
};
|
|
|
|
|
|
enum SeparatorItemPos {
|
|
LH_sip = 0,
|
|
IH_sip = 1,
|
|
II_sip = 2,
|
|
RH_sip = 3,
|
|
|
|
TI_sip = 4,
|
|
BI_sip = 5,
|
|
|
|
SepratorItemPosSize
|
|
};
|
|
|
|
|
|
struct fort_border_style {
|
|
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_BASIC2_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_NICE_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;
|
|
|
|
|
|
struct fort_entire_table_properties {
|
|
unsigned int left_margin;
|
|
unsigned int top_margin;
|
|
unsigned int right_margin;
|
|
unsigned int bottom_margin;
|
|
};
|
|
typedef struct fort_entire_table_properties fort_entire_table_properties_t;
|
|
extern fort_entire_table_properties_t g_entire_table_properties;
|
|
|
|
FT_INTERNAL
|
|
fort_status_t set_entire_table_property(fort_table_properties_t *table_properties, uint32_t property, int value);
|
|
|
|
FT_INTERNAL
|
|
fort_status_t set_default_entire_table_property(uint32_t property, int value);
|
|
|
|
struct fort_table_properties {
|
|
struct fort_border_style border_style;
|
|
fort_cell_prop_container_t *cell_properties;
|
|
fort_entire_table_properties_t entire_table_properties;
|
|
};
|
|
extern fort_table_properties_t g_table_properties;
|
|
|
|
FT_INTERNAL
|
|
size_t max_border_elem_strlen(struct fort_table_properties *);
|
|
|
|
FT_INTERNAL
|
|
fort_table_properties_t *create_table_properties(void);
|
|
|
|
FT_INTERNAL
|
|
void destroy_table_properties(fort_table_properties_t *properties);
|
|
|
|
FT_INTERNAL
|
|
fort_table_properties_t *copy_table_properties(const fort_table_properties_t *property);
|
|
|
|
#endif /* PROPERTIES_H */
|
|
|
|
/********************************************************
|
|
End of file "properties.h"
|
|
********************************************************/
|
|
|
|
|
|
/********************************************************
|
|
Begin of file "cell.h"
|
|
********************************************************/
|
|
|
|
#ifndef CELL_H
|
|
#define CELL_H
|
|
|
|
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
|
|
|
|
FT_INTERNAL
|
|
fort_cell_t *create_cell(void);
|
|
|
|
FT_INTERNAL
|
|
void destroy_cell(fort_cell_t *cell);
|
|
|
|
FT_INTERNAL
|
|
fort_cell_t *copy_cell(fort_cell_t *cell);
|
|
|
|
FT_INTERNAL
|
|
size_t hint_width_cell(const fort_cell_t *cell, const context_t *context, enum request_geom_type geom);
|
|
|
|
FT_INTERNAL
|
|
size_t hint_height_cell(const fort_cell_t *cell, const context_t *context);
|
|
|
|
FT_INTERNAL
|
|
void set_cell_type(fort_cell_t *cell, enum CellType type);
|
|
|
|
FT_INTERNAL
|
|
enum CellType get_cell_type(const fort_cell_t *cell);
|
|
|
|
FT_INTERNAL
|
|
int cell_printf(fort_cell_t *cell, size_t row, char *buf, size_t buf_len, const context_t *context);
|
|
|
|
FT_INTERNAL
|
|
fort_status_t fill_cell_from_string(fort_cell_t *cell, const char *str);
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
FT_INTERNAL
|
|
int cell_wprintf(fort_cell_t *cell, size_t row, wchar_t *buf, size_t buf_len, const context_t *context);
|
|
|
|
FT_INTERNAL
|
|
fort_status_t fill_cell_from_wstring(fort_cell_t *cell, const wchar_t *str);
|
|
#endif
|
|
|
|
FT_INTERNAL
|
|
string_buffer_t *cell_get_string_buffer(fort_cell_t *cell);
|
|
|
|
#endif /* CELL_H */
|
|
|
|
/********************************************************
|
|
End of file "cell.h"
|
|
********************************************************/
|
|
|
|
|
|
/********************************************************
|
|
Begin of file "row.h"
|
|
********************************************************/
|
|
|
|
#ifndef ROW_H
|
|
#define ROW_H
|
|
|
|
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
|
|
#include "fort.h"
|
|
#include <stdarg.h>
|
|
/* #include "properties.h" */ /* Commented by amalgamation script */
|
|
#ifdef FT_HAVE_WCHAR
|
|
#include <wchar.h>
|
|
#endif
|
|
|
|
FT_INTERNAL
|
|
fort_row_t *create_row(void);
|
|
|
|
FT_INTERNAL
|
|
void destroy_row(fort_row_t *row);
|
|
|
|
FT_INTERNAL
|
|
fort_row_t *copy_row(fort_row_t *row);
|
|
|
|
FT_INTERNAL
|
|
fort_row_t *create_row_from_string(const char *str);
|
|
|
|
FT_PRINTF_ATTRIBUTE_FORMAT(1, 0)
|
|
FT_INTERNAL
|
|
fort_row_t *create_row_from_fmt_string(const char *fmt, va_list *va_args);
|
|
|
|
FT_INTERNAL
|
|
size_t columns_in_row(const fort_row_t *row);
|
|
|
|
FT_INTERNAL
|
|
fort_cell_t *get_cell(fort_row_t *row, size_t col);
|
|
|
|
FT_INTERNAL
|
|
const fort_cell_t *get_cell_c(const fort_row_t *row, size_t col);
|
|
|
|
FT_INTERNAL
|
|
fort_cell_t *get_cell_and_create_if_not_exists(fort_row_t *row, size_t col);
|
|
|
|
FT_INTERNAL
|
|
fort_status_t swap_row(fort_row_t *cur_row, fort_row_t *ins_row, size_t pos);
|
|
|
|
FT_INTERNAL
|
|
size_t group_cell_number(const fort_row_t *row, size_t master_cell_col);
|
|
|
|
FT_INTERNAL
|
|
int get_row_cell_types(const fort_row_t *row, enum CellType *types, size_t types_sz);
|
|
|
|
FT_INTERNAL
|
|
fort_status_t row_set_cell_span(fort_row_t *row, size_t cell_column, size_t hor_span);
|
|
|
|
FT_INTERNAL
|
|
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);
|
|
|
|
FT_INTERNAL
|
|
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);
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
FT_INTERNAL
|
|
fort_row_t *create_row_from_wstring(const wchar_t *str);
|
|
|
|
FT_INTERNAL
|
|
fort_row_t *create_row_from_fmt_wstring(const wchar_t *fmt, va_list *va_args);
|
|
|
|
FT_INTERNAL
|
|
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);
|
|
|
|
FT_INTERNAL
|
|
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);
|
|
#endif
|
|
|
|
|
|
#endif /* ROW_H */
|
|
|
|
/********************************************************
|
|
End of file "row.h"
|
|
********************************************************/
|
|
|
|
|
|
/********************************************************
|
|
Begin of file "table.h"
|
|
********************************************************/
|
|
|
|
#ifndef TABLE_H
|
|
#define TABLE_H
|
|
|
|
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
|
|
|
|
struct ft_table {
|
|
vector_t *rows;
|
|
fort_table_properties_t *properties;
|
|
string_buffer_t *conv_buffer;
|
|
size_t cur_row;
|
|
size_t cur_col;
|
|
vector_t *separators;
|
|
};
|
|
|
|
FT_INTERNAL
|
|
separator_t *create_separator(int enabled);
|
|
|
|
FT_INTERNAL
|
|
void destroy_separator(separator_t *sep);
|
|
|
|
FT_INTERNAL
|
|
separator_t *copy_separator(separator_t *sep);
|
|
|
|
FT_INTERNAL
|
|
fort_status_t get_table_sizes(const ft_table_t *table, size_t *rows, size_t *cols);
|
|
|
|
FT_INTERNAL
|
|
fort_row_t *get_row(ft_table_t *table, size_t row);
|
|
|
|
FT_INTERNAL
|
|
const fort_row_t *get_row_c(const ft_table_t *table, size_t row);
|
|
|
|
FT_INTERNAL
|
|
fort_row_t *get_row_and_create_if_not_exists(ft_table_t *table, size_t row);
|
|
|
|
FT_INTERNAL
|
|
string_buffer_t *get_cur_str_buffer_and_create_if_not_exists(ft_table_t *table);
|
|
|
|
|
|
FT_INTERNAL
|
|
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,
|
|
enum request_geom_type geom);
|
|
|
|
FT_INTERNAL
|
|
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 "cell.c"
|
|
********************************************************/
|
|
|
|
/* #include "cell.h" */ /* Commented by amalgamation script */
|
|
/* #include "properties.h" */ /* Commented by amalgamation script */
|
|
/* #include "string_buffer.h" */ /* Commented by amalgamation script */
|
|
#include <assert.h>
|
|
|
|
struct fort_cell {
|
|
string_buffer_t *str_buffer;
|
|
enum CellType cell_type;
|
|
};
|
|
|
|
FT_INTERNAL
|
|
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;
|
|
}
|
|
|
|
FT_INTERNAL
|
|
void destroy_cell(fort_cell_t *cell)
|
|
{
|
|
if (cell == NULL)
|
|
return;
|
|
destroy_string_buffer(cell->str_buffer);
|
|
F_FREE(cell);
|
|
}
|
|
|
|
FT_INTERNAL
|
|
fort_cell_t *copy_cell(fort_cell_t *cell)
|
|
{
|
|
assert(cell);
|
|
|
|
fort_cell_t *result = create_cell();
|
|
destroy_string_buffer(result->str_buffer);
|
|
result->str_buffer = copy_string_buffer(cell->str_buffer);
|
|
if (result->str_buffer == NULL) {
|
|
destroy_cell(result);
|
|
return NULL;
|
|
}
|
|
result->cell_type = cell->cell_type;
|
|
return result;
|
|
}
|
|
|
|
FT_INTERNAL
|
|
void set_cell_type(fort_cell_t *cell, enum CellType type)
|
|
{
|
|
assert(cell);
|
|
cell->cell_type = type;
|
|
}
|
|
|
|
FT_INTERNAL
|
|
enum CellType get_cell_type(const fort_cell_t *cell)
|
|
{
|
|
assert(cell);
|
|
return cell->cell_type;
|
|
}
|
|
|
|
FT_INTERNAL
|
|
size_t hint_width_cell(const fort_cell_t *cell, const context_t *context, enum request_geom_type geom)
|
|
{
|
|
/* 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_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_LEFT_PADDING);
|
|
size_t cell_padding_right = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_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_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_MIN_WIDTH));
|
|
|
|
if (geom == INTERN_REPR_GEOMETRY) {
|
|
char cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
|
|
get_style_tag_for_cell(context->table_properties, context->row, context->column, cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
|
|
result += strlen(cell_style_tag);
|
|
|
|
char reset_cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
|
|
get_reset_style_tag_for_cell(context->table_properties, context->row, context->column, reset_cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
|
|
result += strlen(reset_cell_style_tag);
|
|
|
|
char content_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
|
|
get_style_tag_for_content(context->table_properties, context->row, context->column, content_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
|
|
result += strlen(content_style_tag);
|
|
|
|
char reset_content_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
|
|
get_reset_style_tag_for_content(context->table_properties, context->row, context->column, reset_content_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
|
|
result += strlen(reset_content_style_tag);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
FT_INTERNAL
|
|
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_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_TOP_PADDING);
|
|
size_t cell_padding_bottom = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_BOTTOM_PADDING);
|
|
size_t cell_empty_string_height = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_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;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
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 *, const char *, const char *) = buffer_printf;
|
|
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, VISIBLE_GEOMETRY))) {
|
|
return -1;
|
|
}
|
|
|
|
unsigned int cell_padding_top = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_TOP_PADDING);
|
|
unsigned int cell_padding_left = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_LEFT_PADDING);
|
|
unsigned int cell_padding_right = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_RIGHT_PADDING);
|
|
|
|
int written = 0;
|
|
int invisible_written = 0;
|
|
int tmp = 0;
|
|
|
|
/* todo: Dirty hack with changing buf_len! need refactoring. */
|
|
/* Also maybe it is better to move all struff with colors to buffers? */
|
|
char cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
|
|
get_style_tag_for_cell(context->table_properties, context->row, context->column, cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
|
|
buf_len += strlen(cell_style_tag);
|
|
|
|
char reset_cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
|
|
get_reset_style_tag_for_cell(context->table_properties, context->row, context->column, reset_cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
|
|
buf_len += strlen(reset_cell_style_tag);
|
|
|
|
char content_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
|
|
get_style_tag_for_content(context->table_properties, context->row, context->column, content_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
|
|
buf_len += strlen(content_style_tag);
|
|
|
|
char reset_content_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
|
|
get_reset_style_tag_for_content(context->table_properties, context->row, context->column, reset_content_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
|
|
buf_len += strlen(reset_content_style_tag);
|
|
|
|
/* CELL_STYLE_T LEFT_PADDING CONTENT_STYLE_T CONTENT RESET_CONTENT_STYLE_T RIGHT_PADDING RESET_CELL_STYLE_T
|
|
* | | | | | | | |
|
|
* L1 R1
|
|
* L2 R2
|
|
* L3 R3
|
|
*/
|
|
|
|
size_t L2 = cell_padding_left;
|
|
|
|
size_t R2 = cell_padding_right;
|
|
size_t R3 = strlen(reset_cell_style_tag);
|
|
|
|
#define TOTAL_WRITTEN (written + invisible_written)
|
|
#define RIGHT (cell_padding_right + extra_right)
|
|
|
|
#define WRITE_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, cell_style_tag))
|
|
#define WRITE_RESET_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, reset_cell_style_tag))
|
|
#define WRITE_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, content_style_tag))
|
|
#define WRITE_RESET_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, reset_content_style_tag))
|
|
|
|
if (row >= hint_height_cell(cell, context)
|
|
|| row < cell_padding_top
|
|
|| row >= (cell_padding_top + buffer_text_height(cell->str_buffer))) {
|
|
WRITE_CELL_STYLE_TAG;
|
|
WRITE_CONTENT_STYLE_TAG;
|
|
WRITE_RESET_CONTENT_STYLE_TAG;
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len, buf_len - 1 - TOTAL_WRITTEN - R3, space_char));
|
|
WRITE_RESET_CELL_STYLE_TAG;
|
|
return TOTAL_WRITTEN;
|
|
}
|
|
|
|
WRITE_CELL_STYLE_TAG;
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, L2, space_char));
|
|
if (cell->str_buffer) {
|
|
CHCK_RSLT_ADD_TO_WRITTEN(buffer_printf_(cell->str_buffer, row - cell_padding_top, buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN - R2 - R3, context, content_style_tag, reset_content_style_tag));
|
|
} else {
|
|
WRITE_CONTENT_STYLE_TAG;
|
|
WRITE_RESET_CONTENT_STYLE_TAG;
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN - R2 - R3, space_char));
|
|
}
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, R2, space_char));
|
|
WRITE_RESET_CELL_STYLE_TAG;
|
|
|
|
return TOTAL_WRITTEN;
|
|
|
|
clear:
|
|
return -1;
|
|
#undef WRITE_CELL_STYLE_TAG
|
|
#undef WRITE_RESET_CELL_STYLE_TAG
|
|
#undef WRITE_CONTENT_STYLE_TAG
|
|
#undef WRITE_RESET_CONTENT_STYLE_TAG
|
|
#undef TOTAL_WRITTEN
|
|
#undef RIGHT
|
|
}
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
FT_INTERNAL
|
|
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 *, const char *, const char *) = buffer_wprintf;
|
|
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, VISIBLE_GEOMETRY))) {
|
|
return -1;
|
|
}
|
|
|
|
unsigned int cell_padding_top = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_TOP_PADDING);
|
|
unsigned int cell_padding_left = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_LEFT_PADDING);
|
|
unsigned int cell_padding_right = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_RIGHT_PADDING);
|
|
|
|
int written = 0;
|
|
int invisible_written = 0;
|
|
int tmp = 0;
|
|
|
|
/* todo: Dirty hack with changing buf_len! need refactoring. */
|
|
/* Also maybe it is better to move all struff with colors to buffers? */
|
|
char cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
|
|
get_style_tag_for_cell(context->table_properties, context->row, context->column, cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
|
|
buf_len += strlen(cell_style_tag);
|
|
|
|
char reset_cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
|
|
get_reset_style_tag_for_cell(context->table_properties, context->row, context->column, reset_cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
|
|
buf_len += strlen(reset_cell_style_tag);
|
|
|
|
char content_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
|
|
get_style_tag_for_content(context->table_properties, context->row, context->column, content_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
|
|
buf_len += strlen(content_style_tag);
|
|
|
|
char reset_content_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
|
|
get_reset_style_tag_for_content(context->table_properties, context->row, context->column, reset_content_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
|
|
buf_len += strlen(reset_content_style_tag);
|
|
|
|
/* CELL_STYLE_T LEFT_PADDING CONTENT_STYLE_T CONTENT RESET_CONTENT_STYLE_T RIGHT_PADDING RESET_CELL_STYLE_T
|
|
* | | | | | | | |
|
|
* L1 R1
|
|
* L2 R2
|
|
* L3 R3
|
|
*/
|
|
|
|
size_t L2 = cell_padding_left;
|
|
|
|
size_t R2 = cell_padding_right;
|
|
size_t R3 = strlen(reset_cell_style_tag);
|
|
|
|
#define TOTAL_WRITTEN (written + invisible_written)
|
|
#define RIGHT (right + extra_right)
|
|
|
|
#define WRITE_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, cell_style_tag))
|
|
#define WRITE_RESET_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, reset_cell_style_tag))
|
|
#define WRITE_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, content_style_tag))
|
|
#define WRITE_RESET_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, reset_content_style_tag))
|
|
|
|
if (row >= hint_height_cell(cell, context)
|
|
|| row < cell_padding_top
|
|
|| row >= (cell_padding_top + buffer_text_height(cell->str_buffer))) {
|
|
WRITE_CELL_STYLE_TAG;
|
|
WRITE_CONTENT_STYLE_TAG;
|
|
WRITE_RESET_CONTENT_STYLE_TAG;
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len, buf_len - 1 - TOTAL_WRITTEN - R3, space_char));
|
|
WRITE_RESET_CELL_STYLE_TAG;
|
|
return TOTAL_WRITTEN;
|
|
}
|
|
|
|
WRITE_CELL_STYLE_TAG;
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, L2, space_char));
|
|
if (cell->str_buffer) {
|
|
CHCK_RSLT_ADD_TO_WRITTEN(buffer_printf_(cell->str_buffer, row - cell_padding_top, buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN - R2 - R3, context, content_style_tag, reset_content_style_tag));
|
|
} else {
|
|
WRITE_CONTENT_STYLE_TAG;
|
|
WRITE_RESET_CONTENT_STYLE_TAG;
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN - R2 - R3, space_char));
|
|
}
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, R2, space_char));
|
|
WRITE_RESET_CELL_STYLE_TAG;
|
|
|
|
return TOTAL_WRITTEN;
|
|
|
|
clear:
|
|
return -1;
|
|
#undef WRITE_CELL_STYLE_TAG
|
|
#undef WRITE_RESET_CELL_STYLE_TAG
|
|
#undef WRITE_CONTENT_STYLE_TAG
|
|
#undef WRITE_RESET_CONTENT_STYLE_TAG
|
|
#undef TOTAL_WRITTEN
|
|
#undef RIGHT
|
|
}
|
|
#endif
|
|
|
|
FT_INTERNAL
|
|
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
|
|
FT_INTERNAL
|
|
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
|
|
|
|
FT_INTERNAL
|
|
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"
|
|
********************************************************/
|
|
|
|
|
|
/********************************************************
|
|
Begin of file "fort_impl.c"
|
|
********************************************************/
|
|
|
|
/*
|
|
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>
|
|
#include <wchar.h>
|
|
#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 "properties.h" */ /* Commented by amalgamation script */
|
|
|
|
|
|
ft_table_t *ft_create_table(void)
|
|
{
|
|
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->properties = NULL;
|
|
result->conv_buffer = NULL;
|
|
result->cur_row = 0;
|
|
result->cur_col = 0;
|
|
return result;
|
|
}
|
|
|
|
|
|
void ft_destroy_table(ft_table_t *table)
|
|
{
|
|
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_properties(table->properties);
|
|
destroy_string_buffer(table->conv_buffer);
|
|
F_FREE(table);
|
|
}
|
|
|
|
ft_table_t *ft_copy_table(ft_table_t *table)
|
|
{
|
|
if (table == NULL)
|
|
return NULL;
|
|
|
|
ft_table_t *result = ft_create_table();
|
|
if (result == NULL)
|
|
return NULL;
|
|
|
|
size_t rows_n = vector_size(table->rows);
|
|
for (size_t i = 0; i < rows_n; ++i) {
|
|
fort_row_t *row = *(fort_row_t **)vector_at(table->rows, i);
|
|
fort_row_t *new_row = copy_row(row);
|
|
if (new_row == NULL) {
|
|
ft_destroy_table(result);
|
|
return NULL;
|
|
}
|
|
vector_push(result->rows, &new_row);
|
|
}
|
|
|
|
size_t sep_sz = vector_size(table->separators);
|
|
for (size_t i = 0; i < sep_sz; ++i) {
|
|
separator_t *sep = *(separator_t **)vector_at(table->separators, i);
|
|
separator_t *new_sep = copy_separator(sep);
|
|
if (new_sep == NULL) {
|
|
ft_destroy_table(result);
|
|
return NULL;
|
|
}
|
|
vector_push(result->separators, &new_sep);
|
|
}
|
|
|
|
|
|
result->properties = copy_table_properties(table->properties);
|
|
if (result->properties == NULL) {
|
|
ft_destroy_table(result);
|
|
return NULL;
|
|
}
|
|
|
|
/* todo: copy conv_buffer ?? */
|
|
|
|
result->cur_row = table->cur_row;
|
|
result->cur_col = table->cur_col;
|
|
return result;
|
|
}
|
|
|
|
|
|
void ft_ln(ft_table_t *table)
|
|
{
|
|
assert(table);
|
|
table->cur_col = 0;
|
|
table->cur_row++;
|
|
}
|
|
|
|
size_t ft_cur_row(ft_table_t *table)
|
|
{
|
|
assert(table);
|
|
return table->cur_row;
|
|
}
|
|
|
|
size_t ft_cur_col(ft_table_t *table)
|
|
{
|
|
assert(table);
|
|
return table->cur_col;
|
|
}
|
|
|
|
void ft_set_cur_cell(ft_table_t *table, size_t row, size_t col)
|
|
{
|
|
assert(table);
|
|
table->cur_row = row;
|
|
table->cur_col = col;
|
|
}
|
|
|
|
FT_PRINTF_ATTRIBUTE_FORMAT(3, 0)
|
|
static int ft_row_printf_impl(ft_table_t *table, size_t row, const char *fmt, va_list *va)
|
|
{
|
|
#define CREATE_ROW_FROM_FMT_STRING create_row_from_fmt_string
|
|
size_t i = 0;
|
|
size_t new_cols = 0;
|
|
|
|
if (table == NULL)
|
|
return -1;
|
|
|
|
fort_row_t *new_row = CREATE_ROW_FROM_FMT_STRING(fmt, va);
|
|
|
|
if (new_row == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
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;
|
|
|
|
if (FT_IS_ERROR(vector_push(table->rows, &padding_row))) {
|
|
destroy_row(padding_row);
|
|
goto clear;
|
|
}
|
|
}
|
|
}
|
|
/* todo: clearing pushed items in case of error ?? */
|
|
|
|
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);
|
|
|
|
table->cur_col += new_cols;
|
|
destroy_row(new_row);
|
|
return (int)new_cols;
|
|
|
|
clear:
|
|
destroy_row(new_row);
|
|
return -1;
|
|
#undef CREATE_ROW_FROM_FMT_STRING
|
|
}
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
static int ft_row_wprintf_impl(ft_table_t *table, size_t row, const wchar_t *fmt, va_list *va)
|
|
{
|
|
#define CREATE_ROW_FROM_FMT_STRING create_row_from_fmt_wstring
|
|
size_t i = 0;
|
|
size_t new_cols = 0;
|
|
|
|
if (table == NULL)
|
|
return -1;
|
|
|
|
fort_row_t *new_row = CREATE_ROW_FROM_FMT_STRING(fmt, va);
|
|
|
|
if (new_row == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
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;
|
|
|
|
if (FT_IS_ERROR(vector_push(table->rows, &padding_row))) {
|
|
destroy_row(padding_row);
|
|
goto clear;
|
|
}
|
|
}
|
|
}
|
|
/* todo: clearing pushed items in case of error ?? */
|
|
|
|
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);
|
|
|
|
table->cur_col += new_cols;
|
|
destroy_row(new_row);
|
|
return (int)new_cols;
|
|
|
|
clear:
|
|
destroy_row(new_row);
|
|
return -1;
|
|
#undef CREATE_ROW_FROM_FMT_STRING
|
|
}
|
|
#endif
|
|
|
|
#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
|
|
|
|
|
|
|
|
int FT_PRINTF(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);
|
|
va_end(va);
|
|
return result;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
#undef FT_PRINTF
|
|
#undef FT_PRINTF_LN
|
|
#undef FT_HDR_PRINTF
|
|
#undef FT_HDR_PRINTF_LN
|
|
|
|
#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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
va_end(va);
|
|
return result;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
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;
|
|
|
|
int status = fill_buffer_from_string(str_buffer, cell_content);
|
|
if (FT_IS_SUCCESS(status)) {
|
|
table->cur_col++;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
|
|
static int ft_wwrite_impl(ft_table_t *table, const wchar_t *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;
|
|
|
|
int status = fill_buffer_from_wstring(str_buffer, cell_content);
|
|
if (FT_IS_SUCCESS(status)) {
|
|
table->cur_col++;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
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))
|
|
return status;
|
|
|
|
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);
|
|
return status;
|
|
}
|
|
|
|
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;
|
|
|
|
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);
|
|
|
|
ft_ln(table);
|
|
return status;
|
|
}
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
|
|
int ft_nwwrite(ft_table_t *table, size_t n, const wchar_t *cell_content, ...)
|
|
{
|
|
size_t i = 0;
|
|
assert(table);
|
|
int status = ft_wwrite_impl(table, cell_content);
|
|
if (FT_IS_ERROR(status))
|
|
return status;
|
|
|
|
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);
|
|
return status;
|
|
}
|
|
|
|
int ft_nwwrite_ln(ft_table_t *table, size_t n, const wchar_t *cell_content, ...)
|
|
{
|
|
size_t i = 0;
|
|
assert(table);
|
|
int status = ft_wwrite_impl(table, cell_content);
|
|
if (FT_IS_ERROR(status))
|
|
return status;
|
|
|
|
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);
|
|
|
|
ft_ln(table);
|
|
return status;
|
|
}
|
|
#endif
|
|
|
|
|
|
int ft_row_write(ft_table_t *table, size_t cols, const char *cells[])
|
|
{
|
|
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;
|
|
}
|
|
|
|
int ft_row_write_ln(ft_table_t *table, size_t cols, const char *cells[])
|
|
{
|
|
assert(table);
|
|
int status = ft_row_write(table, cols, cells);
|
|
if (FT_IS_SUCCESS(status)) {
|
|
ft_ln(table);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
int ft_row_wwrite(ft_table_t *table, size_t cols, const wchar_t *cells[])
|
|
{
|
|
size_t i = 0;
|
|
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;
|
|
}
|
|
}
|
|
return FT_SUCCESS;
|
|
}
|
|
|
|
int ft_row_wwrite_ln(ft_table_t *table, size_t cols, const wchar_t *cells[])
|
|
{
|
|
assert(table);
|
|
int status = ft_row_wwrite(table, cols, cells);
|
|
if (FT_IS_SUCCESS(status)) {
|
|
ft_ln(table);
|
|
}
|
|
return status;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
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);
|
|
}
|
|
return FT_SUCCESS;
|
|
}
|
|
|
|
int ft_table_write_ln(ft_table_t *table, size_t rows, size_t cols, const char *table_cells[])
|
|
{
|
|
assert(table);
|
|
int status = ft_table_write(table, rows, cols, table_cells);
|
|
if (FT_IS_SUCCESS(status)) {
|
|
ft_ln(table);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
int ft_table_wwrite(ft_table_t *table, size_t rows, size_t cols, const wchar_t *table_cells[])
|
|
{
|
|
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;
|
|
}
|
|
|
|
int ft_table_wwrite_ln(ft_table_t *table, size_t rows, size_t cols, const wchar_t *table_cells[])
|
|
{
|
|
assert(table);
|
|
int status = ft_table_wwrite(table, rows, cols, table_cells);
|
|
if (FT_IS_SUCCESS(status)) {
|
|
ft_ln(table);
|
|
}
|
|
return status;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
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";
|
|
#define EMPTY_STRING ""
|
|
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);
|
|
|
|
/* 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;
|
|
|
|
/* 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);
|
|
|
|
|
|
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, VISIBLE_GEOMETRY);
|
|
if (FT_IS_ERROR(status))
|
|
return NULL;
|
|
|
|
if (rows == 0)
|
|
return EMPTY_STRING;
|
|
|
|
int written = 0;
|
|
int tmp = 0;
|
|
size_t i = 0;
|
|
context_t context;
|
|
context.table_properties = (table->properties ? table->properties : &g_table_properties);
|
|
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);
|
|
|
|
/* Print top margin */
|
|
for (i = 0; i < context.table_properties->entire_table_properties.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));
|
|
}
|
|
|
|
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));
|
|
|
|
/* Print bottom margin */
|
|
for (i = 0; i < context.table_properties->entire_table_properties.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));
|
|
}
|
|
|
|
|
|
F_FREE(col_width_arr);
|
|
F_FREE(row_height_arr);
|
|
return buffer;
|
|
|
|
clear:
|
|
F_FREE(col_width_arr);
|
|
F_FREE(row_height_arr);
|
|
// F_FREE(buffer);
|
|
return NULL;
|
|
#undef EMPTY_STRING
|
|
}
|
|
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
|
|
const wchar_t *ft_to_wstring(const ft_table_t *table)
|
|
{
|
|
typedef wchar_t char_type;
|
|
const enum str_buf_type buf_type = WCharBuf;
|
|
const char *space_char = " ";
|
|
const char *new_line_char = "\n";
|
|
#define EMPTY_STRING L""
|
|
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;
|
|
|
|
|
|
assert(table);
|
|
|
|
/* 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;
|
|
|
|
/* 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);
|
|
|
|
|
|
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, VISIBLE_GEOMETRY);
|
|
|
|
if (rows == 0)
|
|
return EMPTY_STRING;
|
|
|
|
if (FT_IS_ERROR(status))
|
|
return NULL;
|
|
|
|
int written = 0;
|
|
int tmp = 0;
|
|
size_t i = 0;
|
|
context_t context;
|
|
context.table_properties = (table->properties ? table->properties : &g_table_properties);
|
|
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);
|
|
|
|
/* Print top margin */
|
|
for (i = 0; i < context.table_properties->entire_table_properties.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));
|
|
}
|
|
|
|
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));
|
|
|
|
/* Print bottom margin */
|
|
for (i = 0; i < context.table_properties->entire_table_properties.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));
|
|
}
|
|
|
|
F_FREE(col_width_arr);
|
|
F_FREE(row_height_arr);
|
|
return buffer;
|
|
|
|
clear:
|
|
F_FREE(col_width_arr);
|
|
F_FREE(row_height_arr);
|
|
// F_FREE(buffer);
|
|
return NULL;
|
|
#undef EMPTY_STRING
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
int ft_add_separator(ft_table_t *table)
|
|
{
|
|
assert(table);
|
|
assert(table->separators);
|
|
|
|
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))
|
|
return status;
|
|
}
|
|
|
|
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;
|
|
return FT_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
struct ft_border_style *FT_BASIC_STYLE = (struct ft_border_style *) &FORT_BASIC_STYLE;
|
|
struct ft_border_style *FT_BASIC2_STYLE = (struct ft_border_style *) &FORT_BASIC2_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_NICE_STYLE = (struct ft_border_style *) &FORT_NICE_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;
|
|
|
|
|
|
|
|
static void set_border_props_for_props(fort_table_properties_t *properties, const struct ft_border_style *style)
|
|
{
|
|
if ((const struct fort_border_style *)style == &FORT_BASIC_STYLE
|
|
|| (const struct fort_border_style *)style == &FORT_BASIC2_STYLE
|
|
|| (const struct fort_border_style *)style == &FORT_SIMPLE_STYLE
|
|
|| (const struct fort_border_style *)style == &FORT_DOT_STYLE
|
|
|| (const struct fort_border_style *)style == &FORT_PLAIN_STYLE
|
|
|| (const struct fort_border_style *)style == &FORT_EMPTY_STYLE
|
|
|| (const struct fort_border_style *)style == &FORT_SOLID_STYLE
|
|
|| (const struct fort_border_style *)style == &FORT_SOLID_ROUND_STYLE
|
|
|| (const struct fort_border_style *)style == &FORT_NICE_STYLE
|
|
|| (const struct fort_border_style *)style == &FORT_DOUBLE_STYLE
|
|
|| (const struct fort_border_style *)style == &FORT_DOUBLE2_STYLE
|
|
|| (const struct fort_border_style *)style == &FORT_BOLD_STYLE
|
|
|| (const struct fort_border_style *)style == &FORT_BOLD2_STYLE
|
|
|| (const struct fort_border_style *)style == &FORT_FRAME_STYLE) {
|
|
memcpy(&(properties->border_style), (struct fort_border_style *)style, sizeof(struct fort_border_style));
|
|
return;
|
|
}
|
|
|
|
const struct ft_border_chars *border_chs = &(style->border_chs);
|
|
const struct ft_border_chars *header_border_chs = &(style->header_border_chs);
|
|
|
|
#define BOR_CHARS properties->border_style.border_chars
|
|
#define H_BOR_CHARS properties->border_style.header_border_chars
|
|
#define SEP_CHARS properties->border_style.separator_chars
|
|
|
|
/*
|
|
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;
|
|
|
|
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;
|
|
|
|
BOR_CHARS[LI_bip] = BOR_CHARS[TI_bip] = BOR_CHARS[RI_bip] = BOR_CHARS[BI_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";
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
H_BOR_CHARS[LI_bip] = H_BOR_CHARS[TI_bip] = H_BOR_CHARS[RI_bip] = H_BOR_CHARS[BI_bip] = header_border_chs->in_intersect_ch;
|
|
|
|
// 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";
|
|
}
|
|
|
|
SEP_CHARS[LH_sip] = SEP_CHARS[RH_sip] = SEP_CHARS[II_sip] = header_border_chs->out_intersect_ch;
|
|
SEP_CHARS[TI_sip] = SEP_CHARS[BI_sip] = header_border_chs->out_intersect_ch;
|
|
SEP_CHARS[IH_sip] = style->hor_separator_char;
|
|
|
|
|
|
#undef BOR_CHARS
|
|
#undef H_BOR_CHARS
|
|
#undef SEP_CHARS
|
|
}
|
|
|
|
|
|
int ft_set_default_border_style(const struct ft_border_style *style)
|
|
{
|
|
set_border_props_for_props(&g_table_properties, style);
|
|
return FT_SUCCESS;
|
|
}
|
|
|
|
int ft_set_border_style(ft_table_t *table, const struct ft_border_style *style)
|
|
{
|
|
assert(table);
|
|
if (table->properties == NULL) {
|
|
table->properties = create_table_properties();
|
|
if (table->properties == NULL)
|
|
return FT_MEMORY_ERROR;
|
|
}
|
|
set_border_props_for_props(table->properties, style);
|
|
return FT_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
int ft_set_cell_prop(ft_table_t *table, size_t row, size_t col, uint32_t property, int value)
|
|
{
|
|
assert(table);
|
|
|
|
if (table->properties == NULL) {
|
|
table->properties = create_table_properties();
|
|
if (table->properties == NULL)
|
|
return FT_MEMORY_ERROR;
|
|
}
|
|
if (table->properties->cell_properties == NULL) {
|
|
table->properties->cell_properties = create_cell_prop_container();
|
|
if (table->properties->cell_properties == NULL) {
|
|
return FT_ERROR;
|
|
}
|
|
}
|
|
|
|
if (row == FT_CUR_ROW)
|
|
row = table->cur_row;
|
|
if (row == FT_CUR_COLUMN)
|
|
col = table->cur_col;
|
|
|
|
return set_cell_property(table->properties->cell_properties, row, col, property, value);
|
|
}
|
|
|
|
int ft_set_default_cell_prop(uint32_t property, int value)
|
|
{
|
|
return set_default_cell_property(property, value);
|
|
}
|
|
|
|
|
|
int ft_set_default_tbl_prop(uint32_t property, int value)
|
|
{
|
|
return set_default_entire_table_property(property, value);
|
|
}
|
|
|
|
int ft_set_tbl_prop(ft_table_t *table, uint32_t property, int value)
|
|
{
|
|
assert(table);
|
|
|
|
if (table->properties == NULL) {
|
|
table->properties = create_table_properties();
|
|
if (table->properties == NULL)
|
|
return FT_MEMORY_ERROR;
|
|
}
|
|
return set_entire_table_property(table->properties, property, value);
|
|
}
|
|
|
|
void ft_set_memory_funcs(void *(*f_malloc)(size_t size), void (*f_free)(void *ptr))
|
|
{
|
|
set_memory_funcs(f_malloc, f_free);
|
|
}
|
|
|
|
int ft_set_cell_span(ft_table_t *table, size_t row, size_t col, size_t hor_span)
|
|
{
|
|
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;
|
|
|
|
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);
|
|
}
|
|
|
|
/********************************************************
|
|
End of file "fort_impl.c"
|
|
********************************************************/
|
|
|
|
|
|
/********************************************************
|
|
Begin of file "fort_utils.c"
|
|
********************************************************/
|
|
|
|
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
|
|
#ifdef FT_HAVE_WCHAR
|
|
#include <wchar.h>
|
|
#endif
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* LIBFORT helpers
|
|
*****************************************************************************/
|
|
|
|
#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)
|
|
{
|
|
return malloc(size);
|
|
}
|
|
|
|
static void local_free(void *ptr)
|
|
{
|
|
free(ptr);
|
|
}
|
|
|
|
static void *local_calloc(size_t nmemb, size_t size)
|
|
{
|
|
return calloc(nmemb, size);
|
|
}
|
|
|
|
static void *local_realloc(void *ptr, size_t size)
|
|
{
|
|
return realloc(ptr, size);
|
|
}
|
|
|
|
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
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void *new_chunk = F_MALLOC(size);
|
|
if (new_chunk == NULL)
|
|
return NULL;
|
|
|
|
/*
|
|
* 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;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
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 */);
|
|
|
|
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;
|
|
}
|
|
|
|
}
|
|
|
|
FT_INTERNAL
|
|
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;
|
|
}
|
|
|
|
#if defined(FT_HAVE_WCHAR)
|
|
FT_INTERNAL
|
|
wchar_t *fort_wcsdup(const wchar_t *str)
|
|
{
|
|
if (str == NULL)
|
|
return NULL;
|
|
|
|
size_t sz = wcslen(str);
|
|
wchar_t *str_copy = (wchar_t *)F_MALLOC((sz + 1) * sizeof(wchar_t));
|
|
if (str_copy == NULL)
|
|
return NULL;
|
|
|
|
wcscpy(str_copy, str);
|
|
return str_copy;
|
|
}
|
|
#endif
|
|
|
|
|
|
FT_INTERNAL
|
|
size_t number_of_columns_in_format_string(const char *fmt)
|
|
{
|
|
int separator_counter = 0;
|
|
const char *pos = fmt;
|
|
while (1) {
|
|
pos = strchr(pos, FORT_COL_SEPARATOR);
|
|
if (pos == NULL)
|
|
break;
|
|
|
|
separator_counter++;
|
|
++pos;
|
|
}
|
|
return separator_counter + 1;
|
|
}
|
|
|
|
|
|
#if defined(FT_HAVE_WCHAR)
|
|
FT_INTERNAL
|
|
size_t number_of_columns_in_format_wstring(const wchar_t *fmt)
|
|
{
|
|
int separator_counter = 0;
|
|
const wchar_t *pos = fmt;
|
|
while (1) {
|
|
pos = wcschr(pos, FORT_COL_SEPARATOR);
|
|
if (pos == NULL)
|
|
break;
|
|
|
|
separator_counter++;
|
|
++pos;
|
|
}
|
|
return separator_counter + 1;
|
|
}
|
|
#endif
|
|
|
|
|
|
FT_INTERNAL
|
|
int snprint_n_strings(char *buf, size_t length, size_t n, const char *str)
|
|
{
|
|
size_t str_len = strlen(str);
|
|
if (length <= n * str_len)
|
|
return -1;
|
|
|
|
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;
|
|
|
|
if (str_len == 0)
|
|
return 0;
|
|
|
|
int status = snprintf(buf, length, "%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++) = *(str_p++);
|
|
}
|
|
return (int)(n * str_len);
|
|
}
|
|
|
|
|
|
|
|
#if defined(FT_HAVE_WCHAR)
|
|
#define WCS_SIZE 64
|
|
|
|
FT_INTERNAL
|
|
int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *str)
|
|
{
|
|
size_t str_len = strlen(str);
|
|
|
|
/* note: baybe it's, better to return -1 in case of multibyte character
|
|
* strings (not sure this case is done correctly).
|
|
*/
|
|
if (str_len > 1) {
|
|
const unsigned char *p = (const unsigned char *)str;
|
|
while (*p) {
|
|
if (*p <= 127)
|
|
p++;
|
|
else {
|
|
wchar_t wcs[WCS_SIZE];
|
|
const char *ptr = str;
|
|
size_t wcs_len;
|
|
mbstate_t mbst;
|
|
memset(&mbst, 0, sizeof(mbst));
|
|
wcs_len = mbsrtowcs(wcs, (const char **)&ptr, WCS_SIZE, &mbst);
|
|
/* for simplicity */
|
|
if ((wcs_len == (size_t) - 1) || wcs_len > 1) {
|
|
return -1;
|
|
} else {
|
|
wcs[wcs_len] = L'\0';
|
|
size_t k = n;
|
|
while (k) {
|
|
*buf = *wcs;
|
|
++buf;
|
|
--k;
|
|
}
|
|
buf[n] = L'\0';
|
|
return (int)n;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (length <= n * str_len)
|
|
return -1;
|
|
|
|
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;
|
|
|
|
if (str_len == 0)
|
|
return 0;
|
|
|
|
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);
|
|
}
|
|
#endif
|
|
|
|
/********************************************************
|
|
End of file "fort_utils.c"
|
|
********************************************************/
|
|
|
|
|
|
/********************************************************
|
|
Begin of file "properties.c"
|
|
********************************************************/
|
|
|
|
/* #include "fort_utils.h" */ /* Commented by amalgamation script */
|
|
#include <assert.h>
|
|
/* #include "properties.h" */ /* Commented by amalgamation script */
|
|
/* #include "vector.h" */ /* Commented by amalgamation script */
|
|
|
|
#define FT_RESET_COLOR "\033[0m"
|
|
|
|
const char *fg_colors[] = {
|
|
"",
|
|
"\033[30m",
|
|
"\033[31m",
|
|
"\033[32m",
|
|
"\033[33m",
|
|
"\033[34m",
|
|
"\033[35m",
|
|
"\033[36m",
|
|
"\033[37m",
|
|
"\033[90m",
|
|
"\033[91m",
|
|
"\033[92m",
|
|
"\033[93m",
|
|
"\033[94m",
|
|
"\033[95m",
|
|
"\033[96m",
|
|
"\033[97m",
|
|
};
|
|
|
|
const char *reset_fg_colors[] = {
|
|
"",
|
|
"\033[39m",
|
|
"\033[39m",
|
|
"\033[39m",
|
|
"\033[39m",
|
|
"\033[39m",
|
|
"\033[39m",
|
|
"\033[39m",
|
|
"\033[39m",
|
|
"\033[39m",
|
|
"\033[39m",
|
|
"\033[39m",
|
|
"\033[39m",
|
|
"\033[39m",
|
|
"\033[39m",
|
|
"\033[39m",
|
|
"\033[39m",
|
|
};
|
|
|
|
const char *bg_colors[] = {
|
|
"",
|
|
"\033[40m",
|
|
"\033[41m",
|
|
"\033[42m",
|
|
"\033[43m",
|
|
"\033[44m",
|
|
"\033[45m",
|
|
"\033[46m",
|
|
"\033[47m",
|
|
"\033[100m",
|
|
"\033[101m",
|
|
"\033[102m",
|
|
"\033[103m",
|
|
"\033[104m",
|
|
"\033[105m",
|
|
"\033[106m",
|
|
"\033[107m",
|
|
};
|
|
|
|
const char *reset_bg_colors[] = {
|
|
"",
|
|
"\033[49m",
|
|
"\033[49m",
|
|
"\033[49m",
|
|
"\033[49m",
|
|
"\033[49m",
|
|
"\033[49m",
|
|
"\033[49m",
|
|
"\033[49m",
|
|
"\033[49m",
|
|
"\033[49m",
|
|
"\033[49m",
|
|
"\033[49m",
|
|
"\033[49m",
|
|
"\033[49m",
|
|
"\033[49m",
|
|
"\033[49m",
|
|
};
|
|
|
|
|
|
const char *text_styles[] = {
|
|
"",
|
|
"\033[1m",
|
|
"\033[2m",
|
|
"\033[3m",
|
|
"\033[4m",
|
|
"\033[5m",
|
|
"\033[7m",
|
|
"\033[8m",
|
|
};
|
|
|
|
const char *reset_text_styles[] = {
|
|
"",
|
|
"\033[21m",
|
|
"\033[22m",
|
|
"\033[23m",
|
|
"\033[24m",
|
|
"\033[25m",
|
|
"\033[27m",
|
|
"\033[28m",
|
|
};
|
|
|
|
|
|
static const size_t n_fg_colors = sizeof(fg_colors) / sizeof(fg_colors[0]);
|
|
static const size_t n_bg_colors = sizeof(bg_colors) / sizeof(bg_colors[0]);
|
|
static const size_t n_styles = sizeof(text_styles) / sizeof(text_styles[0]);
|
|
|
|
void get_style_tag_for_cell(const fort_table_properties_t *props,
|
|
size_t row, size_t col, char *style_tag, size_t sz)
|
|
{
|
|
(void)sz;
|
|
|
|
unsigned bg_color_number = get_cell_property_value_hierarcial(props, row, col, FT_CPROP_CELL_BG_COLOR);
|
|
unsigned text_style = get_cell_property_value_hierarcial(props, row, col, FT_CPROP_CELL_TEXT_STYLE);
|
|
|
|
style_tag[0] = '\0';
|
|
|
|
if (text_style < (1U << n_styles)) {
|
|
for (size_t i = 0; i < n_styles; ++i) {
|
|
if (text_style & (1 << i)) {
|
|
strcat(style_tag, text_styles[i]);
|
|
}
|
|
}
|
|
} else {
|
|
goto error;
|
|
}
|
|
|
|
if (bg_color_number < n_bg_colors) {
|
|
strcat(style_tag, bg_colors[bg_color_number]);
|
|
} else {
|
|
goto error;
|
|
}
|
|
|
|
return;
|
|
|
|
error:
|
|
// shouldn't be here
|
|
assert(0);
|
|
style_tag[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
void get_reset_style_tag_for_cell(const fort_table_properties_t *props,
|
|
size_t row, size_t col, char *reset_style_tag, size_t sz)
|
|
{
|
|
(void)sz;
|
|
|
|
unsigned bg_color_number = get_cell_property_value_hierarcial(props, row, col, FT_CPROP_CELL_BG_COLOR);
|
|
unsigned text_style = get_cell_property_value_hierarcial(props, row, col, FT_CPROP_CELL_TEXT_STYLE);
|
|
|
|
reset_style_tag[0] = '\0';
|
|
|
|
if (text_style < (1U << n_styles)) {
|
|
for (size_t i = 0; i < n_styles; ++i) {
|
|
if (text_style & (1 << i)) {
|
|
strcat(reset_style_tag, reset_text_styles[i]);
|
|
}
|
|
}
|
|
} else {
|
|
goto error;
|
|
}
|
|
|
|
if (bg_color_number < n_bg_colors) {
|
|
strcat(reset_style_tag, reset_bg_colors[bg_color_number]);
|
|
} else {
|
|
goto error;
|
|
}
|
|
|
|
return;
|
|
|
|
error:
|
|
// shouldn't be here
|
|
assert(0);
|
|
reset_style_tag[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
|
|
void get_style_tag_for_content(const fort_table_properties_t *props,
|
|
size_t row, size_t col, char *style_tag, size_t sz)
|
|
{
|
|
(void)sz;
|
|
|
|
unsigned text_style = get_cell_property_value_hierarcial(props, row, col, FT_CPROP_CONT_TEXT_STYLE);
|
|
unsigned fg_color_number = get_cell_property_value_hierarcial(props, row, col, FT_CPROP_CONT_FG_COLOR);
|
|
unsigned bg_color_number = get_cell_property_value_hierarcial(props, row, col, FT_CPROP_CONT_BG_COLOR);
|
|
|
|
style_tag[0] = '\0';
|
|
|
|
if (text_style < (1U << n_styles)) {
|
|
for (size_t i = 0; i < n_styles; ++i) {
|
|
if (text_style & (1 << i)) {
|
|
strcat(style_tag, text_styles[i]);
|
|
}
|
|
}
|
|
} else {
|
|
goto error;
|
|
}
|
|
|
|
if (fg_color_number < n_fg_colors) {
|
|
strcat(style_tag, fg_colors[fg_color_number]);
|
|
} else {
|
|
goto error;
|
|
}
|
|
|
|
if (bg_color_number < n_bg_colors) {
|
|
strcat(style_tag, bg_colors[bg_color_number]);
|
|
} else {
|
|
goto error;
|
|
}
|
|
|
|
return;
|
|
|
|
error:
|
|
// shouldn't be here
|
|
assert(0);
|
|
style_tag[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
void get_reset_style_tag_for_content(const fort_table_properties_t *props,
|
|
size_t row, size_t col, char *reset_style_tag, size_t sz)
|
|
{
|
|
(void)sz;
|
|
|
|
unsigned text_style = get_cell_property_value_hierarcial(props, row, col, FT_CPROP_CONT_TEXT_STYLE);
|
|
unsigned fg_color_number = get_cell_property_value_hierarcial(props, row, col, FT_CPROP_CONT_FG_COLOR);
|
|
unsigned bg_color_number = get_cell_property_value_hierarcial(props, row, col, FT_CPROP_CONT_BG_COLOR);
|
|
|
|
reset_style_tag[0] = '\0';
|
|
|
|
if (text_style < (1U << n_styles)) {
|
|
for (size_t i = 0; i < n_styles; ++i) {
|
|
if (text_style & (1 << i)) {
|
|
strcat(reset_style_tag, reset_text_styles[i]);
|
|
}
|
|
}
|
|
} else {
|
|
goto error;
|
|
}
|
|
|
|
if (fg_color_number < n_fg_colors) {
|
|
strcat(reset_style_tag, reset_fg_colors[fg_color_number]);
|
|
} else {
|
|
goto error;
|
|
}
|
|
|
|
if (bg_color_number < n_bg_colors) {
|
|
strcat(reset_style_tag, reset_bg_colors[bg_color_number]);
|
|
} else {
|
|
goto error;
|
|
}
|
|
|
|
return;
|
|
|
|
error:
|
|
// shouldn't be here
|
|
assert(0);
|
|
reset_style_tag[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
|
|
struct fort_cell_props g_default_cell_properties = {
|
|
FT_ANY_ROW, /* cell_row */
|
|
FT_ANY_COLUMN, /* cell_col */
|
|
|
|
/* properties */
|
|
FT_CPROP_MIN_WIDTH | FT_CPROP_TEXT_ALIGN | FT_CPROP_TOP_PADDING
|
|
| FT_CPROP_BOTTOM_PADDING | FT_CPROP_LEFT_PADDING | FT_CPROP_RIGHT_PADDING
|
|
| FT_CPROP_EMPTY_STR_HEIGHT | FT_CPROP_CONT_FG_COLOR | FT_CPROP_CELL_BG_COLOR
|
|
| FT_CPROP_CONT_BG_COLOR | FT_CPROP_CELL_TEXT_STYLE | FT_CPROP_CONT_TEXT_STYLE,
|
|
|
|
0, /* col_min_width */
|
|
FT_ALIGNED_LEFT, /* 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 */
|
|
FT_COLOR_DEFAULT, /* content_fg_color_number */
|
|
FT_COLOR_DEFAULT, /* content_bg_color_number */
|
|
FT_COLOR_DEFAULT, /* cell_bg_color_number */
|
|
FT_TSTYLE_DEFAULT, /* cell_text_style */
|
|
FT_TSTYLE_DEFAULT, /* content_text_style */
|
|
};
|
|
|
|
static int get_prop_value_if_exists_otherwise_default(const struct fort_cell_props *cell_opts, uint32_t property)
|
|
{
|
|
if (cell_opts == NULL || !PROP_IS_SET(cell_opts->properties, property)) {
|
|
cell_opts = &g_default_cell_properties;
|
|
}
|
|
|
|
switch (property) {
|
|
case FT_CPROP_MIN_WIDTH:
|
|
return cell_opts->col_min_width;
|
|
case FT_CPROP_TEXT_ALIGN:
|
|
return cell_opts->align;
|
|
case FT_CPROP_TOP_PADDING:
|
|
return cell_opts->cell_padding_top;
|
|
case FT_CPROP_BOTTOM_PADDING:
|
|
return cell_opts->cell_padding_bottom;
|
|
case FT_CPROP_LEFT_PADDING:
|
|
return cell_opts->cell_padding_left;
|
|
case FT_CPROP_RIGHT_PADDING:
|
|
return cell_opts->cell_padding_right;
|
|
case FT_CPROP_EMPTY_STR_HEIGHT:
|
|
return cell_opts->cell_empty_string_height;
|
|
case FT_CPROP_ROW_TYPE:
|
|
return cell_opts->row_type;
|
|
case FT_CPROP_CONT_FG_COLOR:
|
|
return cell_opts->content_fg_color_number;
|
|
case FT_CPROP_CONT_BG_COLOR:
|
|
return cell_opts->content_bg_color_number;
|
|
case FT_CPROP_CELL_BG_COLOR:
|
|
return cell_opts->cell_bg_color_number;
|
|
case FT_CPROP_CELL_TEXT_STYLE:
|
|
return cell_opts->cell_text_style;
|
|
case FT_CPROP_CONT_TEXT_STYLE:
|
|
return cell_opts->content_text_style;
|
|
default:
|
|
/* todo: implement later */
|
|
exit(333);
|
|
}
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
fort_cell_prop_container_t *create_cell_prop_container(void)
|
|
{
|
|
fort_cell_prop_container_t *ret = create_vector(sizeof(fort_cell_props_t), DEFAULT_VECTOR_CAPACITY);
|
|
return ret;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
void destroy_cell_prop_container(fort_cell_prop_container_t *cont)
|
|
{
|
|
if (cont)
|
|
destroy_vector(cont);
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
const fort_cell_props_t *cget_cell_prop(const fort_cell_prop_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_props_t *opt = (const fort_cell_props_t *)vector_at_c(cont, i);
|
|
if (opt->cell_row == row && opt->cell_col == col)
|
|
return opt;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
fort_cell_props_t *get_cell_prop_and_create_if_not_exists(fort_cell_prop_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_props_t *opt = (fort_cell_props_t *)vector_at(cont, i);
|
|
if (opt->cell_row == row && opt->cell_col == col)
|
|
return opt;
|
|
}
|
|
|
|
fort_cell_props_t opt;
|
|
if (row == FT_ANY_ROW && col == FT_ANY_COLUMN)
|
|
memcpy(&opt, &g_default_cell_properties, sizeof(fort_cell_props_t));
|
|
else
|
|
memset(&opt, 0, sizeof(fort_cell_props_t));
|
|
|
|
opt.cell_row = row;
|
|
opt.cell_col = col;
|
|
if (FT_IS_SUCCESS(vector_push(cont, &opt))) {
|
|
return (fort_cell_props_t *)vector_at(cont, sz);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
int get_cell_property_value_hierarcial(const fort_table_properties_t *propertiess, size_t row, size_t column, uint32_t property)
|
|
{
|
|
assert(propertiess);
|
|
size_t row_origin = row;
|
|
|
|
const fort_cell_props_t *opt = NULL;
|
|
if (propertiess->cell_properties != NULL) {
|
|
while (1) {
|
|
opt = cget_cell_prop(propertiess->cell_properties, row, column);
|
|
if (opt != NULL && PROP_IS_SET(opt->properties, property))
|
|
break;
|
|
|
|
if (row != FT_ANY_ROW && column != FT_ANY_COLUMN) {
|
|
row = FT_ANY_ROW;
|
|
continue;
|
|
} else if (row == FT_ANY_ROW && column != FT_ANY_COLUMN) {
|
|
row = row_origin;
|
|
column = FT_ANY_COLUMN;
|
|
continue;
|
|
} else if (row != FT_ANY_ROW && column == FT_ANY_COLUMN) {
|
|
row = FT_ANY_ROW;
|
|
column = FT_ANY_COLUMN;
|
|
continue;
|
|
}
|
|
|
|
opt = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return get_prop_value_if_exists_otherwise_default(opt, property);
|
|
}
|
|
|
|
|
|
static fort_status_t set_cell_property_impl(fort_cell_props_t *opt, uint32_t property, int value)
|
|
{
|
|
assert(opt);
|
|
|
|
PROP_SET(opt->properties, property);
|
|
if (PROP_IS_SET(property, FT_CPROP_MIN_WIDTH)) {
|
|
CHECK_NOT_NEGATIVE(value);
|
|
opt->col_min_width = value;
|
|
} else if (PROP_IS_SET(property, FT_CPROP_TEXT_ALIGN)) {
|
|
opt->align = (enum ft_text_alignment)value;
|
|
} else if (PROP_IS_SET(property, FT_CPROP_TOP_PADDING)) {
|
|
CHECK_NOT_NEGATIVE(value);
|
|
opt->cell_padding_top = value;
|
|
} else if (PROP_IS_SET(property, FT_CPROP_BOTTOM_PADDING)) {
|
|
CHECK_NOT_NEGATIVE(value);
|
|
opt->cell_padding_bottom = value;
|
|
} else if (PROP_IS_SET(property, FT_CPROP_LEFT_PADDING)) {
|
|
CHECK_NOT_NEGATIVE(value);
|
|
opt->cell_padding_left = value;
|
|
} else if (PROP_IS_SET(property, FT_CPROP_RIGHT_PADDING)) {
|
|
CHECK_NOT_NEGATIVE(value);
|
|
opt->cell_padding_right = value;
|
|
} else if (PROP_IS_SET(property, FT_CPROP_EMPTY_STR_HEIGHT)) {
|
|
CHECK_NOT_NEGATIVE(value);
|
|
opt->cell_empty_string_height = value;
|
|
} else if (PROP_IS_SET(property, FT_CPROP_ROW_TYPE)) {
|
|
opt->row_type = (enum ft_row_type)value;
|
|
} else if (PROP_IS_SET(property, FT_CPROP_CONT_FG_COLOR)) {
|
|
opt->content_fg_color_number = value;
|
|
} else if (PROP_IS_SET(property, FT_CPROP_CONT_BG_COLOR)) {
|
|
opt->content_bg_color_number = value;
|
|
} else if (PROP_IS_SET(property, FT_CPROP_CELL_BG_COLOR)) {
|
|
opt->cell_bg_color_number = value;
|
|
} else if (PROP_IS_SET(property, FT_CPROP_CELL_TEXT_STYLE)) {
|
|
enum ft_text_style v = (enum ft_text_style)value;
|
|
if (v == FT_TSTYLE_DEFAULT) {
|
|
opt->cell_text_style = FT_TSTYLE_DEFAULT;
|
|
} else {
|
|
opt->cell_text_style |= v;
|
|
}
|
|
} else if (PROP_IS_SET(property, FT_CPROP_CONT_TEXT_STYLE)) {
|
|
enum ft_text_style v = (enum ft_text_style)value;
|
|
if (v == FT_TSTYLE_DEFAULT) {
|
|
opt->content_text_style = v;
|
|
} else {
|
|
opt->content_text_style |= v;
|
|
}
|
|
}
|
|
|
|
return FT_SUCCESS;
|
|
|
|
fort_fail:
|
|
return FT_EINVAL;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
fort_status_t set_cell_property(fort_cell_prop_container_t *cont, size_t row, size_t col, uint32_t property, int value)
|
|
{
|
|
fort_cell_props_t *opt = get_cell_prop_and_create_if_not_exists(cont, row, col);
|
|
if (opt == NULL)
|
|
return FT_ERROR;
|
|
|
|
return set_cell_property_impl(opt, property, value);
|
|
/*
|
|
PROP_SET(opt->propertiess, property);
|
|
if (PROP_IS_SET(property, FT_CPROP_MIN_WIDTH)) {
|
|
opt->col_min_width = value;
|
|
} else if (PROP_IS_SET(property, FT_CPROP_TEXT_ALIGN)) {
|
|
opt->align = value;
|
|
}
|
|
|
|
return FT_SUCCESS;
|
|
*/
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
fort_status_t set_default_cell_property(uint32_t property, int value)
|
|
{
|
|
return set_cell_property_impl(&g_default_cell_properties, property, value);
|
|
}
|
|
|
|
|
|
#define BASIC_STYLE { \
|
|
/* border_chars */ \
|
|
{ \
|
|
"+", "-", "+", "+", \
|
|
"|", "|", "|", \
|
|
"\0", "\0", "\0", "\0", \
|
|
"+", "-", "+", "+", \
|
|
"+", "+", "+", "+", \
|
|
}, \
|
|
/* header_border_chars */ \
|
|
{ \
|
|
"+", "-", "+", "+", \
|
|
"|", "|", "|", \
|
|
"+", "-", "+", "+", \
|
|
"+", "-", "+", "+", \
|
|
"+", "+", "+", "+", \
|
|
}, \
|
|
/* separator_chars */ \
|
|
{ \
|
|
"+", "-", "+", "+", \
|
|
"+", "+", \
|
|
}, \
|
|
}
|
|
|
|
#define BASIC2_STYLE { \
|
|
/* border_chars */ \
|
|
{ \
|
|
"+", "-", "+", "+", \
|
|
"|", "|", "|", \
|
|
"+", "-", "+", "+", \
|
|
"+", "-", "+", "+", \
|
|
"+", "+", "+", "+", \
|
|
}, \
|
|
/* 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 NICE_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_BASIC2_STYLE = BASIC2_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_NICE_STYLE = NICE_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_properties_t g_entire_table_properties = {
|
|
0, /* left_margin */
|
|
0, /* top_margin */
|
|
0, /* right_margin */
|
|
0, /* bottom_margin */
|
|
};
|
|
|
|
static fort_status_t set_entire_table_property_internal(fort_entire_table_properties_t *properties, uint32_t property, int value)
|
|
{
|
|
assert(properties);
|
|
CHECK_NOT_NEGATIVE(value);
|
|
if (PROP_IS_SET(property, FT_TPROP_LEFT_MARGIN)) {
|
|
properties->left_margin = value;
|
|
} else if (PROP_IS_SET(property, FT_TPROP_TOP_MARGIN)) {
|
|
properties->top_margin = value;
|
|
} else if (PROP_IS_SET(property, FT_TPROP_RIGHT_MARGIN)) {
|
|
properties->right_margin = value;
|
|
} else if (PROP_IS_SET(property, FT_TPROP_BOTTOM_MARGIN)) {
|
|
properties->bottom_margin = value;
|
|
} else {
|
|
return FT_EINVAL;
|
|
}
|
|
return FT_SUCCESS;
|
|
|
|
fort_fail:
|
|
return FT_EINVAL;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
fort_status_t set_entire_table_property(fort_table_properties_t *table_properties, uint32_t property, int value)
|
|
{
|
|
assert(table_properties);
|
|
return set_entire_table_property_internal(&table_properties->entire_table_properties, property, value);
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
fort_status_t set_default_entire_table_property(uint32_t property, int value)
|
|
{
|
|
return set_entire_table_property_internal(&g_entire_table_properties, property, value);
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
size_t max_border_elem_strlen(struct fort_table_properties *properties)
|
|
{
|
|
assert(properties);
|
|
size_t result = 1;
|
|
int i = 0;
|
|
for (i = 0; i < BorderItemPosSize; ++i) {
|
|
result = MAX(result, strlen(properties->border_style.border_chars[i]));
|
|
}
|
|
|
|
i = 0;
|
|
for (i = 0; i < BorderItemPosSize; ++i) {
|
|
result = MAX(result, strlen(properties->border_style.header_border_chars[i]));
|
|
}
|
|
|
|
i = 0;
|
|
for (i = 0; i < SepratorItemPosSize; ++i) {
|
|
result = MAX(result, strlen(properties->border_style.separator_chars[i]));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
fort_table_properties_t g_table_properties = {
|
|
/* border_style */
|
|
BASIC_STYLE,
|
|
NULL, /* cell_properties */
|
|
/* entire_table_properties */
|
|
{
|
|
0, /* left_margin */
|
|
0, /* top_margin */
|
|
0, /* right_margin */
|
|
0 /* bottom_margin */
|
|
}
|
|
};
|
|
|
|
|
|
FT_INTERNAL
|
|
fort_table_properties_t *create_table_properties(void)
|
|
{
|
|
fort_table_properties_t *properties = (fort_table_properties_t *)F_CALLOC(sizeof(fort_table_properties_t), 1);
|
|
if (properties == NULL) {
|
|
return NULL;
|
|
}
|
|
memcpy(properties, &g_table_properties, sizeof(fort_table_properties_t));
|
|
properties->cell_properties = create_cell_prop_container();
|
|
if (properties->cell_properties == NULL) {
|
|
destroy_table_properties(properties);
|
|
return NULL;
|
|
}
|
|
memcpy(&properties->entire_table_properties, &g_entire_table_properties, sizeof(fort_entire_table_properties_t));
|
|
return properties;
|
|
}
|
|
|
|
FT_INTERNAL
|
|
void destroy_table_properties(fort_table_properties_t *properties)
|
|
{
|
|
if (properties == NULL)
|
|
return;
|
|
|
|
if (properties->cell_properties != NULL) {
|
|
destroy_cell_prop_container(properties->cell_properties);
|
|
}
|
|
F_FREE(properties);
|
|
}
|
|
|
|
static
|
|
fort_cell_prop_container_t *copy_cell_properties(fort_cell_prop_container_t *cont)
|
|
{
|
|
fort_cell_prop_container_t *result = create_cell_prop_container();
|
|
if (result == NULL)
|
|
return NULL;
|
|
|
|
size_t sz = vector_size(cont);
|
|
for (size_t i = 0; i < sz; ++i) {
|
|
fort_cell_props_t *opt = (fort_cell_props_t *)vector_at(cont, i);
|
|
if (FT_IS_ERROR(vector_push(result, opt))) {
|
|
destroy_cell_prop_container(result);
|
|
return NULL;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
FT_INTERNAL
|
|
fort_table_properties_t *copy_table_properties(const fort_table_properties_t *properties)
|
|
{
|
|
fort_table_properties_t *new_opt = create_table_properties();
|
|
if (new_opt == NULL)
|
|
return NULL;
|
|
|
|
destroy_vector(new_opt->cell_properties);
|
|
new_opt->cell_properties = copy_cell_properties(properties->cell_properties);
|
|
if (new_opt->cell_properties == NULL) {
|
|
destroy_table_properties(new_opt);
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(&new_opt->border_style, &properties->border_style, sizeof(struct fort_border_style));
|
|
memcpy(&new_opt->entire_table_properties,
|
|
&properties->entire_table_properties, sizeof(fort_entire_table_properties_t));
|
|
|
|
return new_opt;
|
|
}
|
|
|
|
/********************************************************
|
|
End of file "properties.c"
|
|
********************************************************/
|
|
|
|
|
|
/********************************************************
|
|
Begin of file "row.c"
|
|
********************************************************/
|
|
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
/* #include "row.h" */ /* Commented by amalgamation script */
|
|
/* #include "cell.h" */ /* Commented by amalgamation script */
|
|
/* #include "string_buffer.h" */ /* Commented by amalgamation script */
|
|
/* #include "vector.h" */ /* Commented by amalgamation script */
|
|
|
|
|
|
struct fort_row {
|
|
vector_t *cells;
|
|
/*enum ft_row_type type;*/
|
|
};
|
|
|
|
|
|
FT_INTERNAL
|
|
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;
|
|
}
|
|
|
|
FT_INTERNAL
|
|
void destroy_row(fort_row_t *row)
|
|
{
|
|
if (row == NULL)
|
|
return;
|
|
|
|
if (row->cells) {
|
|
size_t cells_n = vector_size(row->cells);
|
|
for (size_t i = 0; i < cells_n; ++i) {
|
|
fort_cell_t *cell = *(fort_cell_t **)vector_at(row->cells, i);
|
|
destroy_cell(cell);
|
|
}
|
|
destroy_vector(row->cells);
|
|
}
|
|
|
|
F_FREE(row);
|
|
}
|
|
|
|
FT_INTERNAL
|
|
fort_row_t *copy_row(fort_row_t *row)
|
|
{
|
|
assert(row);
|
|
fort_row_t *result = create_row();
|
|
if (result == NULL)
|
|
return NULL;
|
|
|
|
size_t cols_n = vector_size(row->cells);
|
|
for (size_t i = 0; i < cols_n; ++i) {
|
|
fort_cell_t *cell = *(fort_cell_t **)vector_at(row->cells, i);
|
|
fort_cell_t *new_cell = copy_cell(cell);
|
|
if (new_cell == NULL) {
|
|
destroy_row(result);
|
|
return NULL;
|
|
}
|
|
vector_push(result->cells, &new_cell);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
FT_INTERNAL
|
|
size_t columns_in_row(const fort_row_t *row)
|
|
{
|
|
if (row == NULL || row->cells == NULL)
|
|
return 0;
|
|
|
|
return vector_size(row->cells);
|
|
}
|
|
|
|
|
|
static
|
|
fort_cell_t *get_cell_implementation(fort_row_t *row, size_t col, enum PolicyOnNull policy)
|
|
{
|
|
if (row == NULL || row->cells == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
fort_cell_t *get_cell(fort_row_t *row, size_t col)
|
|
{
|
|
return get_cell_implementation(row, col, DoNotCreate);
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
const fort_cell_t *get_cell_c(const fort_row_t *row, size_t col)
|
|
{
|
|
return get_cell((fort_row_t *)row, col);
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
fort_cell_t *get_cell_and_create_if_not_exists(fort_row_t *row, size_t col)
|
|
{
|
|
return get_cell_implementation(row, col, Create);
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
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);
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
size_t group_cell_number(const fort_row_t *row, size_t master_cell_col)
|
|
{
|
|
assert(row);
|
|
const fort_cell_t *master_cell = get_cell_c(row, master_cell_col);
|
|
if (master_cell == NULL)
|
|
return 0;
|
|
|
|
if (get_cell_type(master_cell) != GroupMasterCell)
|
|
return 1;
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
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;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
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;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
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_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 = (enum CellType *)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_property_value_hierarcial(context->table_properties, context->row, FT_ANY_COLUMN, FT_CPROP_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_property_value_hierarcial(context->table_properties, context->row - 1, FT_ANY_COLUMN, FT_CPROP_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_properties->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_properties->border_style.header_border_chars;
|
|
}
|
|
|
|
if (sep && sep->enabled) {
|
|
L = &(context->table_properties->border_style.separator_chars[LH_sip]);
|
|
I = &(context->table_properties->border_style.separator_chars[IH_sip]);
|
|
IV = &(context->table_properties->border_style.separator_chars[II_sip]);
|
|
R = &(context->table_properties->border_style.separator_chars[RH_sip]);
|
|
|
|
IT = &(context->table_properties->border_style.separator_chars[TI_sip]);
|
|
IB = &(context->table_properties->border_style.separator_chars[BI_sip]);
|
|
II = &(context->table_properties->border_style.separator_chars[IH_sip]);
|
|
|
|
if (lower_row == NULL) {
|
|
L = &(*border_chars)[BL_bip];
|
|
R = &(*border_chars)[BR_bip];
|
|
} else if (upper_row == NULL) {
|
|
L = &(*border_chars)[TL_bip];
|
|
R = &(*border_chars)[TR_bip];
|
|
}
|
|
} 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];
|
|
IT = &(*border_chars)[TI_bip];
|
|
IB = &(*border_chars)[BI_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;
|
|
}
|
|
}
|
|
|
|
size_t i = 0;
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* Print left margin */
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, context->table_properties->entire_table_properties.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_properties->entire_table_properties.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;
|
|
}
|
|
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
FT_INTERNAL
|
|
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_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 = (enum CellType *)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_property_value_hierarcial(context->table_properties, context->row, FT_ANY_COLUMN, FT_CPROP_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_property_value_hierarcial(context->table_properties, context->row - 1, FT_ANY_COLUMN, FT_CPROP_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_properties->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_properties->border_style.header_border_chars;
|
|
}
|
|
|
|
if (sep && sep->enabled) {
|
|
L = &(context->table_properties->border_style.separator_chars[LH_sip]);
|
|
I = &(context->table_properties->border_style.separator_chars[IH_sip]);
|
|
IV = &(context->table_properties->border_style.separator_chars[II_sip]);
|
|
R = &(context->table_properties->border_style.separator_chars[RH_sip]);
|
|
|
|
IT = &(context->table_properties->border_style.separator_chars[TI_sip]);
|
|
IB = &(context->table_properties->border_style.separator_chars[BI_sip]);
|
|
II = &(context->table_properties->border_style.separator_chars[IH_sip]);
|
|
|
|
if (lower_row == NULL) {
|
|
L = &(*border_chars)[BL_bip];
|
|
R = &(*border_chars)[BR_bip];
|
|
} else if (upper_row == NULL) {
|
|
L = &(*border_chars)[TL_bip];
|
|
R = &(*border_chars)[TR_bip];
|
|
}
|
|
} 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];
|
|
IT = &(*border_chars)[TI_bip];
|
|
IB = &(*border_chars)[BI_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;
|
|
}
|
|
}
|
|
|
|
size_t i = 0;
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* Print left margin */
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buffer + written, buffer_sz - written, context->table_properties->entire_table_properties.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_properties->entire_table_properties.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;
|
|
}
|
|
|
|
#endif
|
|
|
|
FT_INTERNAL
|
|
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
|
|
FT_INTERNAL
|
|
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
|
|
|
|
FT_INTERNAL
|
|
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
|
|
#define FILL_CELL_FROM_STRING fill_cell_from_string
|
|
#define STR_BUF_TYPE CharBuf
|
|
|
|
string_buffer_t *buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, STR_BUF_TYPE);
|
|
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;
|
|
}
|
|
|
|
if (cols_origin == 1) {
|
|
fort_row_t *row = create_row();
|
|
if (row == NULL) {
|
|
goto clear;
|
|
}
|
|
|
|
fort_cell_t *cell = get_cell_and_create_if_not_exists(row, 0);
|
|
if (cell == NULL) {
|
|
destroy_row(row);
|
|
goto clear;
|
|
}
|
|
|
|
fort_status_t result = FILL_CELL_FROM_STRING(cell, buffer->str.STR_FILED);
|
|
if (FT_IS_ERROR(result)) {
|
|
destroy_row(row);
|
|
goto clear;
|
|
}
|
|
|
|
destroy_string_buffer(buffer);
|
|
return row;
|
|
}
|
|
|
|
/*
|
|
* todo: add processing of cols != cols_origin in a general way
|
|
* (when cols_origin != 1).
|
|
*/
|
|
|
|
clear:
|
|
destroy_string_buffer(buffer);
|
|
return NULL;
|
|
#undef VSNPRINTF
|
|
#undef STR_FILED
|
|
#undef CREATE_ROW_FROM_STRING
|
|
#undef NUMBER_OF_COLUMNS_IN_FORMAT_STRING
|
|
#undef FILL_CELL_FROM_STRING
|
|
#undef STR_BUF_TYPE
|
|
}
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
FT_INTERNAL
|
|
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
|
|
#define FILL_CELL_FROM_STRING fill_cell_from_wstring
|
|
#define STR_BUF_TYPE WCharBuf
|
|
|
|
string_buffer_t *buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, STR_BUF_TYPE);
|
|
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;
|
|
}
|
|
|
|
if (cols_origin == 1) {
|
|
fort_row_t *row = create_row();
|
|
if (row == NULL) {
|
|
goto clear;
|
|
}
|
|
|
|
fort_cell_t *cell = get_cell_and_create_if_not_exists(row, 0);
|
|
if (cell == NULL) {
|
|
destroy_row(row);
|
|
goto clear;
|
|
}
|
|
|
|
fort_status_t result = FILL_CELL_FROM_STRING(cell, buffer->str.STR_FILED);
|
|
if (FT_IS_ERROR(result)) {
|
|
destroy_row(row);
|
|
goto clear;
|
|
}
|
|
|
|
destroy_string_buffer(buffer);
|
|
return row;
|
|
}
|
|
|
|
/*
|
|
* todo: add processing of cols != cols_origin in a general way
|
|
* (when cols_origin != 1).
|
|
*/
|
|
|
|
clear:
|
|
destroy_string_buffer(buffer);
|
|
return NULL;
|
|
#undef VSNPRINTF
|
|
#undef STR_FILED
|
|
#undef CREATE_ROW_FROM_STRING
|
|
#undef NUMBER_OF_COLUMNS_IN_FORMAT_STRING
|
|
#undef FILL_CELL_FROM_STRING
|
|
#undef STR_BUF_TYPE
|
|
}
|
|
#endif
|
|
|
|
|
|
FT_INTERNAL
|
|
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_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_property_value_hierarcial(context->table_properties, context->row, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE);
|
|
const char *(*bord_chars)[BorderItemPosSize] = (row_type == FT_ROW_HEADER)
|
|
? (border_chars_point_t)(&context->table_properties->border_style.header_border_chars)
|
|
: (border_chars_point_t)(&context->table_properties->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_properties->entire_table_properties.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_properties->entire_table_properties.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
|
|
FT_INTERNAL
|
|
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_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_property_value_hierarcial(context->table_properties, context->row, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE);
|
|
const char *(*bord_chars)[BorderItemPosSize] = (row_type == FT_ROW_HEADER)
|
|
? (border_chars_point_t)(&context->table_properties->border_style.header_border_chars)
|
|
: (border_chars_point_t)(&context->table_properties->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_properties->entire_table_properties.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_properties->entire_table_properties.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 "string_buffer.c"
|
|
********************************************************/
|
|
|
|
/* #include "string_buffer.h" */ /* Commented by amalgamation script */
|
|
/* #include "properties.h" */ /* Commented by amalgamation script */
|
|
/* #include "wcwidth.h" */ /* Commented by amalgamation script */
|
|
#include <assert.h>
|
|
#include <stddef.h>
|
|
#include <wchar.h>
|
|
|
|
|
|
static ptrdiff_t str_iter_width(const char *beg, const char *end)
|
|
{
|
|
assert(end >= beg);
|
|
return (end - beg);
|
|
}
|
|
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
static ptrdiff_t wcs_iter_width(const wchar_t *beg, const wchar_t *end)
|
|
{
|
|
assert(end >= beg);
|
|
return mk_wcswidth(beg, (end - beg));
|
|
}
|
|
#endif /* FT_HAVE_WCHAR */
|
|
|
|
|
|
static size_t buf_str_len(const string_buffer_t *buf)
|
|
{
|
|
assert(buf);
|
|
if (buf->type == CharBuf) {
|
|
return strlen(buf->str.cstr);
|
|
} else {
|
|
return wcslen(buf->str.wstr);
|
|
}
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
size_t strchr_count(const char *str, char ch)
|
|
{
|
|
if (str == NULL)
|
|
return 0;
|
|
|
|
size_t count = 0;
|
|
str = strchr(str, ch);
|
|
while (str) {
|
|
count++;
|
|
str++;
|
|
str = strchr(str, ch);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
size_t wstrchr_count(const wchar_t *str, wchar_t ch)
|
|
{
|
|
if (str == NULL)
|
|
return 0;
|
|
|
|
size_t count = 0;
|
|
str = wcschr(str, ch);
|
|
while (str) {
|
|
count++;
|
|
str++;
|
|
str = wcschr(str, ch);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
const char *str_n_substring_beg(const char *str, char ch_separator, size_t n)
|
|
{
|
|
if (str == NULL)
|
|
return NULL;
|
|
|
|
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);
|
|
}
|
|
return str ? (str + 1) : NULL;
|
|
}
|
|
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
FT_INTERNAL
|
|
const wchar_t *wstr_n_substring_beg(const wchar_t *str, wchar_t ch_separator, size_t n)
|
|
{
|
|
if (str == NULL)
|
|
return NULL;
|
|
|
|
if (n == 0)
|
|
return str;
|
|
|
|
str = wcschr(str, ch_separator);
|
|
--n;
|
|
while (n > 0) {
|
|
if (str == NULL)
|
|
return NULL;
|
|
--n;
|
|
str++;
|
|
str = wcschr(str, ch_separator);
|
|
}
|
|
return str ? (str + 1) : NULL;
|
|
}
|
|
#endif /* FT_HAVE_WCHAR */
|
|
|
|
|
|
FT_INTERNAL
|
|
void str_n_substring(const char *str, char ch_separator, size_t n, const char **begin, const char **end)
|
|
{
|
|
const char *beg = str_n_substring_beg(str, ch_separator, n);
|
|
if (beg == NULL) {
|
|
*begin = NULL;
|
|
*end = NULL;
|
|
return;
|
|
}
|
|
|
|
const char *en = strchr(beg, ch_separator);
|
|
if (en == NULL) {
|
|
en = str + strlen(str);
|
|
}
|
|
|
|
*begin = beg;
|
|
*end = en;
|
|
return;
|
|
}
|
|
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
FT_INTERNAL
|
|
void wstr_n_substring(const wchar_t *str, wchar_t ch_separator, size_t n, const wchar_t **begin, const wchar_t **end)
|
|
{
|
|
const wchar_t *beg = wstr_n_substring_beg(str, ch_separator, n);
|
|
if (beg == NULL) {
|
|
*begin = NULL;
|
|
*end = NULL;
|
|
return;
|
|
}
|
|
|
|
const wchar_t *en = wcschr(beg, ch_separator);
|
|
if (en == NULL) {
|
|
en = str + wcslen(str);
|
|
}
|
|
|
|
*begin = beg;
|
|
*end = en;
|
|
return;
|
|
}
|
|
#endif /* FT_HAVE_WCHAR */
|
|
|
|
|
|
FT_INTERNAL
|
|
string_buffer_t *create_string_buffer(size_t number_of_chars, enum str_buf_type type)
|
|
{
|
|
size_t sz = (number_of_chars) * (type == CharBuf ? sizeof(char) : sizeof(wchar_t));
|
|
string_buffer_t *result = (string_buffer_t *)F_MALLOC(sizeof(string_buffer_t));
|
|
if (result == NULL)
|
|
return NULL;
|
|
result->str.data = F_MALLOC(sz);
|
|
if (result->str.data == NULL) {
|
|
F_FREE(result);
|
|
return NULL;
|
|
}
|
|
result->data_sz = sz;
|
|
result->type = type;
|
|
|
|
if (sz && type == CharBuf) {
|
|
result->str.cstr[0] = '\0';
|
|
#ifdef FT_HAVE_WCHAR
|
|
} else if (sz && type == WCharBuf) {
|
|
result->str.wstr[0] = L'\0';
|
|
#endif /* FT_HAVE_WCHAR */
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
void destroy_string_buffer(string_buffer_t *buffer)
|
|
{
|
|
if (buffer == NULL)
|
|
return;
|
|
F_FREE(buffer->str.data);
|
|
buffer->str.data = NULL;
|
|
F_FREE(buffer);
|
|
}
|
|
|
|
FT_INTERNAL
|
|
string_buffer_t *copy_string_buffer(string_buffer_t *buffer)
|
|
{
|
|
assert(buffer);
|
|
string_buffer_t *result = create_string_buffer(buffer->data_sz, buffer->type);
|
|
if (result == NULL)
|
|
return NULL;
|
|
switch (buffer->type) {
|
|
case CharBuf:
|
|
if (FT_IS_ERROR(fill_buffer_from_string(result, buffer->str.cstr))) {
|
|
destroy_string_buffer(buffer);
|
|
return NULL;
|
|
}
|
|
break;
|
|
#ifdef FT_HAVE_WCHAR
|
|
case WCharBuf:
|
|
if (FT_IS_ERROR(fill_buffer_from_wstring(result, buffer->str.wstr))) {
|
|
destroy_string_buffer(buffer);
|
|
return NULL;
|
|
}
|
|
break;
|
|
#endif /* FT_HAVE_WCHAR */
|
|
default:
|
|
destroy_string_buffer(result);
|
|
return NULL;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
FT_INTERNAL
|
|
fort_status_t realloc_string_buffer_without_copy(string_buffer_t *buffer)
|
|
{
|
|
assert(buffer);
|
|
char *new_str = (char *)F_MALLOC(buffer->data_sz * 2);
|
|
if (new_str == NULL) {
|
|
return FT_MEMORY_ERROR;
|
|
}
|
|
F_FREE(buffer->str.data);
|
|
buffer->str.data = new_str;
|
|
buffer->data_sz *= 2;
|
|
return FT_SUCCESS;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str)
|
|
{
|
|
assert(buffer);
|
|
assert(str);
|
|
|
|
char *copy = F_STRDUP(str);
|
|
if (copy == NULL)
|
|
return FT_MEMORY_ERROR;
|
|
|
|
F_FREE(buffer->str.data);
|
|
buffer->str.cstr = copy;
|
|
buffer->type = CharBuf;
|
|
|
|
return FT_SUCCESS;
|
|
}
|
|
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
FT_INTERNAL
|
|
fort_status_t fill_buffer_from_wstring(string_buffer_t *buffer, const wchar_t *str)
|
|
{
|
|
assert(buffer);
|
|
assert(str);
|
|
|
|
wchar_t *copy = F_WCSDUP(str);
|
|
if (copy == NULL)
|
|
return FT_MEMORY_ERROR;
|
|
|
|
F_FREE(buffer->str.data);
|
|
buffer->str.wstr = copy;
|
|
buffer->type = WCharBuf;
|
|
|
|
return FT_SUCCESS;
|
|
}
|
|
#endif /* FT_HAVE_WCHAR */
|
|
|
|
|
|
FT_INTERNAL
|
|
size_t buffer_text_height(string_buffer_t *buffer)
|
|
{
|
|
if (buffer == NULL || buffer->str.data == NULL || buf_str_len(buffer) == 0) {
|
|
return 0;
|
|
}
|
|
if (buffer->type == CharBuf)
|
|
return 1 + strchr_count(buffer->str.cstr, '\n');
|
|
else
|
|
return 1 + wstrchr_count(buffer->str.wstr, L'\n');
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
size_t buffer_text_width(const string_buffer_t *buffer)
|
|
{
|
|
size_t max_length = 0;
|
|
if (buffer->type == CharBuf) {
|
|
int n = 0;
|
|
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;
|
|
|
|
max_length = MAX(max_length, (size_t)(end - beg));
|
|
++n;
|
|
}
|
|
#ifdef FT_HAVE_WCHAR
|
|
} else {
|
|
int n = 0;
|
|
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;
|
|
|
|
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);
|
|
|
|
++n;
|
|
}
|
|
#endif /* FT_HAVE_WCHAR */
|
|
}
|
|
|
|
return max_length; /* shouldn't be here */
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
int buffer_printf(string_buffer_t *buffer, size_t buffer_row, char *buf, size_t total_buf_len,
|
|
const context_t *context, const char *content_style_tag, const char *reset_content_style_tag)
|
|
{
|
|
#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_STRINGS snprint_n_strings
|
|
#define STR_N_SUBSTRING str_n_substring
|
|
#define STR_ITER_WIDTH str_iter_width
|
|
|
|
size_t buf_len = total_buf_len - strlen(content_style_tag) - strlen(reset_content_style_tag);
|
|
|
|
if (buffer == NULL || buffer->str.data == NULL
|
|
|| buffer_row >= buffer_text_height(buffer) || buf_len == 0) {
|
|
return -1;
|
|
}
|
|
|
|
size_t content_width = buffer_text_width(buffer);
|
|
if ((buf_len - 1) < content_width)
|
|
return -1;
|
|
|
|
size_t left = 0;
|
|
size_t right = 0;
|
|
|
|
switch (get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_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;
|
|
}
|
|
|
|
int written = 0;
|
|
int tmp = 0;
|
|
ptrdiff_t str_it_width = 0;
|
|
const CHAR_TYPE *beg = NULL;
|
|
const CHAR_TYPE *end = NULL;
|
|
CHAR_TYPE old_value;
|
|
|
|
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, left, SPACE_CHAR));
|
|
|
|
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;
|
|
|
|
str_it_width = STR_ITER_WIDTH(beg, end);
|
|
if (str_it_width < 0 || content_width < (size_t)str_it_width)
|
|
return - 1;
|
|
|
|
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, 1, content_style_tag));
|
|
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINTF(buf + written, total_buf_len - written, SNPRINTF_FMT_STR, (int)(end - beg), beg));
|
|
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, 1, reset_content_style_tag));
|
|
|
|
*(CHAR_TYPE *)end = old_value;
|
|
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, (content_width - (size_t)str_it_width), SPACE_CHAR));
|
|
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, right, SPACE_CHAR));
|
|
return written;
|
|
|
|
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_STRINGS
|
|
#undef STR_N_SUBSTRING
|
|
#undef STR_ITER_WIDTH
|
|
}
|
|
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
FT_INTERNAL
|
|
int buffer_wprintf(string_buffer_t *buffer, size_t buffer_row, wchar_t *buf, size_t total_buf_len,
|
|
const context_t *context, const char *content_style_tag, const char *reset_content_style_tag)
|
|
{
|
|
#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_STRINGS wsnprint_n_string
|
|
#define STR_N_SUBSTRING wstr_n_substring
|
|
#define STR_ITER_WIDTH wcs_iter_width
|
|
|
|
size_t buf_len = total_buf_len - strlen(content_style_tag) - strlen(reset_content_style_tag);
|
|
|
|
if (buffer == NULL || buffer->str.data == NULL
|
|
|| buffer_row >= buffer_text_height(buffer) || buf_len == 0) {
|
|
return -1;
|
|
}
|
|
|
|
size_t content_width = buffer_text_width(buffer);
|
|
if ((buf_len - 1) < content_width)
|
|
return -1;
|
|
|
|
size_t left = 0;
|
|
size_t right = 0;
|
|
|
|
switch (get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_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;
|
|
}
|
|
|
|
int written = 0;
|
|
int tmp = 0;
|
|
ptrdiff_t str_it_width = 0;
|
|
const CHAR_TYPE *beg = NULL;
|
|
const CHAR_TYPE *end = NULL;
|
|
CHAR_TYPE old_value;
|
|
|
|
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, left, SPACE_CHAR));
|
|
|
|
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;
|
|
|
|
str_it_width = STR_ITER_WIDTH(beg, end);
|
|
if (str_it_width < 0 || content_width < (size_t)str_it_width)
|
|
return - 1;
|
|
|
|
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, 1, content_style_tag));
|
|
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINTF(buf + written, total_buf_len - written, SNPRINTF_FMT_STR, (int)(end - beg), beg));
|
|
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, 1, reset_content_style_tag));
|
|
|
|
*(CHAR_TYPE *)end = old_value;
|
|
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, (content_width - (size_t)str_it_width), SPACE_CHAR));
|
|
CHCK_RSLT_ADD_TO_WRITTEN(SNPRINT_N_STRINGS(buf + written, total_buf_len - written, right, SPACE_CHAR));
|
|
return written;
|
|
|
|
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_STRINGS
|
|
#undef STR_N_SUBSTRING
|
|
#undef STR_ITER_WIDTH
|
|
}
|
|
#endif /* FT_HAVE_WCHAR */
|
|
|
|
|
|
FT_INTERNAL
|
|
size_t string_buffer_capacity(const string_buffer_t *buffer)
|
|
{
|
|
assert(buffer);
|
|
if (buffer->type == CharBuf)
|
|
return buffer->data_sz;
|
|
else
|
|
return buffer->data_sz / sizeof(wchar_t);
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
void *buffer_get_data(string_buffer_t *buffer)
|
|
{
|
|
assert(buffer);
|
|
return buffer->str.data;
|
|
}
|
|
|
|
/********************************************************
|
|
End of file "string_buffer.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 */
|
|
|
|
FT_INTERNAL
|
|
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;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
void destroy_separator(separator_t *sep)
|
|
{
|
|
F_FREE(sep);
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
separator_t *copy_separator(separator_t *sep)
|
|
{
|
|
assert(sep);
|
|
return create_separator(sep->enabled);
|
|
}
|
|
|
|
|
|
static
|
|
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;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
fort_row_t *get_row(ft_table_t *table, size_t row)
|
|
{
|
|
return get_row_implementation(table, row, DoNotCreate);
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
const fort_row_t *get_row_c(const ft_table_t *table, size_t row)
|
|
{
|
|
return get_row((ft_table_t *)table, row);
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
fort_row_t *get_row_and_create_if_not_exists(ft_table_t *table, size_t row)
|
|
{
|
|
return get_row_implementation(table, row, Create);
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
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)
|
|
*/
|
|
FT_INTERNAL
|
|
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) {
|
|
(void)i0;
|
|
size_t cols_in_row = columns_in_row(row);
|
|
if (cols_in_row > *cols)
|
|
*cols = cols_in_row;
|
|
}
|
|
}
|
|
return FT_SUCCESS;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
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,
|
|
enum request_geom_type geom)
|
|
{
|
|
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_properties = (table->properties ? table->properties : &g_table_properties);
|
|
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, geom));
|
|
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, geom);
|
|
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->properties) {
|
|
for (size_t i = 0; i < cols; ++i) {
|
|
col_width_arr[i] = MAX((int)col_width_arr[i], fort_props_column_width(table->properties, 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
|
|
*/
|
|
FT_INTERNAL
|
|
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, INTERN_REPR_GEOMETRY);
|
|
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->properties) {
|
|
*height += table->properties->entire_table_properties.top_margin;
|
|
*height += table->properties->entire_table_properties.bottom_margin;
|
|
*width += table->properties->entire_table_properties.left_margin;
|
|
*width += table->properties->entire_table_properties.right_margin;
|
|
}
|
|
|
|
/* Take into account that border elements can be more than one byte long */
|
|
fort_table_properties_t *table_properties = table->properties ? table->properties : &g_table_properties;
|
|
size_t max_border_elem_len = max_border_elem_strlen(table_properties);
|
|
*width *= max_border_elem_len;
|
|
|
|
return FT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
/********************************************************
|
|
End of file "table.c"
|
|
********************************************************/
|
|
|
|
|
|
/********************************************************
|
|
Begin of file "vector.c"
|
|
********************************************************/
|
|
|
|
/* #include "vector.h" */ /* Commented by amalgamation script */
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
struct vector {
|
|
size_t m_size;
|
|
void *m_data;
|
|
size_t m_capacity;
|
|
size_t m_item_size;
|
|
};
|
|
|
|
|
|
static int vector_reallocate_(vector_t *vector, size_t new_capacity)
|
|
{
|
|
assert(vector);
|
|
assert(new_capacity > vector->m_capacity);
|
|
|
|
size_t new_size = new_capacity * vector->m_item_size;
|
|
vector->m_data = F_REALLOC(vector->m_data, new_size);
|
|
if (vector->m_data == NULL)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
vector->m_size = 0;
|
|
vector->m_capacity = capacity;
|
|
vector->m_item_size = item_size;
|
|
|
|
return vector;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
void destroy_vector(vector_t *vector)
|
|
{
|
|
assert(vector);
|
|
F_FREE(vector->m_data);
|
|
F_FREE(vector);
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
size_t vector_size(const vector_t *vector)
|
|
{
|
|
assert(vector);
|
|
return vector->m_size;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
size_t vector_capacity(const vector_t *vector)
|
|
{
|
|
assert(vector);
|
|
return vector->m_capacity;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
int vector_push(vector_t *vector, const void *item)
|
|
{
|
|
assert(vector);
|
|
assert(item);
|
|
|
|
if (vector->m_size == vector->m_capacity) {
|
|
if (vector_reallocate_(vector, vector->m_capacity * 2) == -1)
|
|
return 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;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
const void *vector_at_c(const vector_t *vector, size_t index)
|
|
{
|
|
if (index >= vector->m_size)
|
|
return NULL;
|
|
|
|
return (char *)vector->m_data + index * vector->m_item_size;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
void *vector_at(vector_t *vector, size_t index)
|
|
{
|
|
if (index >= vector->m_size)
|
|
return NULL;
|
|
|
|
return (char *)vector->m_data + index * vector->m_item_size;
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
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);
|
|
|
|
size_t cur_sz = vector_size(cur_vec);
|
|
size_t mv_sz = vector_size(mv_vec);
|
|
if (mv_sz == 0) {
|
|
return FT_SUCCESS;
|
|
}
|
|
|
|
size_t min_targ_size = pos + mv_sz;
|
|
if (vector_capacity(cur_vec) < min_targ_size) {
|
|
if (vector_reallocate_(cur_vec, min_targ_size) == -1)
|
|
return FT_ERROR;
|
|
cur_vec->m_capacity = min_targ_size;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
if (tmp) {
|
|
memcpy(tmp,
|
|
(char *)cur_vec->m_data + deviation,
|
|
cur_vec->m_item_size * new_mv_sz);
|
|
}
|
|
|
|
memcpy((char *)cur_vec->m_data + deviation,
|
|
mv_vec->m_data,
|
|
cur_vec->m_item_size * mv_sz);
|
|
|
|
if (tmp) {
|
|
memcpy(mv_vec->m_data,
|
|
tmp,
|
|
cur_vec->m_item_size * new_mv_sz);
|
|
}
|
|
|
|
cur_vec->m_size = MAX(cur_vec->m_size, min_targ_size);
|
|
mv_vec->m_size = new_mv_sz;
|
|
F_FREE(tmp);
|
|
return FT_SUCCESS;
|
|
}
|
|
|
|
|
|
#ifdef FT_TEST_BUILD
|
|
|
|
vector_t *copy_vector(vector_t *v)
|
|
{
|
|
if (v == NULL)
|
|
return NULL;
|
|
|
|
vector_t *new_vector = create_vector(v->m_item_size, v->m_capacity);
|
|
if (new_vector == NULL)
|
|
return NULL;
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
return INVALID_VEC_INDEX;
|
|
}
|
|
|
|
|
|
int vector_erase(vector_t *vector, size_t index)
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
void vector_clear(vector_t *vector)
|
|
{
|
|
vector->m_size = 0;
|
|
}
|
|
#endif
|
|
|
|
/********************************************************
|
|
End of file "vector.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 "wcwidth.h" */ /* Commented by amalgamation script */
|
|
|
|
#ifdef FT_HAVE_WCHAR
|
|
|
|
|
|
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;
|
|
|
|
if (ucs < table[0].first || ucs > table[max].last)
|
|
return 0;
|
|
while (max >= min) {
|
|
int 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.
|
|
*/
|
|
|
|
static 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)));
|
|
}
|
|
|
|
|
|
FT_INTERNAL
|
|
int mk_wcswidth(const wchar_t *pwcs, size_t n)
|
|
{
|
|
int width = 0;
|
|
|
|
for (; *pwcs && n-- > 0; pwcs++) {
|
|
int w;
|
|
if ((w = mk_wcwidth(*pwcs)) < 0)
|
|
return -1;
|
|
else
|
|
width += w;
|
|
}
|
|
|
|
return width;
|
|
}
|
|
#endif /* FT_HAVE_WCHAR */
|
|
|
|
/********************************************************
|
|
End of file "wcwidth.c"
|
|
********************************************************/
|
|
|