1c99fb5f9SBaptiste Daroussin /* Copyright (c) 2013, Vsevolod Stakhov 2c99fb5f9SBaptiste Daroussin * All rights reserved. 3c99fb5f9SBaptiste Daroussin * 4c99fb5f9SBaptiste Daroussin * Redistribution and use in source and binary forms, with or without 5c99fb5f9SBaptiste Daroussin * modification, are permitted provided that the following conditions are met: 6c99fb5f9SBaptiste Daroussin * * Redistributions of source code must retain the above copyright 7c99fb5f9SBaptiste Daroussin * notice, this list of conditions and the following disclaimer. 8c99fb5f9SBaptiste Daroussin * * Redistributions in binary form must reproduce the above copyright 9c99fb5f9SBaptiste Daroussin * notice, this list of conditions and the following disclaimer in the 10c99fb5f9SBaptiste Daroussin * documentation and/or other materials provided with the distribution. 11c99fb5f9SBaptiste Daroussin * 12c99fb5f9SBaptiste Daroussin * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY 13c99fb5f9SBaptiste Daroussin * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14c99fb5f9SBaptiste Daroussin * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15c99fb5f9SBaptiste Daroussin * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY 16c99fb5f9SBaptiste Daroussin * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17c99fb5f9SBaptiste Daroussin * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18c99fb5f9SBaptiste Daroussin * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19c99fb5f9SBaptiste Daroussin * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20c99fb5f9SBaptiste Daroussin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21c99fb5f9SBaptiste Daroussin * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22c99fb5f9SBaptiste Daroussin */ 23c99fb5f9SBaptiste Daroussin 24c99fb5f9SBaptiste Daroussin #include "ucl.h" 25c99fb5f9SBaptiste Daroussin #include "ucl_internal.h" 26c99fb5f9SBaptiste Daroussin #include "ucl_chartable.h" 27c99fb5f9SBaptiste Daroussin 2897bd480fSBaptiste Daroussin #ifdef HAVE_LIBGEN_H 29c99fb5f9SBaptiste Daroussin #include <libgen.h> /* For dirname */ 3097bd480fSBaptiste Daroussin #endif 31c99fb5f9SBaptiste Daroussin 32c99fb5f9SBaptiste Daroussin #ifdef HAVE_OPENSSL 33c99fb5f9SBaptiste Daroussin #include <openssl/err.h> 34c99fb5f9SBaptiste Daroussin #include <openssl/sha.h> 35c99fb5f9SBaptiste Daroussin #include <openssl/rsa.h> 36c99fb5f9SBaptiste Daroussin #include <openssl/ssl.h> 37c99fb5f9SBaptiste Daroussin #include <openssl/evp.h> 38c99fb5f9SBaptiste Daroussin #endif 39c99fb5f9SBaptiste Daroussin 4097bd480fSBaptiste Daroussin #ifdef CURL_FOUND 4197bd480fSBaptiste Daroussin #include <curl/curl.h> 4297bd480fSBaptiste Daroussin #endif 4397bd480fSBaptiste Daroussin #ifdef HAVE_FETCH_H 4497bd480fSBaptiste Daroussin #include <fetch.h> 4597bd480fSBaptiste Daroussin #endif 4697bd480fSBaptiste Daroussin 4736c53d67SBaptiste Daroussin #ifdef _WIN32 4836c53d67SBaptiste Daroussin #include <windows.h> 4936c53d67SBaptiste Daroussin 5097bd480fSBaptiste Daroussin #ifndef PROT_READ 5136c53d67SBaptiste Daroussin #define PROT_READ 1 5297bd480fSBaptiste Daroussin #endif 5397bd480fSBaptiste Daroussin #ifndef PROT_WRITE 5436c53d67SBaptiste Daroussin #define PROT_WRITE 2 5597bd480fSBaptiste Daroussin #endif 5697bd480fSBaptiste Daroussin #ifndef PROT_READWRITE 5736c53d67SBaptiste Daroussin #define PROT_READWRITE 3 5897bd480fSBaptiste Daroussin #endif 5997bd480fSBaptiste Daroussin #ifndef MAP_SHARED 6036c53d67SBaptiste Daroussin #define MAP_SHARED 1 6197bd480fSBaptiste Daroussin #endif 6297bd480fSBaptiste Daroussin #ifndef MAP_PRIVATE 6336c53d67SBaptiste Daroussin #define MAP_PRIVATE 2 6497bd480fSBaptiste Daroussin #endif 6597bd480fSBaptiste Daroussin #ifndef MAP_FAILED 6636c53d67SBaptiste Daroussin #define MAP_FAILED ((void *) -1) 6797bd480fSBaptiste Daroussin #endif 6836c53d67SBaptiste Daroussin 6997bd480fSBaptiste Daroussin static void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset) 7036c53d67SBaptiste Daroussin { 7136c53d67SBaptiste Daroussin void *map = NULL; 7236c53d67SBaptiste Daroussin HANDLE handle = INVALID_HANDLE_VALUE; 7336c53d67SBaptiste Daroussin 7436c53d67SBaptiste Daroussin switch (prot) { 7536c53d67SBaptiste Daroussin default: 7636c53d67SBaptiste Daroussin case PROT_READ: 7736c53d67SBaptiste Daroussin { 7836c53d67SBaptiste Daroussin handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0); 7936c53d67SBaptiste Daroussin if (!handle) break; 8036c53d67SBaptiste Daroussin map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length); 8136c53d67SBaptiste Daroussin CloseHandle(handle); 8236c53d67SBaptiste Daroussin break; 8336c53d67SBaptiste Daroussin } 8436c53d67SBaptiste Daroussin case PROT_WRITE: 8536c53d67SBaptiste Daroussin { 8636c53d67SBaptiste Daroussin handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 8736c53d67SBaptiste Daroussin if (!handle) break; 8836c53d67SBaptiste Daroussin map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length); 8936c53d67SBaptiste Daroussin CloseHandle(handle); 9036c53d67SBaptiste Daroussin break; 9136c53d67SBaptiste Daroussin } 9236c53d67SBaptiste Daroussin case PROT_READWRITE: 9336c53d67SBaptiste Daroussin { 9436c53d67SBaptiste Daroussin handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 9536c53d67SBaptiste Daroussin if (!handle) break; 9636c53d67SBaptiste Daroussin map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length); 9736c53d67SBaptiste Daroussin CloseHandle(handle); 9836c53d67SBaptiste Daroussin break; 9936c53d67SBaptiste Daroussin } 10036c53d67SBaptiste Daroussin } 10136c53d67SBaptiste Daroussin if (map == (void *) NULL) { 10236c53d67SBaptiste Daroussin return (void *) MAP_FAILED; 10336c53d67SBaptiste Daroussin } 10436c53d67SBaptiste Daroussin return (void *) ((char *) map + offset); 10536c53d67SBaptiste Daroussin } 10636c53d67SBaptiste Daroussin 10797bd480fSBaptiste Daroussin static int ucl_munmap(void *map,size_t length) 10836c53d67SBaptiste Daroussin { 10936c53d67SBaptiste Daroussin if (!UnmapViewOfFile(map)) { 11036c53d67SBaptiste Daroussin return(-1); 11136c53d67SBaptiste Daroussin } 11236c53d67SBaptiste Daroussin return(0); 11336c53d67SBaptiste Daroussin } 11436c53d67SBaptiste Daroussin 11597bd480fSBaptiste Daroussin static char* ucl_realpath(const char *path, char *resolved_path) { 11636c53d67SBaptiste Daroussin char *p; 11736c53d67SBaptiste Daroussin char tmp[MAX_PATH + 1]; 11836c53d67SBaptiste Daroussin strncpy(tmp, path, sizeof(tmp)-1); 11936c53d67SBaptiste Daroussin p = tmp; 12036c53d67SBaptiste Daroussin while(*p) { 12136c53d67SBaptiste Daroussin if (*p == '/') *p = '\\'; 12236c53d67SBaptiste Daroussin p++; 12336c53d67SBaptiste Daroussin } 12436c53d67SBaptiste Daroussin return _fullpath(resolved_path, tmp, MAX_PATH); 12536c53d67SBaptiste Daroussin } 12697bd480fSBaptiste Daroussin #else 12797bd480fSBaptiste Daroussin #define ucl_mmap mmap 12897bd480fSBaptiste Daroussin #define ucl_munmap munmap 12997bd480fSBaptiste Daroussin #define ucl_realpath realpath 13036c53d67SBaptiste Daroussin #endif 13136c53d67SBaptiste Daroussin 132c99fb5f9SBaptiste Daroussin /** 133c99fb5f9SBaptiste Daroussin * @file rcl_util.c 134c99fb5f9SBaptiste Daroussin * Utilities for rcl parsing 135c99fb5f9SBaptiste Daroussin */ 136c99fb5f9SBaptiste Daroussin 137*b04a7a0bSBaptiste Daroussin typedef void (*ucl_object_dtor) (ucl_object_t *obj); 138*b04a7a0bSBaptiste Daroussin static void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, 139*b04a7a0bSBaptiste Daroussin ucl_object_dtor dtor); 140*b04a7a0bSBaptiste Daroussin static void ucl_object_dtor_unref (ucl_object_t *obj); 141c99fb5f9SBaptiste Daroussin 142c99fb5f9SBaptiste Daroussin static void 143*b04a7a0bSBaptiste Daroussin ucl_object_dtor_free (ucl_object_t *obj) 144c99fb5f9SBaptiste Daroussin { 145c99fb5f9SBaptiste Daroussin if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 146c99fb5f9SBaptiste Daroussin UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]); 147c99fb5f9SBaptiste Daroussin } 148c99fb5f9SBaptiste Daroussin if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 149c99fb5f9SBaptiste Daroussin UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]); 150c99fb5f9SBaptiste Daroussin } 151*b04a7a0bSBaptiste Daroussin UCL_FREE (sizeof (ucl_object_t), obj); 152*b04a7a0bSBaptiste Daroussin } 153c99fb5f9SBaptiste Daroussin 154*b04a7a0bSBaptiste Daroussin /* 155*b04a7a0bSBaptiste Daroussin * This is a helper function that performs exactly the same as 156*b04a7a0bSBaptiste Daroussin * `ucl_object_unref` but it doesn't iterate over elements allowing 157*b04a7a0bSBaptiste Daroussin * to use it for individual elements of arrays and multiple values 158*b04a7a0bSBaptiste Daroussin */ 159*b04a7a0bSBaptiste Daroussin static void 160*b04a7a0bSBaptiste Daroussin ucl_object_dtor_unref_single (ucl_object_t *obj) 161*b04a7a0bSBaptiste Daroussin { 162*b04a7a0bSBaptiste Daroussin if (obj != NULL) { 163*b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS 164*b04a7a0bSBaptiste Daroussin unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); 165*b04a7a0bSBaptiste Daroussin if (rc == 0) { 166*b04a7a0bSBaptiste Daroussin #else 167*b04a7a0bSBaptiste Daroussin if (--obj->ref == 0) { 168*b04a7a0bSBaptiste Daroussin #endif 169*b04a7a0bSBaptiste Daroussin ucl_object_free_internal (obj, false, ucl_object_dtor_unref); 170*b04a7a0bSBaptiste Daroussin } 171*b04a7a0bSBaptiste Daroussin } 172*b04a7a0bSBaptiste Daroussin } 173*b04a7a0bSBaptiste Daroussin 174*b04a7a0bSBaptiste Daroussin static void 175*b04a7a0bSBaptiste Daroussin ucl_object_dtor_unref (ucl_object_t *obj) 176*b04a7a0bSBaptiste Daroussin { 177*b04a7a0bSBaptiste Daroussin if (obj->ref == 0) { 178*b04a7a0bSBaptiste Daroussin ucl_object_dtor_free (obj); 179*b04a7a0bSBaptiste Daroussin } 180*b04a7a0bSBaptiste Daroussin else { 181*b04a7a0bSBaptiste Daroussin /* This may cause dtor unref being called one more time */ 182*b04a7a0bSBaptiste Daroussin ucl_object_dtor_unref_single (obj); 183*b04a7a0bSBaptiste Daroussin } 184*b04a7a0bSBaptiste Daroussin } 185*b04a7a0bSBaptiste Daroussin 186*b04a7a0bSBaptiste Daroussin static void 187*b04a7a0bSBaptiste Daroussin ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor) 188*b04a7a0bSBaptiste Daroussin { 189*b04a7a0bSBaptiste Daroussin ucl_object_t *sub, *tmp; 190*b04a7a0bSBaptiste Daroussin 191*b04a7a0bSBaptiste Daroussin while (obj != NULL) { 192c99fb5f9SBaptiste Daroussin if (obj->type == UCL_ARRAY) { 193c99fb5f9SBaptiste Daroussin sub = obj->value.av; 194c99fb5f9SBaptiste Daroussin while (sub != NULL) { 195c99fb5f9SBaptiste Daroussin tmp = sub->next; 196*b04a7a0bSBaptiste Daroussin dtor (sub); 197c99fb5f9SBaptiste Daroussin sub = tmp; 198c99fb5f9SBaptiste Daroussin } 199c99fb5f9SBaptiste Daroussin } 200c99fb5f9SBaptiste Daroussin else if (obj->type == UCL_OBJECT) { 201c99fb5f9SBaptiste Daroussin if (obj->value.ov != NULL) { 202*b04a7a0bSBaptiste Daroussin ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)dtor); 203c99fb5f9SBaptiste Daroussin } 204c99fb5f9SBaptiste Daroussin } 205c99fb5f9SBaptiste Daroussin tmp = obj->next; 206*b04a7a0bSBaptiste Daroussin dtor (obj); 207c99fb5f9SBaptiste Daroussin obj = tmp; 208c99fb5f9SBaptiste Daroussin 209c99fb5f9SBaptiste Daroussin if (!allow_rec) { 210c99fb5f9SBaptiste Daroussin break; 211c99fb5f9SBaptiste Daroussin } 212c99fb5f9SBaptiste Daroussin } 213c99fb5f9SBaptiste Daroussin } 214c99fb5f9SBaptiste Daroussin 215c99fb5f9SBaptiste Daroussin void 216c99fb5f9SBaptiste Daroussin ucl_object_free (ucl_object_t *obj) 217c99fb5f9SBaptiste Daroussin { 218*b04a7a0bSBaptiste Daroussin ucl_object_free_internal (obj, true, ucl_object_dtor_free); 219c99fb5f9SBaptiste Daroussin } 220c99fb5f9SBaptiste Daroussin 221c99fb5f9SBaptiste Daroussin size_t 222c99fb5f9SBaptiste Daroussin ucl_unescape_json_string (char *str, size_t len) 223c99fb5f9SBaptiste Daroussin { 224c99fb5f9SBaptiste Daroussin char *t = str, *h = str; 225c99fb5f9SBaptiste Daroussin int i, uval; 226c99fb5f9SBaptiste Daroussin 22797bd480fSBaptiste Daroussin if (len <= 1) { 22897bd480fSBaptiste Daroussin return len; 22997bd480fSBaptiste Daroussin } 230c99fb5f9SBaptiste Daroussin /* t is target (tortoise), h is source (hare) */ 231c99fb5f9SBaptiste Daroussin 232c99fb5f9SBaptiste Daroussin while (len) { 233c99fb5f9SBaptiste Daroussin if (*h == '\\') { 234c99fb5f9SBaptiste Daroussin h ++; 235c99fb5f9SBaptiste Daroussin switch (*h) { 236c99fb5f9SBaptiste Daroussin case 'n': 237c99fb5f9SBaptiste Daroussin *t++ = '\n'; 238c99fb5f9SBaptiste Daroussin break; 239c99fb5f9SBaptiste Daroussin case 'r': 240c99fb5f9SBaptiste Daroussin *t++ = '\r'; 241c99fb5f9SBaptiste Daroussin break; 242c99fb5f9SBaptiste Daroussin case 'b': 243c99fb5f9SBaptiste Daroussin *t++ = '\b'; 244c99fb5f9SBaptiste Daroussin break; 245c99fb5f9SBaptiste Daroussin case 't': 246c99fb5f9SBaptiste Daroussin *t++ = '\t'; 247c99fb5f9SBaptiste Daroussin break; 248c99fb5f9SBaptiste Daroussin case 'f': 249c99fb5f9SBaptiste Daroussin *t++ = '\f'; 250c99fb5f9SBaptiste Daroussin break; 251c99fb5f9SBaptiste Daroussin case '\\': 252c99fb5f9SBaptiste Daroussin *t++ = '\\'; 253c99fb5f9SBaptiste Daroussin break; 254c99fb5f9SBaptiste Daroussin case '"': 255c99fb5f9SBaptiste Daroussin *t++ = '"'; 256c99fb5f9SBaptiste Daroussin break; 257c99fb5f9SBaptiste Daroussin case 'u': 258c99fb5f9SBaptiste Daroussin /* Unicode escape */ 259c99fb5f9SBaptiste Daroussin uval = 0; 26097bd480fSBaptiste Daroussin if (len > 3) { 261c99fb5f9SBaptiste Daroussin for (i = 0; i < 4; i++) { 262c99fb5f9SBaptiste Daroussin uval <<= 4; 263c99fb5f9SBaptiste Daroussin if (isdigit (h[i])) { 264c99fb5f9SBaptiste Daroussin uval += h[i] - '0'; 265c99fb5f9SBaptiste Daroussin } 266c99fb5f9SBaptiste Daroussin else if (h[i] >= 'a' && h[i] <= 'f') { 267c99fb5f9SBaptiste Daroussin uval += h[i] - 'a' + 10; 268c99fb5f9SBaptiste Daroussin } 269c99fb5f9SBaptiste Daroussin else if (h[i] >= 'A' && h[i] <= 'F') { 270c99fb5f9SBaptiste Daroussin uval += h[i] - 'A' + 10; 271c99fb5f9SBaptiste Daroussin } 27297bd480fSBaptiste Daroussin else { 27397bd480fSBaptiste Daroussin break; 27497bd480fSBaptiste Daroussin } 275c99fb5f9SBaptiste Daroussin } 276c99fb5f9SBaptiste Daroussin h += 3; 277c99fb5f9SBaptiste Daroussin len -= 3; 278c99fb5f9SBaptiste Daroussin /* Encode */ 279c99fb5f9SBaptiste Daroussin if(uval < 0x80) { 280c99fb5f9SBaptiste Daroussin t[0] = (char)uval; 281c99fb5f9SBaptiste Daroussin t ++; 282c99fb5f9SBaptiste Daroussin } 283c99fb5f9SBaptiste Daroussin else if(uval < 0x800) { 284c99fb5f9SBaptiste Daroussin t[0] = 0xC0 + ((uval & 0x7C0) >> 6); 285c99fb5f9SBaptiste Daroussin t[1] = 0x80 + ((uval & 0x03F)); 286c99fb5f9SBaptiste Daroussin t += 2; 287c99fb5f9SBaptiste Daroussin } 288c99fb5f9SBaptiste Daroussin else if(uval < 0x10000) { 289c99fb5f9SBaptiste Daroussin t[0] = 0xE0 + ((uval & 0xF000) >> 12); 290c99fb5f9SBaptiste Daroussin t[1] = 0x80 + ((uval & 0x0FC0) >> 6); 291c99fb5f9SBaptiste Daroussin t[2] = 0x80 + ((uval & 0x003F)); 292c99fb5f9SBaptiste Daroussin t += 3; 293c99fb5f9SBaptiste Daroussin } 294c99fb5f9SBaptiste Daroussin else if(uval <= 0x10FFFF) { 295c99fb5f9SBaptiste Daroussin t[0] = 0xF0 + ((uval & 0x1C0000) >> 18); 296c99fb5f9SBaptiste Daroussin t[1] = 0x80 + ((uval & 0x03F000) >> 12); 297c99fb5f9SBaptiste Daroussin t[2] = 0x80 + ((uval & 0x000FC0) >> 6); 298c99fb5f9SBaptiste Daroussin t[3] = 0x80 + ((uval & 0x00003F)); 299c99fb5f9SBaptiste Daroussin t += 4; 300c99fb5f9SBaptiste Daroussin } 301c99fb5f9SBaptiste Daroussin else { 302c99fb5f9SBaptiste Daroussin *t++ = '?'; 303c99fb5f9SBaptiste Daroussin } 30497bd480fSBaptiste Daroussin } 30597bd480fSBaptiste Daroussin else { 30697bd480fSBaptiste Daroussin *t++ = 'u'; 30797bd480fSBaptiste Daroussin } 308c99fb5f9SBaptiste Daroussin break; 309c99fb5f9SBaptiste Daroussin default: 310c99fb5f9SBaptiste Daroussin *t++ = *h; 311c99fb5f9SBaptiste Daroussin break; 312c99fb5f9SBaptiste Daroussin } 313c99fb5f9SBaptiste Daroussin h ++; 314c99fb5f9SBaptiste Daroussin len --; 315c99fb5f9SBaptiste Daroussin } 316c99fb5f9SBaptiste Daroussin else { 317c99fb5f9SBaptiste Daroussin *t++ = *h++; 318c99fb5f9SBaptiste Daroussin } 319c99fb5f9SBaptiste Daroussin len --; 320c99fb5f9SBaptiste Daroussin } 321c99fb5f9SBaptiste Daroussin *t = '\0'; 322c99fb5f9SBaptiste Daroussin 323c99fb5f9SBaptiste Daroussin return (t - str); 324c99fb5f9SBaptiste Daroussin } 325c99fb5f9SBaptiste Daroussin 326*b04a7a0bSBaptiste Daroussin char * 327*b04a7a0bSBaptiste Daroussin ucl_copy_key_trash (const ucl_object_t *obj) 328c99fb5f9SBaptiste Daroussin { 329*b04a7a0bSBaptiste Daroussin ucl_object_t *deconst; 330*b04a7a0bSBaptiste Daroussin 33197bd480fSBaptiste Daroussin if (obj == NULL) { 33297bd480fSBaptiste Daroussin return NULL; 33397bd480fSBaptiste Daroussin } 334c99fb5f9SBaptiste Daroussin if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) { 335*b04a7a0bSBaptiste Daroussin deconst = __DECONST (ucl_object_t *, obj); 336*b04a7a0bSBaptiste Daroussin deconst->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1); 337*b04a7a0bSBaptiste Daroussin if (deconst->trash_stack[UCL_TRASH_KEY] != NULL) { 338*b04a7a0bSBaptiste Daroussin memcpy (deconst->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen); 339*b04a7a0bSBaptiste Daroussin deconst->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0'; 340c99fb5f9SBaptiste Daroussin } 341*b04a7a0bSBaptiste Daroussin deconst->key = obj->trash_stack[UCL_TRASH_KEY]; 342*b04a7a0bSBaptiste Daroussin deconst->flags |= UCL_OBJECT_ALLOCATED_KEY; 343c99fb5f9SBaptiste Daroussin } 344c99fb5f9SBaptiste Daroussin 345c99fb5f9SBaptiste Daroussin return obj->trash_stack[UCL_TRASH_KEY]; 346c99fb5f9SBaptiste Daroussin } 347c99fb5f9SBaptiste Daroussin 348*b04a7a0bSBaptiste Daroussin char * 349*b04a7a0bSBaptiste Daroussin ucl_copy_value_trash (const ucl_object_t *obj) 350c99fb5f9SBaptiste Daroussin { 351*b04a7a0bSBaptiste Daroussin ucl_object_t *deconst; 352*b04a7a0bSBaptiste Daroussin 35397bd480fSBaptiste Daroussin if (obj == NULL) { 35497bd480fSBaptiste Daroussin return NULL; 35597bd480fSBaptiste Daroussin } 356c99fb5f9SBaptiste Daroussin if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) { 357*b04a7a0bSBaptiste Daroussin deconst = __DECONST (ucl_object_t *, obj); 358c99fb5f9SBaptiste Daroussin if (obj->type == UCL_STRING) { 359*b04a7a0bSBaptiste Daroussin 360c99fb5f9SBaptiste Daroussin /* Special case for strings */ 361*b04a7a0bSBaptiste Daroussin deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1); 362*b04a7a0bSBaptiste Daroussin if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) { 363*b04a7a0bSBaptiste Daroussin memcpy (deconst->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len); 364*b04a7a0bSBaptiste Daroussin deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0'; 365*b04a7a0bSBaptiste Daroussin deconst->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; 366c99fb5f9SBaptiste Daroussin } 367c99fb5f9SBaptiste Daroussin } 368c99fb5f9SBaptiste Daroussin else { 369c99fb5f9SBaptiste Daroussin /* Just emit value in json notation */ 370*b04a7a0bSBaptiste Daroussin deconst->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj); 371*b04a7a0bSBaptiste Daroussin deconst->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]); 372c99fb5f9SBaptiste Daroussin } 373*b04a7a0bSBaptiste Daroussin deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE; 374c99fb5f9SBaptiste Daroussin } 375c99fb5f9SBaptiste Daroussin return obj->trash_stack[UCL_TRASH_VALUE]; 376c99fb5f9SBaptiste Daroussin } 377c99fb5f9SBaptiste Daroussin 37836c53d67SBaptiste Daroussin UCL_EXTERN ucl_object_t* 379c99fb5f9SBaptiste Daroussin ucl_parser_get_object (struct ucl_parser *parser) 380c99fb5f9SBaptiste Daroussin { 381c99fb5f9SBaptiste Daroussin if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) { 382c99fb5f9SBaptiste Daroussin return ucl_object_ref (parser->top_obj); 383c99fb5f9SBaptiste Daroussin } 384c99fb5f9SBaptiste Daroussin 385c99fb5f9SBaptiste Daroussin return NULL; 386c99fb5f9SBaptiste Daroussin } 387c99fb5f9SBaptiste Daroussin 38836c53d67SBaptiste Daroussin UCL_EXTERN void 389c99fb5f9SBaptiste Daroussin ucl_parser_free (struct ucl_parser *parser) 390c99fb5f9SBaptiste Daroussin { 391c99fb5f9SBaptiste Daroussin struct ucl_stack *stack, *stmp; 392c99fb5f9SBaptiste Daroussin struct ucl_macro *macro, *mtmp; 393c99fb5f9SBaptiste Daroussin struct ucl_chunk *chunk, *ctmp; 394c99fb5f9SBaptiste Daroussin struct ucl_pubkey *key, *ktmp; 395c99fb5f9SBaptiste Daroussin struct ucl_variable *var, *vtmp; 396c99fb5f9SBaptiste Daroussin 39797bd480fSBaptiste Daroussin if (parser == NULL) { 39897bd480fSBaptiste Daroussin return; 39997bd480fSBaptiste Daroussin } 40097bd480fSBaptiste Daroussin 401c99fb5f9SBaptiste Daroussin if (parser->top_obj != NULL) { 402c99fb5f9SBaptiste Daroussin ucl_object_unref (parser->top_obj); 403c99fb5f9SBaptiste Daroussin } 404c99fb5f9SBaptiste Daroussin 405c99fb5f9SBaptiste Daroussin LL_FOREACH_SAFE (parser->stack, stack, stmp) { 406c99fb5f9SBaptiste Daroussin free (stack); 407c99fb5f9SBaptiste Daroussin } 408c99fb5f9SBaptiste Daroussin HASH_ITER (hh, parser->macroes, macro, mtmp) { 409c99fb5f9SBaptiste Daroussin free (macro->name); 410c99fb5f9SBaptiste Daroussin HASH_DEL (parser->macroes, macro); 411c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_macro), macro); 412c99fb5f9SBaptiste Daroussin } 413c99fb5f9SBaptiste Daroussin LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) { 414c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_chunk), chunk); 415c99fb5f9SBaptiste Daroussin } 416c99fb5f9SBaptiste Daroussin LL_FOREACH_SAFE (parser->keys, key, ktmp) { 417c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_pubkey), key); 418c99fb5f9SBaptiste Daroussin } 419c99fb5f9SBaptiste Daroussin LL_FOREACH_SAFE (parser->variables, var, vtmp) { 420c99fb5f9SBaptiste Daroussin free (var->value); 421c99fb5f9SBaptiste Daroussin free (var->var); 422c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_variable), var); 423c99fb5f9SBaptiste Daroussin } 424c99fb5f9SBaptiste Daroussin 425c99fb5f9SBaptiste Daroussin if (parser->err != NULL) { 426c99fb5f9SBaptiste Daroussin utstring_free(parser->err); 427c99fb5f9SBaptiste Daroussin } 428c99fb5f9SBaptiste Daroussin 429c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_parser), parser); 430c99fb5f9SBaptiste Daroussin } 431c99fb5f9SBaptiste Daroussin 43236c53d67SBaptiste Daroussin UCL_EXTERN const char * 433c99fb5f9SBaptiste Daroussin ucl_parser_get_error(struct ucl_parser *parser) 434c99fb5f9SBaptiste Daroussin { 43597bd480fSBaptiste Daroussin if (parser == NULL) { 43697bd480fSBaptiste Daroussin return NULL; 43797bd480fSBaptiste Daroussin } 43897bd480fSBaptiste Daroussin 439c99fb5f9SBaptiste Daroussin if (parser->err == NULL) 440c99fb5f9SBaptiste Daroussin return NULL; 441c99fb5f9SBaptiste Daroussin 442c99fb5f9SBaptiste Daroussin return utstring_body(parser->err); 443c99fb5f9SBaptiste Daroussin } 444c99fb5f9SBaptiste Daroussin 44536c53d67SBaptiste Daroussin UCL_EXTERN bool 446c99fb5f9SBaptiste Daroussin ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) 447c99fb5f9SBaptiste Daroussin { 448c99fb5f9SBaptiste Daroussin #ifndef HAVE_OPENSSL 449c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "cannot check signatures without openssl"); 450c99fb5f9SBaptiste Daroussin return false; 451c99fb5f9SBaptiste Daroussin #else 452c99fb5f9SBaptiste Daroussin # if (OPENSSL_VERSION_NUMBER < 0x10000000L) 453c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported"); 454c99fb5f9SBaptiste Daroussin return EXIT_FAILURE; 455c99fb5f9SBaptiste Daroussin # else 456c99fb5f9SBaptiste Daroussin struct ucl_pubkey *nkey; 457c99fb5f9SBaptiste Daroussin BIO *mem; 458c99fb5f9SBaptiste Daroussin 459c99fb5f9SBaptiste Daroussin mem = BIO_new_mem_buf ((void *)key, len); 460c99fb5f9SBaptiste Daroussin nkey = UCL_ALLOC (sizeof (struct ucl_pubkey)); 46197bd480fSBaptiste Daroussin if (nkey == NULL) { 46297bd480fSBaptiste Daroussin ucl_create_err (&parser->err, "cannot allocate memory for key"); 46397bd480fSBaptiste Daroussin return false; 46497bd480fSBaptiste Daroussin } 465c99fb5f9SBaptiste Daroussin nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL); 466c99fb5f9SBaptiste Daroussin BIO_free (mem); 467c99fb5f9SBaptiste Daroussin if (nkey->key == NULL) { 468c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_pubkey), nkey); 469c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "%s", 470c99fb5f9SBaptiste Daroussin ERR_error_string (ERR_get_error (), NULL)); 471c99fb5f9SBaptiste Daroussin return false; 472c99fb5f9SBaptiste Daroussin } 473c99fb5f9SBaptiste Daroussin LL_PREPEND (parser->keys, nkey); 474c99fb5f9SBaptiste Daroussin # endif 475c99fb5f9SBaptiste Daroussin #endif 476c99fb5f9SBaptiste Daroussin return true; 477c99fb5f9SBaptiste Daroussin } 478c99fb5f9SBaptiste Daroussin 479c99fb5f9SBaptiste Daroussin #ifdef CURL_FOUND 480c99fb5f9SBaptiste Daroussin struct ucl_curl_cbdata { 481c99fb5f9SBaptiste Daroussin unsigned char *buf; 482c99fb5f9SBaptiste Daroussin size_t buflen; 483c99fb5f9SBaptiste Daroussin }; 484c99fb5f9SBaptiste Daroussin 485c99fb5f9SBaptiste Daroussin static size_t 486c99fb5f9SBaptiste Daroussin ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud) 487c99fb5f9SBaptiste Daroussin { 488c99fb5f9SBaptiste Daroussin struct ucl_curl_cbdata *cbdata = ud; 489c99fb5f9SBaptiste Daroussin size_t realsize = size * nmemb; 490c99fb5f9SBaptiste Daroussin 491c99fb5f9SBaptiste Daroussin cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1); 492c99fb5f9SBaptiste Daroussin if (cbdata->buf == NULL) { 493c99fb5f9SBaptiste Daroussin return 0; 494c99fb5f9SBaptiste Daroussin } 495c99fb5f9SBaptiste Daroussin 496c99fb5f9SBaptiste Daroussin memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize); 497c99fb5f9SBaptiste Daroussin cbdata->buflen += realsize; 498c99fb5f9SBaptiste Daroussin cbdata->buf[cbdata->buflen] = 0; 499c99fb5f9SBaptiste Daroussin 500c99fb5f9SBaptiste Daroussin return realsize; 501c99fb5f9SBaptiste Daroussin } 502c99fb5f9SBaptiste Daroussin #endif 503c99fb5f9SBaptiste Daroussin 504c99fb5f9SBaptiste Daroussin /** 505c99fb5f9SBaptiste Daroussin * Fetch a url and save results to the memory buffer 506c99fb5f9SBaptiste Daroussin * @param url url to fetch 507c99fb5f9SBaptiste Daroussin * @param len length of url 508c99fb5f9SBaptiste Daroussin * @param buf target buffer 509c99fb5f9SBaptiste Daroussin * @param buflen target length 510c99fb5f9SBaptiste Daroussin * @return 511c99fb5f9SBaptiste Daroussin */ 512c99fb5f9SBaptiste Daroussin static bool 513c99fb5f9SBaptiste Daroussin ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, 514c99fb5f9SBaptiste Daroussin UT_string **err, bool must_exist) 515c99fb5f9SBaptiste Daroussin { 516c99fb5f9SBaptiste Daroussin 517c99fb5f9SBaptiste Daroussin #ifdef HAVE_FETCH_H 518c99fb5f9SBaptiste Daroussin struct url *fetch_url; 519c99fb5f9SBaptiste Daroussin struct url_stat us; 520c99fb5f9SBaptiste Daroussin FILE *in; 521c99fb5f9SBaptiste Daroussin 522c99fb5f9SBaptiste Daroussin fetch_url = fetchParseURL (url); 523c99fb5f9SBaptiste Daroussin if (fetch_url == NULL) { 524c99fb5f9SBaptiste Daroussin ucl_create_err (err, "invalid URL %s: %s", 525c99fb5f9SBaptiste Daroussin url, strerror (errno)); 526c99fb5f9SBaptiste Daroussin return false; 527c99fb5f9SBaptiste Daroussin } 528c99fb5f9SBaptiste Daroussin if ((in = fetchXGet (fetch_url, &us, "")) == NULL) { 529c99fb5f9SBaptiste Daroussin if (!must_exist) { 530c99fb5f9SBaptiste Daroussin ucl_create_err (err, "cannot fetch URL %s: %s", 531c99fb5f9SBaptiste Daroussin url, strerror (errno)); 532c99fb5f9SBaptiste Daroussin } 533c99fb5f9SBaptiste Daroussin fetchFreeURL (fetch_url); 534c99fb5f9SBaptiste Daroussin return false; 535c99fb5f9SBaptiste Daroussin } 536c99fb5f9SBaptiste Daroussin 537c99fb5f9SBaptiste Daroussin *buflen = us.size; 538c99fb5f9SBaptiste Daroussin *buf = malloc (*buflen); 539c99fb5f9SBaptiste Daroussin if (*buf == NULL) { 540c99fb5f9SBaptiste Daroussin ucl_create_err (err, "cannot allocate buffer for URL %s: %s", 541c99fb5f9SBaptiste Daroussin url, strerror (errno)); 542c99fb5f9SBaptiste Daroussin fclose (in); 543c99fb5f9SBaptiste Daroussin fetchFreeURL (fetch_url); 544c99fb5f9SBaptiste Daroussin return false; 545c99fb5f9SBaptiste Daroussin } 546c99fb5f9SBaptiste Daroussin 547c99fb5f9SBaptiste Daroussin if (fread (*buf, *buflen, 1, in) != 1) { 548c99fb5f9SBaptiste Daroussin ucl_create_err (err, "cannot read URL %s: %s", 549c99fb5f9SBaptiste Daroussin url, strerror (errno)); 550c99fb5f9SBaptiste Daroussin fclose (in); 551c99fb5f9SBaptiste Daroussin fetchFreeURL (fetch_url); 552c99fb5f9SBaptiste Daroussin return false; 553c99fb5f9SBaptiste Daroussin } 554c99fb5f9SBaptiste Daroussin 555c99fb5f9SBaptiste Daroussin fetchFreeURL (fetch_url); 556c99fb5f9SBaptiste Daroussin return true; 557c99fb5f9SBaptiste Daroussin #elif defined(CURL_FOUND) 558c99fb5f9SBaptiste Daroussin CURL *curl; 559c99fb5f9SBaptiste Daroussin int r; 560c99fb5f9SBaptiste Daroussin struct ucl_curl_cbdata cbdata; 561c99fb5f9SBaptiste Daroussin 562c99fb5f9SBaptiste Daroussin curl = curl_easy_init (); 563c99fb5f9SBaptiste Daroussin if (curl == NULL) { 564c99fb5f9SBaptiste Daroussin ucl_create_err (err, "CURL interface is broken"); 565c99fb5f9SBaptiste Daroussin return false; 566c99fb5f9SBaptiste Daroussin } 567c99fb5f9SBaptiste Daroussin if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) { 568c99fb5f9SBaptiste Daroussin ucl_create_err (err, "invalid URL %s: %s", 569c99fb5f9SBaptiste Daroussin url, curl_easy_strerror (r)); 570c99fb5f9SBaptiste Daroussin curl_easy_cleanup (curl); 571c99fb5f9SBaptiste Daroussin return false; 572c99fb5f9SBaptiste Daroussin } 573c99fb5f9SBaptiste Daroussin curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback); 574c99fb5f9SBaptiste Daroussin cbdata.buf = *buf; 575c99fb5f9SBaptiste Daroussin cbdata.buflen = *buflen; 576c99fb5f9SBaptiste Daroussin curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata); 577c99fb5f9SBaptiste Daroussin 578c99fb5f9SBaptiste Daroussin if ((r = curl_easy_perform (curl)) != CURLE_OK) { 579c99fb5f9SBaptiste Daroussin if (!must_exist) { 580c99fb5f9SBaptiste Daroussin ucl_create_err (err, "error fetching URL %s: %s", 581c99fb5f9SBaptiste Daroussin url, curl_easy_strerror (r)); 582c99fb5f9SBaptiste Daroussin } 583c99fb5f9SBaptiste Daroussin curl_easy_cleanup (curl); 584c99fb5f9SBaptiste Daroussin if (cbdata.buf) { 585c99fb5f9SBaptiste Daroussin free (cbdata.buf); 586c99fb5f9SBaptiste Daroussin } 587c99fb5f9SBaptiste Daroussin return false; 588c99fb5f9SBaptiste Daroussin } 589c99fb5f9SBaptiste Daroussin *buf = cbdata.buf; 590c99fb5f9SBaptiste Daroussin *buflen = cbdata.buflen; 591c99fb5f9SBaptiste Daroussin 592c99fb5f9SBaptiste Daroussin return true; 593c99fb5f9SBaptiste Daroussin #else 594c99fb5f9SBaptiste Daroussin ucl_create_err (err, "URL support is disabled"); 595c99fb5f9SBaptiste Daroussin return false; 596c99fb5f9SBaptiste Daroussin #endif 597c99fb5f9SBaptiste Daroussin } 598c99fb5f9SBaptiste Daroussin 599c99fb5f9SBaptiste Daroussin /** 600c99fb5f9SBaptiste Daroussin * Fetch a file and save results to the memory buffer 601c99fb5f9SBaptiste Daroussin * @param filename filename to fetch 602c99fb5f9SBaptiste Daroussin * @param len length of filename 603c99fb5f9SBaptiste Daroussin * @param buf target buffer 604c99fb5f9SBaptiste Daroussin * @param buflen target length 605c99fb5f9SBaptiste Daroussin * @return 606c99fb5f9SBaptiste Daroussin */ 607c99fb5f9SBaptiste Daroussin static bool 608c99fb5f9SBaptiste Daroussin ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen, 609c99fb5f9SBaptiste Daroussin UT_string **err, bool must_exist) 610c99fb5f9SBaptiste Daroussin { 611c99fb5f9SBaptiste Daroussin int fd; 612c99fb5f9SBaptiste Daroussin struct stat st; 613c99fb5f9SBaptiste Daroussin 614c99fb5f9SBaptiste Daroussin if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { 615c99fb5f9SBaptiste Daroussin if (must_exist) { 616c99fb5f9SBaptiste Daroussin ucl_create_err (err, "cannot stat file %s: %s", 617c99fb5f9SBaptiste Daroussin filename, strerror (errno)); 618c99fb5f9SBaptiste Daroussin } 619c99fb5f9SBaptiste Daroussin return false; 620c99fb5f9SBaptiste Daroussin } 621c99fb5f9SBaptiste Daroussin if (st.st_size == 0) { 622c99fb5f9SBaptiste Daroussin /* Do not map empty files */ 623c99fb5f9SBaptiste Daroussin *buf = ""; 624c99fb5f9SBaptiste Daroussin *buflen = 0; 625c99fb5f9SBaptiste Daroussin } 626c99fb5f9SBaptiste Daroussin else { 627c99fb5f9SBaptiste Daroussin if ((fd = open (filename, O_RDONLY)) == -1) { 628c99fb5f9SBaptiste Daroussin ucl_create_err (err, "cannot open file %s: %s", 629c99fb5f9SBaptiste Daroussin filename, strerror (errno)); 630c99fb5f9SBaptiste Daroussin return false; 631c99fb5f9SBaptiste Daroussin } 63297bd480fSBaptiste Daroussin if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 633c99fb5f9SBaptiste Daroussin close (fd); 634c99fb5f9SBaptiste Daroussin ucl_create_err (err, "cannot mmap file %s: %s", 635c99fb5f9SBaptiste Daroussin filename, strerror (errno)); 636c99fb5f9SBaptiste Daroussin return false; 637c99fb5f9SBaptiste Daroussin } 638c99fb5f9SBaptiste Daroussin *buflen = st.st_size; 639c99fb5f9SBaptiste Daroussin close (fd); 640c99fb5f9SBaptiste Daroussin } 641c99fb5f9SBaptiste Daroussin 642c99fb5f9SBaptiste Daroussin return true; 643c99fb5f9SBaptiste Daroussin } 644c99fb5f9SBaptiste Daroussin 645c99fb5f9SBaptiste Daroussin 646c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 647c99fb5f9SBaptiste Daroussin static inline bool 648c99fb5f9SBaptiste Daroussin ucl_sig_check (const unsigned char *data, size_t datalen, 649c99fb5f9SBaptiste Daroussin const unsigned char *sig, size_t siglen, struct ucl_parser *parser) 650c99fb5f9SBaptiste Daroussin { 651c99fb5f9SBaptiste Daroussin struct ucl_pubkey *key; 652c99fb5f9SBaptiste Daroussin char dig[EVP_MAX_MD_SIZE]; 653c99fb5f9SBaptiste Daroussin unsigned int diglen; 654c99fb5f9SBaptiste Daroussin EVP_PKEY_CTX *key_ctx; 655c99fb5f9SBaptiste Daroussin EVP_MD_CTX *sign_ctx = NULL; 656c99fb5f9SBaptiste Daroussin 657c99fb5f9SBaptiste Daroussin sign_ctx = EVP_MD_CTX_create (); 658c99fb5f9SBaptiste Daroussin 659c99fb5f9SBaptiste Daroussin LL_FOREACH (parser->keys, key) { 660c99fb5f9SBaptiste Daroussin key_ctx = EVP_PKEY_CTX_new (key->key, NULL); 661c99fb5f9SBaptiste Daroussin if (key_ctx != NULL) { 662c99fb5f9SBaptiste Daroussin if (EVP_PKEY_verify_init (key_ctx) <= 0) { 663c99fb5f9SBaptiste Daroussin EVP_PKEY_CTX_free (key_ctx); 664c99fb5f9SBaptiste Daroussin continue; 665c99fb5f9SBaptiste Daroussin } 666c99fb5f9SBaptiste Daroussin if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) { 667c99fb5f9SBaptiste Daroussin EVP_PKEY_CTX_free (key_ctx); 668c99fb5f9SBaptiste Daroussin continue; 669c99fb5f9SBaptiste Daroussin } 670c99fb5f9SBaptiste Daroussin if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) { 671c99fb5f9SBaptiste Daroussin EVP_PKEY_CTX_free (key_ctx); 672c99fb5f9SBaptiste Daroussin continue; 673c99fb5f9SBaptiste Daroussin } 674c99fb5f9SBaptiste Daroussin EVP_DigestInit (sign_ctx, EVP_sha256 ()); 675c99fb5f9SBaptiste Daroussin EVP_DigestUpdate (sign_ctx, data, datalen); 676c99fb5f9SBaptiste Daroussin EVP_DigestFinal (sign_ctx, dig, &diglen); 677c99fb5f9SBaptiste Daroussin 678c99fb5f9SBaptiste Daroussin if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) { 679c99fb5f9SBaptiste Daroussin EVP_MD_CTX_destroy (sign_ctx); 680c99fb5f9SBaptiste Daroussin EVP_PKEY_CTX_free (key_ctx); 681c99fb5f9SBaptiste Daroussin return true; 682c99fb5f9SBaptiste Daroussin } 683c99fb5f9SBaptiste Daroussin 684c99fb5f9SBaptiste Daroussin EVP_PKEY_CTX_free (key_ctx); 685c99fb5f9SBaptiste Daroussin } 686c99fb5f9SBaptiste Daroussin } 687c99fb5f9SBaptiste Daroussin 688c99fb5f9SBaptiste Daroussin EVP_MD_CTX_destroy (sign_ctx); 689c99fb5f9SBaptiste Daroussin 690c99fb5f9SBaptiste Daroussin return false; 691c99fb5f9SBaptiste Daroussin } 692c99fb5f9SBaptiste Daroussin #endif 693c99fb5f9SBaptiste Daroussin 694c99fb5f9SBaptiste Daroussin /** 695c99fb5f9SBaptiste Daroussin * Include an url to configuration 696c99fb5f9SBaptiste Daroussin * @param data 697c99fb5f9SBaptiste Daroussin * @param len 698c99fb5f9SBaptiste Daroussin * @param parser 699c99fb5f9SBaptiste Daroussin * @param err 700c99fb5f9SBaptiste Daroussin * @return 701c99fb5f9SBaptiste Daroussin */ 702c99fb5f9SBaptiste Daroussin static bool 703c99fb5f9SBaptiste Daroussin ucl_include_url (const unsigned char *data, size_t len, 704c99fb5f9SBaptiste Daroussin struct ucl_parser *parser, bool check_signature, bool must_exist) 705c99fb5f9SBaptiste Daroussin { 706c99fb5f9SBaptiste Daroussin 707c99fb5f9SBaptiste Daroussin bool res; 708c99fb5f9SBaptiste Daroussin unsigned char *buf = NULL; 709c99fb5f9SBaptiste Daroussin size_t buflen = 0; 710c99fb5f9SBaptiste Daroussin struct ucl_chunk *chunk; 711c99fb5f9SBaptiste Daroussin char urlbuf[PATH_MAX]; 712c99fb5f9SBaptiste Daroussin int prev_state; 713c99fb5f9SBaptiste Daroussin 714c99fb5f9SBaptiste Daroussin snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); 715c99fb5f9SBaptiste Daroussin 716c99fb5f9SBaptiste Daroussin if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) { 717c99fb5f9SBaptiste Daroussin return (!must_exist || false); 718c99fb5f9SBaptiste Daroussin } 719c99fb5f9SBaptiste Daroussin 720c99fb5f9SBaptiste Daroussin if (check_signature) { 721c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 722c99fb5f9SBaptiste Daroussin unsigned char *sigbuf = NULL; 723c99fb5f9SBaptiste Daroussin size_t siglen = 0; 724c99fb5f9SBaptiste Daroussin /* We need to check signature first */ 725c99fb5f9SBaptiste Daroussin snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data); 726c99fb5f9SBaptiste Daroussin if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) { 727c99fb5f9SBaptiste Daroussin return false; 728c99fb5f9SBaptiste Daroussin } 729c99fb5f9SBaptiste Daroussin if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 730c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "cannot verify url %s: %s", 731c99fb5f9SBaptiste Daroussin urlbuf, 732c99fb5f9SBaptiste Daroussin ERR_error_string (ERR_get_error (), NULL)); 733c99fb5f9SBaptiste Daroussin if (siglen > 0) { 73497bd480fSBaptiste Daroussin ucl_munmap (sigbuf, siglen); 735c99fb5f9SBaptiste Daroussin } 736c99fb5f9SBaptiste Daroussin return false; 737c99fb5f9SBaptiste Daroussin } 738c99fb5f9SBaptiste Daroussin if (siglen > 0) { 73997bd480fSBaptiste Daroussin ucl_munmap (sigbuf, siglen); 740c99fb5f9SBaptiste Daroussin } 741c99fb5f9SBaptiste Daroussin #endif 742c99fb5f9SBaptiste Daroussin } 743c99fb5f9SBaptiste Daroussin 744c99fb5f9SBaptiste Daroussin prev_state = parser->state; 745c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_INIT; 746c99fb5f9SBaptiste Daroussin 747c99fb5f9SBaptiste Daroussin res = ucl_parser_add_chunk (parser, buf, buflen); 748c99fb5f9SBaptiste Daroussin if (res == true) { 749c99fb5f9SBaptiste Daroussin /* Remove chunk from the stack */ 750c99fb5f9SBaptiste Daroussin chunk = parser->chunks; 751c99fb5f9SBaptiste Daroussin if (chunk != NULL) { 752c99fb5f9SBaptiste Daroussin parser->chunks = chunk->next; 753c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_chunk), chunk); 754c99fb5f9SBaptiste Daroussin } 755c99fb5f9SBaptiste Daroussin } 756c99fb5f9SBaptiste Daroussin 757c99fb5f9SBaptiste Daroussin parser->state = prev_state; 758c99fb5f9SBaptiste Daroussin free (buf); 759c99fb5f9SBaptiste Daroussin 760c99fb5f9SBaptiste Daroussin return res; 761c99fb5f9SBaptiste Daroussin } 762c99fb5f9SBaptiste Daroussin 763c99fb5f9SBaptiste Daroussin /** 764c99fb5f9SBaptiste Daroussin * Include a file to configuration 765c99fb5f9SBaptiste Daroussin * @param data 766c99fb5f9SBaptiste Daroussin * @param len 767c99fb5f9SBaptiste Daroussin * @param parser 768c99fb5f9SBaptiste Daroussin * @param err 769c99fb5f9SBaptiste Daroussin * @return 770c99fb5f9SBaptiste Daroussin */ 771c99fb5f9SBaptiste Daroussin static bool 772c99fb5f9SBaptiste Daroussin ucl_include_file (const unsigned char *data, size_t len, 773c99fb5f9SBaptiste Daroussin struct ucl_parser *parser, bool check_signature, bool must_exist) 774c99fb5f9SBaptiste Daroussin { 775c99fb5f9SBaptiste Daroussin bool res; 776c99fb5f9SBaptiste Daroussin struct ucl_chunk *chunk; 777c99fb5f9SBaptiste Daroussin unsigned char *buf = NULL; 778c99fb5f9SBaptiste Daroussin size_t buflen; 779c99fb5f9SBaptiste Daroussin char filebuf[PATH_MAX], realbuf[PATH_MAX]; 780c99fb5f9SBaptiste Daroussin int prev_state; 781c99fb5f9SBaptiste Daroussin 782c99fb5f9SBaptiste Daroussin snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); 78397bd480fSBaptiste Daroussin if (ucl_realpath (filebuf, realbuf) == NULL) { 784c99fb5f9SBaptiste Daroussin if (!must_exist) { 785c99fb5f9SBaptiste Daroussin return true; 786c99fb5f9SBaptiste Daroussin } 787c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "cannot open file %s: %s", 788c99fb5f9SBaptiste Daroussin filebuf, 789c99fb5f9SBaptiste Daroussin strerror (errno)); 790c99fb5f9SBaptiste Daroussin return false; 791c99fb5f9SBaptiste Daroussin } 792c99fb5f9SBaptiste Daroussin 793c99fb5f9SBaptiste Daroussin if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) { 794c99fb5f9SBaptiste Daroussin return (!must_exist || false); 795c99fb5f9SBaptiste Daroussin } 796c99fb5f9SBaptiste Daroussin 797c99fb5f9SBaptiste Daroussin if (check_signature) { 798c99fb5f9SBaptiste Daroussin #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 799c99fb5f9SBaptiste Daroussin unsigned char *sigbuf = NULL; 800c99fb5f9SBaptiste Daroussin size_t siglen = 0; 801c99fb5f9SBaptiste Daroussin /* We need to check signature first */ 802c99fb5f9SBaptiste Daroussin snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf); 803c99fb5f9SBaptiste Daroussin if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) { 804c99fb5f9SBaptiste Daroussin return false; 805c99fb5f9SBaptiste Daroussin } 806c99fb5f9SBaptiste Daroussin if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 807c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "cannot verify file %s: %s", 808c99fb5f9SBaptiste Daroussin filebuf, 809c99fb5f9SBaptiste Daroussin ERR_error_string (ERR_get_error (), NULL)); 810c99fb5f9SBaptiste Daroussin if (siglen > 0) { 81197bd480fSBaptiste Daroussin ucl_munmap (sigbuf, siglen); 812c99fb5f9SBaptiste Daroussin } 813c99fb5f9SBaptiste Daroussin return false; 814c99fb5f9SBaptiste Daroussin } 815c99fb5f9SBaptiste Daroussin if (siglen > 0) { 81697bd480fSBaptiste Daroussin ucl_munmap (sigbuf, siglen); 817c99fb5f9SBaptiste Daroussin } 818c99fb5f9SBaptiste Daroussin #endif 819c99fb5f9SBaptiste Daroussin } 820c99fb5f9SBaptiste Daroussin 821c99fb5f9SBaptiste Daroussin ucl_parser_set_filevars (parser, realbuf, false); 822c99fb5f9SBaptiste Daroussin 823c99fb5f9SBaptiste Daroussin prev_state = parser->state; 824c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_INIT; 825c99fb5f9SBaptiste Daroussin 826c99fb5f9SBaptiste Daroussin res = ucl_parser_add_chunk (parser, buf, buflen); 827c99fb5f9SBaptiste Daroussin if (res == true) { 828c99fb5f9SBaptiste Daroussin /* Remove chunk from the stack */ 829c99fb5f9SBaptiste Daroussin chunk = parser->chunks; 830c99fb5f9SBaptiste Daroussin if (chunk != NULL) { 831c99fb5f9SBaptiste Daroussin parser->chunks = chunk->next; 832c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_chunk), chunk); 833c99fb5f9SBaptiste Daroussin } 834c99fb5f9SBaptiste Daroussin } 835c99fb5f9SBaptiste Daroussin 836c99fb5f9SBaptiste Daroussin parser->state = prev_state; 837c99fb5f9SBaptiste Daroussin 838c99fb5f9SBaptiste Daroussin if (buflen > 0) { 83997bd480fSBaptiste Daroussin ucl_munmap (buf, buflen); 840c99fb5f9SBaptiste Daroussin } 841c99fb5f9SBaptiste Daroussin 842c99fb5f9SBaptiste Daroussin return res; 843c99fb5f9SBaptiste Daroussin } 844c99fb5f9SBaptiste Daroussin 845c99fb5f9SBaptiste Daroussin /** 846c99fb5f9SBaptiste Daroussin * Handle include macro 847c99fb5f9SBaptiste Daroussin * @param data include data 848c99fb5f9SBaptiste Daroussin * @param len length of data 849c99fb5f9SBaptiste Daroussin * @param ud user data 850c99fb5f9SBaptiste Daroussin * @param err error ptr 851c99fb5f9SBaptiste Daroussin * @return 852c99fb5f9SBaptiste Daroussin */ 85336c53d67SBaptiste Daroussin UCL_EXTERN bool 854c99fb5f9SBaptiste Daroussin ucl_include_handler (const unsigned char *data, size_t len, void* ud) 855c99fb5f9SBaptiste Daroussin { 856c99fb5f9SBaptiste Daroussin struct ucl_parser *parser = ud; 857c99fb5f9SBaptiste Daroussin 858c99fb5f9SBaptiste Daroussin if (*data == '/' || *data == '.') { 859c99fb5f9SBaptiste Daroussin /* Try to load a file */ 860c99fb5f9SBaptiste Daroussin return ucl_include_file (data, len, parser, false, true); 861c99fb5f9SBaptiste Daroussin } 862c99fb5f9SBaptiste Daroussin 863c99fb5f9SBaptiste Daroussin return ucl_include_url (data, len, parser, false, true); 864c99fb5f9SBaptiste Daroussin } 865c99fb5f9SBaptiste Daroussin 866c99fb5f9SBaptiste Daroussin /** 867c99fb5f9SBaptiste Daroussin * Handle includes macro 868c99fb5f9SBaptiste Daroussin * @param data include data 869c99fb5f9SBaptiste Daroussin * @param len length of data 870c99fb5f9SBaptiste Daroussin * @param ud user data 871c99fb5f9SBaptiste Daroussin * @param err error ptr 872c99fb5f9SBaptiste Daroussin * @return 873c99fb5f9SBaptiste Daroussin */ 87436c53d67SBaptiste Daroussin UCL_EXTERN bool 875c99fb5f9SBaptiste Daroussin ucl_includes_handler (const unsigned char *data, size_t len, void* ud) 876c99fb5f9SBaptiste Daroussin { 877c99fb5f9SBaptiste Daroussin struct ucl_parser *parser = ud; 878c99fb5f9SBaptiste Daroussin 879c99fb5f9SBaptiste Daroussin if (*data == '/' || *data == '.') { 880c99fb5f9SBaptiste Daroussin /* Try to load a file */ 881c99fb5f9SBaptiste Daroussin return ucl_include_file (data, len, parser, true, true); 882c99fb5f9SBaptiste Daroussin } 883c99fb5f9SBaptiste Daroussin 884c99fb5f9SBaptiste Daroussin return ucl_include_url (data, len, parser, true, true); 885c99fb5f9SBaptiste Daroussin } 886c99fb5f9SBaptiste Daroussin 887c99fb5f9SBaptiste Daroussin 88836c53d67SBaptiste Daroussin UCL_EXTERN bool 889c99fb5f9SBaptiste Daroussin ucl_try_include_handler (const unsigned char *data, size_t len, void* ud) 890c99fb5f9SBaptiste Daroussin { 891c99fb5f9SBaptiste Daroussin struct ucl_parser *parser = ud; 892c99fb5f9SBaptiste Daroussin 893c99fb5f9SBaptiste Daroussin if (*data == '/' || *data == '.') { 894c99fb5f9SBaptiste Daroussin /* Try to load a file */ 895c99fb5f9SBaptiste Daroussin return ucl_include_file (data, len, parser, false, false); 896c99fb5f9SBaptiste Daroussin } 897c99fb5f9SBaptiste Daroussin 898c99fb5f9SBaptiste Daroussin return ucl_include_url (data, len, parser, false, false); 899c99fb5f9SBaptiste Daroussin } 900c99fb5f9SBaptiste Daroussin 90136c53d67SBaptiste Daroussin UCL_EXTERN bool 902c99fb5f9SBaptiste Daroussin ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand) 903c99fb5f9SBaptiste Daroussin { 904c99fb5f9SBaptiste Daroussin char realbuf[PATH_MAX], *curdir; 905c99fb5f9SBaptiste Daroussin 906c99fb5f9SBaptiste Daroussin if (filename != NULL) { 907c99fb5f9SBaptiste Daroussin if (need_expand) { 90897bd480fSBaptiste Daroussin if (ucl_realpath (filename, realbuf) == NULL) { 909c99fb5f9SBaptiste Daroussin return false; 910c99fb5f9SBaptiste Daroussin } 911c99fb5f9SBaptiste Daroussin } 912c99fb5f9SBaptiste Daroussin else { 913c99fb5f9SBaptiste Daroussin ucl_strlcpy (realbuf, filename, sizeof (realbuf)); 914c99fb5f9SBaptiste Daroussin } 915c99fb5f9SBaptiste Daroussin 916c99fb5f9SBaptiste Daroussin /* Define variables */ 917c99fb5f9SBaptiste Daroussin ucl_parser_register_variable (parser, "FILENAME", realbuf); 918c99fb5f9SBaptiste Daroussin curdir = dirname (realbuf); 919c99fb5f9SBaptiste Daroussin ucl_parser_register_variable (parser, "CURDIR", curdir); 920c99fb5f9SBaptiste Daroussin } 921c99fb5f9SBaptiste Daroussin else { 922c99fb5f9SBaptiste Daroussin /* Set everything from the current dir */ 923c99fb5f9SBaptiste Daroussin curdir = getcwd (realbuf, sizeof (realbuf)); 924c99fb5f9SBaptiste Daroussin ucl_parser_register_variable (parser, "FILENAME", "undef"); 925c99fb5f9SBaptiste Daroussin ucl_parser_register_variable (parser, "CURDIR", curdir); 926c99fb5f9SBaptiste Daroussin } 927c99fb5f9SBaptiste Daroussin 928c99fb5f9SBaptiste Daroussin return true; 929c99fb5f9SBaptiste Daroussin } 930c99fb5f9SBaptiste Daroussin 93136c53d67SBaptiste Daroussin UCL_EXTERN bool 932c99fb5f9SBaptiste Daroussin ucl_parser_add_file (struct ucl_parser *parser, const char *filename) 933c99fb5f9SBaptiste Daroussin { 934c99fb5f9SBaptiste Daroussin unsigned char *buf; 935c99fb5f9SBaptiste Daroussin size_t len; 936c99fb5f9SBaptiste Daroussin bool ret; 937c99fb5f9SBaptiste Daroussin char realbuf[PATH_MAX]; 938c99fb5f9SBaptiste Daroussin 93997bd480fSBaptiste Daroussin if (ucl_realpath (filename, realbuf) == NULL) { 940c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "cannot open file %s: %s", 941c99fb5f9SBaptiste Daroussin filename, 942c99fb5f9SBaptiste Daroussin strerror (errno)); 943c99fb5f9SBaptiste Daroussin return false; 944c99fb5f9SBaptiste Daroussin } 945c99fb5f9SBaptiste Daroussin 946c99fb5f9SBaptiste Daroussin if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) { 947c99fb5f9SBaptiste Daroussin return false; 948c99fb5f9SBaptiste Daroussin } 949c99fb5f9SBaptiste Daroussin 950c99fb5f9SBaptiste Daroussin ucl_parser_set_filevars (parser, realbuf, false); 951c99fb5f9SBaptiste Daroussin ret = ucl_parser_add_chunk (parser, buf, len); 952c99fb5f9SBaptiste Daroussin 953c99fb5f9SBaptiste Daroussin if (len > 0) { 95497bd480fSBaptiste Daroussin ucl_munmap (buf, len); 955c99fb5f9SBaptiste Daroussin } 956c99fb5f9SBaptiste Daroussin 957c99fb5f9SBaptiste Daroussin return ret; 958c99fb5f9SBaptiste Daroussin } 959c99fb5f9SBaptiste Daroussin 960c99fb5f9SBaptiste Daroussin size_t 961c99fb5f9SBaptiste Daroussin ucl_strlcpy (char *dst, const char *src, size_t siz) 962c99fb5f9SBaptiste Daroussin { 963c99fb5f9SBaptiste Daroussin char *d = dst; 964c99fb5f9SBaptiste Daroussin const char *s = src; 965c99fb5f9SBaptiste Daroussin size_t n = siz; 966c99fb5f9SBaptiste Daroussin 967c99fb5f9SBaptiste Daroussin /* Copy as many bytes as will fit */ 968c99fb5f9SBaptiste Daroussin if (n != 0) { 969c99fb5f9SBaptiste Daroussin while (--n != 0) { 970c99fb5f9SBaptiste Daroussin if ((*d++ = *s++) == '\0') { 971c99fb5f9SBaptiste Daroussin break; 972c99fb5f9SBaptiste Daroussin } 973c99fb5f9SBaptiste Daroussin } 974c99fb5f9SBaptiste Daroussin } 975c99fb5f9SBaptiste Daroussin 976c99fb5f9SBaptiste Daroussin if (n == 0 && siz != 0) { 977c99fb5f9SBaptiste Daroussin *d = '\0'; 978c99fb5f9SBaptiste Daroussin } 979c99fb5f9SBaptiste Daroussin 980c99fb5f9SBaptiste Daroussin return (s - src - 1); /* count does not include NUL */ 981c99fb5f9SBaptiste Daroussin } 982c99fb5f9SBaptiste Daroussin 983c99fb5f9SBaptiste Daroussin size_t 984c99fb5f9SBaptiste Daroussin ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz) 985c99fb5f9SBaptiste Daroussin { 986c99fb5f9SBaptiste Daroussin memcpy (dst, src, siz - 1); 987c99fb5f9SBaptiste Daroussin dst[siz - 1] = '\0'; 988c99fb5f9SBaptiste Daroussin 989c99fb5f9SBaptiste Daroussin return siz - 1; 990c99fb5f9SBaptiste Daroussin } 991c99fb5f9SBaptiste Daroussin 992c99fb5f9SBaptiste Daroussin size_t 993c99fb5f9SBaptiste Daroussin ucl_strlcpy_tolower (char *dst, const char *src, size_t siz) 994c99fb5f9SBaptiste Daroussin { 995c99fb5f9SBaptiste Daroussin char *d = dst; 996c99fb5f9SBaptiste Daroussin const char *s = src; 997c99fb5f9SBaptiste Daroussin size_t n = siz; 998c99fb5f9SBaptiste Daroussin 999c99fb5f9SBaptiste Daroussin /* Copy as many bytes as will fit */ 1000c99fb5f9SBaptiste Daroussin if (n != 0) { 1001c99fb5f9SBaptiste Daroussin while (--n != 0) { 1002c99fb5f9SBaptiste Daroussin if ((*d++ = tolower (*s++)) == '\0') { 1003c99fb5f9SBaptiste Daroussin break; 1004c99fb5f9SBaptiste Daroussin } 1005c99fb5f9SBaptiste Daroussin } 1006c99fb5f9SBaptiste Daroussin } 1007c99fb5f9SBaptiste Daroussin 1008c99fb5f9SBaptiste Daroussin if (n == 0 && siz != 0) { 1009c99fb5f9SBaptiste Daroussin *d = '\0'; 1010c99fb5f9SBaptiste Daroussin } 1011c99fb5f9SBaptiste Daroussin 1012c99fb5f9SBaptiste Daroussin return (s - src); /* count does not include NUL */ 1013c99fb5f9SBaptiste Daroussin } 1014c99fb5f9SBaptiste Daroussin 1015c99fb5f9SBaptiste Daroussin ucl_object_t * 1016c99fb5f9SBaptiste Daroussin ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags) 1017c99fb5f9SBaptiste Daroussin { 1018c99fb5f9SBaptiste Daroussin ucl_object_t *obj; 1019c99fb5f9SBaptiste Daroussin const char *start, *end, *p, *pos; 1020c99fb5f9SBaptiste Daroussin char *dst, *d; 1021c99fb5f9SBaptiste Daroussin size_t escaped_len; 1022c99fb5f9SBaptiste Daroussin 1023c99fb5f9SBaptiste Daroussin if (str == NULL) { 1024c99fb5f9SBaptiste Daroussin return NULL; 1025c99fb5f9SBaptiste Daroussin } 1026c99fb5f9SBaptiste Daroussin 1027c99fb5f9SBaptiste Daroussin obj = ucl_object_new (); 1028c99fb5f9SBaptiste Daroussin if (obj) { 1029c99fb5f9SBaptiste Daroussin if (len == 0) { 1030c99fb5f9SBaptiste Daroussin len = strlen (str); 1031c99fb5f9SBaptiste Daroussin } 1032c99fb5f9SBaptiste Daroussin if (flags & UCL_STRING_TRIM) { 1033c99fb5f9SBaptiste Daroussin /* Skip leading spaces */ 1034c99fb5f9SBaptiste Daroussin for (start = str; (size_t)(start - str) < len; start ++) { 1035c99fb5f9SBaptiste Daroussin if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1036c99fb5f9SBaptiste Daroussin break; 1037c99fb5f9SBaptiste Daroussin } 1038c99fb5f9SBaptiste Daroussin } 1039c99fb5f9SBaptiste Daroussin /* Skip trailing spaces */ 1040c99fb5f9SBaptiste Daroussin for (end = str + len - 1; end > start; end --) { 1041c99fb5f9SBaptiste Daroussin if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1042c99fb5f9SBaptiste Daroussin break; 1043c99fb5f9SBaptiste Daroussin } 1044c99fb5f9SBaptiste Daroussin } 1045c99fb5f9SBaptiste Daroussin end ++; 1046c99fb5f9SBaptiste Daroussin } 1047c99fb5f9SBaptiste Daroussin else { 1048c99fb5f9SBaptiste Daroussin start = str; 1049c99fb5f9SBaptiste Daroussin end = str + len; 1050c99fb5f9SBaptiste Daroussin } 1051c99fb5f9SBaptiste Daroussin 1052c99fb5f9SBaptiste Daroussin obj->type = UCL_STRING; 1053c99fb5f9SBaptiste Daroussin if (flags & UCL_STRING_ESCAPE) { 1054c99fb5f9SBaptiste Daroussin for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) { 1055c99fb5f9SBaptiste Daroussin if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1056c99fb5f9SBaptiste Daroussin escaped_len ++; 1057c99fb5f9SBaptiste Daroussin } 1058c99fb5f9SBaptiste Daroussin } 1059c99fb5f9SBaptiste Daroussin dst = malloc (escaped_len + 1); 1060c99fb5f9SBaptiste Daroussin if (dst != NULL) { 1061c99fb5f9SBaptiste Daroussin for (p = start, d = dst; p < end; p ++, d ++) { 1062c99fb5f9SBaptiste Daroussin if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 1063c99fb5f9SBaptiste Daroussin switch (*p) { 1064c99fb5f9SBaptiste Daroussin case '\n': 1065c99fb5f9SBaptiste Daroussin *d++ = '\\'; 1066c99fb5f9SBaptiste Daroussin *d = 'n'; 1067c99fb5f9SBaptiste Daroussin break; 1068c99fb5f9SBaptiste Daroussin case '\r': 1069c99fb5f9SBaptiste Daroussin *d++ = '\\'; 1070c99fb5f9SBaptiste Daroussin *d = 'r'; 1071c99fb5f9SBaptiste Daroussin break; 1072c99fb5f9SBaptiste Daroussin case '\b': 1073c99fb5f9SBaptiste Daroussin *d++ = '\\'; 1074c99fb5f9SBaptiste Daroussin *d = 'b'; 1075c99fb5f9SBaptiste Daroussin break; 1076c99fb5f9SBaptiste Daroussin case '\t': 1077c99fb5f9SBaptiste Daroussin *d++ = '\\'; 1078c99fb5f9SBaptiste Daroussin *d = 't'; 1079c99fb5f9SBaptiste Daroussin break; 1080c99fb5f9SBaptiste Daroussin case '\f': 1081c99fb5f9SBaptiste Daroussin *d++ = '\\'; 1082c99fb5f9SBaptiste Daroussin *d = 'f'; 1083c99fb5f9SBaptiste Daroussin break; 1084c99fb5f9SBaptiste Daroussin case '\\': 1085c99fb5f9SBaptiste Daroussin *d++ = '\\'; 1086c99fb5f9SBaptiste Daroussin *d = '\\'; 1087c99fb5f9SBaptiste Daroussin break; 1088c99fb5f9SBaptiste Daroussin case '"': 1089c99fb5f9SBaptiste Daroussin *d++ = '\\'; 1090c99fb5f9SBaptiste Daroussin *d = '"'; 1091c99fb5f9SBaptiste Daroussin break; 1092c99fb5f9SBaptiste Daroussin } 1093c99fb5f9SBaptiste Daroussin } 1094c99fb5f9SBaptiste Daroussin else { 1095c99fb5f9SBaptiste Daroussin *d = *p; 1096c99fb5f9SBaptiste Daroussin } 1097c99fb5f9SBaptiste Daroussin } 1098c99fb5f9SBaptiste Daroussin *d = '\0'; 1099c99fb5f9SBaptiste Daroussin obj->value.sv = dst; 1100c99fb5f9SBaptiste Daroussin obj->trash_stack[UCL_TRASH_VALUE] = dst; 1101c99fb5f9SBaptiste Daroussin obj->len = escaped_len; 1102c99fb5f9SBaptiste Daroussin } 1103c99fb5f9SBaptiste Daroussin } 1104c99fb5f9SBaptiste Daroussin else { 1105c99fb5f9SBaptiste Daroussin dst = malloc (end - start + 1); 1106c99fb5f9SBaptiste Daroussin if (dst != NULL) { 1107c99fb5f9SBaptiste Daroussin ucl_strlcpy_unsafe (dst, start, end - start + 1); 1108c99fb5f9SBaptiste Daroussin obj->value.sv = dst; 1109c99fb5f9SBaptiste Daroussin obj->trash_stack[UCL_TRASH_VALUE] = dst; 1110c99fb5f9SBaptiste Daroussin obj->len = end - start; 1111c99fb5f9SBaptiste Daroussin } 1112c99fb5f9SBaptiste Daroussin } 1113c99fb5f9SBaptiste Daroussin if ((flags & UCL_STRING_PARSE) && dst != NULL) { 1114c99fb5f9SBaptiste Daroussin /* Parse what we have */ 1115c99fb5f9SBaptiste Daroussin if (flags & UCL_STRING_PARSE_BOOLEAN) { 1116c99fb5f9SBaptiste Daroussin if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) { 1117c99fb5f9SBaptiste Daroussin ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1118c99fb5f9SBaptiste Daroussin flags & UCL_STRING_PARSE_DOUBLE, 111997bd480fSBaptiste Daroussin flags & UCL_STRING_PARSE_BYTES, 112097bd480fSBaptiste Daroussin flags & UCL_STRING_PARSE_TIME); 1121c99fb5f9SBaptiste Daroussin } 1122c99fb5f9SBaptiste Daroussin } 1123c99fb5f9SBaptiste Daroussin else { 1124c99fb5f9SBaptiste Daroussin ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1125c99fb5f9SBaptiste Daroussin flags & UCL_STRING_PARSE_DOUBLE, 112697bd480fSBaptiste Daroussin flags & UCL_STRING_PARSE_BYTES, 112797bd480fSBaptiste Daroussin flags & UCL_STRING_PARSE_TIME); 1128c99fb5f9SBaptiste Daroussin } 1129c99fb5f9SBaptiste Daroussin } 1130c99fb5f9SBaptiste Daroussin } 1131c99fb5f9SBaptiste Daroussin 1132c99fb5f9SBaptiste Daroussin return obj; 1133c99fb5f9SBaptiste Daroussin } 1134c99fb5f9SBaptiste Daroussin 1135*b04a7a0bSBaptiste Daroussin static bool 1136c99fb5f9SBaptiste Daroussin ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, 1137c99fb5f9SBaptiste Daroussin const char *key, size_t keylen, bool copy_key, bool merge, bool replace) 1138c99fb5f9SBaptiste Daroussin { 1139*b04a7a0bSBaptiste Daroussin ucl_object_t *found, *tmp; 1140*b04a7a0bSBaptiste Daroussin const ucl_object_t *cur; 1141c99fb5f9SBaptiste Daroussin ucl_object_iter_t it = NULL; 1142c99fb5f9SBaptiste Daroussin const char *p; 1143*b04a7a0bSBaptiste Daroussin int ret = true; 1144c99fb5f9SBaptiste Daroussin 1145c99fb5f9SBaptiste Daroussin if (elt == NULL || key == NULL) { 1146*b04a7a0bSBaptiste Daroussin return false; 1147c99fb5f9SBaptiste Daroussin } 1148c99fb5f9SBaptiste Daroussin 1149c99fb5f9SBaptiste Daroussin if (top == NULL) { 1150*b04a7a0bSBaptiste Daroussin return false; 1151c99fb5f9SBaptiste Daroussin } 1152c99fb5f9SBaptiste Daroussin 1153c99fb5f9SBaptiste Daroussin if (top->type != UCL_OBJECT) { 1154c99fb5f9SBaptiste Daroussin /* It is possible to convert NULL type to an object */ 1155c99fb5f9SBaptiste Daroussin if (top->type == UCL_NULL) { 1156c99fb5f9SBaptiste Daroussin top->type = UCL_OBJECT; 1157c99fb5f9SBaptiste Daroussin } 1158c99fb5f9SBaptiste Daroussin else { 1159c99fb5f9SBaptiste Daroussin /* Refuse converting of other object types */ 1160*b04a7a0bSBaptiste Daroussin return false; 1161c99fb5f9SBaptiste Daroussin } 1162c99fb5f9SBaptiste Daroussin } 1163c99fb5f9SBaptiste Daroussin 1164c99fb5f9SBaptiste Daroussin if (top->value.ov == NULL) { 1165c99fb5f9SBaptiste Daroussin top->value.ov = ucl_hash_create (); 1166c99fb5f9SBaptiste Daroussin } 1167c99fb5f9SBaptiste Daroussin 1168c99fb5f9SBaptiste Daroussin if (keylen == 0) { 1169c99fb5f9SBaptiste Daroussin keylen = strlen (key); 1170c99fb5f9SBaptiste Daroussin } 1171c99fb5f9SBaptiste Daroussin 1172c99fb5f9SBaptiste Daroussin for (p = key; p < key + keylen; p ++) { 1173c99fb5f9SBaptiste Daroussin if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) { 1174c99fb5f9SBaptiste Daroussin elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; 1175c99fb5f9SBaptiste Daroussin break; 1176c99fb5f9SBaptiste Daroussin } 1177c99fb5f9SBaptiste Daroussin } 1178c99fb5f9SBaptiste Daroussin 1179c99fb5f9SBaptiste Daroussin elt->key = key; 1180c99fb5f9SBaptiste Daroussin elt->keylen = keylen; 1181c99fb5f9SBaptiste Daroussin 1182c99fb5f9SBaptiste Daroussin if (copy_key) { 1183c99fb5f9SBaptiste Daroussin ucl_copy_key_trash (elt); 1184c99fb5f9SBaptiste Daroussin } 1185c99fb5f9SBaptiste Daroussin 1186*b04a7a0bSBaptiste Daroussin found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt)); 1187c99fb5f9SBaptiste Daroussin 1188c99fb5f9SBaptiste Daroussin if (!found) { 1189c99fb5f9SBaptiste Daroussin top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1190c99fb5f9SBaptiste Daroussin DL_APPEND (found, elt); 119197bd480fSBaptiste Daroussin top->len ++; 1192*b04a7a0bSBaptiste Daroussin if (replace) { 1193*b04a7a0bSBaptiste Daroussin ret = false; 1194*b04a7a0bSBaptiste Daroussin } 1195c99fb5f9SBaptiste Daroussin } 1196c99fb5f9SBaptiste Daroussin else { 1197c99fb5f9SBaptiste Daroussin if (replace) { 1198c99fb5f9SBaptiste Daroussin ucl_hash_delete (top->value.ov, found); 1199c99fb5f9SBaptiste Daroussin ucl_object_unref (found); 1200c99fb5f9SBaptiste Daroussin top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1201c99fb5f9SBaptiste Daroussin found = NULL; 1202c99fb5f9SBaptiste Daroussin DL_APPEND (found, elt); 1203c99fb5f9SBaptiste Daroussin } 1204c99fb5f9SBaptiste Daroussin else if (merge) { 1205c99fb5f9SBaptiste Daroussin if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) { 1206c99fb5f9SBaptiste Daroussin /* Insert old elt to new one */ 1207*b04a7a0bSBaptiste Daroussin ucl_object_insert_key_common (elt, found, found->key, 1208*b04a7a0bSBaptiste Daroussin found->keylen, copy_key, false, false); 1209c99fb5f9SBaptiste Daroussin ucl_hash_delete (top->value.ov, found); 1210c99fb5f9SBaptiste Daroussin top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1211c99fb5f9SBaptiste Daroussin } 1212c99fb5f9SBaptiste Daroussin else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) { 1213c99fb5f9SBaptiste Daroussin /* Insert new to old */ 1214*b04a7a0bSBaptiste Daroussin ucl_object_insert_key_common (found, elt, elt->key, 1215*b04a7a0bSBaptiste Daroussin elt->keylen, copy_key, false, false); 1216c99fb5f9SBaptiste Daroussin } 1217c99fb5f9SBaptiste Daroussin else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) { 1218c99fb5f9SBaptiste Daroussin /* Mix two hashes */ 1219c99fb5f9SBaptiste Daroussin while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) { 1220*b04a7a0bSBaptiste Daroussin tmp = ucl_object_ref (cur); 1221*b04a7a0bSBaptiste Daroussin ucl_object_insert_key_common (found, tmp, cur->key, 1222*b04a7a0bSBaptiste Daroussin cur->keylen, copy_key, false, false); 1223c99fb5f9SBaptiste Daroussin } 1224c99fb5f9SBaptiste Daroussin ucl_object_unref (elt); 1225c99fb5f9SBaptiste Daroussin } 1226c99fb5f9SBaptiste Daroussin else { 1227c99fb5f9SBaptiste Daroussin /* Just make a list of scalars */ 1228c99fb5f9SBaptiste Daroussin DL_APPEND (found, elt); 1229c99fb5f9SBaptiste Daroussin } 1230c99fb5f9SBaptiste Daroussin } 1231c99fb5f9SBaptiste Daroussin else { 1232c99fb5f9SBaptiste Daroussin DL_APPEND (found, elt); 1233c99fb5f9SBaptiste Daroussin } 1234c99fb5f9SBaptiste Daroussin } 1235c99fb5f9SBaptiste Daroussin 1236*b04a7a0bSBaptiste Daroussin return ret; 1237c99fb5f9SBaptiste Daroussin } 1238c99fb5f9SBaptiste Daroussin 123936c53d67SBaptiste Daroussin bool 124036c53d67SBaptiste Daroussin ucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen) 124136c53d67SBaptiste Daroussin { 124236c53d67SBaptiste Daroussin ucl_object_t *found; 124336c53d67SBaptiste Daroussin 124497bd480fSBaptiste Daroussin if (top == NULL || key == NULL) { 124597bd480fSBaptiste Daroussin return false; 124697bd480fSBaptiste Daroussin } 124797bd480fSBaptiste Daroussin 1248*b04a7a0bSBaptiste Daroussin found = __DECONST (ucl_object_t *, ucl_object_find_keyl (top, key, keylen)); 124936c53d67SBaptiste Daroussin 125097bd480fSBaptiste Daroussin if (found == NULL) { 125136c53d67SBaptiste Daroussin return false; 125297bd480fSBaptiste Daroussin } 125336c53d67SBaptiste Daroussin 125436c53d67SBaptiste Daroussin ucl_hash_delete (top->value.ov, found); 125536c53d67SBaptiste Daroussin ucl_object_unref (found); 125636c53d67SBaptiste Daroussin top->len --; 125736c53d67SBaptiste Daroussin 125836c53d67SBaptiste Daroussin return true; 125936c53d67SBaptiste Daroussin } 126036c53d67SBaptiste Daroussin 126136c53d67SBaptiste Daroussin bool 126236c53d67SBaptiste Daroussin ucl_object_delete_key (ucl_object_t *top, const char *key) 126336c53d67SBaptiste Daroussin { 1264*b04a7a0bSBaptiste Daroussin return ucl_object_delete_keyl (top, key, strlen(key)); 126536c53d67SBaptiste Daroussin } 126636c53d67SBaptiste Daroussin 1267c99fb5f9SBaptiste Daroussin ucl_object_t* 126897bd480fSBaptiste Daroussin ucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen) 126997bd480fSBaptiste Daroussin { 1270*b04a7a0bSBaptiste Daroussin const ucl_object_t *found; 127197bd480fSBaptiste Daroussin 127297bd480fSBaptiste Daroussin if (top == NULL || key == NULL) { 127397bd480fSBaptiste Daroussin return false; 127497bd480fSBaptiste Daroussin } 127597bd480fSBaptiste Daroussin found = ucl_object_find_keyl (top, key, keylen); 127697bd480fSBaptiste Daroussin 127797bd480fSBaptiste Daroussin if (found == NULL) { 127897bd480fSBaptiste Daroussin return NULL; 127997bd480fSBaptiste Daroussin } 128097bd480fSBaptiste Daroussin ucl_hash_delete (top->value.ov, found); 128197bd480fSBaptiste Daroussin top->len --; 128297bd480fSBaptiste Daroussin 1283*b04a7a0bSBaptiste Daroussin return __DECONST (ucl_object_t *, found); 128497bd480fSBaptiste Daroussin } 128597bd480fSBaptiste Daroussin 128697bd480fSBaptiste Daroussin ucl_object_t* 128797bd480fSBaptiste Daroussin ucl_object_pop_key (ucl_object_t *top, const char *key) 128897bd480fSBaptiste Daroussin { 1289*b04a7a0bSBaptiste Daroussin return ucl_object_pop_keyl (top, key, strlen(key)); 129097bd480fSBaptiste Daroussin } 129197bd480fSBaptiste Daroussin 1292*b04a7a0bSBaptiste Daroussin bool 1293c99fb5f9SBaptiste Daroussin ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, 1294c99fb5f9SBaptiste Daroussin const char *key, size_t keylen, bool copy_key) 1295c99fb5f9SBaptiste Daroussin { 1296c99fb5f9SBaptiste Daroussin return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false); 1297c99fb5f9SBaptiste Daroussin } 1298c99fb5f9SBaptiste Daroussin 1299*b04a7a0bSBaptiste Daroussin bool 1300c99fb5f9SBaptiste Daroussin ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt, 1301c99fb5f9SBaptiste Daroussin const char *key, size_t keylen, bool copy_key) 1302c99fb5f9SBaptiste Daroussin { 1303c99fb5f9SBaptiste Daroussin return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false); 1304c99fb5f9SBaptiste Daroussin } 1305c99fb5f9SBaptiste Daroussin 1306*b04a7a0bSBaptiste Daroussin bool 1307c99fb5f9SBaptiste Daroussin ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt, 1308c99fb5f9SBaptiste Daroussin const char *key, size_t keylen, bool copy_key) 1309c99fb5f9SBaptiste Daroussin { 1310c99fb5f9SBaptiste Daroussin return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true); 1311c99fb5f9SBaptiste Daroussin } 1312c99fb5f9SBaptiste Daroussin 1313*b04a7a0bSBaptiste Daroussin const ucl_object_t * 1314*b04a7a0bSBaptiste Daroussin ucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen) 1315c99fb5f9SBaptiste Daroussin { 1316*b04a7a0bSBaptiste Daroussin const ucl_object_t *ret; 1317*b04a7a0bSBaptiste Daroussin ucl_object_t srch; 1318c99fb5f9SBaptiste Daroussin 1319c99fb5f9SBaptiste Daroussin if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1320c99fb5f9SBaptiste Daroussin return NULL; 1321c99fb5f9SBaptiste Daroussin } 1322c99fb5f9SBaptiste Daroussin 1323c99fb5f9SBaptiste Daroussin srch.key = key; 1324c99fb5f9SBaptiste Daroussin srch.keylen = klen; 1325c99fb5f9SBaptiste Daroussin ret = ucl_hash_search_obj (obj->value.ov, &srch); 1326c99fb5f9SBaptiste Daroussin 1327c99fb5f9SBaptiste Daroussin return ret; 1328c99fb5f9SBaptiste Daroussin } 1329c99fb5f9SBaptiste Daroussin 1330*b04a7a0bSBaptiste Daroussin const ucl_object_t * 1331*b04a7a0bSBaptiste Daroussin ucl_object_find_key (const ucl_object_t *obj, const char *key) 1332c99fb5f9SBaptiste Daroussin { 1333c99fb5f9SBaptiste Daroussin size_t klen; 1334*b04a7a0bSBaptiste Daroussin const ucl_object_t *ret; 1335*b04a7a0bSBaptiste Daroussin ucl_object_t srch; 1336c99fb5f9SBaptiste Daroussin 1337c99fb5f9SBaptiste Daroussin if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1338c99fb5f9SBaptiste Daroussin return NULL; 1339c99fb5f9SBaptiste Daroussin } 1340c99fb5f9SBaptiste Daroussin 1341c99fb5f9SBaptiste Daroussin klen = strlen (key); 1342c99fb5f9SBaptiste Daroussin srch.key = key; 1343c99fb5f9SBaptiste Daroussin srch.keylen = klen; 1344c99fb5f9SBaptiste Daroussin ret = ucl_hash_search_obj (obj->value.ov, &srch); 1345c99fb5f9SBaptiste Daroussin 1346c99fb5f9SBaptiste Daroussin return ret; 1347c99fb5f9SBaptiste Daroussin } 1348c99fb5f9SBaptiste Daroussin 1349*b04a7a0bSBaptiste Daroussin const ucl_object_t* 1350*b04a7a0bSBaptiste Daroussin ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) 1351c99fb5f9SBaptiste Daroussin { 1352*b04a7a0bSBaptiste Daroussin const ucl_object_t *elt; 1353c99fb5f9SBaptiste Daroussin 135497bd480fSBaptiste Daroussin if (obj == NULL || iter == NULL) { 135597bd480fSBaptiste Daroussin return NULL; 135697bd480fSBaptiste Daroussin } 135797bd480fSBaptiste Daroussin 1358c99fb5f9SBaptiste Daroussin if (expand_values) { 1359c99fb5f9SBaptiste Daroussin switch (obj->type) { 1360c99fb5f9SBaptiste Daroussin case UCL_OBJECT: 1361*b04a7a0bSBaptiste Daroussin return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); 1362c99fb5f9SBaptiste Daroussin break; 1363c99fb5f9SBaptiste Daroussin case UCL_ARRAY: 1364c99fb5f9SBaptiste Daroussin elt = *iter; 1365c99fb5f9SBaptiste Daroussin if (elt == NULL) { 1366c99fb5f9SBaptiste Daroussin elt = obj->value.av; 1367c99fb5f9SBaptiste Daroussin if (elt == NULL) { 1368c99fb5f9SBaptiste Daroussin return NULL; 1369c99fb5f9SBaptiste Daroussin } 1370c99fb5f9SBaptiste Daroussin } 1371c99fb5f9SBaptiste Daroussin else if (elt == obj->value.av) { 1372c99fb5f9SBaptiste Daroussin return NULL; 1373c99fb5f9SBaptiste Daroussin } 1374c99fb5f9SBaptiste Daroussin *iter = elt->next ? elt->next : obj->value.av; 1375c99fb5f9SBaptiste Daroussin return elt; 1376c99fb5f9SBaptiste Daroussin default: 1377c99fb5f9SBaptiste Daroussin /* Go to linear iteration */ 1378c99fb5f9SBaptiste Daroussin break; 1379c99fb5f9SBaptiste Daroussin } 1380c99fb5f9SBaptiste Daroussin } 1381c99fb5f9SBaptiste Daroussin /* Treat everything as a linear list */ 1382c99fb5f9SBaptiste Daroussin elt = *iter; 1383c99fb5f9SBaptiste Daroussin if (elt == NULL) { 1384c99fb5f9SBaptiste Daroussin elt = obj; 1385c99fb5f9SBaptiste Daroussin if (elt == NULL) { 1386c99fb5f9SBaptiste Daroussin return NULL; 1387c99fb5f9SBaptiste Daroussin } 1388c99fb5f9SBaptiste Daroussin } 1389c99fb5f9SBaptiste Daroussin else if (elt == obj) { 1390c99fb5f9SBaptiste Daroussin return NULL; 1391c99fb5f9SBaptiste Daroussin } 1392*b04a7a0bSBaptiste Daroussin *iter = __DECONST (void *, elt->next ? elt->next : obj); 1393c99fb5f9SBaptiste Daroussin return elt; 1394c99fb5f9SBaptiste Daroussin 1395c99fb5f9SBaptiste Daroussin /* Not reached */ 1396c99fb5f9SBaptiste Daroussin return NULL; 1397c99fb5f9SBaptiste Daroussin } 139897bd480fSBaptiste Daroussin 139997bd480fSBaptiste Daroussin 140097bd480fSBaptiste Daroussin ucl_object_t * 140197bd480fSBaptiste Daroussin ucl_object_new (void) 140297bd480fSBaptiste Daroussin { 140397bd480fSBaptiste Daroussin ucl_object_t *new; 140497bd480fSBaptiste Daroussin new = malloc (sizeof (ucl_object_t)); 140597bd480fSBaptiste Daroussin if (new != NULL) { 140697bd480fSBaptiste Daroussin memset (new, 0, sizeof (ucl_object_t)); 140797bd480fSBaptiste Daroussin new->ref = 1; 140897bd480fSBaptiste Daroussin new->type = UCL_NULL; 140997bd480fSBaptiste Daroussin } 141097bd480fSBaptiste Daroussin return new; 141197bd480fSBaptiste Daroussin } 141297bd480fSBaptiste Daroussin 141397bd480fSBaptiste Daroussin ucl_object_t * 141497bd480fSBaptiste Daroussin ucl_object_typed_new (unsigned int type) 141597bd480fSBaptiste Daroussin { 141697bd480fSBaptiste Daroussin ucl_object_t *new; 141797bd480fSBaptiste Daroussin new = malloc (sizeof (ucl_object_t)); 141897bd480fSBaptiste Daroussin if (new != NULL) { 141997bd480fSBaptiste Daroussin memset (new, 0, sizeof (ucl_object_t)); 142097bd480fSBaptiste Daroussin new->ref = 1; 142197bd480fSBaptiste Daroussin new->type = (type <= UCL_NULL ? type : UCL_NULL); 142297bd480fSBaptiste Daroussin } 142397bd480fSBaptiste Daroussin return new; 142497bd480fSBaptiste Daroussin } 142597bd480fSBaptiste Daroussin 142697bd480fSBaptiste Daroussin ucl_object_t* 142797bd480fSBaptiste Daroussin ucl_object_fromstring (const char *str) 142897bd480fSBaptiste Daroussin { 142997bd480fSBaptiste Daroussin return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE); 143097bd480fSBaptiste Daroussin } 143197bd480fSBaptiste Daroussin 143297bd480fSBaptiste Daroussin ucl_object_t * 143397bd480fSBaptiste Daroussin ucl_object_fromlstring (const char *str, size_t len) 143497bd480fSBaptiste Daroussin { 143597bd480fSBaptiste Daroussin return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE); 143697bd480fSBaptiste Daroussin } 143797bd480fSBaptiste Daroussin 143897bd480fSBaptiste Daroussin ucl_object_t * 143997bd480fSBaptiste Daroussin ucl_object_fromint (int64_t iv) 144097bd480fSBaptiste Daroussin { 144197bd480fSBaptiste Daroussin ucl_object_t *obj; 144297bd480fSBaptiste Daroussin 144397bd480fSBaptiste Daroussin obj = ucl_object_new (); 144497bd480fSBaptiste Daroussin if (obj != NULL) { 144597bd480fSBaptiste Daroussin obj->type = UCL_INT; 144697bd480fSBaptiste Daroussin obj->value.iv = iv; 144797bd480fSBaptiste Daroussin } 144897bd480fSBaptiste Daroussin 144997bd480fSBaptiste Daroussin return obj; 145097bd480fSBaptiste Daroussin } 145197bd480fSBaptiste Daroussin 145297bd480fSBaptiste Daroussin ucl_object_t * 145397bd480fSBaptiste Daroussin ucl_object_fromdouble (double dv) 145497bd480fSBaptiste Daroussin { 145597bd480fSBaptiste Daroussin ucl_object_t *obj; 145697bd480fSBaptiste Daroussin 145797bd480fSBaptiste Daroussin obj = ucl_object_new (); 145897bd480fSBaptiste Daroussin if (obj != NULL) { 145997bd480fSBaptiste Daroussin obj->type = UCL_FLOAT; 146097bd480fSBaptiste Daroussin obj->value.dv = dv; 146197bd480fSBaptiste Daroussin } 146297bd480fSBaptiste Daroussin 146397bd480fSBaptiste Daroussin return obj; 146497bd480fSBaptiste Daroussin } 146597bd480fSBaptiste Daroussin 146697bd480fSBaptiste Daroussin ucl_object_t* 146797bd480fSBaptiste Daroussin ucl_object_frombool (bool bv) 146897bd480fSBaptiste Daroussin { 146997bd480fSBaptiste Daroussin ucl_object_t *obj; 147097bd480fSBaptiste Daroussin 147197bd480fSBaptiste Daroussin obj = ucl_object_new (); 147297bd480fSBaptiste Daroussin if (obj != NULL) { 147397bd480fSBaptiste Daroussin obj->type = UCL_BOOLEAN; 147497bd480fSBaptiste Daroussin obj->value.iv = bv; 147597bd480fSBaptiste Daroussin } 147697bd480fSBaptiste Daroussin 147797bd480fSBaptiste Daroussin return obj; 147897bd480fSBaptiste Daroussin } 147997bd480fSBaptiste Daroussin 1480*b04a7a0bSBaptiste Daroussin bool 148197bd480fSBaptiste Daroussin ucl_array_append (ucl_object_t *top, ucl_object_t *elt) 148297bd480fSBaptiste Daroussin { 148397bd480fSBaptiste Daroussin ucl_object_t *head; 148497bd480fSBaptiste Daroussin 1485*b04a7a0bSBaptiste Daroussin if (elt == NULL || top == NULL) { 1486*b04a7a0bSBaptiste Daroussin return false; 148797bd480fSBaptiste Daroussin } 148897bd480fSBaptiste Daroussin 148997bd480fSBaptiste Daroussin head = top->value.av; 149097bd480fSBaptiste Daroussin if (head == NULL) { 149197bd480fSBaptiste Daroussin top->value.av = elt; 149297bd480fSBaptiste Daroussin elt->prev = elt; 149397bd480fSBaptiste Daroussin } 149497bd480fSBaptiste Daroussin else { 149597bd480fSBaptiste Daroussin elt->prev = head->prev; 149697bd480fSBaptiste Daroussin head->prev->next = elt; 149797bd480fSBaptiste Daroussin head->prev = elt; 149897bd480fSBaptiste Daroussin } 149997bd480fSBaptiste Daroussin elt->next = NULL; 150097bd480fSBaptiste Daroussin top->len ++; 1501*b04a7a0bSBaptiste Daroussin 1502*b04a7a0bSBaptiste Daroussin return true; 150397bd480fSBaptiste Daroussin } 150497bd480fSBaptiste Daroussin 1505*b04a7a0bSBaptiste Daroussin bool 150697bd480fSBaptiste Daroussin ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt) 150797bd480fSBaptiste Daroussin { 150897bd480fSBaptiste Daroussin ucl_object_t *head; 150997bd480fSBaptiste Daroussin 1510*b04a7a0bSBaptiste Daroussin if (elt == NULL || top == NULL) { 1511*b04a7a0bSBaptiste Daroussin return false; 151297bd480fSBaptiste Daroussin } 151397bd480fSBaptiste Daroussin 1514*b04a7a0bSBaptiste Daroussin 151597bd480fSBaptiste Daroussin head = top->value.av; 151697bd480fSBaptiste Daroussin if (head == NULL) { 151797bd480fSBaptiste Daroussin top->value.av = elt; 151897bd480fSBaptiste Daroussin elt->prev = elt; 151997bd480fSBaptiste Daroussin } 152097bd480fSBaptiste Daroussin else { 152197bd480fSBaptiste Daroussin elt->prev = head->prev; 152297bd480fSBaptiste Daroussin head->prev = elt; 152397bd480fSBaptiste Daroussin } 152497bd480fSBaptiste Daroussin elt->next = head; 152597bd480fSBaptiste Daroussin top->value.av = elt; 152697bd480fSBaptiste Daroussin top->len ++; 152797bd480fSBaptiste Daroussin 1528*b04a7a0bSBaptiste Daroussin return true; 152997bd480fSBaptiste Daroussin } 153097bd480fSBaptiste Daroussin 153197bd480fSBaptiste Daroussin ucl_object_t * 153297bd480fSBaptiste Daroussin ucl_array_delete (ucl_object_t *top, ucl_object_t *elt) 153397bd480fSBaptiste Daroussin { 153497bd480fSBaptiste Daroussin ucl_object_t *head; 153597bd480fSBaptiste Daroussin 153697bd480fSBaptiste Daroussin if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 153797bd480fSBaptiste Daroussin return NULL; 153897bd480fSBaptiste Daroussin } 153997bd480fSBaptiste Daroussin head = top->value.av; 154097bd480fSBaptiste Daroussin 154197bd480fSBaptiste Daroussin if (elt->prev == elt) { 154297bd480fSBaptiste Daroussin top->value.av = NULL; 154397bd480fSBaptiste Daroussin } 154497bd480fSBaptiste Daroussin else if (elt == head) { 154597bd480fSBaptiste Daroussin elt->next->prev = elt->prev; 154697bd480fSBaptiste Daroussin top->value.av = elt->next; 154797bd480fSBaptiste Daroussin } 154897bd480fSBaptiste Daroussin else { 154997bd480fSBaptiste Daroussin elt->prev->next = elt->next; 155097bd480fSBaptiste Daroussin if (elt->next) { 155197bd480fSBaptiste Daroussin elt->next->prev = elt->prev; 155297bd480fSBaptiste Daroussin } 155397bd480fSBaptiste Daroussin else { 155497bd480fSBaptiste Daroussin head->prev = elt->prev; 155597bd480fSBaptiste Daroussin } 155697bd480fSBaptiste Daroussin } 155797bd480fSBaptiste Daroussin elt->next = NULL; 155897bd480fSBaptiste Daroussin elt->prev = elt; 155997bd480fSBaptiste Daroussin top->len --; 156097bd480fSBaptiste Daroussin 156197bd480fSBaptiste Daroussin return elt; 156297bd480fSBaptiste Daroussin } 156397bd480fSBaptiste Daroussin 1564*b04a7a0bSBaptiste Daroussin const ucl_object_t * 1565*b04a7a0bSBaptiste Daroussin ucl_array_head (const ucl_object_t *top) 156697bd480fSBaptiste Daroussin { 156797bd480fSBaptiste Daroussin if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 156897bd480fSBaptiste Daroussin return NULL; 156997bd480fSBaptiste Daroussin } 157097bd480fSBaptiste Daroussin return top->value.av; 157197bd480fSBaptiste Daroussin } 157297bd480fSBaptiste Daroussin 1573*b04a7a0bSBaptiste Daroussin const ucl_object_t * 1574*b04a7a0bSBaptiste Daroussin ucl_array_tail (const ucl_object_t *top) 157597bd480fSBaptiste Daroussin { 157697bd480fSBaptiste Daroussin if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { 157797bd480fSBaptiste Daroussin return NULL; 157897bd480fSBaptiste Daroussin } 157997bd480fSBaptiste Daroussin return top->value.av->prev; 158097bd480fSBaptiste Daroussin } 158197bd480fSBaptiste Daroussin 158297bd480fSBaptiste Daroussin ucl_object_t * 158397bd480fSBaptiste Daroussin ucl_array_pop_last (ucl_object_t *top) 158497bd480fSBaptiste Daroussin { 1585*b04a7a0bSBaptiste Daroussin return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_tail (top))); 158697bd480fSBaptiste Daroussin } 158797bd480fSBaptiste Daroussin 158897bd480fSBaptiste Daroussin ucl_object_t * 158997bd480fSBaptiste Daroussin ucl_array_pop_first (ucl_object_t *top) 159097bd480fSBaptiste Daroussin { 1591*b04a7a0bSBaptiste Daroussin return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_head (top))); 159297bd480fSBaptiste Daroussin } 159397bd480fSBaptiste Daroussin 159497bd480fSBaptiste Daroussin ucl_object_t * 159597bd480fSBaptiste Daroussin ucl_elt_append (ucl_object_t *head, ucl_object_t *elt) 159697bd480fSBaptiste Daroussin { 159797bd480fSBaptiste Daroussin 159897bd480fSBaptiste Daroussin if (head == NULL) { 159997bd480fSBaptiste Daroussin elt->next = NULL; 160097bd480fSBaptiste Daroussin elt->prev = elt; 160197bd480fSBaptiste Daroussin head = elt; 160297bd480fSBaptiste Daroussin } 160397bd480fSBaptiste Daroussin else { 160497bd480fSBaptiste Daroussin elt->prev = head->prev; 160597bd480fSBaptiste Daroussin head->prev->next = elt; 160697bd480fSBaptiste Daroussin head->prev = elt; 160797bd480fSBaptiste Daroussin elt->next = NULL; 160897bd480fSBaptiste Daroussin } 160997bd480fSBaptiste Daroussin 161097bd480fSBaptiste Daroussin return head; 161197bd480fSBaptiste Daroussin } 161297bd480fSBaptiste Daroussin 161397bd480fSBaptiste Daroussin bool 1614*b04a7a0bSBaptiste Daroussin ucl_object_todouble_safe (const ucl_object_t *obj, double *target) 161597bd480fSBaptiste Daroussin { 161697bd480fSBaptiste Daroussin if (obj == NULL || target == NULL) { 161797bd480fSBaptiste Daroussin return false; 161897bd480fSBaptiste Daroussin } 161997bd480fSBaptiste Daroussin switch (obj->type) { 162097bd480fSBaptiste Daroussin case UCL_INT: 162197bd480fSBaptiste Daroussin *target = obj->value.iv; /* Probaly could cause overflow */ 162297bd480fSBaptiste Daroussin break; 162397bd480fSBaptiste Daroussin case UCL_FLOAT: 162497bd480fSBaptiste Daroussin case UCL_TIME: 162597bd480fSBaptiste Daroussin *target = obj->value.dv; 162697bd480fSBaptiste Daroussin break; 162797bd480fSBaptiste Daroussin default: 162897bd480fSBaptiste Daroussin return false; 162997bd480fSBaptiste Daroussin } 163097bd480fSBaptiste Daroussin 163197bd480fSBaptiste Daroussin return true; 163297bd480fSBaptiste Daroussin } 163397bd480fSBaptiste Daroussin 163497bd480fSBaptiste Daroussin double 1635*b04a7a0bSBaptiste Daroussin ucl_object_todouble (const ucl_object_t *obj) 163697bd480fSBaptiste Daroussin { 163797bd480fSBaptiste Daroussin double result = 0.; 163897bd480fSBaptiste Daroussin 163997bd480fSBaptiste Daroussin ucl_object_todouble_safe (obj, &result); 164097bd480fSBaptiste Daroussin return result; 164197bd480fSBaptiste Daroussin } 164297bd480fSBaptiste Daroussin 164397bd480fSBaptiste Daroussin bool 1644*b04a7a0bSBaptiste Daroussin ucl_object_toint_safe (const ucl_object_t *obj, int64_t *target) 164597bd480fSBaptiste Daroussin { 164697bd480fSBaptiste Daroussin if (obj == NULL || target == NULL) { 164797bd480fSBaptiste Daroussin return false; 164897bd480fSBaptiste Daroussin } 164997bd480fSBaptiste Daroussin switch (obj->type) { 165097bd480fSBaptiste Daroussin case UCL_INT: 165197bd480fSBaptiste Daroussin *target = obj->value.iv; 165297bd480fSBaptiste Daroussin break; 165397bd480fSBaptiste Daroussin case UCL_FLOAT: 165497bd480fSBaptiste Daroussin case UCL_TIME: 165597bd480fSBaptiste Daroussin *target = obj->value.dv; /* Loosing of decimal points */ 165697bd480fSBaptiste Daroussin break; 165797bd480fSBaptiste Daroussin default: 165897bd480fSBaptiste Daroussin return false; 165997bd480fSBaptiste Daroussin } 166097bd480fSBaptiste Daroussin 166197bd480fSBaptiste Daroussin return true; 166297bd480fSBaptiste Daroussin } 166397bd480fSBaptiste Daroussin 166497bd480fSBaptiste Daroussin int64_t 1665*b04a7a0bSBaptiste Daroussin ucl_object_toint (const ucl_object_t *obj) 166697bd480fSBaptiste Daroussin { 166797bd480fSBaptiste Daroussin int64_t result = 0; 166897bd480fSBaptiste Daroussin 166997bd480fSBaptiste Daroussin ucl_object_toint_safe (obj, &result); 167097bd480fSBaptiste Daroussin return result; 167197bd480fSBaptiste Daroussin } 167297bd480fSBaptiste Daroussin 167397bd480fSBaptiste Daroussin bool 1674*b04a7a0bSBaptiste Daroussin ucl_object_toboolean_safe (const ucl_object_t *obj, bool *target) 167597bd480fSBaptiste Daroussin { 167697bd480fSBaptiste Daroussin if (obj == NULL || target == NULL) { 167797bd480fSBaptiste Daroussin return false; 167897bd480fSBaptiste Daroussin } 167997bd480fSBaptiste Daroussin switch (obj->type) { 168097bd480fSBaptiste Daroussin case UCL_BOOLEAN: 168197bd480fSBaptiste Daroussin *target = (obj->value.iv == true); 168297bd480fSBaptiste Daroussin break; 168397bd480fSBaptiste Daroussin default: 168497bd480fSBaptiste Daroussin return false; 168597bd480fSBaptiste Daroussin } 168697bd480fSBaptiste Daroussin 168797bd480fSBaptiste Daroussin return true; 168897bd480fSBaptiste Daroussin } 168997bd480fSBaptiste Daroussin 169097bd480fSBaptiste Daroussin bool 1691*b04a7a0bSBaptiste Daroussin ucl_object_toboolean (const ucl_object_t *obj) 169297bd480fSBaptiste Daroussin { 169397bd480fSBaptiste Daroussin bool result = false; 169497bd480fSBaptiste Daroussin 169597bd480fSBaptiste Daroussin ucl_object_toboolean_safe (obj, &result); 169697bd480fSBaptiste Daroussin return result; 169797bd480fSBaptiste Daroussin } 169897bd480fSBaptiste Daroussin 169997bd480fSBaptiste Daroussin bool 1700*b04a7a0bSBaptiste Daroussin ucl_object_tostring_safe (const ucl_object_t *obj, const char **target) 170197bd480fSBaptiste Daroussin { 170297bd480fSBaptiste Daroussin if (obj == NULL || target == NULL) { 170397bd480fSBaptiste Daroussin return false; 170497bd480fSBaptiste Daroussin } 170597bd480fSBaptiste Daroussin 170697bd480fSBaptiste Daroussin switch (obj->type) { 170797bd480fSBaptiste Daroussin case UCL_STRING: 170897bd480fSBaptiste Daroussin *target = ucl_copy_value_trash (obj); 170997bd480fSBaptiste Daroussin break; 171097bd480fSBaptiste Daroussin default: 171197bd480fSBaptiste Daroussin return false; 171297bd480fSBaptiste Daroussin } 171397bd480fSBaptiste Daroussin 171497bd480fSBaptiste Daroussin return true; 171597bd480fSBaptiste Daroussin } 171697bd480fSBaptiste Daroussin 171797bd480fSBaptiste Daroussin const char * 1718*b04a7a0bSBaptiste Daroussin ucl_object_tostring (const ucl_object_t *obj) 171997bd480fSBaptiste Daroussin { 172097bd480fSBaptiste Daroussin const char *result = NULL; 172197bd480fSBaptiste Daroussin 172297bd480fSBaptiste Daroussin ucl_object_tostring_safe (obj, &result); 172397bd480fSBaptiste Daroussin return result; 172497bd480fSBaptiste Daroussin } 172597bd480fSBaptiste Daroussin 172697bd480fSBaptiste Daroussin const char * 1727*b04a7a0bSBaptiste Daroussin ucl_object_tostring_forced (const ucl_object_t *obj) 172897bd480fSBaptiste Daroussin { 172997bd480fSBaptiste Daroussin return ucl_copy_value_trash (obj); 173097bd480fSBaptiste Daroussin } 173197bd480fSBaptiste Daroussin 173297bd480fSBaptiste Daroussin bool 1733*b04a7a0bSBaptiste Daroussin ucl_object_tolstring_safe (const ucl_object_t *obj, const char **target, size_t *tlen) 173497bd480fSBaptiste Daroussin { 173597bd480fSBaptiste Daroussin if (obj == NULL || target == NULL) { 173697bd480fSBaptiste Daroussin return false; 173797bd480fSBaptiste Daroussin } 173897bd480fSBaptiste Daroussin switch (obj->type) { 173997bd480fSBaptiste Daroussin case UCL_STRING: 174097bd480fSBaptiste Daroussin *target = obj->value.sv; 174197bd480fSBaptiste Daroussin if (tlen != NULL) { 174297bd480fSBaptiste Daroussin *tlen = obj->len; 174397bd480fSBaptiste Daroussin } 174497bd480fSBaptiste Daroussin break; 174597bd480fSBaptiste Daroussin default: 174697bd480fSBaptiste Daroussin return false; 174797bd480fSBaptiste Daroussin } 174897bd480fSBaptiste Daroussin 174997bd480fSBaptiste Daroussin return true; 175097bd480fSBaptiste Daroussin } 175197bd480fSBaptiste Daroussin 175297bd480fSBaptiste Daroussin const char * 1753*b04a7a0bSBaptiste Daroussin ucl_object_tolstring (const ucl_object_t *obj, size_t *tlen) 175497bd480fSBaptiste Daroussin { 175597bd480fSBaptiste Daroussin const char *result = NULL; 175697bd480fSBaptiste Daroussin 175797bd480fSBaptiste Daroussin ucl_object_tolstring_safe (obj, &result, tlen); 175897bd480fSBaptiste Daroussin return result; 175997bd480fSBaptiste Daroussin } 176097bd480fSBaptiste Daroussin 176197bd480fSBaptiste Daroussin const char * 1762*b04a7a0bSBaptiste Daroussin ucl_object_key (const ucl_object_t *obj) 176397bd480fSBaptiste Daroussin { 176497bd480fSBaptiste Daroussin return ucl_copy_key_trash (obj); 176597bd480fSBaptiste Daroussin } 176697bd480fSBaptiste Daroussin 176797bd480fSBaptiste Daroussin const char * 1768*b04a7a0bSBaptiste Daroussin ucl_object_keyl (const ucl_object_t *obj, size_t *len) 176997bd480fSBaptiste Daroussin { 177097bd480fSBaptiste Daroussin if (len == NULL || obj == NULL) { 177197bd480fSBaptiste Daroussin return NULL; 177297bd480fSBaptiste Daroussin } 177397bd480fSBaptiste Daroussin *len = obj->keylen; 177497bd480fSBaptiste Daroussin return obj->key; 177597bd480fSBaptiste Daroussin } 177697bd480fSBaptiste Daroussin 177797bd480fSBaptiste Daroussin ucl_object_t * 1778*b04a7a0bSBaptiste Daroussin ucl_object_ref (const ucl_object_t *obj) 177997bd480fSBaptiste Daroussin { 1780*b04a7a0bSBaptiste Daroussin ucl_object_t *res = NULL; 1781*b04a7a0bSBaptiste Daroussin 178297bd480fSBaptiste Daroussin if (obj != NULL) { 1783*b04a7a0bSBaptiste Daroussin res = __DECONST (ucl_object_t *, obj); 1784*b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS 1785*b04a7a0bSBaptiste Daroussin (void)__sync_add_and_fetch (&res->ref, 1); 1786*b04a7a0bSBaptiste Daroussin #else 1787*b04a7a0bSBaptiste Daroussin res->ref ++; 1788*b04a7a0bSBaptiste Daroussin #endif 178997bd480fSBaptiste Daroussin } 1790*b04a7a0bSBaptiste Daroussin return res; 179197bd480fSBaptiste Daroussin } 179297bd480fSBaptiste Daroussin 179397bd480fSBaptiste Daroussin void 179497bd480fSBaptiste Daroussin ucl_object_unref (ucl_object_t *obj) 179597bd480fSBaptiste Daroussin { 1796*b04a7a0bSBaptiste Daroussin if (obj != NULL) { 1797*b04a7a0bSBaptiste Daroussin #ifdef HAVE_ATOMIC_BUILTINS 1798*b04a7a0bSBaptiste Daroussin unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); 1799*b04a7a0bSBaptiste Daroussin if (rc == 0) { 1800*b04a7a0bSBaptiste Daroussin #else 1801*b04a7a0bSBaptiste Daroussin if (--obj->ref == 0) { 1802*b04a7a0bSBaptiste Daroussin #endif 1803*b04a7a0bSBaptiste Daroussin ucl_object_free_internal (obj, true, ucl_object_dtor_unref); 1804*b04a7a0bSBaptiste Daroussin } 180597bd480fSBaptiste Daroussin } 180697bd480fSBaptiste Daroussin } 180797bd480fSBaptiste Daroussin 180897bd480fSBaptiste Daroussin int 1809*b04a7a0bSBaptiste Daroussin ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2) 181097bd480fSBaptiste Daroussin { 1811*b04a7a0bSBaptiste Daroussin const ucl_object_t *it1, *it2; 181297bd480fSBaptiste Daroussin ucl_object_iter_t iter = NULL; 181397bd480fSBaptiste Daroussin int ret = 0; 181497bd480fSBaptiste Daroussin 181597bd480fSBaptiste Daroussin if (o1->type != o2->type) { 181697bd480fSBaptiste Daroussin return (o1->type) - (o2->type); 181797bd480fSBaptiste Daroussin } 181897bd480fSBaptiste Daroussin 181997bd480fSBaptiste Daroussin switch (o1->type) { 182097bd480fSBaptiste Daroussin case UCL_STRING: 182197bd480fSBaptiste Daroussin if (o1->len == o2->len) { 182297bd480fSBaptiste Daroussin ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2)); 182397bd480fSBaptiste Daroussin } 182497bd480fSBaptiste Daroussin else { 182597bd480fSBaptiste Daroussin ret = o1->len - o2->len; 182697bd480fSBaptiste Daroussin } 182797bd480fSBaptiste Daroussin break; 182897bd480fSBaptiste Daroussin case UCL_FLOAT: 182997bd480fSBaptiste Daroussin case UCL_INT: 183097bd480fSBaptiste Daroussin case UCL_TIME: 183197bd480fSBaptiste Daroussin ret = ucl_object_todouble (o1) - ucl_object_todouble (o2); 183297bd480fSBaptiste Daroussin break; 183397bd480fSBaptiste Daroussin case UCL_BOOLEAN: 183497bd480fSBaptiste Daroussin ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2); 183597bd480fSBaptiste Daroussin break; 183697bd480fSBaptiste Daroussin case UCL_ARRAY: 183797bd480fSBaptiste Daroussin if (o1->len == o2->len) { 183897bd480fSBaptiste Daroussin it1 = o1->value.av; 183997bd480fSBaptiste Daroussin it2 = o2->value.av; 184097bd480fSBaptiste Daroussin /* Compare all elements in both arrays */ 184197bd480fSBaptiste Daroussin while (it1 != NULL && it2 != NULL) { 184297bd480fSBaptiste Daroussin ret = ucl_object_compare (it1, it2); 184397bd480fSBaptiste Daroussin if (ret != 0) { 184497bd480fSBaptiste Daroussin break; 184597bd480fSBaptiste Daroussin } 184697bd480fSBaptiste Daroussin it1 = it1->next; 184797bd480fSBaptiste Daroussin it2 = it2->next; 184897bd480fSBaptiste Daroussin } 184997bd480fSBaptiste Daroussin } 185097bd480fSBaptiste Daroussin else { 185197bd480fSBaptiste Daroussin ret = o1->len - o2->len; 185297bd480fSBaptiste Daroussin } 185397bd480fSBaptiste Daroussin break; 185497bd480fSBaptiste Daroussin case UCL_OBJECT: 185597bd480fSBaptiste Daroussin if (o1->len == o2->len) { 185697bd480fSBaptiste Daroussin while ((it1 = ucl_iterate_object (o1, &iter, true)) != NULL) { 185797bd480fSBaptiste Daroussin it2 = ucl_object_find_key (o2, ucl_object_key (it1)); 185897bd480fSBaptiste Daroussin if (it2 == NULL) { 185997bd480fSBaptiste Daroussin ret = 1; 186097bd480fSBaptiste Daroussin break; 186197bd480fSBaptiste Daroussin } 186297bd480fSBaptiste Daroussin ret = ucl_object_compare (it1, it2); 186397bd480fSBaptiste Daroussin if (ret != 0) { 186497bd480fSBaptiste Daroussin break; 186597bd480fSBaptiste Daroussin } 186697bd480fSBaptiste Daroussin } 186797bd480fSBaptiste Daroussin } 186897bd480fSBaptiste Daroussin else { 186997bd480fSBaptiste Daroussin ret = o1->len - o2->len; 187097bd480fSBaptiste Daroussin } 187197bd480fSBaptiste Daroussin break; 187297bd480fSBaptiste Daroussin default: 187397bd480fSBaptiste Daroussin ret = 0; 187497bd480fSBaptiste Daroussin break; 187597bd480fSBaptiste Daroussin } 187697bd480fSBaptiste Daroussin 187797bd480fSBaptiste Daroussin return ret; 187897bd480fSBaptiste Daroussin } 187997bd480fSBaptiste Daroussin 188097bd480fSBaptiste Daroussin void 188197bd480fSBaptiste Daroussin ucl_object_array_sort (ucl_object_t *ar, 1882*b04a7a0bSBaptiste Daroussin int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2)) 188397bd480fSBaptiste Daroussin { 188497bd480fSBaptiste Daroussin if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) { 188597bd480fSBaptiste Daroussin return; 188697bd480fSBaptiste Daroussin } 188797bd480fSBaptiste Daroussin 188897bd480fSBaptiste Daroussin DL_SORT (ar->value.av, cmp); 188997bd480fSBaptiste Daroussin } 1890