2023-10-16 18:20:08 +07:00

1697 lines
58 KiB
C

/*
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2017-2021 Michael Drake <tlsa@netsurf-browser.org>
*/
/**
* \file
* \brief CYAML library public header.
*
* CYAML is a C library for parsing and serialising structured YAML documents.
*/
#ifndef CYAML_H
#define CYAML_H
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdarg.h>
#include <stdint.h>
#include <stddef.h>
/**
* CYAML library version string.
*/
extern const char *cyaml_version_str;
/**
* CYAML library version number suitable for comparisons.
*
* Version number binary composition is `0bRUUUUUUUJJJJJJJJNNNNNNNNPPPPPPPP`.
*
* | Character | Meaning |
* | --------- | -------------------------------------- |
* | `R` | Release flag. If set, it's a release. |
* | `U` | Unused / reserved. |
* | `J` | Major component of version. |
* | `N` | Minor component of version. |
* | `P` | Patch component of version. |
*/
extern const uint32_t cyaml_version;
/**
* CYAML value types.
*
* These are the fundamental data types that apply to "values" in CYAML.
*
* CYAML "values" are represented in by \ref cyaml_schema_value.
*/
typedef enum cyaml_type {
CYAML_INT, /**< Value is a signed integer. */
CYAML_UINT, /**< Value is an unsigned signed integer. */
CYAML_BOOL, /**< Value is a boolean. */
/**
* Value is an enum. Values of this type require a string / value
* mapping array in the schema entry, to define the list of valid
* enum values.
*/
CYAML_ENUM,
/**
* Value is a flags bit field. Values of this type require a string /
* value list in the schema entry, to define the list of valid flag
* values. Each bit is a boolean flag. To store values of various
* bit sizes, use a \ref CYAML_BITFIELD instead.
*
* In the YAML, a \ref CYAML_FLAGS value must be presented as a
* sequence of strings.
*/
CYAML_FLAGS,
CYAML_FLOAT, /**< Value is floating point. */
CYAML_STRING, /**< Value is a string. */
/**
* Value is a mapping. Values of this type require mapping schema
* array in the schema entry.
*/
CYAML_MAPPING,
/**
* Value is a bit field. Values of this type require an array of value
* definitions in the schema entry. If the bit field is used to store
* only single-bit flags, it may be better to use \ref CYAML_FLAGS
* instead.
*
* In the YAML, a \ref CYAML_FLAGS value must be presented as a
* mapping of bit field entry names to their numerical values.
*/
CYAML_BITFIELD,
/**
* Value is a sequence. Values of this type must be the direct
* children of a mapping. They require:
*
* - A schema describing the type of the sequence entries.
* - Offset to the array entry count member in the mapping structure.
* - Size in bytes of the count member in the mapping structure.
* - The minimum and maximum number of sequence count entries.
* Set `max` to \ref CYAML_UNLIMITED to make array count
* unconstrained.
*/
CYAML_SEQUENCE,
/**
* Value is a **fixed length** sequence. It is similar to \ref
* CYAML_SEQUENCE, however:
*
* - Values of this type do not need to be direct children of a mapping.
* - The minimum and maximum entry count must be the same. If not
* \ref CYAML_ERR_SEQUENCE_FIXED_COUNT will be returned.
* - Unlike with \ref CYAML_SEQUENCE, where the min and max are limits,
* here they are the actual entry count.
* - Since values of this type represent a constant size array, the
* given entry count must not be \ref CYAML_UNLIMITED, because that
* would cause it to attempt a massive allocation, which on most
* systems would fail.
* - The offset and size of the count structure member is unused.
* Because the count is a schema-defined constant, it does not need
* to be recorded.
*/
CYAML_SEQUENCE_FIXED,
/**
* Value of this type is completely ignored. This is most useful for
* ignoring particular keys in a mapping, when the LivCYAML client has
* not set a configuration of \ref CYAML_CFG_IGNORE_UNKNOWN_KEYS.
*/
CYAML_IGNORE,
/**
* Count of the valid CYAML types. This value is **not a valid type**
* itself.
*/
CYAML__TYPE_COUNT,
} cyaml_type_e;
/**
* CYAML value flags.
*
* These may be bitwise-ORed together.
*/
typedef enum cyaml_flag {
CYAML_FLAG_DEFAULT = 0, /**< Default value flags (none set). */
CYAML_FLAG_OPTIONAL = (1 << 0), /**< Mapping field is optional. */
/**
* Value is a pointer to its type.
*
* With this there must be a non-NULL value. Consider using
* \ref CYAML_FLAG_POINTER_NULL or \ref CYAML_FLAG_POINTER_NULL_STR
* if you want to allow NULL values.
*/
CYAML_FLAG_POINTER = (1 << 1),
/**
* Permit `NULL` values for \ref CYAML_FLAG_POINTER types.
*
* An empty value in the YAML is loaded as a NULL pointer, and NULL
* pointers are saved in YAML as empty values.
*
* Note, when you set \ref CYAML_FLAG_POINTER_NULL, then
* \ref CYAML_FLAG_POINTER is set automatically.
*/
CYAML_FLAG_POINTER_NULL = (1 << 2) | CYAML_FLAG_POINTER,
/**
* Permit storage of `NULL` values as special NULL strings in YAML.
*
* This extends \ref CYAML_FLAG_POINTER_NULL, but in addition to
* treating empty values as NULL, any of the following are also treated
* as NULL:
*
* * `null`,
* * `Null`,
* * `NULL`,
* * `~`,
*
* Note that as a side effect, loading a \ref CYAML_STRING field with
* one of these values will not store the literal string, it will store
* NULL.
*
* When saving, a NULL value will be recorded in the YAML as `null`.
*
* Note, when you set \ref CYAML_FLAG_POINTER_NULL_STR, then both
* \ref CYAML_FLAG_POINTER and \ref CYAML_FLAG_POINTER_NULL are set
* automatically.
*/
CYAML_FLAG_POINTER_NULL_STR = (1 << 3) | CYAML_FLAG_POINTER_NULL,
/**
* Make value handling strict.
*
* For \ref CYAML_ENUM and \ref CYAML_FLAGS types, in strict mode
* the YAML must contain a matching string. Without strict, numerical
* values are also permitted.
*
* * For \ref CYAML_ENUM, the value becomes the value of the enum.
* The numerical value is treated as signed.
* * For \ref CYAML_FLAGS, the values are bitwise ORed together.
* The numerical values are treated as unsigned.
*
* For \ref CYAML_FLOAT types, in strict mode floating point values
* that would cause overflow or underflow are not permitted.
*/
CYAML_FLAG_STRICT = (1 << 4),
/**
* When saving, emit mapping / sequence value in block style.
*
* This can be used to override, for this value, any default style set
* in the \ref cyaml_cfg_flags CYAML behavioural configuration flags.
*
* \note This is ignored unless the value's type is \ref CYAML_MAPPING,
* \ref CYAML_SEQUENCE, or \ref CYAML_SEQUENCE_FIXED.
*
* \note If both \ref CYAML_FLAG_BLOCK and \ref CYAML_FLAG_FLOW are set,
* then block style takes precedence.
*
* \note If neither block nor flow style set either here, or in the
* \ref cyaml_cfg_flags CYAML behavioural configuration flags,
* then libyaml's default behaviour is used.
*/
CYAML_FLAG_BLOCK = (1 << 5),
/**
* When saving, emit mapping / sequence value in flow style.
*
* This can be used to override, for this value, any default style set
* in the \ref cyaml_cfg_flags CYAML behavioural configuration flags.
*
* \note This is ignored unless the value's type is \ref CYAML_MAPPING,
* \ref CYAML_SEQUENCE, or \ref CYAML_SEQUENCE_FIXED.
*
* \note If both \ref CYAML_FLAG_BLOCK and \ref CYAML_FLAG_FLOW are set,
* then block style takes precedence.
*
* \note If neither block nor flow style set either here, or in the
* \ref cyaml_cfg_flags CYAML behavioural configuration flags,
* then libyaml's default behaviour is used.
*/
CYAML_FLAG_FLOW = (1 << 6),
/**
* When comparing strings for this value, compare with case sensitivity.
*
* By default, strings are compared with case sensitivity.
* If \ref CYAML_CFG_CASE_INSENSITIVE is set, this can override
* the configured behaviour for this specific value.
*
* \note If both \ref CYAML_FLAG_CASE_SENSITIVE and
* \ref CYAML_FLAG_CASE_INSENSITIVE are set,
* then case insensitive takes precedence.
*
* \note This applies to values of types \ref CYAML_MAPPING,
* \ref CYAML_ENUM, and \ref CYAML_FLAGS. For mappings,
* it applies to matching of the mappings' keys. For
* enums and flags it applies to the comparison of
* \ref cyaml_strval strings.
*/
CYAML_FLAG_CASE_SENSITIVE = (1 << 7),
/**
* When comparing strings for this value, compare with case sensitivity.
*
* By default, strings are compared with case sensitivity.
* If \ref CYAML_CFG_CASE_INSENSITIVE is set, this can override
* the configured behaviour for this specific value.
*
* \note If both \ref CYAML_FLAG_CASE_SENSITIVE and
* \ref CYAML_FLAG_CASE_INSENSITIVE are set,
* then case insensitive takes precedence.
*
* \note This applies to values of types \ref CYAML_MAPPING,
* \ref CYAML_ENUM, and \ref CYAML_FLAGS. For mappings,
* it applies to matching of the mappings' keys. For
* enums and flags it applies to the comparison of
* \ref cyaml_strval strings.
*/
CYAML_FLAG_CASE_INSENSITIVE = (1 << 8),
/**
* When saving, emit scalar value with plain style (no quotes).
*
* \note This is ignored if the value is non-scaler.
*
* \note In cases where conflicting scalar style flags are set, the
* the one with the highest precedence is used. From lowest to
* highest precedence:
* \ref CYAML_FLAG_SCALAR_PLAIN,
* \ref CYAML_FLAG_SCALAR_FOLDED,
* \ref CYAML_FLAG_SCALAR_LITERAL,
* \ref CYAML_FLAG_SCALAR_QUOTE_SINGLE,
* \ref CYAML_FLAG_SCALAR_QUOTE_DOUBLE,
*
* If none of these are set, libyaml's default behaviour is used.
*/
CYAML_FLAG_SCALAR_PLAIN = (1 << 9),
/**
* When saving, emit scalar value with folded style:
*
* ```yaml
* string: >
* This string
* really has no line breaks!
* ```
*
* See the notes for \ref CYAML_FLAG_SCALAR_PLAIN for applicability
* and precedence.
*/
CYAML_FLAG_SCALAR_FOLDED = (1 << 10),
/**
* When saving, emit scalar value with literal style:
*
* ```yaml
* string: |
* This is a
* multi-line string!
* ```
*
* See the notes for \ref CYAML_FLAG_SCALAR_PLAIN for applicability
* and precedence.
*/
CYAML_FLAG_SCALAR_LITERAL = (1 << 11),
/**
* When saving, emit scalar value with single quotes (`'`).
*
* See the notes for \ref CYAML_FLAG_SCALAR_PLAIN for applicability
* and precedence.
*/
CYAML_FLAG_SCALAR_QUOTE_SINGLE = (1 << 12),
/**
* When saving, emit scalar value with double quotes (`"`).
*
* See the notes for \ref CYAML_FLAG_SCALAR_PLAIN for applicability
* and precedence.
*/
CYAML_FLAG_SCALAR_QUOTE_DOUBLE = (1 << 13),
} cyaml_flag_e;
/**
* Mapping between a string and a signed value.
*
* Used for \ref CYAML_ENUM and \ref CYAML_FLAGS types.
*/
typedef struct cyaml_strval {
const char *str; /**< String representing enum or flag value. */
int64_t val; /**< Value of given string. */
} cyaml_strval_t;
/**
* Bitfield value info.
*
* Used for \ref CYAML_BITFIELD type.
*/
typedef struct cyaml_bitdef {
const char *name; /**< String representing the value's name. */
uint8_t offset; /**< Bit offset to value in bit field. */
uint8_t bits; /**< Maximum bits available for value. */
} cyaml_bitdef_t;
/**
* Schema definition for a value.
*
* \note There are convenience macros for each of the types to assist in
* building a CYAML schema data structure for your YAML documents.
*
* This is the fundamental building block of CYAML schemas. The load, save and
* free functions take parameters of this type to explain what the top-level
* type of the YAML document should be.
*
* Values of type \ref CYAML_SEQUENCE and \ref CYAML_SEQUENCE_FIXED
* contain a reference to another \ref cyaml_schema_value representing
* the type of the entries of the sequence. For example, if you want
* a sequence of integers, you'd have a \ref cyaml_schema_value for the
* for the sequence value type, and another for the integer value type.
*
* Values of type \ref CYAML_MAPPING contain an array of \ref cyaml_schema_field
* entries, defining the YAML keys allowed by the mapping. Each field contains
* a \ref cyaml_schema_value representing the schema for the value.
*/
typedef struct cyaml_schema_value {
/**
* The type of the value defined by this schema entry.
*/
enum cyaml_type type;
/** Flags indicating value's characteristics. */
enum cyaml_flag flags;
/**
* Size of the value's client data type in bytes.
*
* For example, `short` `int`, `long`, `int8_t`, etc are all signed
* integer types, so they would have the type \ref CYAML_INT,
* however, they have different sizes.
*/
uint32_t data_size;
/** Anonymous union containing type-specific attributes. */
union {
/** \ref CYAML_STRING type-specific schema data. */
struct {
/**
* Minimum string length (bytes).
*
* \note Excludes trailing NUL.
*/
uint32_t min;
/**
* Maximum string length (bytes).
*
* \note Excludes trailing NULL, so for character array
* strings (rather than pointer strings), this
* must be no more than `data_size - 1`.
*/
uint32_t max;
} string;
/** \ref CYAML_MAPPING type-specific schema data. */
struct {
/**
* Array of cyaml mapping field schema definitions.
*
* The array must be terminated by an entry with a
* NULL key. See \ref cyaml_schema_field_t
* and \ref CYAML_FIELD_END for more info.
*/
const struct cyaml_schema_field *fields;
} mapping;
/** \ref CYAML_BITFIELD type-specific schema data. */
struct {
/** Array of bit definitions for the bit field. */
const struct cyaml_bitdef *bitdefs;
/** Entry count for bitdefs array. */
uint32_t count;
} bitfield;
/**
* \ref CYAML_SEQUENCE and \ref CYAML_SEQUENCE_FIXED
* type-specific schema data.
*/
struct {
/**
* Schema definition for the type of the entries in the
* sequence.
*
* All of a sequence's entries must be of the same
* type, and a sequence can not have an entry type of
* type \ref CYAML_SEQUENCE (although \ref
* CYAML_SEQUENCE_FIXED is allowed). That is, you
* can't have a sequence of variable-length sequences.
*/
const struct cyaml_schema_value *entry;
/**
* Minimum number of sequence entries.
*
* \note min and max must be the same for \ref
* CYAML_SEQUENCE_FIXED.
*/
uint32_t min;
/**
* Maximum number of sequence entries.
*
* \note min and max must be the same for \ref
* CYAML_SEQUENCE_FIXED.
*/
uint32_t max;
} sequence;
/**
* \ref CYAML_ENUM and \ref CYAML_FLAGS type-specific schema
* data.
*/
struct {
/** Array of string / value mappings defining enum. */
const cyaml_strval_t *strings;
/** Entry count for strings array. */
uint32_t count;
} enumeration;
};
} cyaml_schema_value_t;
/**
* Schema definition entry for mapping fields.
*
* YAML mappings are key:value pairs. CYAML only supports scalar mapping keys,
* i.e. the keys must be strings. Each mapping field schema contains a
* \ref cyaml_schema_value to define field's value.
*
* The schema for mappings is composed of an array of entries of this
* data structure. It specifies the name of the key, and the type of
* the value. It also specifies the offset into the data at which value
* data should be placed. The array is terminated by an entry with a NULL key.
*/
typedef struct cyaml_schema_field {
/**
* String for YAML mapping key that his schema entry describes,
* or NULL to indicated the end of an array of \ref cyaml_schema_field
* entries.
*/
const char *key;
/**
* Offset in data structure at which the value for this key should
* be placed / read from.
*/
uint32_t data_offset;
/**
* \ref CYAML_SEQUENCE only: Offset to sequence
* entry count member in mapping's data structure.
*/
uint32_t count_offset;
/**
* \ref CYAML_SEQUENCE only: Size in bytes of sequence
* entry count member in mapping's data structure.
*/
uint8_t count_size;
/**
* Defines the schema for the mapping field's value.
*/
struct cyaml_schema_value value;
} cyaml_schema_field_t;
/**
* CYAML behavioural configuration flags for clients
*
* These may be bitwise-ORed together.
*/
typedef enum cyaml_cfg_flags {
/**
* This indicates CYAML's default behaviour.
*/
CYAML_CFG_DEFAULT = 0,
/**
* When set, unknown mapping keys are ignored when loading YAML.
* Without this flag set, CYAML's default behaviour is to return
* with the error \ref CYAML_ERR_INVALID_KEY.
*/
CYAML_CFG_IGNORE_UNKNOWN_KEYS = (1 << 0),
/**
* When saving, emit mapping / sequence values in block style.
*
* This setting can be overridden for specific values using schema
* value flags (\ref cyaml_flag).
*
* \note This only applies to values of type \ref CYAML_MAPPING,
* \ref CYAML_SEQUENCE, or \ref CYAML_SEQUENCE_FIXED.
*
* \note If both \ref CYAML_CFG_STYLE_BLOCK and
* \ref CYAML_CFG_STYLE_FLOW are set, then block style takes
* precedence.
*/
CYAML_CFG_STYLE_BLOCK = (1 << 1),
/**
* When saving, emit mapping / sequence values in flow style.
*
* This setting can be overridden for specific values using schema
* value flags (\ref cyaml_flag).
*
* \note This only applies to values of type \ref CYAML_MAPPING,
* \ref CYAML_SEQUENCE, or \ref CYAML_SEQUENCE_FIXED.
*
* \note If both \ref CYAML_CFG_STYLE_BLOCK and
* \ref CYAML_CFG_STYLE_FLOW are set, then block style takes
* precedence.
*/
CYAML_CFG_STYLE_FLOW = (1 << 2),
/**
* When saving, emit "---" at document start and "..." at document end.
*
* If this flag isn't set, these document delimiting marks will not
* be emitted.
*/
CYAML_CFG_DOCUMENT_DELIM = (1 << 3),
/**
* When comparing strings, compare without case sensitivity.
*
* By default, strings are compared with case sensitivity.
*/
CYAML_CFG_CASE_INSENSITIVE = (1 << 4),
/**
* When loading, don't allow YAML aliases in the document.
*
* If this option is enabled, anchors will be ignored, and the
* error code \ref CYAML_ERR_ALIAS will be returned if an alias
* is encountered.
*
* Setting this removes the overhead of recording anchors, so
* it may be worth setting if aliases are not required, and
* memory is constrained.
*/
CYAML_CFG_NO_ALIAS = (1 << 5),
/**
* Log any ignored mapping keys at \ref CYAML_LOG_WARNING level.
*/
CYAML_CFG_IGNORED_KEY_WARNING = (1 << 6),
} cyaml_cfg_flags_t;
/**
* CYAML function return codes indicating success or reason for failure.
*
* Use \ref cyaml_strerror() to convert an error code to a human-readable
* string.
*/
typedef enum cyaml_err {
CYAML_OK, /**< Success. */
CYAML_ERR_OOM, /**< Memory allocation failed. */
CYAML_ERR_ALIAS, /**< See \ref CYAML_CFG_NO_ALIAS. */
CYAML_ERR_FILE_OPEN, /**< Failed to open file. */
CYAML_ERR_INVALID_KEY, /**< Mapping key rejected by schema. */
CYAML_ERR_INVALID_VALUE, /**< Value rejected by schema. */
CYAML_ERR_INVALID_ALIAS, /**< No anchor found for alias. */
CYAML_ERR_INTERNAL_ERROR, /**< Internal error in LibCYAML. */
CYAML_ERR_UNEXPECTED_EVENT, /**< YAML event rejected by schema. */
CYAML_ERR_STRING_LENGTH_MIN, /**< String length too short. */
CYAML_ERR_STRING_LENGTH_MAX, /**< String length too long. */
CYAML_ERR_INVALID_DATA_SIZE, /**< Value's data size unsupported. */
CYAML_ERR_TOP_LEVEL_NON_PTR, /**< Top level type must be pointer. */
CYAML_ERR_BAD_TYPE_IN_SCHEMA, /**< Schema contains invalid type. */
CYAML_ERR_BAD_MIN_MAX_SCHEMA, /**< Schema minimum exceeds maximum. */
CYAML_ERR_BAD_PARAM_SEQ_COUNT, /**< Bad seq_count param for schema. */
CYAML_ERR_BAD_PARAM_NULL_DATA, /**< Client gave NULL data argument. */
CYAML_ERR_BAD_BITVAL_IN_SCHEMA, /**< Bit value beyond bit field size. */
CYAML_ERR_SEQUENCE_ENTRIES_MIN, /**< Too few sequence entries. */
CYAML_ERR_SEQUENCE_ENTRIES_MAX, /**< Too many sequence entries. */
CYAML_ERR_SEQUENCE_FIXED_COUNT, /**< Mismatch between min and max. */
CYAML_ERR_SEQUENCE_IN_SEQUENCE, /**< Non-fixed sequence in sequence. */
CYAML_ERR_MAPPING_FIELD_MISSING, /**< Required mapping field missing. */
CYAML_ERR_BAD_CONFIG_NULL_MEMFN, /**< Client gave NULL mem function. */
CYAML_ERR_BAD_PARAM_NULL_CONFIG, /**< Client gave NULL config arg. */
CYAML_ERR_BAD_PARAM_NULL_SCHEMA, /**< Client gave NULL schema arg. */
CYAML_ERR_LIBYAML_EMITTER_INIT, /**< Failed to initialise libyaml. */
CYAML_ERR_LIBYAML_PARSER_INIT, /**< Failed to initialise libyaml. */
CYAML_ERR_LIBYAML_EVENT_INIT, /**< Failed to initialise libyaml. */
CYAML_ERR_LIBYAML_EMITTER, /**< Error inside libyaml emitter. */
CYAML_ERR_LIBYAML_PARSER, /**< Error inside libyaml parser. */
CYAML_ERR__COUNT, /**< Count of CYAML return codes.
* This is **not a valid return
* code** itself.
*/
} cyaml_err_t;
/**
* Value schema helper macro for values with \ref CYAML_INT type.
*
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _type The C type for this value.
*/
#define CYAML_VALUE_INT( \
_flags, _type) \
.type = CYAML_INT, \
.flags = (enum cyaml_flag)(_flags), \
.data_size = sizeof(_type)
/**
* Mapping schema helper macro for keys with \ref CYAML_INT type.
*
* Use this for integers contained in structs.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
*/
#define CYAML_FIELD_INT( \
_key, _flags, _structure, _member) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_INT(((_flags) & (~CYAML_FLAG_POINTER)), \
(((_structure *)NULL)->_member)), \
}, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_INT type.
*
* Use this for pointers to integers.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
*/
#define CYAML_FIELD_INT_PTR( \
_key, _flags, _structure, _member) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_INT(((_flags) | CYAML_FLAG_POINTER), \
(*(((_structure *)NULL)->_member))), \
}, \
}
/**
* Value schema helper macro for values with \ref CYAML_UINT type.
*
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _type The C type for this value.
*/
#define CYAML_VALUE_UINT( \
_flags, _type) \
.type = CYAML_UINT, \
.flags = (enum cyaml_flag)(_flags), \
.data_size = sizeof(_type)
/**
* Mapping schema helper macro for keys with \ref CYAML_UINT type.
*
* Use this for unsigned integers contained in structs.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
*/
#define CYAML_FIELD_UINT( \
_key, _flags, _structure, _member) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_UINT(((_flags) & (~CYAML_FLAG_POINTER)), \
(((_structure *)NULL)->_member)), \
}, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_UINT type.
*
* Use this for pointers to unsigned integers.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
*/
#define CYAML_FIELD_UINT_PTR( \
_key, _flags, _structure, _member) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_UINT(((_flags) | CYAML_FLAG_POINTER), \
(*(((_structure *)NULL)->_member))), \
}, \
}
/**
* Value schema helper macro for values with \ref CYAML_BOOL type.
*
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _type The C type for this value.
*/
#define CYAML_VALUE_BOOL( \
_flags, _type) \
.type = CYAML_BOOL, \
.flags = (enum cyaml_flag)(_flags), \
.data_size = sizeof(_type)
/**
* Mapping schema helper macro for keys with \ref CYAML_BOOL type.
*
* Use this for boolean types contained in structs.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
*/
#define CYAML_FIELD_BOOL( \
_key, _flags, _structure, _member) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_BOOL(((_flags) & (~CYAML_FLAG_POINTER)), \
(((_structure *)NULL)->_member)), \
}, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_BOOL type.
*
* Use this for pointers to boolean types.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
*/
#define CYAML_FIELD_BOOL_PTR( \
_key, _flags, _structure, _member) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_BOOL(((_flags) | CYAML_FLAG_POINTER), \
(*(((_structure *)NULL)->_member))), \
}, \
}
/**
* Value schema helper macro for values with \ref CYAML_ENUM type.
*
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _type The C type for this value.
* \param[in] _strings Array of string data for enumeration values.
* \param[in] _strings_count Number of entries in _strings.
*/
#define CYAML_VALUE_ENUM( \
_flags, _type, _strings, _strings_count) \
.type = CYAML_ENUM, \
.flags = (enum cyaml_flag)(_flags), \
.data_size = sizeof(_type), \
.enumeration = { \
.strings = _strings, \
.count = _strings_count, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_ENUM type.
*
* Use this for enumerated types contained in structs.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
* \param[in] _strings Array of string data for enumeration values.
* \param[in] _strings_count Number of entries in _strings.
*/
#define CYAML_FIELD_ENUM( \
_key, _flags, _structure, _member, _strings, _strings_count) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_ENUM(((_flags) & (~CYAML_FLAG_POINTER)), \
(((_structure *)NULL)->_member), \
_strings, _strings_count), \
}, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_ENUM type.
*
* Use this for pointers to enumerated types.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
* \param[in] _strings Array of string data for enumeration values.
* \param[in] _strings_count Number of entries in _strings.
*/
#define CYAML_FIELD_ENUM_PTR( \
_key, _flags, _structure, _member, _strings, _strings_count) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_ENUM(((_flags) | CYAML_FLAG_POINTER), \
(*(((_structure *)NULL)->_member)), \
_strings, _strings_count), \
}, \
}
/**
* Value schema helper macro for values with \ref CYAML_FLAGS type.
*
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _type The C type for this value.
* \param[in] _strings Array of string data for flag values.
* \param[in] _strings_count Number of entries in _strings.
*/
#define CYAML_VALUE_FLAGS( \
_flags, _type, _strings, _strings_count) \
.type = CYAML_FLAGS, \
.flags = (enum cyaml_flag)(_flags), \
.data_size = sizeof(_type), \
.enumeration = { \
.strings = _strings, \
.count = _strings_count, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_FLAGS type.
*
* Use this for flag types contained in structs.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
* \param[in] _strings Array of string data for flag values.
* \param[in] _strings_count Number of entries in _strings.
*/
#define CYAML_FIELD_FLAGS( \
_key, _flags, _structure, _member, _strings, _strings_count) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_FLAGS(((_flags) & (~CYAML_FLAG_POINTER)), \
(((_structure *)NULL)->_member), \
_strings, _strings_count), \
}, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_FLAGS type.
*
* Use this for pointers to flag types.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
* \param[in] _strings Array of string data for flag values.
* \param[in] _strings_count Number of entries in _strings.
*/
#define CYAML_FIELD_FLAGS_PTR( \
_key, _flags, _structure, _member, _strings, _strings_count) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_FLAGS(((_flags) | CYAML_FLAG_POINTER), \
(*(((_structure *)NULL)->_member)), \
_strings, _strings_count), \
}, \
}
/**
* Value schema helper macro for values with \ref CYAML_BITFIELD type.
*
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _type The C type for this value.
* \param[in] _bitvals Array of bit field value data for the bit field.
* \param[in] _bitvals_count Number of entries in _bitvals.
*/
#define CYAML_VALUE_BITFIELD( \
_flags, _type, _bitvals, _bitvals_count) \
.type = CYAML_BITFIELD, \
.flags = (enum cyaml_flag)(_flags), \
.data_size = sizeof(_type), \
.bitfield = { \
.bitdefs = _bitvals, \
.count = _bitvals_count, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_BITFIELD type.
*
* Use this for bit field types contained in structs.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
* \param[in] _bitvals Array of bit field value data for the bit field.
* \param[in] _bitvals_count Number of entries in _bitvals.
*/
#define CYAML_FIELD_BITFIELD( \
_key, _flags, _structure, _member, _bitvals, _bitvals_count) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_BITFIELD(((_flags) & (~CYAML_FLAG_POINTER)), \
(((_structure *)NULL)->_member), \
_bitvals, _bitvals_count), \
}, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_BITFIELD type.
*
* Use this for pointers to bit field types.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
* \param[in] _bitvals Array of bit field value data for the bit field.
* \param[in] _bitvals_count Number of entries in _bitvals.
*/
#define CYAML_FIELD_BITFIELD_PTR( \
_key, _flags, _structure, _member, _bitvals, _bitvals_count) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_BITFIELD(((_flags) | CYAML_FLAG_POINTER), \
(*(((_structure *)NULL)->_member)), \
_bitvals, _bitvals_count), \
}, \
}
/**
* Value schema helper macro for values with \ref CYAML_FLOAT type.
*
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _type The C type for this value.
*/
#define CYAML_VALUE_FLOAT( \
_flags, _type) \
.type = CYAML_FLOAT, \
.flags = (enum cyaml_flag)(_flags), \
.data_size = sizeof(_type)
/**
* Mapping schema helper macro for keys with \ref CYAML_FLOAT type.
*
* Use this for floating point types contained in structs.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
*/
#define CYAML_FIELD_FLOAT( \
_key, _flags, _structure, _member) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_FLOAT(((_flags) & (~CYAML_FLAG_POINTER)), \
(((_structure *)NULL)->_member)), \
}, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_FLOAT type.
*
* Use this for pointers to floating point types.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
*/
#define CYAML_FIELD_FLOAT_PTR( \
_key, _flags, _structure, _member) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_FLOAT(((_flags) | CYAML_FLAG_POINTER), \
(*(((_structure *)NULL)->_member))), \
}, \
}
/**
* Value schema helper macro for values with \ref CYAML_STRING type.
*
* \note If the string is an array (`char str[N];`) then the \ref
* CYAML_FLAG_POINTER flag must **not** be set, and the max
* length must be no more than `N-1`.
*
* If the string is a pointer (`char *str;`), then the \ref
* CYAML_FLAG_POINTER flag **must be set**.
*
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _type The C type for this value.
* \param[in] _min Minimum string length in bytes.
* Excludes trailing '\0'.
* \param[in] _max The C type for this value.
* Excludes trailing '\0'.
*/
#define CYAML_VALUE_STRING( \
_flags, _type, _min, _max) \
.type = CYAML_STRING, \
.flags = (enum cyaml_flag)(_flags), \
.data_size = sizeof(_type), \
.string = { \
.min = _min, \
.max = _max, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_STRING type.
*
* Use this for fields with C array type, e.g. `char str[N];`. This fills the
* maximum string length (`N-1`) out automatically.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
* \param[in] _min Minimum string length in bytes. Excludes '\0'.
*/
#define CYAML_FIELD_STRING( \
_key, _flags, _structure, _member, _min) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_STRING(((_flags) & (~CYAML_FLAG_POINTER)), \
(((_structure *)NULL)->_member), _min, \
sizeof(((_structure *)NULL)->_member) - 1), \
}, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_STRING type.
*
* Use this for fields with C pointer type, e.g. `char *str;`. This creates
* a separate allocation for the string data, and fills in the pointer.
*
* Use `0` for _min and \ref CYAML_UNLIMITED for _max for unconstrained string
* lengths.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
* \param[in] _min Minimum string length in bytes. Excludes '\0'.
* \param[in] _max Maximum string length in bytes. Excludes '\0'.
*/
#define CYAML_FIELD_STRING_PTR( \
_key, _flags, _structure, _member, _min, _max) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_STRING(((_flags) | CYAML_FLAG_POINTER), \
(((_structure *)NULL)->_member), \
_min, _max), \
}, \
}
/**
* Value schema helper macro for values with \ref CYAML_MAPPING type.
*
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _type The C type of structure corresponding to mapping.
* \param[in] _fields Pointer to mapping fields schema array.
*/
#define CYAML_VALUE_MAPPING( \
_flags, _type, _fields) \
.type = CYAML_MAPPING, \
.flags = (enum cyaml_flag)(_flags), \
.data_size = sizeof(_type), \
.mapping = { \
.fields = _fields, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_MAPPING type.
*
* Use this for structures contained within other structures.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the containing mapping.
* \param[in] _member The member in _structure for this mapping value.
* \param[in] _fields Pointer to mapping fields schema array.
*/
#define CYAML_FIELD_MAPPING( \
_key, _flags, _structure, _member, _fields) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_MAPPING(((_flags) & (~CYAML_FLAG_POINTER)), \
(((_structure *)NULL)->_member), _fields), \
}, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_MAPPING type.
*
* Use this for pointers to structures.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the containing mapping.
* \param[in] _member The member in _structure for this mapping value.
* \param[in] _fields Pointer to mapping fields schema array.
*/
#define CYAML_FIELD_MAPPING_PTR( \
_key, _flags, _structure, _member, _fields) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_MAPPING(((_flags) | CYAML_FLAG_POINTER), \
(*(((_structure *)NULL)->_member)), _fields), \
}, \
}
/**
* Value schema helper macro for values with \ref CYAML_SEQUENCE type.
*
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _type The C type of sequence **entries**.
* \param[in] _entry Pointer to schema for the **entries** in sequence.
* \param[in] _min Minimum number of sequence entries required.
* \param[in] _max Maximum number of sequence entries required.
*/
#define CYAML_VALUE_SEQUENCE( \
_flags, _type, _entry, _min, _max) \
.type = CYAML_SEQUENCE, \
.flags = (enum cyaml_flag)(_flags), \
.data_size = sizeof(_type), \
.sequence = { \
.entry = _entry, \
.min = _min, \
.max = _max, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_SEQUENCE type.
*
* To use this, there must be a member in {_structure} called "{_member}_count",
* for storing the number of entries in the sequence.
*
* For example, for the following structure:
*
* ```
* struct my_structure {
* unsigned *my_sequence;
* unsigned my_sequence_count;
* };
* ```
*
* Pass the following as parameters:
*
* | Parameter | Value |
* | ---------- | --------------------- |
* | _structure | `struct my_structure` |
* | _member | `my_sequence` |
*
* If you want to call the structure member for storing the sequence entry
* count something else, then use \ref CYAML_FIELD_SEQUENCE_COUNT instead.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
* \param[in] _entry Pointer to schema for the **entries** in sequence.
* \param[in] _min Minimum number of sequence entries required.
* \param[in] _max Maximum number of sequence entries required.
*/
#define CYAML_FIELD_SEQUENCE( \
_key, _flags, _structure, _member, _entry, _min, _max) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.count_offset = offsetof(_structure, _member ## _count), \
.count_size = sizeof(((_structure *)NULL)->_member ## _count), \
.value = { \
CYAML_VALUE_SEQUENCE((_flags), \
(*(((_structure *)NULL)->_member)), \
_entry, _min, _max), \
}, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_SEQUENCE type.
*
* Compared to .\ref CYAML_FIELD_SEQUENCE, this macro takes an extra `_count`
* parameter, allowing the structure member name for the sequence entry count
* to be provided explicitly.
*
* For example, for the following structure:
*
* ```
* struct my_structure {
* unsigned *things;
* unsigned n_things;
* };
* ```
*
* Pass the following as parameters:
*
* | Parameter | Value |
* | ---------- | --------------------- |
* | _structure | `struct my_structure` |
* | _member | `things` |
* | _count | `n_things` |
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
* \param[in] _count The member in _structure for this sequence's
* entry count.
* \param[in] _entry Pointer to schema for the **entries** in sequence.
* \param[in] _min Minimum number of sequence entries required.
* \param[in] _max Maximum number of sequence entries required.
*/
#define CYAML_FIELD_SEQUENCE_COUNT( \
_key, _flags, _structure, _member, _count, _entry, _min, _max) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.count_offset = offsetof(_structure, _count), \
.count_size = sizeof(((_structure *)NULL)->_count), \
.value = { \
CYAML_VALUE_SEQUENCE((_flags), \
(*(((_structure *)NULL)->_member)), \
_entry, _min, _max), \
}, \
}
/**
* Value schema helper macro for values with \ref CYAML_SEQUENCE_FIXED type.
*
* Note that since this is a fixed size sequence, it must not be used with an
* excessive entry count. For example, passing \ref CYAML_UNLIMITED as the count
* to a \ref CYAML_SEQUENCE_FIXED with the \ref CYAML_FLAG_POINTER flag would
* cause an enormous allocation, which would fail on many systems.
*
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _type The C type of sequence **entries**.
* \param[in] _entry Pointer to schema for the **entries** in sequence.
* \param[in] _count Number of sequence entries required.
*/
#define CYAML_VALUE_SEQUENCE_FIXED( \
_flags, _type, _entry, _count) \
.type = CYAML_SEQUENCE_FIXED, \
.flags = (enum cyaml_flag)(_flags), \
.data_size = sizeof(_type), \
.sequence = { \
.entry = _entry, \
.min = _count, \
.max = _count, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_SEQUENCE_FIXED type.
*
* Note that since this is a fixed size sequence, it must not be used with an
* excessive entry count. For example, passing \ref CYAML_UNLIMITED as the count
* to a \ref CYAML_SEQUENCE_FIXED with the \ref CYAML_FLAG_POINTER flag would
* cause an enormous allocation, which would fail on many systems.
*
* \param[in] _key String defining the YAML mapping key for this value.
* \param[in] _flags Any behavioural flags relevant to this value.
* \param[in] _structure The structure corresponding to the mapping.
* \param[in] _member The member in _structure for this mapping value.
* \param[in] _entry Pointer to schema for the **entries** in sequence.
* \param[in] _count Number of sequence entries required.
*/
#define CYAML_FIELD_SEQUENCE_FIXED( \
_key, _flags, _structure, _member, _entry, _count) \
{ \
.key = _key, \
.data_offset = offsetof(_structure, _member), \
.value = { \
CYAML_VALUE_SEQUENCE_FIXED((_flags), \
(*(((_structure *)NULL)->_member)), \
_entry, _count), \
}, \
}
/**
* Mapping schema helper macro for keys with \ref CYAML_IGNORE type.
*
* \param[in] _key String defining the YAML mapping key to ignore.
* \param[in] _flags Any behavioural flags relevant to this key.
*/
#define CYAML_FIELD_IGNORE( \
_key, _flags) \
{ \
.key = _key, \
.value = { \
.type = CYAML_IGNORE, \
.flags = (_flags), \
}, \
}
/**
* Mapping schema helper macro for terminating an array of mapping fields.
*
* CYAML mapping schemas are formed from an array of \ref cyaml_schema_field
* entries, and an entry with a NULL key indicates the end of the array.
*/
#define CYAML_FIELD_END { .key = NULL }
/**
* Identifies that a \ref CYAML_SEQUENCE has unconstrained maximum entry
* count.
*/
#define CYAML_UNLIMITED 0xffffffff
/**
* Helper macro for counting array elements.
*
* \note Don't use this macro on pointers.
*
* \param[in] _a A C array.
* \return Array element count.
*/
#define CYAML_ARRAY_LEN(_a) ((sizeof(_a)) / (sizeof(_a[0])))
/**
* Data loaded or saved by CYAML has this type. CYAML schemas are used
* to describe the data contained.
*/
typedef void cyaml_data_t;
/** CYAML logging levels. */
typedef enum cyaml_log_e {
CYAML_LOG_DEBUG, /**< Debug level logging. */
CYAML_LOG_INFO, /**< Info level logging. */
CYAML_LOG_NOTICE, /**< Notice level logging. */
CYAML_LOG_WARNING, /**< Warning level logging. */
CYAML_LOG_ERROR, /**< Error level logging. */
} cyaml_log_t;
/**
* CYAML logging function prototype.
*
* Clients may implement this to manage logging from CYAML themselves.
* Otherwise, consider using the standard logging function, \ref cyaml_log.
*
* \param[in] level Log level of message to log.
* \param[in] ctx Client's private logging context.
* \param[in] fmt Format string for message to log.
* \param[in] args Additional arguments used by fmt.
*/
typedef void (*cyaml_log_fn_t)(
cyaml_log_t level,
void *ctx,
const char *fmt,
va_list args);
/**
* CYAML memory allocation / freeing function.
*
* Clients may implement this to handle memory allocation / freeing.
*
* \param[in] ctx Client's private allocation context.
* \param[in] ptr Existing allocation to resize, or NULL.
* \param[in] size The new size for the allocation. \note setting 0 must
* be treated as free().
* \return If `size == 0`, returns NULL. If `size > 0`, returns NULL on failure,
* and any existing allocation is left untouched, or return non-NULL as
* the new allocation on success, and the original pointer becomes
* invalid.
*/
typedef void * (*cyaml_mem_fn_t)(
void *ctx,
void *ptr,
size_t size);
/**
* Client CYAML configuration data.
*
* \todo Should provide facility for client to provide its own custom
* allocation functions.
*/
typedef struct cyaml_config {
/**
* Client function to use for logging.
*
* Clients can implement their own logging function and set it here.
* Otherwise, set `log_fn` to \ref cyaml_log if CYAML's default
* logging to `stderr` is suitable (see its documentation for more
* details), or set to `NULL` to suppress all logging.
*
* \note Useful backtraces are issued through the `log_fn` at
* \ref CYAML_LOG_ERROR level. If your application needs
* to load user YAML data, these backtraces can help users
* figure out what's wrong with their YAML, causing it to
* be rejected by your schema.
*/
cyaml_log_fn_t log_fn;
/**
* Client logging function context pointer.
*
* Clients using their own custom logging function can pass their
* context here, which will be passed through to their log_fn.
*
* The default logging function, \ref cyaml_log doesn't require a
* logging context, so pass NULL for the log_ctx if using that.
*/
void *log_ctx;
/**
* Client function to use for memory allocation handling.
*
* Clients can implement their own, or pass \ref cyaml_mem to use
* CYAML's default allocator.
*
* \note Depending on platform, when using CYAML's default allocator,
* clients may need to take care to ensure any allocated memory
* is freed using \ref cyaml_mem too.
*/
cyaml_mem_fn_t mem_fn;
/**
* Client memory function context pointer.
*
* Clients using their own custom allocation function can pass their
* context here, which will be passed through to their mem_fn.
*
* The default allocation function, \ref cyaml_mem doesn't require an
* allocation context, so pass NULL for the mem_ctx if using that.
*/
void *mem_ctx;
/**
* Minimum logging priority level to be issued.
*
* Specifying e.g. \ref CYAML_LOG_WARNING will cause only warnings and
* errors to emerge.
*/
cyaml_log_t log_level;
/** CYAML behaviour flags. */
cyaml_cfg_flags_t flags;
} cyaml_config_t;
/**
* Standard CYAML logging function.
*
* This logs to `stderr`. It clients want to log elsewhere they must
* implement their own logging function, and pass it to CYAML in the
* \ref cyaml_config_t structure.
*
* \note This default logging function composes single log messages from
* multiple separate fprintfs to `stderr`. If the client application
* writes to `stderr` from multiple threads, individual \ref cyaml_log
* messages may get broken up by the client applications logging. To
* avoid this, clients should implement their own \ref cyaml_log_fn_t and
* pass it in via \ref cyaml_config_t.
*
* \param[in] level Log level of message to log.
* \param[in] ctx Logging context, unused.
* \param[in] fmt Format string for message to log.
* \param[in] args Additional arguments used by fmt.
*/
extern void cyaml_log(
cyaml_log_t level,
void *ctx,
const char *fmt,
va_list args);
/**
* CYAML default memory allocation / freeing function.
*
* This is used when clients don't supply their own. It is exposed to
* enable clients to use the same allocator as libcyaml used internally
* to allocate/free memory when they have not provided their own allocation
* function.
*
* \param[in] ctx Allocation context, unused.
* \param[in] ptr Existing allocation to resize, or NULL.
* \param[in] size The new size for the allocation. \note When `size == 0`
* this frees `ptr`.
* \return If `size == 0`, returns NULL. If `size > 0`, returns NULL on failure,
* and any existing allocation is left untouched, or return non-NULL as
* the new allocation on success, and the original pointer becomes
* invalid.
*/
extern void * cyaml_mem(
void *ctx,
void *ptr,
size_t size);
/**
* Load a YAML document from a file at the given path.
*
* \note In the event of the top-level mapping having only optional fields,
* and the YAML not setting any of them, this function can return \ref
* CYAML_OK, and `NULL` in the `data_out` parameter.
*
* \param[in] path Path to YAML file to load.
* \param[in] config Client's CYAML configuration structure.
* \param[in] schema CYAML schema for the YAML to be loaded.
* \param[out] data_out Returns the caller-owned loaded data on success.
* Untouched on failure.
* \param[out] seq_count_out On success, returns the sequence entry count.
* Untouched on failure.
* Must be non-NULL if top-level schema type is
* \ref CYAML_SEQUENCE, otherwise, must be NULL.
* \return \ref CYAML_OK on success, or appropriate error code otherwise.
*/
extern cyaml_err_t cyaml_load_file(
const char *path,
const cyaml_config_t *config,
const cyaml_schema_value_t *schema,
cyaml_data_t **data_out,
unsigned *seq_count_out);
/**
* Load a YAML document from a data buffer.
*
* \note In the event of the top-level mapping having only optional fields,
* and the YAML not setting any of them, this function can return \ref
* CYAML_OK, and `NULL` in the `data_out` parameter.
*
* \param[in] input Buffer to load YAML data from.
* \param[in] input_len Length of input in bytes.
* \param[in] config Client's CYAML configuration structure.
* \param[in] schema CYAML schema for the YAML to be loaded.
* \param[out] data_out Returns the caller-owned loaded data on success.
* Untouched on failure.
* \param[out] seq_count_out On success, returns the sequence entry count.
* Untouched on failure.
* Must be non-NULL if top-level schema type is
* \ref CYAML_SEQUENCE, otherwise, must be NULL.
* \return \ref CYAML_OK on success, or appropriate error code otherwise.
*/
extern cyaml_err_t cyaml_load_data(
const uint8_t *input,
size_t input_len,
const cyaml_config_t *config,
const cyaml_schema_value_t *schema,
cyaml_data_t **data_out,
unsigned *seq_count_out);
/**
* Save a YAML document to a file at the given path.
*
* \param[in] path Path to YAML file to write.
* \param[in] config Client's CYAML configuration structure.
* \param[in] schema CYAML schema for the YAML to be saved.
* \param[in] data The caller-owned data to be saved.
* \param[in] seq_count If top level type is sequence, this should be the
* entry count, otherwise it is ignored.
* \return \ref CYAML_OK on success, or appropriate error code otherwise.
*/
extern cyaml_err_t cyaml_save_file(
const char *path,
const cyaml_config_t *config,
const cyaml_schema_value_t *schema,
const cyaml_data_t *data,
unsigned seq_count);
/**
* Save a YAML document into a string in memory.
*
* This allocates a buffer containing the serialised YAML data.
*
* To free the returned YAML string, clients should use the \ref cyaml_mem_fn_t
* function set in the \ref cyaml_config_t passed to this function.
* For example:
*
* ```
* char *yaml;
* size_t len;
* err = cyaml_save_file(&yaml, &len, &config, &client_schema, client_data, 0);
* if (err == CYAML_OK) {
* // Use `yaml`:
* printf("%*s\n", len, yaml);
* // Free `yaml`:
* config.mem_fn(config.mem_ctx, yaml, 0);
* }
* ```
*
* \note The returned YAML string does not have a trailing '\0'.
*
* \param[out] output Returns the caller-owned serialised YAML data on
* success, untouched on failure. Clients should use
* the \ref cyaml_mem_fn_t function set in the \ref
* cyaml_config_t to free the data.
* \param[out] len Returns the length of the data in output on success,
* untouched on failure.
* \param[in] config Client's CYAML configuration structure.
* \param[in] schema CYAML schema for the YAML to be saved.
* \param[in] data The caller-owned data to be saved.
* \param[in] seq_count If top level type is sequence, this should be the
* entry count, otherwise it is ignored.
* \return \ref CYAML_OK on success, or appropriate error code otherwise.
*/
extern cyaml_err_t cyaml_save_data(
char **output,
size_t *len,
const cyaml_config_t *config,
const cyaml_schema_value_t *schema,
const cyaml_data_t *data,
unsigned seq_count);
/**
* Free data returned by a CYAML load function.
*
* This is a convenience function, which is here purely to minimise the
* amount of code required in clients. Clients would be better off writing
* their own free function for the specific data once loaded.
*
* \note This is a recursive operation, freeing all nested data.
*
* \param[in] config The client's CYAML library config.
* \param[in] schema The schema describing the content of data. Must match
* the schema given to the CYAML load function used to
* load the data.
* \param[in] data The data structure to free.
* \param[in] seq_count If top level type is sequence, this should be the
* entry count, otherwise it is ignored.
* \return \ref CYAML_OK on success, or appropriate error code otherwise.
*/
extern cyaml_err_t cyaml_free(
const cyaml_config_t *config,
const cyaml_schema_value_t *schema,
cyaml_data_t *data,
unsigned seq_count);
/**
* Convert a cyaml error code to a human-readable string.
*
* \param[in] err Error code code to convert.
* \return String representing err. The string is '\0' terminated, and owned
* by libcyaml.
*/
extern const char * cyaml_strerror(
cyaml_err_t err);
#ifdef __cplusplus
}
#endif
#endif