Deleted Added
full compact
ucl_util.c (262975) ucl_util.c (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#include "ucl.h"
25#include "ucl_internal.h"
26#include "ucl_chartable.h"
27
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#include "ucl.h"
25#include "ucl_internal.h"
26#include "ucl_chartable.h"
27
28#ifdef HAVE_LIBGEN_H
28#include <libgen.h> /* For dirname */
29#include <libgen.h> /* For dirname */
30#endif
29
30#ifdef HAVE_OPENSSL
31#include <openssl/err.h>
32#include <openssl/sha.h>
33#include <openssl/rsa.h>
34#include <openssl/ssl.h>
35#include <openssl/evp.h>
36#endif
37
31
32#ifdef HAVE_OPENSSL
33#include <openssl/err.h>
34#include <openssl/sha.h>
35#include <openssl/rsa.h>
36#include <openssl/ssl.h>
37#include <openssl/evp.h>
38#endif
39
40#ifdef CURL_FOUND
41#include <curl/curl.h>
42#endif
43#ifdef HAVE_FETCH_H
44#include <fetch.h>
45#endif
46
38#ifdef _WIN32
39#include <windows.h>
40
47#ifdef _WIN32
48#include <windows.h>
49
50#ifndef PROT_READ
41#define PROT_READ 1
51#define PROT_READ 1
52#endif
53#ifndef PROT_WRITE
42#define PROT_WRITE 2
54#define PROT_WRITE 2
55#endif
56#ifndef PROT_READWRITE
43#define PROT_READWRITE 3
57#define PROT_READWRITE 3
58#endif
59#ifndef MAP_SHARED
44#define MAP_SHARED 1
60#define MAP_SHARED 1
61#endif
62#ifndef MAP_PRIVATE
45#define MAP_PRIVATE 2
63#define MAP_PRIVATE 2
64#endif
65#ifndef MAP_FAILED
46#define MAP_FAILED ((void *) -1)
66#define MAP_FAILED ((void *) -1)
67#endif
47
68
48static void *mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset)
69static void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset)
49{
50 void *map = NULL;
51 HANDLE handle = INVALID_HANDLE_VALUE;
52
53 switch (prot) {
54 default:
55 case PROT_READ:
56 {
57 handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0);
58 if (!handle) break;
59 map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length);
60 CloseHandle(handle);
61 break;
62 }
63 case PROT_WRITE:
64 {
65 handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
66 if (!handle) break;
67 map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length);
68 CloseHandle(handle);
69 break;
70 }
71 case PROT_READWRITE:
72 {
73 handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
74 if (!handle) break;
75 map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length);
76 CloseHandle(handle);
77 break;
78 }
79 }
80 if (map == (void *) NULL) {
81 return (void *) MAP_FAILED;
82 }
83 return (void *) ((char *) map + offset);
84}
85
70{
71 void *map = NULL;
72 HANDLE handle = INVALID_HANDLE_VALUE;
73
74 switch (prot) {
75 default:
76 case PROT_READ:
77 {
78 handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0);
79 if (!handle) break;
80 map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length);
81 CloseHandle(handle);
82 break;
83 }
84 case PROT_WRITE:
85 {
86 handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
87 if (!handle) break;
88 map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length);
89 CloseHandle(handle);
90 break;
91 }
92 case PROT_READWRITE:
93 {
94 handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
95 if (!handle) break;
96 map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length);
97 CloseHandle(handle);
98 break;
99 }
100 }
101 if (map == (void *) NULL) {
102 return (void *) MAP_FAILED;
103 }
104 return (void *) ((char *) map + offset);
105}
106
86static int munmap(void *map,size_t length)
107static int ucl_munmap(void *map,size_t length)
87{
88 if (!UnmapViewOfFile(map)) {
89 return(-1);
90 }
91 return(0);
92}
93
108{
109 if (!UnmapViewOfFile(map)) {
110 return(-1);
111 }
112 return(0);
113}
114
94static char* realpath(const char *path, char *resolved_path) {
115static char* ucl_realpath(const char *path, char *resolved_path) {
95 char *p;
96 char tmp[MAX_PATH + 1];
97 strncpy(tmp, path, sizeof(tmp)-1);
98 p = tmp;
99 while(*p) {
100 if (*p == '/') *p = '\\';
101 p++;
102 }
103 return _fullpath(resolved_path, tmp, MAX_PATH);
104}
116 char *p;
117 char tmp[MAX_PATH + 1];
118 strncpy(tmp, path, sizeof(tmp)-1);
119 p = tmp;
120 while(*p) {
121 if (*p == '/') *p = '\\';
122 p++;
123 }
124 return _fullpath(resolved_path, tmp, MAX_PATH);
125}
126#else
127#define ucl_mmap mmap
128#define ucl_munmap munmap
129#define ucl_realpath realpath
105#endif
106
107/**
108 * @file rcl_util.c
109 * Utilities for rcl parsing
110 */
111
112
113static void
114ucl_object_free_internal (ucl_object_t *obj, bool allow_rec)
115{
116 ucl_object_t *sub, *tmp;
117
118 while (obj != NULL) {
119 if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
120 UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]);
121 }
122 if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
123 UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]);
124 }
125
126 if (obj->type == UCL_ARRAY) {
127 sub = obj->value.av;
128 while (sub != NULL) {
129 tmp = sub->next;
130 ucl_object_free_internal (sub, false);
131 sub = tmp;
132 }
133 }
134 else if (obj->type == UCL_OBJECT) {
135 if (obj->value.ov != NULL) {
136 ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)ucl_object_unref);
137 }
138 }
139 tmp = obj->next;
140 UCL_FREE (sizeof (ucl_object_t), obj);
141 obj = tmp;
142
143 if (!allow_rec) {
144 break;
145 }
146 }
147}
148
149void
150ucl_object_free (ucl_object_t *obj)
151{
152 ucl_object_free_internal (obj, true);
153}
154
155size_t
156ucl_unescape_json_string (char *str, size_t len)
157{
158 char *t = str, *h = str;
159 int i, uval;
160
130#endif
131
132/**
133 * @file rcl_util.c
134 * Utilities for rcl parsing
135 */
136
137
138static void
139ucl_object_free_internal (ucl_object_t *obj, bool allow_rec)
140{
141 ucl_object_t *sub, *tmp;
142
143 while (obj != NULL) {
144 if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
145 UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]);
146 }
147 if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
148 UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]);
149 }
150
151 if (obj->type == UCL_ARRAY) {
152 sub = obj->value.av;
153 while (sub != NULL) {
154 tmp = sub->next;
155 ucl_object_free_internal (sub, false);
156 sub = tmp;
157 }
158 }
159 else if (obj->type == UCL_OBJECT) {
160 if (obj->value.ov != NULL) {
161 ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)ucl_object_unref);
162 }
163 }
164 tmp = obj->next;
165 UCL_FREE (sizeof (ucl_object_t), obj);
166 obj = tmp;
167
168 if (!allow_rec) {
169 break;
170 }
171 }
172}
173
174void
175ucl_object_free (ucl_object_t *obj)
176{
177 ucl_object_free_internal (obj, true);
178}
179
180size_t
181ucl_unescape_json_string (char *str, size_t len)
182{
183 char *t = str, *h = str;
184 int i, uval;
185
186 if (len <= 1) {
187 return len;
188 }
161 /* t is target (tortoise), h is source (hare) */
162
163 while (len) {
164 if (*h == '\\') {
165 h ++;
166 switch (*h) {
167 case 'n':
168 *t++ = '\n';
169 break;
170 case 'r':
171 *t++ = '\r';
172 break;
173 case 'b':
174 *t++ = '\b';
175 break;
176 case 't':
177 *t++ = '\t';
178 break;
179 case 'f':
180 *t++ = '\f';
181 break;
182 case '\\':
183 *t++ = '\\';
184 break;
185 case '"':
186 *t++ = '"';
187 break;
188 case 'u':
189 /* Unicode escape */
190 uval = 0;
189 /* t is target (tortoise), h is source (hare) */
190
191 while (len) {
192 if (*h == '\\') {
193 h ++;
194 switch (*h) {
195 case 'n':
196 *t++ = '\n';
197 break;
198 case 'r':
199 *t++ = '\r';
200 break;
201 case 'b':
202 *t++ = '\b';
203 break;
204 case 't':
205 *t++ = '\t';
206 break;
207 case 'f':
208 *t++ = '\f';
209 break;
210 case '\\':
211 *t++ = '\\';
212 break;
213 case '"':
214 *t++ = '"';
215 break;
216 case 'u':
217 /* Unicode escape */
218 uval = 0;
191 for (i = 0; i < 4; i++) {
192 uval <<= 4;
193 if (isdigit (h[i])) {
194 uval += h[i] - '0';
219 if (len > 3) {
220 for (i = 0; i < 4; i++) {
221 uval <<= 4;
222 if (isdigit (h[i])) {
223 uval += h[i] - '0';
224 }
225 else if (h[i] >= 'a' && h[i] <= 'f') {
226 uval += h[i] - 'a' + 10;
227 }
228 else if (h[i] >= 'A' && h[i] <= 'F') {
229 uval += h[i] - 'A' + 10;
230 }
231 else {
232 break;
233 }
195 }
234 }
196 else if (h[i] >= 'a' && h[i] <= 'f') {
197 uval += h[i] - 'a' + 10;
235 h += 3;
236 len -= 3;
237 /* Encode */
238 if(uval < 0x80) {
239 t[0] = (char)uval;
240 t ++;
198 }
241 }
199 else if (h[i] >= 'A' && h[i] <= 'F') {
200 uval += h[i] - 'A' + 10;
242 else if(uval < 0x800) {
243 t[0] = 0xC0 + ((uval & 0x7C0) >> 6);
244 t[1] = 0x80 + ((uval & 0x03F));
245 t += 2;
201 }
246 }
247 else if(uval < 0x10000) {
248 t[0] = 0xE0 + ((uval & 0xF000) >> 12);
249 t[1] = 0x80 + ((uval & 0x0FC0) >> 6);
250 t[2] = 0x80 + ((uval & 0x003F));
251 t += 3;
252 }
253 else if(uval <= 0x10FFFF) {
254 t[0] = 0xF0 + ((uval & 0x1C0000) >> 18);
255 t[1] = 0x80 + ((uval & 0x03F000) >> 12);
256 t[2] = 0x80 + ((uval & 0x000FC0) >> 6);
257 t[3] = 0x80 + ((uval & 0x00003F));
258 t += 4;
259 }
260 else {
261 *t++ = '?';
262 }
202 }
263 }
203 h += 3;
204 len -= 3;
205 /* Encode */
206 if(uval < 0x80) {
207 t[0] = (char)uval;
208 t ++;
209 }
210 else if(uval < 0x800) {
211 t[0] = 0xC0 + ((uval & 0x7C0) >> 6);
212 t[1] = 0x80 + ((uval & 0x03F));
213 t += 2;
214 }
215 else if(uval < 0x10000) {
216 t[0] = 0xE0 + ((uval & 0xF000) >> 12);
217 t[1] = 0x80 + ((uval & 0x0FC0) >> 6);
218 t[2] = 0x80 + ((uval & 0x003F));
219 t += 3;
220 }
221 else if(uval <= 0x10FFFF) {
222 t[0] = 0xF0 + ((uval & 0x1C0000) >> 18);
223 t[1] = 0x80 + ((uval & 0x03F000) >> 12);
224 t[2] = 0x80 + ((uval & 0x000FC0) >> 6);
225 t[3] = 0x80 + ((uval & 0x00003F));
226 t += 4;
227 }
228 else {
264 else {
229 *t++ = '?';
265 *t++ = 'u';
230 }
231 break;
232 default:
233 *t++ = *h;
234 break;
235 }
236 h ++;
237 len --;
238 }
239 else {
240 *t++ = *h++;
241 }
242 len --;
243 }
244 *t = '\0';
245
246 return (t - str);
247}
248
249UCL_EXTERN char *
250ucl_copy_key_trash (ucl_object_t *obj)
251{
266 }
267 break;
268 default:
269 *t++ = *h;
270 break;
271 }
272 h ++;
273 len --;
274 }
275 else {
276 *t++ = *h++;
277 }
278 len --;
279 }
280 *t = '\0';
281
282 return (t - str);
283}
284
285UCL_EXTERN char *
286ucl_copy_key_trash (ucl_object_t *obj)
287{
288 if (obj == NULL) {
289 return NULL;
290 }
252 if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) {
253 obj->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1);
254 if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
255 memcpy (obj->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen);
256 obj->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0';
257 }
258 obj->key = obj->trash_stack[UCL_TRASH_KEY];
259 obj->flags |= UCL_OBJECT_ALLOCATED_KEY;
260 }
261
262 return obj->trash_stack[UCL_TRASH_KEY];
263}
264
265UCL_EXTERN char *
266ucl_copy_value_trash (ucl_object_t *obj)
267{
291 if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) {
292 obj->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1);
293 if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
294 memcpy (obj->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen);
295 obj->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0';
296 }
297 obj->key = obj->trash_stack[UCL_TRASH_KEY];
298 obj->flags |= UCL_OBJECT_ALLOCATED_KEY;
299 }
300
301 return obj->trash_stack[UCL_TRASH_KEY];
302}
303
304UCL_EXTERN char *
305ucl_copy_value_trash (ucl_object_t *obj)
306{
307 if (obj == NULL) {
308 return NULL;
309 }
268 if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) {
269 if (obj->type == UCL_STRING) {
270 /* Special case for strings */
271 obj->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1);
272 if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
273 memcpy (obj->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len);
274 obj->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0';
275 obj->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
276 }
277 }
278 else {
279 /* Just emit value in json notation */
280 obj->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj);
281 obj->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]);
282 }
283 obj->flags |= UCL_OBJECT_ALLOCATED_VALUE;
284 }
285 return obj->trash_stack[UCL_TRASH_VALUE];
286}
287
288UCL_EXTERN ucl_object_t*
289ucl_parser_get_object (struct ucl_parser *parser)
290{
291 if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) {
292 return ucl_object_ref (parser->top_obj);
293 }
294
295 return NULL;
296}
297
298UCL_EXTERN void
299ucl_parser_free (struct ucl_parser *parser)
300{
301 struct ucl_stack *stack, *stmp;
302 struct ucl_macro *macro, *mtmp;
303 struct ucl_chunk *chunk, *ctmp;
304 struct ucl_pubkey *key, *ktmp;
305 struct ucl_variable *var, *vtmp;
306
310 if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) {
311 if (obj->type == UCL_STRING) {
312 /* Special case for strings */
313 obj->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1);
314 if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
315 memcpy (obj->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len);
316 obj->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0';
317 obj->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
318 }
319 }
320 else {
321 /* Just emit value in json notation */
322 obj->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj);
323 obj->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]);
324 }
325 obj->flags |= UCL_OBJECT_ALLOCATED_VALUE;
326 }
327 return obj->trash_stack[UCL_TRASH_VALUE];
328}
329
330UCL_EXTERN ucl_object_t*
331ucl_parser_get_object (struct ucl_parser *parser)
332{
333 if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) {
334 return ucl_object_ref (parser->top_obj);
335 }
336
337 return NULL;
338}
339
340UCL_EXTERN void
341ucl_parser_free (struct ucl_parser *parser)
342{
343 struct ucl_stack *stack, *stmp;
344 struct ucl_macro *macro, *mtmp;
345 struct ucl_chunk *chunk, *ctmp;
346 struct ucl_pubkey *key, *ktmp;
347 struct ucl_variable *var, *vtmp;
348
349 if (parser == NULL) {
350 return;
351 }
352
307 if (parser->top_obj != NULL) {
308 ucl_object_unref (parser->top_obj);
309 }
310
311 LL_FOREACH_SAFE (parser->stack, stack, stmp) {
312 free (stack);
313 }
314 HASH_ITER (hh, parser->macroes, macro, mtmp) {
315 free (macro->name);
316 HASH_DEL (parser->macroes, macro);
317 UCL_FREE (sizeof (struct ucl_macro), macro);
318 }
319 LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) {
320 UCL_FREE (sizeof (struct ucl_chunk), chunk);
321 }
322 LL_FOREACH_SAFE (parser->keys, key, ktmp) {
323 UCL_FREE (sizeof (struct ucl_pubkey), key);
324 }
325 LL_FOREACH_SAFE (parser->variables, var, vtmp) {
326 free (var->value);
327 free (var->var);
328 UCL_FREE (sizeof (struct ucl_variable), var);
329 }
330
331 if (parser->err != NULL) {
332 utstring_free(parser->err);
333 }
334
335 UCL_FREE (sizeof (struct ucl_parser), parser);
336}
337
338UCL_EXTERN const char *
339ucl_parser_get_error(struct ucl_parser *parser)
340{
353 if (parser->top_obj != NULL) {
354 ucl_object_unref (parser->top_obj);
355 }
356
357 LL_FOREACH_SAFE (parser->stack, stack, stmp) {
358 free (stack);
359 }
360 HASH_ITER (hh, parser->macroes, macro, mtmp) {
361 free (macro->name);
362 HASH_DEL (parser->macroes, macro);
363 UCL_FREE (sizeof (struct ucl_macro), macro);
364 }
365 LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) {
366 UCL_FREE (sizeof (struct ucl_chunk), chunk);
367 }
368 LL_FOREACH_SAFE (parser->keys, key, ktmp) {
369 UCL_FREE (sizeof (struct ucl_pubkey), key);
370 }
371 LL_FOREACH_SAFE (parser->variables, var, vtmp) {
372 free (var->value);
373 free (var->var);
374 UCL_FREE (sizeof (struct ucl_variable), var);
375 }
376
377 if (parser->err != NULL) {
378 utstring_free(parser->err);
379 }
380
381 UCL_FREE (sizeof (struct ucl_parser), parser);
382}
383
384UCL_EXTERN const char *
385ucl_parser_get_error(struct ucl_parser *parser)
386{
387 if (parser == NULL) {
388 return NULL;
389 }
390
341 if (parser->err == NULL)
342 return NULL;
343
344 return utstring_body(parser->err);
345}
346
347UCL_EXTERN bool
348ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
349{
350#ifndef HAVE_OPENSSL
351 ucl_create_err (&parser->err, "cannot check signatures without openssl");
352 return false;
353#else
354# if (OPENSSL_VERSION_NUMBER < 0x10000000L)
355 ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported");
356 return EXIT_FAILURE;
357# else
358 struct ucl_pubkey *nkey;
359 BIO *mem;
360
361 mem = BIO_new_mem_buf ((void *)key, len);
362 nkey = UCL_ALLOC (sizeof (struct ucl_pubkey));
391 if (parser->err == NULL)
392 return NULL;
393
394 return utstring_body(parser->err);
395}
396
397UCL_EXTERN bool
398ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
399{
400#ifndef HAVE_OPENSSL
401 ucl_create_err (&parser->err, "cannot check signatures without openssl");
402 return false;
403#else
404# if (OPENSSL_VERSION_NUMBER < 0x10000000L)
405 ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported");
406 return EXIT_FAILURE;
407# else
408 struct ucl_pubkey *nkey;
409 BIO *mem;
410
411 mem = BIO_new_mem_buf ((void *)key, len);
412 nkey = UCL_ALLOC (sizeof (struct ucl_pubkey));
413 if (nkey == NULL) {
414 ucl_create_err (&parser->err, "cannot allocate memory for key");
415 return false;
416 }
363 nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL);
364 BIO_free (mem);
365 if (nkey->key == NULL) {
366 UCL_FREE (sizeof (struct ucl_pubkey), nkey);
367 ucl_create_err (&parser->err, "%s",
368 ERR_error_string (ERR_get_error (), NULL));
369 return false;
370 }
371 LL_PREPEND (parser->keys, nkey);
372# endif
373#endif
374 return true;
375}
376
377#ifdef CURL_FOUND
378struct ucl_curl_cbdata {
379 unsigned char *buf;
380 size_t buflen;
381};
382
383static size_t
384ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud)
385{
386 struct ucl_curl_cbdata *cbdata = ud;
387 size_t realsize = size * nmemb;
388
389 cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1);
390 if (cbdata->buf == NULL) {
391 return 0;
392 }
393
394 memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize);
395 cbdata->buflen += realsize;
396 cbdata->buf[cbdata->buflen] = 0;
397
398 return realsize;
399}
400#endif
401
402/**
403 * Fetch a url and save results to the memory buffer
404 * @param url url to fetch
405 * @param len length of url
406 * @param buf target buffer
407 * @param buflen target length
408 * @return
409 */
410static bool
411ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
412 UT_string **err, bool must_exist)
413{
414
415#ifdef HAVE_FETCH_H
416 struct url *fetch_url;
417 struct url_stat us;
418 FILE *in;
419
420 fetch_url = fetchParseURL (url);
421 if (fetch_url == NULL) {
422 ucl_create_err (err, "invalid URL %s: %s",
423 url, strerror (errno));
424 return false;
425 }
426 if ((in = fetchXGet (fetch_url, &us, "")) == NULL) {
427 if (!must_exist) {
428 ucl_create_err (err, "cannot fetch URL %s: %s",
429 url, strerror (errno));
430 }
431 fetchFreeURL (fetch_url);
432 return false;
433 }
434
435 *buflen = us.size;
436 *buf = malloc (*buflen);
437 if (*buf == NULL) {
438 ucl_create_err (err, "cannot allocate buffer for URL %s: %s",
439 url, strerror (errno));
440 fclose (in);
441 fetchFreeURL (fetch_url);
442 return false;
443 }
444
445 if (fread (*buf, *buflen, 1, in) != 1) {
446 ucl_create_err (err, "cannot read URL %s: %s",
447 url, strerror (errno));
448 fclose (in);
449 fetchFreeURL (fetch_url);
450 return false;
451 }
452
453 fetchFreeURL (fetch_url);
454 return true;
455#elif defined(CURL_FOUND)
456 CURL *curl;
457 int r;
458 struct ucl_curl_cbdata cbdata;
459
460 curl = curl_easy_init ();
461 if (curl == NULL) {
462 ucl_create_err (err, "CURL interface is broken");
463 return false;
464 }
465 if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) {
466 ucl_create_err (err, "invalid URL %s: %s",
467 url, curl_easy_strerror (r));
468 curl_easy_cleanup (curl);
469 return false;
470 }
471 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback);
472 cbdata.buf = *buf;
473 cbdata.buflen = *buflen;
474 curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata);
475
476 if ((r = curl_easy_perform (curl)) != CURLE_OK) {
477 if (!must_exist) {
478 ucl_create_err (err, "error fetching URL %s: %s",
479 url, curl_easy_strerror (r));
480 }
481 curl_easy_cleanup (curl);
482 if (cbdata.buf) {
483 free (cbdata.buf);
484 }
485 return false;
486 }
487 *buf = cbdata.buf;
488 *buflen = cbdata.buflen;
489
490 return true;
491#else
492 ucl_create_err (err, "URL support is disabled");
493 return false;
494#endif
495}
496
497/**
498 * Fetch a file and save results to the memory buffer
499 * @param filename filename to fetch
500 * @param len length of filename
501 * @param buf target buffer
502 * @param buflen target length
503 * @return
504 */
505static bool
506ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen,
507 UT_string **err, bool must_exist)
508{
509 int fd;
510 struct stat st;
511
512 if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) {
513 if (must_exist) {
514 ucl_create_err (err, "cannot stat file %s: %s",
515 filename, strerror (errno));
516 }
517 return false;
518 }
519 if (st.st_size == 0) {
520 /* Do not map empty files */
521 *buf = "";
522 *buflen = 0;
523 }
524 else {
525 if ((fd = open (filename, O_RDONLY)) == -1) {
526 ucl_create_err (err, "cannot open file %s: %s",
527 filename, strerror (errno));
528 return false;
529 }
417 nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL);
418 BIO_free (mem);
419 if (nkey->key == NULL) {
420 UCL_FREE (sizeof (struct ucl_pubkey), nkey);
421 ucl_create_err (&parser->err, "%s",
422 ERR_error_string (ERR_get_error (), NULL));
423 return false;
424 }
425 LL_PREPEND (parser->keys, nkey);
426# endif
427#endif
428 return true;
429}
430
431#ifdef CURL_FOUND
432struct ucl_curl_cbdata {
433 unsigned char *buf;
434 size_t buflen;
435};
436
437static size_t
438ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud)
439{
440 struct ucl_curl_cbdata *cbdata = ud;
441 size_t realsize = size * nmemb;
442
443 cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1);
444 if (cbdata->buf == NULL) {
445 return 0;
446 }
447
448 memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize);
449 cbdata->buflen += realsize;
450 cbdata->buf[cbdata->buflen] = 0;
451
452 return realsize;
453}
454#endif
455
456/**
457 * Fetch a url and save results to the memory buffer
458 * @param url url to fetch
459 * @param len length of url
460 * @param buf target buffer
461 * @param buflen target length
462 * @return
463 */
464static bool
465ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
466 UT_string **err, bool must_exist)
467{
468
469#ifdef HAVE_FETCH_H
470 struct url *fetch_url;
471 struct url_stat us;
472 FILE *in;
473
474 fetch_url = fetchParseURL (url);
475 if (fetch_url == NULL) {
476 ucl_create_err (err, "invalid URL %s: %s",
477 url, strerror (errno));
478 return false;
479 }
480 if ((in = fetchXGet (fetch_url, &us, "")) == NULL) {
481 if (!must_exist) {
482 ucl_create_err (err, "cannot fetch URL %s: %s",
483 url, strerror (errno));
484 }
485 fetchFreeURL (fetch_url);
486 return false;
487 }
488
489 *buflen = us.size;
490 *buf = malloc (*buflen);
491 if (*buf == NULL) {
492 ucl_create_err (err, "cannot allocate buffer for URL %s: %s",
493 url, strerror (errno));
494 fclose (in);
495 fetchFreeURL (fetch_url);
496 return false;
497 }
498
499 if (fread (*buf, *buflen, 1, in) != 1) {
500 ucl_create_err (err, "cannot read URL %s: %s",
501 url, strerror (errno));
502 fclose (in);
503 fetchFreeURL (fetch_url);
504 return false;
505 }
506
507 fetchFreeURL (fetch_url);
508 return true;
509#elif defined(CURL_FOUND)
510 CURL *curl;
511 int r;
512 struct ucl_curl_cbdata cbdata;
513
514 curl = curl_easy_init ();
515 if (curl == NULL) {
516 ucl_create_err (err, "CURL interface is broken");
517 return false;
518 }
519 if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) {
520 ucl_create_err (err, "invalid URL %s: %s",
521 url, curl_easy_strerror (r));
522 curl_easy_cleanup (curl);
523 return false;
524 }
525 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback);
526 cbdata.buf = *buf;
527 cbdata.buflen = *buflen;
528 curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata);
529
530 if ((r = curl_easy_perform (curl)) != CURLE_OK) {
531 if (!must_exist) {
532 ucl_create_err (err, "error fetching URL %s: %s",
533 url, curl_easy_strerror (r));
534 }
535 curl_easy_cleanup (curl);
536 if (cbdata.buf) {
537 free (cbdata.buf);
538 }
539 return false;
540 }
541 *buf = cbdata.buf;
542 *buflen = cbdata.buflen;
543
544 return true;
545#else
546 ucl_create_err (err, "URL support is disabled");
547 return false;
548#endif
549}
550
551/**
552 * Fetch a file and save results to the memory buffer
553 * @param filename filename to fetch
554 * @param len length of filename
555 * @param buf target buffer
556 * @param buflen target length
557 * @return
558 */
559static bool
560ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen,
561 UT_string **err, bool must_exist)
562{
563 int fd;
564 struct stat st;
565
566 if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) {
567 if (must_exist) {
568 ucl_create_err (err, "cannot stat file %s: %s",
569 filename, strerror (errno));
570 }
571 return false;
572 }
573 if (st.st_size == 0) {
574 /* Do not map empty files */
575 *buf = "";
576 *buflen = 0;
577 }
578 else {
579 if ((fd = open (filename, O_RDONLY)) == -1) {
580 ucl_create_err (err, "cannot open file %s: %s",
581 filename, strerror (errno));
582 return false;
583 }
530 if ((*buf = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
584 if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
531 close (fd);
532 ucl_create_err (err, "cannot mmap file %s: %s",
533 filename, strerror (errno));
534 return false;
535 }
536 *buflen = st.st_size;
537 close (fd);
538 }
539
540 return true;
541}
542
543
544#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
545static inline bool
546ucl_sig_check (const unsigned char *data, size_t datalen,
547 const unsigned char *sig, size_t siglen, struct ucl_parser *parser)
548{
549 struct ucl_pubkey *key;
550 char dig[EVP_MAX_MD_SIZE];
551 unsigned int diglen;
552 EVP_PKEY_CTX *key_ctx;
553 EVP_MD_CTX *sign_ctx = NULL;
554
555 sign_ctx = EVP_MD_CTX_create ();
556
557 LL_FOREACH (parser->keys, key) {
558 key_ctx = EVP_PKEY_CTX_new (key->key, NULL);
559 if (key_ctx != NULL) {
560 if (EVP_PKEY_verify_init (key_ctx) <= 0) {
561 EVP_PKEY_CTX_free (key_ctx);
562 continue;
563 }
564 if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) {
565 EVP_PKEY_CTX_free (key_ctx);
566 continue;
567 }
568 if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) {
569 EVP_PKEY_CTX_free (key_ctx);
570 continue;
571 }
572 EVP_DigestInit (sign_ctx, EVP_sha256 ());
573 EVP_DigestUpdate (sign_ctx, data, datalen);
574 EVP_DigestFinal (sign_ctx, dig, &diglen);
575
576 if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) {
577 EVP_MD_CTX_destroy (sign_ctx);
578 EVP_PKEY_CTX_free (key_ctx);
579 return true;
580 }
581
582 EVP_PKEY_CTX_free (key_ctx);
583 }
584 }
585
586 EVP_MD_CTX_destroy (sign_ctx);
587
588 return false;
589}
590#endif
591
592/**
593 * Include an url to configuration
594 * @param data
595 * @param len
596 * @param parser
597 * @param err
598 * @return
599 */
600static bool
601ucl_include_url (const unsigned char *data, size_t len,
602 struct ucl_parser *parser, bool check_signature, bool must_exist)
603{
604
605 bool res;
606 unsigned char *buf = NULL;
607 size_t buflen = 0;
608 struct ucl_chunk *chunk;
609 char urlbuf[PATH_MAX];
610 int prev_state;
611
612 snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data);
613
614 if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) {
615 return (!must_exist || false);
616 }
617
618 if (check_signature) {
619#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
620 unsigned char *sigbuf = NULL;
621 size_t siglen = 0;
622 /* We need to check signature first */
623 snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data);
624 if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) {
625 return false;
626 }
627 if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
628 ucl_create_err (&parser->err, "cannot verify url %s: %s",
629 urlbuf,
630 ERR_error_string (ERR_get_error (), NULL));
631 if (siglen > 0) {
585 close (fd);
586 ucl_create_err (err, "cannot mmap file %s: %s",
587 filename, strerror (errno));
588 return false;
589 }
590 *buflen = st.st_size;
591 close (fd);
592 }
593
594 return true;
595}
596
597
598#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
599static inline bool
600ucl_sig_check (const unsigned char *data, size_t datalen,
601 const unsigned char *sig, size_t siglen, struct ucl_parser *parser)
602{
603 struct ucl_pubkey *key;
604 char dig[EVP_MAX_MD_SIZE];
605 unsigned int diglen;
606 EVP_PKEY_CTX *key_ctx;
607 EVP_MD_CTX *sign_ctx = NULL;
608
609 sign_ctx = EVP_MD_CTX_create ();
610
611 LL_FOREACH (parser->keys, key) {
612 key_ctx = EVP_PKEY_CTX_new (key->key, NULL);
613 if (key_ctx != NULL) {
614 if (EVP_PKEY_verify_init (key_ctx) <= 0) {
615 EVP_PKEY_CTX_free (key_ctx);
616 continue;
617 }
618 if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) {
619 EVP_PKEY_CTX_free (key_ctx);
620 continue;
621 }
622 if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) {
623 EVP_PKEY_CTX_free (key_ctx);
624 continue;
625 }
626 EVP_DigestInit (sign_ctx, EVP_sha256 ());
627 EVP_DigestUpdate (sign_ctx, data, datalen);
628 EVP_DigestFinal (sign_ctx, dig, &diglen);
629
630 if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) {
631 EVP_MD_CTX_destroy (sign_ctx);
632 EVP_PKEY_CTX_free (key_ctx);
633 return true;
634 }
635
636 EVP_PKEY_CTX_free (key_ctx);
637 }
638 }
639
640 EVP_MD_CTX_destroy (sign_ctx);
641
642 return false;
643}
644#endif
645
646/**
647 * Include an url to configuration
648 * @param data
649 * @param len
650 * @param parser
651 * @param err
652 * @return
653 */
654static bool
655ucl_include_url (const unsigned char *data, size_t len,
656 struct ucl_parser *parser, bool check_signature, bool must_exist)
657{
658
659 bool res;
660 unsigned char *buf = NULL;
661 size_t buflen = 0;
662 struct ucl_chunk *chunk;
663 char urlbuf[PATH_MAX];
664 int prev_state;
665
666 snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data);
667
668 if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) {
669 return (!must_exist || false);
670 }
671
672 if (check_signature) {
673#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
674 unsigned char *sigbuf = NULL;
675 size_t siglen = 0;
676 /* We need to check signature first */
677 snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data);
678 if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) {
679 return false;
680 }
681 if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
682 ucl_create_err (&parser->err, "cannot verify url %s: %s",
683 urlbuf,
684 ERR_error_string (ERR_get_error (), NULL));
685 if (siglen > 0) {
632 munmap (sigbuf, siglen);
686 ucl_munmap (sigbuf, siglen);
633 }
634 return false;
635 }
636 if (siglen > 0) {
687 }
688 return false;
689 }
690 if (siglen > 0) {
637 munmap (sigbuf, siglen);
691 ucl_munmap (sigbuf, siglen);
638 }
639#endif
640 }
641
642 prev_state = parser->state;
643 parser->state = UCL_STATE_INIT;
644
645 res = ucl_parser_add_chunk (parser, buf, buflen);
646 if (res == true) {
647 /* Remove chunk from the stack */
648 chunk = parser->chunks;
649 if (chunk != NULL) {
650 parser->chunks = chunk->next;
651 UCL_FREE (sizeof (struct ucl_chunk), chunk);
652 }
653 }
654
655 parser->state = prev_state;
656 free (buf);
657
658 return res;
659}
660
661/**
662 * Include a file to configuration
663 * @param data
664 * @param len
665 * @param parser
666 * @param err
667 * @return
668 */
669static bool
670ucl_include_file (const unsigned char *data, size_t len,
671 struct ucl_parser *parser, bool check_signature, bool must_exist)
672{
673 bool res;
674 struct ucl_chunk *chunk;
675 unsigned char *buf = NULL;
676 size_t buflen;
677 char filebuf[PATH_MAX], realbuf[PATH_MAX];
678 int prev_state;
679
680 snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
692 }
693#endif
694 }
695
696 prev_state = parser->state;
697 parser->state = UCL_STATE_INIT;
698
699 res = ucl_parser_add_chunk (parser, buf, buflen);
700 if (res == true) {
701 /* Remove chunk from the stack */
702 chunk = parser->chunks;
703 if (chunk != NULL) {
704 parser->chunks = chunk->next;
705 UCL_FREE (sizeof (struct ucl_chunk), chunk);
706 }
707 }
708
709 parser->state = prev_state;
710 free (buf);
711
712 return res;
713}
714
715/**
716 * Include a file to configuration
717 * @param data
718 * @param len
719 * @param parser
720 * @param err
721 * @return
722 */
723static bool
724ucl_include_file (const unsigned char *data, size_t len,
725 struct ucl_parser *parser, bool check_signature, bool must_exist)
726{
727 bool res;
728 struct ucl_chunk *chunk;
729 unsigned char *buf = NULL;
730 size_t buflen;
731 char filebuf[PATH_MAX], realbuf[PATH_MAX];
732 int prev_state;
733
734 snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
681 if (realpath (filebuf, realbuf) == NULL) {
735 if (ucl_realpath (filebuf, realbuf) == NULL) {
682 if (!must_exist) {
683 return true;
684 }
685 ucl_create_err (&parser->err, "cannot open file %s: %s",
686 filebuf,
687 strerror (errno));
688 return false;
689 }
690
691 if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) {
692 return (!must_exist || false);
693 }
694
695 if (check_signature) {
696#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
697 unsigned char *sigbuf = NULL;
698 size_t siglen = 0;
699 /* We need to check signature first */
700 snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf);
701 if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) {
702 return false;
703 }
704 if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
705 ucl_create_err (&parser->err, "cannot verify file %s: %s",
706 filebuf,
707 ERR_error_string (ERR_get_error (), NULL));
708 if (siglen > 0) {
736 if (!must_exist) {
737 return true;
738 }
739 ucl_create_err (&parser->err, "cannot open file %s: %s",
740 filebuf,
741 strerror (errno));
742 return false;
743 }
744
745 if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) {
746 return (!must_exist || false);
747 }
748
749 if (check_signature) {
750#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
751 unsigned char *sigbuf = NULL;
752 size_t siglen = 0;
753 /* We need to check signature first */
754 snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf);
755 if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) {
756 return false;
757 }
758 if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
759 ucl_create_err (&parser->err, "cannot verify file %s: %s",
760 filebuf,
761 ERR_error_string (ERR_get_error (), NULL));
762 if (siglen > 0) {
709 munmap (sigbuf, siglen);
763 ucl_munmap (sigbuf, siglen);
710 }
711 return false;
712 }
713 if (siglen > 0) {
764 }
765 return false;
766 }
767 if (siglen > 0) {
714 munmap (sigbuf, siglen);
768 ucl_munmap (sigbuf, siglen);
715 }
716#endif
717 }
718
719 ucl_parser_set_filevars (parser, realbuf, false);
720
721 prev_state = parser->state;
722 parser->state = UCL_STATE_INIT;
723
724 res = ucl_parser_add_chunk (parser, buf, buflen);
725 if (res == true) {
726 /* Remove chunk from the stack */
727 chunk = parser->chunks;
728 if (chunk != NULL) {
729 parser->chunks = chunk->next;
730 UCL_FREE (sizeof (struct ucl_chunk), chunk);
731 }
732 }
733
734 parser->state = prev_state;
735
736 if (buflen > 0) {
769 }
770#endif
771 }
772
773 ucl_parser_set_filevars (parser, realbuf, false);
774
775 prev_state = parser->state;
776 parser->state = UCL_STATE_INIT;
777
778 res = ucl_parser_add_chunk (parser, buf, buflen);
779 if (res == true) {
780 /* Remove chunk from the stack */
781 chunk = parser->chunks;
782 if (chunk != NULL) {
783 parser->chunks = chunk->next;
784 UCL_FREE (sizeof (struct ucl_chunk), chunk);
785 }
786 }
787
788 parser->state = prev_state;
789
790 if (buflen > 0) {
737 munmap (buf, buflen);
791 ucl_munmap (buf, buflen);
738 }
739
740 return res;
741}
742
743/**
744 * Handle include macro
745 * @param data include data
746 * @param len length of data
747 * @param ud user data
748 * @param err error ptr
749 * @return
750 */
751UCL_EXTERN bool
752ucl_include_handler (const unsigned char *data, size_t len, void* ud)
753{
754 struct ucl_parser *parser = ud;
755
756 if (*data == '/' || *data == '.') {
757 /* Try to load a file */
758 return ucl_include_file (data, len, parser, false, true);
759 }
760
761 return ucl_include_url (data, len, parser, false, true);
762}
763
764/**
765 * Handle includes macro
766 * @param data include data
767 * @param len length of data
768 * @param ud user data
769 * @param err error ptr
770 * @return
771 */
772UCL_EXTERN bool
773ucl_includes_handler (const unsigned char *data, size_t len, void* ud)
774{
775 struct ucl_parser *parser = ud;
776
777 if (*data == '/' || *data == '.') {
778 /* Try to load a file */
779 return ucl_include_file (data, len, parser, true, true);
780 }
781
782 return ucl_include_url (data, len, parser, true, true);
783}
784
785
786UCL_EXTERN bool
787ucl_try_include_handler (const unsigned char *data, size_t len, void* ud)
788{
789 struct ucl_parser *parser = ud;
790
791 if (*data == '/' || *data == '.') {
792 /* Try to load a file */
793 return ucl_include_file (data, len, parser, false, false);
794 }
795
796 return ucl_include_url (data, len, parser, false, false);
797}
798
799UCL_EXTERN bool
800ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand)
801{
802 char realbuf[PATH_MAX], *curdir;
803
804 if (filename != NULL) {
805 if (need_expand) {
792 }
793
794 return res;
795}
796
797/**
798 * Handle include macro
799 * @param data include data
800 * @param len length of data
801 * @param ud user data
802 * @param err error ptr
803 * @return
804 */
805UCL_EXTERN bool
806ucl_include_handler (const unsigned char *data, size_t len, void* ud)
807{
808 struct ucl_parser *parser = ud;
809
810 if (*data == '/' || *data == '.') {
811 /* Try to load a file */
812 return ucl_include_file (data, len, parser, false, true);
813 }
814
815 return ucl_include_url (data, len, parser, false, true);
816}
817
818/**
819 * Handle includes macro
820 * @param data include data
821 * @param len length of data
822 * @param ud user data
823 * @param err error ptr
824 * @return
825 */
826UCL_EXTERN bool
827ucl_includes_handler (const unsigned char *data, size_t len, void* ud)
828{
829 struct ucl_parser *parser = ud;
830
831 if (*data == '/' || *data == '.') {
832 /* Try to load a file */
833 return ucl_include_file (data, len, parser, true, true);
834 }
835
836 return ucl_include_url (data, len, parser, true, true);
837}
838
839
840UCL_EXTERN bool
841ucl_try_include_handler (const unsigned char *data, size_t len, void* ud)
842{
843 struct ucl_parser *parser = ud;
844
845 if (*data == '/' || *data == '.') {
846 /* Try to load a file */
847 return ucl_include_file (data, len, parser, false, false);
848 }
849
850 return ucl_include_url (data, len, parser, false, false);
851}
852
853UCL_EXTERN bool
854ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand)
855{
856 char realbuf[PATH_MAX], *curdir;
857
858 if (filename != NULL) {
859 if (need_expand) {
806 if (realpath (filename, realbuf) == NULL) {
860 if (ucl_realpath (filename, realbuf) == NULL) {
807 return false;
808 }
809 }
810 else {
811 ucl_strlcpy (realbuf, filename, sizeof (realbuf));
812 }
813
814 /* Define variables */
815 ucl_parser_register_variable (parser, "FILENAME", realbuf);
816 curdir = dirname (realbuf);
817 ucl_parser_register_variable (parser, "CURDIR", curdir);
818 }
819 else {
820 /* Set everything from the current dir */
821 curdir = getcwd (realbuf, sizeof (realbuf));
822 ucl_parser_register_variable (parser, "FILENAME", "undef");
823 ucl_parser_register_variable (parser, "CURDIR", curdir);
824 }
825
826 return true;
827}
828
829UCL_EXTERN bool
830ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
831{
832 unsigned char *buf;
833 size_t len;
834 bool ret;
835 char realbuf[PATH_MAX];
836
861 return false;
862 }
863 }
864 else {
865 ucl_strlcpy (realbuf, filename, sizeof (realbuf));
866 }
867
868 /* Define variables */
869 ucl_parser_register_variable (parser, "FILENAME", realbuf);
870 curdir = dirname (realbuf);
871 ucl_parser_register_variable (parser, "CURDIR", curdir);
872 }
873 else {
874 /* Set everything from the current dir */
875 curdir = getcwd (realbuf, sizeof (realbuf));
876 ucl_parser_register_variable (parser, "FILENAME", "undef");
877 ucl_parser_register_variable (parser, "CURDIR", curdir);
878 }
879
880 return true;
881}
882
883UCL_EXTERN bool
884ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
885{
886 unsigned char *buf;
887 size_t len;
888 bool ret;
889 char realbuf[PATH_MAX];
890
837 if (realpath (filename, realbuf) == NULL) {
891 if (ucl_realpath (filename, realbuf) == NULL) {
838 ucl_create_err (&parser->err, "cannot open file %s: %s",
839 filename,
840 strerror (errno));
841 return false;
842 }
843
844 if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) {
845 return false;
846 }
847
848 ucl_parser_set_filevars (parser, realbuf, false);
849 ret = ucl_parser_add_chunk (parser, buf, len);
850
851 if (len > 0) {
892 ucl_create_err (&parser->err, "cannot open file %s: %s",
893 filename,
894 strerror (errno));
895 return false;
896 }
897
898 if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) {
899 return false;
900 }
901
902 ucl_parser_set_filevars (parser, realbuf, false);
903 ret = ucl_parser_add_chunk (parser, buf, len);
904
905 if (len > 0) {
852 munmap (buf, len);
906 ucl_munmap (buf, len);
853 }
854
855 return ret;
856}
857
858size_t
859ucl_strlcpy (char *dst, const char *src, size_t siz)
860{
861 char *d = dst;
862 const char *s = src;
863 size_t n = siz;
864
865 /* Copy as many bytes as will fit */
866 if (n != 0) {
867 while (--n != 0) {
868 if ((*d++ = *s++) == '\0') {
869 break;
870 }
871 }
872 }
873
874 if (n == 0 && siz != 0) {
875 *d = '\0';
876 }
877
878 return (s - src - 1); /* count does not include NUL */
879}
880
881size_t
882ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz)
883{
884 memcpy (dst, src, siz - 1);
885 dst[siz - 1] = '\0';
886
887 return siz - 1;
888}
889
890size_t
891ucl_strlcpy_tolower (char *dst, const char *src, size_t siz)
892{
893 char *d = dst;
894 const char *s = src;
895 size_t n = siz;
896
897 /* Copy as many bytes as will fit */
898 if (n != 0) {
899 while (--n != 0) {
900 if ((*d++ = tolower (*s++)) == '\0') {
901 break;
902 }
903 }
904 }
905
906 if (n == 0 && siz != 0) {
907 *d = '\0';
908 }
909
910 return (s - src); /* count does not include NUL */
911}
912
913ucl_object_t *
914ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags)
915{
916 ucl_object_t *obj;
917 const char *start, *end, *p, *pos;
918 char *dst, *d;
919 size_t escaped_len;
920
921 if (str == NULL) {
922 return NULL;
923 }
924
925 obj = ucl_object_new ();
926 if (obj) {
927 if (len == 0) {
928 len = strlen (str);
929 }
930 if (flags & UCL_STRING_TRIM) {
931 /* Skip leading spaces */
932 for (start = str; (size_t)(start - str) < len; start ++) {
933 if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
934 break;
935 }
936 }
937 /* Skip trailing spaces */
938 for (end = str + len - 1; end > start; end --) {
939 if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
940 break;
941 }
942 }
943 end ++;
944 }
945 else {
946 start = str;
947 end = str + len;
948 }
949
950 obj->type = UCL_STRING;
951 if (flags & UCL_STRING_ESCAPE) {
952 for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) {
953 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
954 escaped_len ++;
955 }
956 }
957 dst = malloc (escaped_len + 1);
958 if (dst != NULL) {
959 for (p = start, d = dst; p < end; p ++, d ++) {
960 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
961 switch (*p) {
962 case '\n':
963 *d++ = '\\';
964 *d = 'n';
965 break;
966 case '\r':
967 *d++ = '\\';
968 *d = 'r';
969 break;
970 case '\b':
971 *d++ = '\\';
972 *d = 'b';
973 break;
974 case '\t':
975 *d++ = '\\';
976 *d = 't';
977 break;
978 case '\f':
979 *d++ = '\\';
980 *d = 'f';
981 break;
982 case '\\':
983 *d++ = '\\';
984 *d = '\\';
985 break;
986 case '"':
987 *d++ = '\\';
988 *d = '"';
989 break;
990 }
991 }
992 else {
993 *d = *p;
994 }
995 }
996 *d = '\0';
997 obj->value.sv = dst;
998 obj->trash_stack[UCL_TRASH_VALUE] = dst;
999 obj->len = escaped_len;
1000 }
1001 }
1002 else {
1003 dst = malloc (end - start + 1);
1004 if (dst != NULL) {
1005 ucl_strlcpy_unsafe (dst, start, end - start + 1);
1006 obj->value.sv = dst;
1007 obj->trash_stack[UCL_TRASH_VALUE] = dst;
1008 obj->len = end - start;
1009 }
1010 }
1011 if ((flags & UCL_STRING_PARSE) && dst != NULL) {
1012 /* Parse what we have */
1013 if (flags & UCL_STRING_PARSE_BOOLEAN) {
1014 if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) {
1015 ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
1016 flags & UCL_STRING_PARSE_DOUBLE,
907 }
908
909 return ret;
910}
911
912size_t
913ucl_strlcpy (char *dst, const char *src, size_t siz)
914{
915 char *d = dst;
916 const char *s = src;
917 size_t n = siz;
918
919 /* Copy as many bytes as will fit */
920 if (n != 0) {
921 while (--n != 0) {
922 if ((*d++ = *s++) == '\0') {
923 break;
924 }
925 }
926 }
927
928 if (n == 0 && siz != 0) {
929 *d = '\0';
930 }
931
932 return (s - src - 1); /* count does not include NUL */
933}
934
935size_t
936ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz)
937{
938 memcpy (dst, src, siz - 1);
939 dst[siz - 1] = '\0';
940
941 return siz - 1;
942}
943
944size_t
945ucl_strlcpy_tolower (char *dst, const char *src, size_t siz)
946{
947 char *d = dst;
948 const char *s = src;
949 size_t n = siz;
950
951 /* Copy as many bytes as will fit */
952 if (n != 0) {
953 while (--n != 0) {
954 if ((*d++ = tolower (*s++)) == '\0') {
955 break;
956 }
957 }
958 }
959
960 if (n == 0 && siz != 0) {
961 *d = '\0';
962 }
963
964 return (s - src); /* count does not include NUL */
965}
966
967ucl_object_t *
968ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags)
969{
970 ucl_object_t *obj;
971 const char *start, *end, *p, *pos;
972 char *dst, *d;
973 size_t escaped_len;
974
975 if (str == NULL) {
976 return NULL;
977 }
978
979 obj = ucl_object_new ();
980 if (obj) {
981 if (len == 0) {
982 len = strlen (str);
983 }
984 if (flags & UCL_STRING_TRIM) {
985 /* Skip leading spaces */
986 for (start = str; (size_t)(start - str) < len; start ++) {
987 if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
988 break;
989 }
990 }
991 /* Skip trailing spaces */
992 for (end = str + len - 1; end > start; end --) {
993 if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
994 break;
995 }
996 }
997 end ++;
998 }
999 else {
1000 start = str;
1001 end = str + len;
1002 }
1003
1004 obj->type = UCL_STRING;
1005 if (flags & UCL_STRING_ESCAPE) {
1006 for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) {
1007 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
1008 escaped_len ++;
1009 }
1010 }
1011 dst = malloc (escaped_len + 1);
1012 if (dst != NULL) {
1013 for (p = start, d = dst; p < end; p ++, d ++) {
1014 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
1015 switch (*p) {
1016 case '\n':
1017 *d++ = '\\';
1018 *d = 'n';
1019 break;
1020 case '\r':
1021 *d++ = '\\';
1022 *d = 'r';
1023 break;
1024 case '\b':
1025 *d++ = '\\';
1026 *d = 'b';
1027 break;
1028 case '\t':
1029 *d++ = '\\';
1030 *d = 't';
1031 break;
1032 case '\f':
1033 *d++ = '\\';
1034 *d = 'f';
1035 break;
1036 case '\\':
1037 *d++ = '\\';
1038 *d = '\\';
1039 break;
1040 case '"':
1041 *d++ = '\\';
1042 *d = '"';
1043 break;
1044 }
1045 }
1046 else {
1047 *d = *p;
1048 }
1049 }
1050 *d = '\0';
1051 obj->value.sv = dst;
1052 obj->trash_stack[UCL_TRASH_VALUE] = dst;
1053 obj->len = escaped_len;
1054 }
1055 }
1056 else {
1057 dst = malloc (end - start + 1);
1058 if (dst != NULL) {
1059 ucl_strlcpy_unsafe (dst, start, end - start + 1);
1060 obj->value.sv = dst;
1061 obj->trash_stack[UCL_TRASH_VALUE] = dst;
1062 obj->len = end - start;
1063 }
1064 }
1065 if ((flags & UCL_STRING_PARSE) && dst != NULL) {
1066 /* Parse what we have */
1067 if (flags & UCL_STRING_PARSE_BOOLEAN) {
1068 if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) {
1069 ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
1070 flags & UCL_STRING_PARSE_DOUBLE,
1017 flags & UCL_STRING_PARSE_BYTES);
1071 flags & UCL_STRING_PARSE_BYTES,
1072 flags & UCL_STRING_PARSE_TIME);
1018 }
1019 }
1020 else {
1021 ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
1022 flags & UCL_STRING_PARSE_DOUBLE,
1073 }
1074 }
1075 else {
1076 ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
1077 flags & UCL_STRING_PARSE_DOUBLE,
1023 flags & UCL_STRING_PARSE_BYTES);
1078 flags & UCL_STRING_PARSE_BYTES,
1079 flags & UCL_STRING_PARSE_TIME);
1024 }
1025 }
1026 }
1027
1028 return obj;
1029}
1030
1031static ucl_object_t *
1032ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
1033 const char *key, size_t keylen, bool copy_key, bool merge, bool replace)
1034{
1035 ucl_object_t *found, *cur;
1036 ucl_object_iter_t it = NULL;
1037 const char *p;
1038
1039 if (elt == NULL || key == NULL) {
1040 return NULL;
1041 }
1042
1043 if (top == NULL) {
1044 top = ucl_object_new ();
1045 top->type = UCL_OBJECT;
1046 }
1047
1048 if (top->type != UCL_OBJECT) {
1049 /* It is possible to convert NULL type to an object */
1050 if (top->type == UCL_NULL) {
1051 top->type = UCL_OBJECT;
1052 }
1053 else {
1054 /* Refuse converting of other object types */
1055 return top;
1056 }
1057 }
1058
1059 if (top->value.ov == NULL) {
1060 top->value.ov = ucl_hash_create ();
1061 }
1062
1063 if (keylen == 0) {
1064 keylen = strlen (key);
1065 }
1066
1067 for (p = key; p < key + keylen; p ++) {
1068 if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) {
1069 elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1070 break;
1071 }
1072 }
1073
1074 elt->key = key;
1075 elt->keylen = keylen;
1076
1077 if (copy_key) {
1078 ucl_copy_key_trash (elt);
1079 }
1080
1081 found = ucl_hash_search_obj (top->value.ov, elt);
1082
1083 if (!found) {
1084 top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1085 DL_APPEND (found, elt);
1080 }
1081 }
1082 }
1083
1084 return obj;
1085}
1086
1087static ucl_object_t *
1088ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
1089 const char *key, size_t keylen, bool copy_key, bool merge, bool replace)
1090{
1091 ucl_object_t *found, *cur;
1092 ucl_object_iter_t it = NULL;
1093 const char *p;
1094
1095 if (elt == NULL || key == NULL) {
1096 return NULL;
1097 }
1098
1099 if (top == NULL) {
1100 top = ucl_object_new ();
1101 top->type = UCL_OBJECT;
1102 }
1103
1104 if (top->type != UCL_OBJECT) {
1105 /* It is possible to convert NULL type to an object */
1106 if (top->type == UCL_NULL) {
1107 top->type = UCL_OBJECT;
1108 }
1109 else {
1110 /* Refuse converting of other object types */
1111 return top;
1112 }
1113 }
1114
1115 if (top->value.ov == NULL) {
1116 top->value.ov = ucl_hash_create ();
1117 }
1118
1119 if (keylen == 0) {
1120 keylen = strlen (key);
1121 }
1122
1123 for (p = key; p < key + keylen; p ++) {
1124 if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) {
1125 elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1126 break;
1127 }
1128 }
1129
1130 elt->key = key;
1131 elt->keylen = keylen;
1132
1133 if (copy_key) {
1134 ucl_copy_key_trash (elt);
1135 }
1136
1137 found = ucl_hash_search_obj (top->value.ov, elt);
1138
1139 if (!found) {
1140 top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1141 DL_APPEND (found, elt);
1142 top->len ++;
1086 }
1087 else {
1088 if (replace) {
1089 ucl_hash_delete (top->value.ov, found);
1090 ucl_object_unref (found);
1091 top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1092 found = NULL;
1093 DL_APPEND (found, elt);
1094 }
1095 else if (merge) {
1096 if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
1097 /* Insert old elt to new one */
1098 elt = ucl_object_insert_key_common (elt, found, found->key, found->keylen, copy_key, false, false);
1099 ucl_hash_delete (top->value.ov, found);
1100 top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1101 }
1102 else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) {
1103 /* Insert new to old */
1104 found = ucl_object_insert_key_common (found, elt, elt->key, elt->keylen, copy_key, false, false);
1105 }
1106 else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) {
1107 /* Mix two hashes */
1108 while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) {
1109 ucl_object_ref (cur);
1110 found = ucl_object_insert_key_common (found, cur, cur->key, cur->keylen, copy_key, false, false);
1111 }
1112 ucl_object_unref (elt);
1113 }
1114 else {
1115 /* Just make a list of scalars */
1116 DL_APPEND (found, elt);
1117 }
1118 }
1119 else {
1120 DL_APPEND (found, elt);
1121 }
1122 }
1123
1124 return top;
1125}
1126
1127bool
1128ucl_object_delete_keyl(ucl_object_t *top, const char *key, size_t keylen)
1129{
1130 ucl_object_t *found;
1131
1143 }
1144 else {
1145 if (replace) {
1146 ucl_hash_delete (top->value.ov, found);
1147 ucl_object_unref (found);
1148 top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1149 found = NULL;
1150 DL_APPEND (found, elt);
1151 }
1152 else if (merge) {
1153 if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
1154 /* Insert old elt to new one */
1155 elt = ucl_object_insert_key_common (elt, found, found->key, found->keylen, copy_key, false, false);
1156 ucl_hash_delete (top->value.ov, found);
1157 top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1158 }
1159 else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) {
1160 /* Insert new to old */
1161 found = ucl_object_insert_key_common (found, elt, elt->key, elt->keylen, copy_key, false, false);
1162 }
1163 else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) {
1164 /* Mix two hashes */
1165 while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) {
1166 ucl_object_ref (cur);
1167 found = ucl_object_insert_key_common (found, cur, cur->key, cur->keylen, copy_key, false, false);
1168 }
1169 ucl_object_unref (elt);
1170 }
1171 else {
1172 /* Just make a list of scalars */
1173 DL_APPEND (found, elt);
1174 }
1175 }
1176 else {
1177 DL_APPEND (found, elt);
1178 }
1179 }
1180
1181 return top;
1182}
1183
1184bool
1185ucl_object_delete_keyl(ucl_object_t *top, const char *key, size_t keylen)
1186{
1187 ucl_object_t *found;
1188
1189 if (top == NULL || key == NULL) {
1190 return false;
1191 }
1192
1132 found = ucl_object_find_keyl(top, key, keylen);
1133
1193 found = ucl_object_find_keyl(top, key, keylen);
1194
1134 if (found == NULL)
1195 if (found == NULL) {
1135 return false;
1196 return false;
1197 }
1136
1137 ucl_hash_delete(top->value.ov, found);
1138 ucl_object_unref (found);
1139 top->len --;
1140
1141 return true;
1142}
1143
1144bool
1145ucl_object_delete_key(ucl_object_t *top, const char *key)
1146{
1147 return ucl_object_delete_keyl(top, key, 0);
1148}
1149
1198
1199 ucl_hash_delete(top->value.ov, found);
1200 ucl_object_unref (found);
1201 top->len --;
1202
1203 return true;
1204}
1205
1206bool
1207ucl_object_delete_key(ucl_object_t *top, const char *key)
1208{
1209 return ucl_object_delete_keyl(top, key, 0);
1210}
1211
1212ucl_object_t*
1213ucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen)
1214{
1215 ucl_object_t *found;
1216
1217 if (top == NULL || key == NULL) {
1218 return false;
1219 }
1220 found = ucl_object_find_keyl(top, key, keylen);
1221
1222 if (found == NULL) {
1223 return NULL;
1224 }
1225 ucl_hash_delete(top->value.ov, found);
1226 top->len --;
1227
1228 return found;
1229}
1230
1231ucl_object_t*
1232ucl_object_pop_key (ucl_object_t *top, const char *key)
1233{
1234 return ucl_object_pop_keyl (top, key, 0);
1235}
1236
1150ucl_object_t *
1151ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
1152 const char *key, size_t keylen, bool copy_key)
1153{
1154 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false);
1155}
1156
1157ucl_object_t *
1158ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt,
1159 const char *key, size_t keylen, bool copy_key)
1160{
1161 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false);
1162}
1163
1164ucl_object_t *
1165ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
1166 const char *key, size_t keylen, bool copy_key)
1167{
1168 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true);
1169}
1170
1171ucl_object_t *
1172ucl_object_find_keyl (ucl_object_t *obj, const char *key, size_t klen)
1173{
1174 ucl_object_t *ret, srch;
1175
1176 if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
1177 return NULL;
1178 }
1179
1180 srch.key = key;
1181 srch.keylen = klen;
1182 ret = ucl_hash_search_obj (obj->value.ov, &srch);
1183
1184 return ret;
1185}
1186
1187ucl_object_t *
1188ucl_object_find_key (ucl_object_t *obj, const char *key)
1189{
1190 size_t klen;
1191 ucl_object_t *ret, srch;
1192
1193 if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
1194 return NULL;
1195 }
1196
1197 klen = strlen (key);
1198 srch.key = key;
1199 srch.keylen = klen;
1200 ret = ucl_hash_search_obj (obj->value.ov, &srch);
1201
1202 return ret;
1203}
1204
1205ucl_object_t*
1206ucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values)
1207{
1208 ucl_object_t *elt;
1209
1237ucl_object_t *
1238ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
1239 const char *key, size_t keylen, bool copy_key)
1240{
1241 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false);
1242}
1243
1244ucl_object_t *
1245ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt,
1246 const char *key, size_t keylen, bool copy_key)
1247{
1248 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false);
1249}
1250
1251ucl_object_t *
1252ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
1253 const char *key, size_t keylen, bool copy_key)
1254{
1255 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true);
1256}
1257
1258ucl_object_t *
1259ucl_object_find_keyl (ucl_object_t *obj, const char *key, size_t klen)
1260{
1261 ucl_object_t *ret, srch;
1262
1263 if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
1264 return NULL;
1265 }
1266
1267 srch.key = key;
1268 srch.keylen = klen;
1269 ret = ucl_hash_search_obj (obj->value.ov, &srch);
1270
1271 return ret;
1272}
1273
1274ucl_object_t *
1275ucl_object_find_key (ucl_object_t *obj, const char *key)
1276{
1277 size_t klen;
1278 ucl_object_t *ret, srch;
1279
1280 if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
1281 return NULL;
1282 }
1283
1284 klen = strlen (key);
1285 srch.key = key;
1286 srch.keylen = klen;
1287 ret = ucl_hash_search_obj (obj->value.ov, &srch);
1288
1289 return ret;
1290}
1291
1292ucl_object_t*
1293ucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values)
1294{
1295 ucl_object_t *elt;
1296
1297 if (obj == NULL || iter == NULL) {
1298 return NULL;
1299 }
1300
1210 if (expand_values) {
1211 switch (obj->type) {
1212 case UCL_OBJECT:
1213 return (ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter);
1214 break;
1215 case UCL_ARRAY:
1216 elt = *iter;
1217 if (elt == NULL) {
1218 elt = obj->value.av;
1219 if (elt == NULL) {
1220 return NULL;
1221 }
1222 }
1223 else if (elt == obj->value.av) {
1224 return NULL;
1225 }
1226 *iter = elt->next ? elt->next : obj->value.av;
1227 return elt;
1228 default:
1229 /* Go to linear iteration */
1230 break;
1231 }
1232 }
1233 /* Treat everything as a linear list */
1234 elt = *iter;
1235 if (elt == NULL) {
1236 elt = obj;
1237 if (elt == NULL) {
1238 return NULL;
1239 }
1240 }
1241 else if (elt == obj) {
1242 return NULL;
1243 }
1244 *iter = elt->next ? elt->next : obj;
1245 return elt;
1246
1247 /* Not reached */
1248 return NULL;
1249}
1301 if (expand_values) {
1302 switch (obj->type) {
1303 case UCL_OBJECT:
1304 return (ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter);
1305 break;
1306 case UCL_ARRAY:
1307 elt = *iter;
1308 if (elt == NULL) {
1309 elt = obj->value.av;
1310 if (elt == NULL) {
1311 return NULL;
1312 }
1313 }
1314 else if (elt == obj->value.av) {
1315 return NULL;
1316 }
1317 *iter = elt->next ? elt->next : obj->value.av;
1318 return elt;
1319 default:
1320 /* Go to linear iteration */
1321 break;
1322 }
1323 }
1324 /* Treat everything as a linear list */
1325 elt = *iter;
1326 if (elt == NULL) {
1327 elt = obj;
1328 if (elt == NULL) {
1329 return NULL;
1330 }
1331 }
1332 else if (elt == obj) {
1333 return NULL;
1334 }
1335 *iter = elt->next ? elt->next : obj;
1336 return elt;
1337
1338 /* Not reached */
1339 return NULL;
1340}
1341
1342
1343ucl_object_t *
1344ucl_object_new (void)
1345{
1346 ucl_object_t *new;
1347 new = malloc (sizeof (ucl_object_t));
1348 if (new != NULL) {
1349 memset (new, 0, sizeof (ucl_object_t));
1350 new->ref = 1;
1351 new->type = UCL_NULL;
1352 }
1353 return new;
1354}
1355
1356ucl_object_t *
1357ucl_object_typed_new (unsigned int type)
1358{
1359 ucl_object_t *new;
1360 new = malloc (sizeof (ucl_object_t));
1361 if (new != NULL) {
1362 memset (new, 0, sizeof (ucl_object_t));
1363 new->ref = 1;
1364 new->type = (type <= UCL_NULL ? type : UCL_NULL);
1365 }
1366 return new;
1367}
1368
1369ucl_object_t*
1370ucl_object_fromstring (const char *str)
1371{
1372 return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE);
1373}
1374
1375ucl_object_t *
1376ucl_object_fromlstring (const char *str, size_t len)
1377{
1378 return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE);
1379}
1380
1381ucl_object_t *
1382ucl_object_fromint (int64_t iv)
1383{
1384 ucl_object_t *obj;
1385
1386 obj = ucl_object_new ();
1387 if (obj != NULL) {
1388 obj->type = UCL_INT;
1389 obj->value.iv = iv;
1390 }
1391
1392 return obj;
1393}
1394
1395ucl_object_t *
1396ucl_object_fromdouble (double dv)
1397{
1398 ucl_object_t *obj;
1399
1400 obj = ucl_object_new ();
1401 if (obj != NULL) {
1402 obj->type = UCL_FLOAT;
1403 obj->value.dv = dv;
1404 }
1405
1406 return obj;
1407}
1408
1409ucl_object_t*
1410ucl_object_frombool (bool bv)
1411{
1412 ucl_object_t *obj;
1413
1414 obj = ucl_object_new ();
1415 if (obj != NULL) {
1416 obj->type = UCL_BOOLEAN;
1417 obj->value.iv = bv;
1418 }
1419
1420 return obj;
1421}
1422
1423ucl_object_t *
1424ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
1425{
1426 ucl_object_t *head;
1427
1428 if (elt == NULL) {
1429 return NULL;
1430 }
1431
1432 if (top == NULL) {
1433 top = ucl_object_typed_new (UCL_ARRAY);
1434 top->value.av = elt;
1435 elt->next = NULL;
1436 elt->prev = elt;
1437 top->len = 1;
1438 }
1439 else {
1440 head = top->value.av;
1441 if (head == NULL) {
1442 top->value.av = elt;
1443 elt->prev = elt;
1444 }
1445 else {
1446 elt->prev = head->prev;
1447 head->prev->next = elt;
1448 head->prev = elt;
1449 }
1450 elt->next = NULL;
1451 top->len ++;
1452 }
1453
1454 return top;
1455}
1456
1457ucl_object_t *
1458ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
1459{
1460 ucl_object_t *head;
1461
1462 if (elt == NULL) {
1463 return NULL;
1464 }
1465
1466 if (top == NULL) {
1467 top = ucl_object_typed_new (UCL_ARRAY);
1468 top->value.av = elt;
1469 elt->next = NULL;
1470 elt->prev = elt;
1471 top->len = 1;
1472 }
1473 else {
1474 head = top->value.av;
1475 if (head == NULL) {
1476 top->value.av = elt;
1477 elt->prev = elt;
1478 }
1479 else {
1480 elt->prev = head->prev;
1481 head->prev = elt;
1482 }
1483 elt->next = head;
1484 top->value.av = elt;
1485 top->len ++;
1486 }
1487
1488 return top;
1489}
1490
1491ucl_object_t *
1492ucl_array_delete (ucl_object_t *top, ucl_object_t *elt)
1493{
1494 ucl_object_t *head;
1495
1496 if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
1497 return NULL;
1498 }
1499 head = top->value.av;
1500
1501 if (elt->prev == elt) {
1502 top->value.av = NULL;
1503 }
1504 else if (elt == head) {
1505 elt->next->prev = elt->prev;
1506 top->value.av = elt->next;
1507 }
1508 else {
1509 elt->prev->next = elt->next;
1510 if (elt->next) {
1511 elt->next->prev = elt->prev;
1512 }
1513 else {
1514 head->prev = elt->prev;
1515 }
1516 }
1517 elt->next = NULL;
1518 elt->prev = elt;
1519 top->len --;
1520
1521 return elt;
1522}
1523
1524ucl_object_t *
1525ucl_array_head (ucl_object_t *top)
1526{
1527 if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
1528 return NULL;
1529 }
1530 return top->value.av;
1531}
1532
1533ucl_object_t *
1534ucl_array_tail (ucl_object_t *top)
1535{
1536 if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
1537 return NULL;
1538 }
1539 return top->value.av->prev;
1540}
1541
1542ucl_object_t *
1543ucl_array_pop_last (ucl_object_t *top)
1544{
1545 return ucl_array_delete (top, ucl_array_tail (top));
1546}
1547
1548ucl_object_t *
1549ucl_array_pop_first (ucl_object_t *top)
1550{
1551 return ucl_array_delete (top, ucl_array_head (top));
1552}
1553
1554ucl_object_t *
1555ucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
1556{
1557
1558 if (head == NULL) {
1559 elt->next = NULL;
1560 elt->prev = elt;
1561 head = elt;
1562 }
1563 else {
1564 elt->prev = head->prev;
1565 head->prev->next = elt;
1566 head->prev = elt;
1567 elt->next = NULL;
1568 }
1569
1570 return head;
1571}
1572
1573bool
1574ucl_object_todouble_safe (ucl_object_t *obj, double *target)
1575{
1576 if (obj == NULL || target == NULL) {
1577 return false;
1578 }
1579 switch (obj->type) {
1580 case UCL_INT:
1581 *target = obj->value.iv; /* Probaly could cause overflow */
1582 break;
1583 case UCL_FLOAT:
1584 case UCL_TIME:
1585 *target = obj->value.dv;
1586 break;
1587 default:
1588 return false;
1589 }
1590
1591 return true;
1592}
1593
1594double
1595ucl_object_todouble (ucl_object_t *obj)
1596{
1597 double result = 0.;
1598
1599 ucl_object_todouble_safe (obj, &result);
1600 return result;
1601}
1602
1603bool
1604ucl_object_toint_safe (ucl_object_t *obj, int64_t *target)
1605{
1606 if (obj == NULL || target == NULL) {
1607 return false;
1608 }
1609 switch (obj->type) {
1610 case UCL_INT:
1611 *target = obj->value.iv;
1612 break;
1613 case UCL_FLOAT:
1614 case UCL_TIME:
1615 *target = obj->value.dv; /* Loosing of decimal points */
1616 break;
1617 default:
1618 return false;
1619 }
1620
1621 return true;
1622}
1623
1624int64_t
1625ucl_object_toint (ucl_object_t *obj)
1626{
1627 int64_t result = 0;
1628
1629 ucl_object_toint_safe (obj, &result);
1630 return result;
1631}
1632
1633bool
1634ucl_object_toboolean_safe (ucl_object_t *obj, bool *target)
1635{
1636 if (obj == NULL || target == NULL) {
1637 return false;
1638 }
1639 switch (obj->type) {
1640 case UCL_BOOLEAN:
1641 *target = (obj->value.iv == true);
1642 break;
1643 default:
1644 return false;
1645 }
1646
1647 return true;
1648}
1649
1650bool
1651ucl_object_toboolean (ucl_object_t *obj)
1652{
1653 bool result = false;
1654
1655 ucl_object_toboolean_safe (obj, &result);
1656 return result;
1657}
1658
1659bool
1660ucl_object_tostring_safe (ucl_object_t *obj, const char **target)
1661{
1662 if (obj == NULL || target == NULL) {
1663 return false;
1664 }
1665
1666 switch (obj->type) {
1667 case UCL_STRING:
1668 *target = ucl_copy_value_trash (obj);
1669 break;
1670 default:
1671 return false;
1672 }
1673
1674 return true;
1675}
1676
1677const char *
1678ucl_object_tostring (ucl_object_t *obj)
1679{
1680 const char *result = NULL;
1681
1682 ucl_object_tostring_safe (obj, &result);
1683 return result;
1684}
1685
1686const char *
1687ucl_object_tostring_forced (ucl_object_t *obj)
1688{
1689 return ucl_copy_value_trash (obj);
1690}
1691
1692bool
1693ucl_object_tolstring_safe (ucl_object_t *obj, const char **target, size_t *tlen)
1694{
1695 if (obj == NULL || target == NULL) {
1696 return false;
1697 }
1698 switch (obj->type) {
1699 case UCL_STRING:
1700 *target = obj->value.sv;
1701 if (tlen != NULL) {
1702 *tlen = obj->len;
1703 }
1704 break;
1705 default:
1706 return false;
1707 }
1708
1709 return true;
1710}
1711
1712const char *
1713ucl_object_tolstring (ucl_object_t *obj, size_t *tlen)
1714{
1715 const char *result = NULL;
1716
1717 ucl_object_tolstring_safe (obj, &result, tlen);
1718 return result;
1719}
1720
1721const char *
1722ucl_object_key (ucl_object_t *obj)
1723{
1724 return ucl_copy_key_trash (obj);
1725}
1726
1727const char *
1728ucl_object_keyl (ucl_object_t *obj, size_t *len)
1729{
1730 if (len == NULL || obj == NULL) {
1731 return NULL;
1732 }
1733 *len = obj->keylen;
1734 return obj->key;
1735}
1736
1737ucl_object_t *
1738ucl_object_ref (ucl_object_t *obj)
1739{
1740 if (obj != NULL) {
1741 obj->ref ++;
1742 }
1743 return obj;
1744}
1745
1746void
1747ucl_object_unref (ucl_object_t *obj)
1748{
1749 if (obj != NULL && --obj->ref <= 0) {
1750 ucl_object_free (obj);
1751 }
1752}
1753
1754int
1755ucl_object_compare (ucl_object_t *o1, ucl_object_t *o2)
1756{
1757 ucl_object_t *it1, *it2;
1758 ucl_object_iter_t iter = NULL;
1759 int ret = 0;
1760
1761 if (o1->type != o2->type) {
1762 return (o1->type) - (o2->type);
1763 }
1764
1765 switch (o1->type) {
1766 case UCL_STRING:
1767 if (o1->len == o2->len) {
1768 ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2));
1769 }
1770 else {
1771 ret = o1->len - o2->len;
1772 }
1773 break;
1774 case UCL_FLOAT:
1775 case UCL_INT:
1776 case UCL_TIME:
1777 ret = ucl_object_todouble (o1) - ucl_object_todouble (o2);
1778 break;
1779 case UCL_BOOLEAN:
1780 ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2);
1781 break;
1782 case UCL_ARRAY:
1783 if (o1->len == o2->len) {
1784 it1 = o1->value.av;
1785 it2 = o2->value.av;
1786 /* Compare all elements in both arrays */
1787 while (it1 != NULL && it2 != NULL) {
1788 ret = ucl_object_compare (it1, it2);
1789 if (ret != 0) {
1790 break;
1791 }
1792 it1 = it1->next;
1793 it2 = it2->next;
1794 }
1795 }
1796 else {
1797 ret = o1->len - o2->len;
1798 }
1799 break;
1800 case UCL_OBJECT:
1801 if (o1->len == o2->len) {
1802 while ((it1 = ucl_iterate_object (o1, &iter, true)) != NULL) {
1803 it2 = ucl_object_find_key (o2, ucl_object_key (it1));
1804 if (it2 == NULL) {
1805 ret = 1;
1806 break;
1807 }
1808 ret = ucl_object_compare (it1, it2);
1809 if (ret != 0) {
1810 break;
1811 }
1812 }
1813 }
1814 else {
1815 ret = o1->len - o2->len;
1816 }
1817 break;
1818 default:
1819 ret = 0;
1820 break;
1821 }
1822
1823 return ret;
1824}
1825
1826void
1827ucl_object_array_sort (ucl_object_t *ar,
1828 int (*cmp)(ucl_object_t *o1, ucl_object_t *o2))
1829{
1830 if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) {
1831 return;
1832 }
1833
1834 DL_SORT (ar->value.av, cmp);
1835}