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}
|
| |