forked from tlsa/libcyaml
-
Notifications
You must be signed in to change notification settings - Fork 0
/
util.h
200 lines (178 loc) · 5.19 KB
/
util.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*
* SPDX-License-Identifier: ISC
*
* Copyright (C) 2017-2021 Michael Drake <[email protected]>
*/
/**
* \file
* \brief CYAML common utility functions.
*/
#ifndef CYAML_UTIL_H
#define CYAML_UTIL_H
#include "cyaml/cyaml.h"
#include "utf8.h"
/** Macro to squash unused variable compiler warnings. */
#define CYAML_UNUSED(_x) ((void)(_x))
/**
* Check whether the host is little endian.
*
* Checks whether least significant bit is in the first byte of a `uint16_t`.
*
* \return true if host is little endian.
*/
static inline bool cyaml__host_is_little_endian(void)
{
const uint16_t test = 1;
return ((const uint8_t *) &test)[0];
}
/**
* Check whether the host is big endian.
*
* \return true if host is big endian.
*/
static inline bool cyaml__host_is_big_endian(void)
{
return !cyaml__host_is_little_endian();
}
/** CYAML bitfield type. */
typedef uint32_t cyaml_bitfield_t;
/** Number of bits in \ref cyaml_bitfield_t. */
#define CYAML_BITFIELD_BITS (sizeof(cyaml_bitfield_t) * CHAR_BIT)
/** CYAML state machine states. */
enum cyaml_state_e {
CYAML_STATE_START, /**< Initial state. */
CYAML_STATE_IN_STREAM, /**< In a stream. */
CYAML_STATE_IN_DOC, /**< In a document. */
CYAML_STATE_IN_MAP_KEY, /**< In a mapping. */
CYAML_STATE_IN_MAP_VALUE, /**< In a mapping. */
CYAML_STATE_IN_SEQUENCE, /**< In a sequence. */
CYAML_STATE__COUNT, /**< Count of states, **not a valid
state itself**. */
};
/**
* Convert a CYAML state into a human readable string.
*
* \param[in] state The state to convert.
* \return String representing state.
*/
static inline const char * cyaml__state_to_str(enum cyaml_state_e state)
{
static const char * const strings[CYAML_STATE__COUNT] = {
[CYAML_STATE_START] = "start",
[CYAML_STATE_IN_STREAM] = "in stream",
[CYAML_STATE_IN_DOC] = "in doc",
[CYAML_STATE_IN_MAP_KEY] = "in mapping (key)",
[CYAML_STATE_IN_MAP_VALUE] = "in mapping (value)",
[CYAML_STATE_IN_SEQUENCE] = "in sequence",
};
if ((unsigned)state >= CYAML_STATE__COUNT) {
return "<invalid>";
}
return strings[state];
}
/**
* Convert a CYAML type into a human readable string.
*
* \param[in] type The state to convert.
* \return String representing state.
*/
static inline const char * cyaml__type_to_str(cyaml_type_e type)
{
static const char * const strings[CYAML__TYPE_COUNT] = {
[CYAML_INT] = "INT",
[CYAML_UINT] = "UINT",
[CYAML_BOOL] = "BOOL",
[CYAML_ENUM] = "ENUM",
[CYAML_FLAGS] = "FLAGS",
[CYAML_FLOAT] = "FLOAT",
[CYAML_STRING] = "STRING",
[CYAML_MAPPING] = "MAPPING",
[CYAML_BITFIELD] = "BITFIELD",
[CYAML_SEQUENCE] = "SEQUENCE",
[CYAML_SEQUENCE_FIXED] = "SEQUENCE_FIXED",
[CYAML_IGNORE] = "IGNORE",
};
if ((unsigned)type >= CYAML__TYPE_COUNT) {
return "<invalid>";
}
return strings[type];
}
/**
* Log to client's logging function, if provided.
*
* \param[in] cfg CYAML client config structure.
* \param[in] level Log level of message to log.
* \param[in] fmt Format string for message to log.
* \param[in] ... Additional arguments used by fmt.
*/
static inline void cyaml__log(
const cyaml_config_t *cfg,
cyaml_log_t level,
const char *fmt, ...)
{
if (level >= cfg->log_level && cfg->log_fn != NULL) {
va_list args;
va_start(args, fmt);
cfg->log_fn(level, cfg->log_ctx, fmt, args);
va_end(args);
}
}
/**
* Check if comparason should be case sensitive.
*
* As described in the API, schema flags take priority over config flags.
*
* \param[in] config Client's CYAML configuration structure.
* \param[in] schema The CYAML schema for the value to be compared.
* \return Whether to use case-sensitive comparason.
*/
static inline bool cyaml__is_case_sensitive(
const cyaml_config_t *config,
const cyaml_schema_value_t *schema)
{
if (schema->flags & CYAML_FLAG_CASE_INSENSITIVE) {
return false;
} else if (schema->flags & CYAML_FLAG_CASE_SENSITIVE) {
return true;
} else if (config->flags & CYAML_CFG_CASE_INSENSITIVE) {
return false;
}
return true;
}
/**
* Compare two strings.
*
* Depending on the client's configuration, and the value's schema,
* this will do either a case-sensitive or case-insensitive comparason.
*
* \param[in] config Client's CYAML configuration structure.
* \param[in] schema The CYAML schema for the value to be compared.
* \param[in] str1 First string to be compared.
* \param[in] str2 Second string to be compared.
* \return 0 if and only if strings are equal.
*/
static inline int cyaml__strcmp(
const cyaml_config_t *config,
const cyaml_schema_value_t *schema,
const void * const str1,
const void * const str2)
{
if (cyaml__is_case_sensitive(config, schema)) {
return strcmp(str1, str2);
}
return cyaml_utf8_casecmp(str1, str2);
}
/**
* Check of all the bits of a mask are set in a cyaml value flag word.
*
* \param[in] flags The value flags to test.
* \param[in] mask Mask of the bits to test for in flags.
* \return true if all bits of mask are set in flags.
*/
static inline bool cyaml__flag_check_all(
enum cyaml_flag flags,
enum cyaml_flag mask)
{
return ((flags & mask) == mask);
}
#endif