xref: /freebsd/contrib/libucl/src/ucl_internal.h (revision 1709ccf9d38a5753192420ce5fccd93b04ce4d07)
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
52 #include <sys/types.h>
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
61 #include <sys/stat.h>
62 #endif
63 #ifdef HAVE_SYS_PARAM_H
64 #include <sys/param.h>
65 #endif
66 
67 #ifdef HAVE_LIMITS_H
68 #include <limits.h>
69 #endif
70 #ifdef HAVE_FCNTL_H
71 #include <fcntl.h>
72 #endif
73 #ifdef HAVE_ERRNO_H
74 #include <errno.h>
75 #endif
76 #ifdef HAVE_UNISTD_H
77 #include <unistd.h>
78 #endif
79 #ifdef HAVE_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
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 
109 enum 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 
124 enum 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 
140 struct ucl_macro {
141 	char *name;
142 	ucl_macro_handler handler;
143 	void* ud;
144 	UT_hash_handle hh;
145 };
146 
147 struct ucl_stack {
148 	ucl_object_t *obj;
149 	struct ucl_stack *next;
150 	int level;
151 };
152 
153 struct 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
164 struct ucl_pubkey {
165 	EVP_PKEY *key;
166 	struct ucl_pubkey *next;
167 };
168 #else
169 struct ucl_pubkey {
170 	struct ucl_pubkey *next;
171 };
172 #endif
173 
174 struct 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 
182 struct 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  */
201 size_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  */
211 bool ucl_include_handler (const unsigned char *data, size_t len, void* ud);
212 
213 bool 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  */
223 bool ucl_includes_handler (const unsigned char *data, size_t len, void* ud);
224 
225 size_t ucl_strlcpy (char *dst, const char *src, size_t siz);
226 size_t ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz);
227 size_t ucl_strlcpy_tolower (char *dst, const char *src, size_t siz);
228 
229 
230 #ifdef __GNUC__
231 static inline void
232 ucl_create_err (UT_string **err, const char *fmt, ...)
233 __attribute__ (( format( printf, 2, 3) ));
234 #endif
235 
236 static inline void
237 ucl_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  */
256 static inline bool
257 ucl_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  */
312 int ucl_maybe_parse_number (ucl_object_t *obj,
313 		const char *start, const char *end, const char **pos,
314 		bool allow_double, bool number_bytes, bool allow_time);
315 
316 
317 static inline ucl_object_t *
318 ucl_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 
323 static inline ucl_hash_t *
324 ucl_hash_insert_object (ucl_hash_t *hashlin, ucl_object_t *obj) UCL_WARN_UNUSED_RESULT;
325 
326 static inline ucl_hash_t *
327 ucl_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  */
342 unsigned char * ucl_object_emit_single_json (ucl_object_t *obj);
343 
344 #endif /* UCL_INTERNAL_H_ */
345