xref: /freebsd/contrib/libucl/src/ucl_internal.h (revision dda5b39711dab90ae1c5624bdd6ff7453177df31)
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 #include <sys/types.h>
28 #ifndef _WIN32
29 #include <sys/mman.h>
30 #endif
31 #include <sys/stat.h>
32 #include <sys/param.h>
33 
34 #include <limits.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <unistd.h>
38 #include <ctype.h>
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 
60 enum 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 
75 enum 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 
91 struct ucl_macro {
92 	char *name;
93 	ucl_macro_handler handler;
94 	void* ud;
95 	UT_hash_handle hh;
96 };
97 
98 struct ucl_stack {
99 	ucl_object_t *obj;
100 	struct ucl_stack *next;
101 	int level;
102 };
103 
104 struct 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
115 struct ucl_pubkey {
116 	EVP_PKEY *key;
117 	struct ucl_pubkey *next;
118 };
119 #else
120 struct ucl_pubkey {
121 	struct ucl_pubkey *next;
122 };
123 #endif
124 
125 struct 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 
133 struct 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  */
152 size_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  */
162 bool ucl_include_handler (const unsigned char *data, size_t len, void* ud);
163 
164 bool 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  */
174 bool ucl_includes_handler (const unsigned char *data, size_t len, void* ud);
175 
176 size_t ucl_strlcpy (char *dst, const char *src, size_t siz);
177 size_t ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz);
178 size_t ucl_strlcpy_tolower (char *dst, const char *src, size_t siz);
179 
180 
181 #ifdef __GNUC__
182 static inline void
183 ucl_create_err (UT_string **err, const char *fmt, ...)
184 __attribute__ (( format( printf, 2, 3) ));
185 #endif
186 
187 static inline void
188 ucl_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  */
207 static inline bool
208 ucl_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  */
263 int ucl_maybe_parse_number (ucl_object_t *obj,
264 		const char *start, const char *end, const char **pos, bool allow_double, bool number_bytes);
265 
266 
267 static inline ucl_object_t *
268 ucl_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 
273 static inline ucl_hash_t *
274 ucl_hash_insert_object (ucl_hash_t *hashlin, ucl_object_t *obj) UCL_WARN_UNUSED_RESULT;
275 
276 static inline ucl_hash_t *
277 ucl_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  */
292 unsigned char * ucl_object_emit_single_json (ucl_object_t *obj);
293 
294 #endif /* UCL_INTERNAL_H_ */
295