Deleted Added
full compact
ucl_internal.h (262975) ucl_internal.h (263648)
1/* Copyright (c) 2013, Vsevolod Stakhov
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 *
12 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 */
23
24#ifndef UCL_INTERNAL_H_
25#define UCL_INTERNAL_H_
26
1/* Copyright (c) 2013, Vsevolod Stakhov
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 *
12 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 */
23
24#ifndef UCL_INTERNAL_H_
25#define UCL_INTERNAL_H_
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#else
30/* Help embedded builds */
31#define HAVE_SYS_TYPES_H
32#define HAVE_SYS_MMAN_H
33#define HAVE_SYS_STAT_H
34#define HAVE_SYS_PARAM_H
35#define HAVE_LIMITS_H
36#define HAVE_FCNTL_H
37#define HAVE_ERRNO_H
38#define HAVE_UNISTD_H
39#define HAVE_CTYPE_H
40#define HAVE_STDIO_H
41#define HAVE_STRING_H
42#define HAVE_FLOAT_H
43#define HAVE_LIBGEN_H
44#define HAVE_MATH_H
45#define HAVE_STDBOOL_H
46#define HAVE_STDINT_H
47#define HAVE_STDARG_H
48#define HAVE_REGEX_H
49#endif
50
51#ifdef HAVE_SYS_TYPES_H
27#include <sys/types.h>
52#include <sys/types.h>
28#ifndef _WIN32
29#include <sys/mman.h>
30#endif
53#endif
54
55#ifdef HAVE_SYS_MMAN_H
56# ifndef _WIN32
57# include <sys/mman.h>
58# endif
59#endif
60#ifdef HAVE_SYS_STAT_H
31#include <sys/stat.h>
61#include <sys/stat.h>
62#endif
63#ifdef HAVE_SYS_PARAM_H
32#include <sys/param.h>
64#include <sys/param.h>
65#endif
33
66
67#ifdef HAVE_LIMITS_H
34#include <limits.h>
68#include <limits.h>
69#endif
70#ifdef HAVE_FCNTL_H
35#include <fcntl.h>
71#include <fcntl.h>
72#endif
73#ifdef HAVE_ERRNO_H
36#include <errno.h>
74#include <errno.h>
75#endif
76#ifdef HAVE_UNISTD_H
37#include <unistd.h>
77#include <unistd.h>
78#endif
79#ifdef HAVE_CTYPE_H
38#include <ctype.h>
80#include <ctype.h>
81#endif
82#ifdef HAVE_STDIO_H
83#include <stdio.h>
84#endif
85#ifdef HAVE_STRING_H
86#include <string.h>
87#endif
39
40#include "utlist.h"
41#include "utstring.h"
42#include "uthash.h"
43#include "ucl.h"
44#include "ucl_hash.h"
45#include "xxhash.h"
46
47#ifdef HAVE_OPENSSL
48#include <openssl/evp.h>
49#endif
50
51/**
52 * @file rcl_internal.h
53 * Internal structures and functions of UCL library
54 */
55
56#define UCL_MAX_RECURSION 16
57#define UCL_TRASH_KEY 0
58#define UCL_TRASH_VALUE 1
59
60enum ucl_parser_state {
61 UCL_STATE_INIT = 0,
62 UCL_STATE_OBJECT,
63 UCL_STATE_ARRAY,
64 UCL_STATE_KEY,
65 UCL_STATE_VALUE,
66 UCL_STATE_AFTER_VALUE,
67 UCL_STATE_ARRAY_VALUE,
68 UCL_STATE_SCOMMENT,
69 UCL_STATE_MCOMMENT,
70 UCL_STATE_MACRO_NAME,
71 UCL_STATE_MACRO,
72 UCL_STATE_ERROR
73};
74
75enum ucl_character_type {
76 UCL_CHARACTER_DENIED = 0,
77 UCL_CHARACTER_KEY = 1,
78 UCL_CHARACTER_KEY_START = 1 << 1,
79 UCL_CHARACTER_WHITESPACE = 1 << 2,
80 UCL_CHARACTER_WHITESPACE_UNSAFE = 1 << 3,
81 UCL_CHARACTER_VALUE_END = 1 << 4,
82 UCL_CHARACTER_VALUE_STR = 1 << 5,
83 UCL_CHARACTER_VALUE_DIGIT = 1 << 6,
84 UCL_CHARACTER_VALUE_DIGIT_START = 1 << 7,
85 UCL_CHARACTER_ESCAPE = 1 << 8,
86 UCL_CHARACTER_KEY_SEP = 1 << 9,
87 UCL_CHARACTER_JSON_UNSAFE = 1 << 10,
88 UCL_CHARACTER_UCL_UNSAFE = 1 << 11
89};
90
91struct ucl_macro {
92 char *name;
93 ucl_macro_handler handler;
94 void* ud;
95 UT_hash_handle hh;
96};
97
98struct ucl_stack {
99 ucl_object_t *obj;
100 struct ucl_stack *next;
101 int level;
102};
103
104struct ucl_chunk {
105 const unsigned char *begin;
106 const unsigned char *end;
107 const unsigned char *pos;
108 size_t remain;
109 unsigned int line;
110 unsigned int column;
111 struct ucl_chunk *next;
112};
113
114#ifdef HAVE_OPENSSL
115struct ucl_pubkey {
116 EVP_PKEY *key;
117 struct ucl_pubkey *next;
118};
119#else
120struct ucl_pubkey {
121 struct ucl_pubkey *next;
122};
123#endif
124
125struct ucl_variable {
126 char *var;
127 char *value;
128 size_t var_len;
129 size_t value_len;
130 struct ucl_variable *next;
131};
132
133struct ucl_parser {
134 enum ucl_parser_state state;
135 enum ucl_parser_state prev_state;
136 unsigned int recursion;
137 int flags;
138 ucl_object_t *top_obj;
139 ucl_object_t *cur_obj;
140 struct ucl_macro *macroes;
141 struct ucl_stack *stack;
142 struct ucl_chunk *chunks;
143 struct ucl_pubkey *keys;
144 struct ucl_variable *variables;
145 UT_string *err;
146};
147
148/**
149 * Unescape json string inplace
150 * @param str
151 */
152size_t ucl_unescape_json_string (char *str, size_t len);
153
154/**
155 * Handle include macro
156 * @param data include data
157 * @param len length of data
158 * @param ud user data
159 * @param err error ptr
160 * @return
161 */
162bool ucl_include_handler (const unsigned char *data, size_t len, void* ud);
163
164bool ucl_try_include_handler (const unsigned char *data, size_t len, void* ud);
165
166/**
167 * Handle includes macro
168 * @param data include data
169 * @param len length of data
170 * @param ud user data
171 * @param err error ptr
172 * @return
173 */
174bool ucl_includes_handler (const unsigned char *data, size_t len, void* ud);
175
176size_t ucl_strlcpy (char *dst, const char *src, size_t siz);
177size_t ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz);
178size_t ucl_strlcpy_tolower (char *dst, const char *src, size_t siz);
179
180
181#ifdef __GNUC__
182static inline void
183ucl_create_err (UT_string **err, const char *fmt, ...)
184__attribute__ (( format( printf, 2, 3) ));
185#endif
186
187static inline void
188ucl_create_err (UT_string **err, const char *fmt, ...)
189
190{
191 if (*err == NULL) {
192 utstring_new (*err);
193 va_list ap;
194 va_start (ap, fmt);
195 utstring_printf_va (*err, fmt, ap);
196 va_end (ap);
197 }
198}
199
200/**
201 * Check whether a given string contains a boolean value
202 * @param obj object to set
203 * @param start start of a string
204 * @param len length of a string
205 * @return true if a string is a boolean value
206 */
207static inline bool
208ucl_maybe_parse_boolean (ucl_object_t *obj, const unsigned char *start, size_t len)
209{
210 const unsigned char *p = start;
211 bool ret = false, val = false;
212
213 if (len == 5) {
214 if ((p[0] == 'f' || p[0] == 'F') && strncasecmp (p, "false", 5) == 0) {
215 ret = true;
216 val = false;
217 }
218 }
219 else if (len == 4) {
220 if ((p[0] == 't' || p[0] == 'T') && strncasecmp (p, "true", 4) == 0) {
221 ret = true;
222 val = true;
223 }
224 }
225 else if (len == 3) {
226 if ((p[0] == 'y' || p[0] == 'Y') && strncasecmp (p, "yes", 3) == 0) {
227 ret = true;
228 val = true;
229 }
230 else if ((p[0] == 'o' || p[0] == 'O') && strncasecmp (p, "off", 3) == 0) {
231 ret = true;
232 val = false;
233 }
234 }
235 else if (len == 2) {
236 if ((p[0] == 'n' || p[0] == 'N') && strncasecmp (p, "no", 2) == 0) {
237 ret = true;
238 val = false;
239 }
240 else if ((p[0] == 'o' || p[0] == 'O') && strncasecmp (p, "on", 2) == 0) {
241 ret = true;
242 val = true;
243 }
244 }
245
246 if (ret) {
247 obj->type = UCL_BOOLEAN;
248 obj->value.iv = val;
249 }
250
251 return ret;
252}
253
254/**
255 * Check numeric string
256 * @param obj object to set if a string is numeric
257 * @param start start of string
258 * @param end end of string
259 * @param pos position where parsing has stopped
260 * @param allow_double allow parsing of floating point values
261 * @return 0 if string is numeric and error code (EINVAL or ERANGE) in case of conversion error
262 */
263int ucl_maybe_parse_number (ucl_object_t *obj,
88
89#include "utlist.h"
90#include "utstring.h"
91#include "uthash.h"
92#include "ucl.h"
93#include "ucl_hash.h"
94#include "xxhash.h"
95
96#ifdef HAVE_OPENSSL
97#include <openssl/evp.h>
98#endif
99
100/**
101 * @file rcl_internal.h
102 * Internal structures and functions of UCL library
103 */
104
105#define UCL_MAX_RECURSION 16
106#define UCL_TRASH_KEY 0
107#define UCL_TRASH_VALUE 1
108
109enum ucl_parser_state {
110 UCL_STATE_INIT = 0,
111 UCL_STATE_OBJECT,
112 UCL_STATE_ARRAY,
113 UCL_STATE_KEY,
114 UCL_STATE_VALUE,
115 UCL_STATE_AFTER_VALUE,
116 UCL_STATE_ARRAY_VALUE,
117 UCL_STATE_SCOMMENT,
118 UCL_STATE_MCOMMENT,
119 UCL_STATE_MACRO_NAME,
120 UCL_STATE_MACRO,
121 UCL_STATE_ERROR
122};
123
124enum ucl_character_type {
125 UCL_CHARACTER_DENIED = 0,
126 UCL_CHARACTER_KEY = 1,
127 UCL_CHARACTER_KEY_START = 1 << 1,
128 UCL_CHARACTER_WHITESPACE = 1 << 2,
129 UCL_CHARACTER_WHITESPACE_UNSAFE = 1 << 3,
130 UCL_CHARACTER_VALUE_END = 1 << 4,
131 UCL_CHARACTER_VALUE_STR = 1 << 5,
132 UCL_CHARACTER_VALUE_DIGIT = 1 << 6,
133 UCL_CHARACTER_VALUE_DIGIT_START = 1 << 7,
134 UCL_CHARACTER_ESCAPE = 1 << 8,
135 UCL_CHARACTER_KEY_SEP = 1 << 9,
136 UCL_CHARACTER_JSON_UNSAFE = 1 << 10,
137 UCL_CHARACTER_UCL_UNSAFE = 1 << 11
138};
139
140struct ucl_macro {
141 char *name;
142 ucl_macro_handler handler;
143 void* ud;
144 UT_hash_handle hh;
145};
146
147struct ucl_stack {
148 ucl_object_t *obj;
149 struct ucl_stack *next;
150 int level;
151};
152
153struct ucl_chunk {
154 const unsigned char *begin;
155 const unsigned char *end;
156 const unsigned char *pos;
157 size_t remain;
158 unsigned int line;
159 unsigned int column;
160 struct ucl_chunk *next;
161};
162
163#ifdef HAVE_OPENSSL
164struct ucl_pubkey {
165 EVP_PKEY *key;
166 struct ucl_pubkey *next;
167};
168#else
169struct ucl_pubkey {
170 struct ucl_pubkey *next;
171};
172#endif
173
174struct ucl_variable {
175 char *var;
176 char *value;
177 size_t var_len;
178 size_t value_len;
179 struct ucl_variable *next;
180};
181
182struct ucl_parser {
183 enum ucl_parser_state state;
184 enum ucl_parser_state prev_state;
185 unsigned int recursion;
186 int flags;
187 ucl_object_t *top_obj;
188 ucl_object_t *cur_obj;
189 struct ucl_macro *macroes;
190 struct ucl_stack *stack;
191 struct ucl_chunk *chunks;
192 struct ucl_pubkey *keys;
193 struct ucl_variable *variables;
194 UT_string *err;
195};
196
197/**
198 * Unescape json string inplace
199 * @param str
200 */
201size_t ucl_unescape_json_string (char *str, size_t len);
202
203/**
204 * Handle include macro
205 * @param data include data
206 * @param len length of data
207 * @param ud user data
208 * @param err error ptr
209 * @return
210 */
211bool ucl_include_handler (const unsigned char *data, size_t len, void* ud);
212
213bool ucl_try_include_handler (const unsigned char *data, size_t len, void* ud);
214
215/**
216 * Handle includes macro
217 * @param data include data
218 * @param len length of data
219 * @param ud user data
220 * @param err error ptr
221 * @return
222 */
223bool ucl_includes_handler (const unsigned char *data, size_t len, void* ud);
224
225size_t ucl_strlcpy (char *dst, const char *src, size_t siz);
226size_t ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz);
227size_t ucl_strlcpy_tolower (char *dst, const char *src, size_t siz);
228
229
230#ifdef __GNUC__
231static inline void
232ucl_create_err (UT_string **err, const char *fmt, ...)
233__attribute__ (( format( printf, 2, 3) ));
234#endif
235
236static inline void
237ucl_create_err (UT_string **err, const char *fmt, ...)
238
239{
240 if (*err == NULL) {
241 utstring_new (*err);
242 va_list ap;
243 va_start (ap, fmt);
244 utstring_printf_va (*err, fmt, ap);
245 va_end (ap);
246 }
247}
248
249/**
250 * Check whether a given string contains a boolean value
251 * @param obj object to set
252 * @param start start of a string
253 * @param len length of a string
254 * @return true if a string is a boolean value
255 */
256static inline bool
257ucl_maybe_parse_boolean (ucl_object_t *obj, const unsigned char *start, size_t len)
258{
259 const unsigned char *p = start;
260 bool ret = false, val = false;
261
262 if (len == 5) {
263 if ((p[0] == 'f' || p[0] == 'F') && strncasecmp (p, "false", 5) == 0) {
264 ret = true;
265 val = false;
266 }
267 }
268 else if (len == 4) {
269 if ((p[0] == 't' || p[0] == 'T') && strncasecmp (p, "true", 4) == 0) {
270 ret = true;
271 val = true;
272 }
273 }
274 else if (len == 3) {
275 if ((p[0] == 'y' || p[0] == 'Y') && strncasecmp (p, "yes", 3) == 0) {
276 ret = true;
277 val = true;
278 }
279 else if ((p[0] == 'o' || p[0] == 'O') && strncasecmp (p, "off", 3) == 0) {
280 ret = true;
281 val = false;
282 }
283 }
284 else if (len == 2) {
285 if ((p[0] == 'n' || p[0] == 'N') && strncasecmp (p, "no", 2) == 0) {
286 ret = true;
287 val = false;
288 }
289 else if ((p[0] == 'o' || p[0] == 'O') && strncasecmp (p, "on", 2) == 0) {
290 ret = true;
291 val = true;
292 }
293 }
294
295 if (ret) {
296 obj->type = UCL_BOOLEAN;
297 obj->value.iv = val;
298 }
299
300 return ret;
301}
302
303/**
304 * Check numeric string
305 * @param obj object to set if a string is numeric
306 * @param start start of string
307 * @param end end of string
308 * @param pos position where parsing has stopped
309 * @param allow_double allow parsing of floating point values
310 * @return 0 if string is numeric and error code (EINVAL or ERANGE) in case of conversion error
311 */
312int ucl_maybe_parse_number (ucl_object_t *obj,
264 const char *start, const char *end, const char **pos, bool allow_double, bool number_bytes);
313 const char *start, const char *end, const char **pos,
314 bool allow_double, bool number_bytes, bool allow_time);
265
266
267static inline ucl_object_t *
268ucl_hash_search_obj (ucl_hash_t* hashlin, ucl_object_t *obj)
269{
270 return (ucl_object_t *)ucl_hash_search (hashlin, obj->key, obj->keylen);
271}
272
273static inline ucl_hash_t *
274ucl_hash_insert_object (ucl_hash_t *hashlin, ucl_object_t *obj) UCL_WARN_UNUSED_RESULT;
275
276static inline ucl_hash_t *
277ucl_hash_insert_object (ucl_hash_t *hashlin, ucl_object_t *obj)
278{
279 if (hashlin == NULL) {
280 hashlin = ucl_hash_create ();
281 }
282 ucl_hash_insert (hashlin, obj, obj->key, obj->keylen);
283
284 return hashlin;
285}
286
287/**
288 * Emit a single object to string
289 * @param obj
290 * @return
291 */
292unsigned char * ucl_object_emit_single_json (ucl_object_t *obj);
293
294#endif /* UCL_INTERNAL_H_ */
315
316
317static inline ucl_object_t *
318ucl_hash_search_obj (ucl_hash_t* hashlin, ucl_object_t *obj)
319{
320 return (ucl_object_t *)ucl_hash_search (hashlin, obj->key, obj->keylen);
321}
322
323static inline ucl_hash_t *
324ucl_hash_insert_object (ucl_hash_t *hashlin, ucl_object_t *obj) UCL_WARN_UNUSED_RESULT;
325
326static inline ucl_hash_t *
327ucl_hash_insert_object (ucl_hash_t *hashlin, ucl_object_t *obj)
328{
329 if (hashlin == NULL) {
330 hashlin = ucl_hash_create ();
331 }
332 ucl_hash_insert (hashlin, obj, obj->key, obj->keylen);
333
334 return hashlin;
335}
336
337/**
338 * Emit a single object to string
339 * @param obj
340 * @return
341 */
342unsigned char * ucl_object_emit_single_json (ucl_object_t *obj);
343
344#endif /* UCL_INTERNAL_H_ */