Update libucl to git version 8d3b186

This commit is contained in:
Baptiste Daroussin 2015-03-02 21:41:09 +00:00
commit 8e3b1ab2b5
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=279549
31 changed files with 1569 additions and 843 deletions

View File

@ -20,3 +20,15 @@
### Libucl 0.6.1
- Various utilities fixes
### Libucl 0.7.0
- Move to klib library from uthash to reduce memory overhead and increase performance
### Libucl 0.7.1
- Added safe iterators API
### Libucl 0.7.2
- Fixed serious bugs in schema and arrays iteration

View File

@ -1,5 +1,5 @@
ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = uthash README.md
EXTRA_DIST = uthash klib README.md
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libucl.pc

View File

@ -1,6 +1,6 @@
# LIBUCL
[![Build Status](https://travis-ci.org/vstakhov/libucl.svg?branch=master)](https://travis-ci.org/vstakhov/libucl)
[![Build Status](https://travis-ci.org/vstakhov/libucl.svg?branch=master)](https://travis-ci.org/vstakhov/libucl)[![Coverity](https://scan.coverity.com/projects/4138/badge.svg)](https://scan.coverity.com/projects/4138)
**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)*
@ -156,10 +156,10 @@ is converted to the following object:
```nginx
section {
blah {
key = value;
key = value;
}
foo {
key = value;
key = value;
}
}
```
@ -177,9 +177,9 @@ is presented as:
```nginx
section {
blah {
foo {
key = value;
}
foo {
key = value;
}
}
}
```
@ -219,8 +219,8 @@ UCL supports external macros both multiline and single line ones:
```nginx
.macro "sometext";
.macro {
Some long text
....
Some long text
....
};
```

View File

@ -82,6 +82,7 @@ ENDIF(ENABLE_URL_SIGN MATCHES "ON")
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../src")
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../include")
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../uthash")
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../klib")
SET(UCLSRC ../src/ucl_util.c
../src/ucl_parser.c

View File

@ -1,7 +1,7 @@
m4_define([maj_ver], [0])
m4_define([med_ver], [6])
m4_define([min_ver], [1])
m4_define([so_version], [3:0:1])
m4_define([med_ver], [7])
m4_define([min_ver], [2])
m4_define([so_version], [5:0:1])
m4_define([ucl_version], [maj_ver.med_ver.min_ver])
AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl])

View File

@ -4,5 +4,6 @@ dist_man_MANS = libucl.3
gen-man: @PANDOC@
tail -n +$$(grep -n '# Synopsis' api.md | cut -d':' -f1) api.md | \
cat pandoc.template - | sed -e 's/^# \(.*\)/# \U\1/' | \
cat pandoc.template - | sed -e 's/^# \(.*\)/# \U\1/' \
-e "s/%%date%%/$$(LANG=C date +'%d %B, %Y')/" | \
@PANDOC@ -s -f markdown -t man -o libucl.3

View File

@ -377,7 +377,9 @@ If parsing operations fail then the resulting UCL object will be a `UCL_STRING`.
# Iteration functions
Iteration are used to iterate over UCL compound types: arrays and objects. Moreover, iterations could be performed over the keys with multiple values (implicit arrays). To iterate over an object, an array or a key with multiple values there is a function `ucl_iterate_object`.
Iteration are used to iterate over UCL compound types: arrays and objects. Moreover, iterations could be performed over the keys with multiple values (implicit arrays).
There are two types of iterators API: old and unsafe one via `ucl_iterate_object` and the proposed interface of safe iterators.
## ucl_iterate_object
~~~C
@ -402,6 +404,60 @@ while ((obj = ucl_iterate_object (top, &it, true))) {
}
~~~
## Safe iterators API
Safe iterators are defined to clarify iterating over UCL objects and simplify flattening of UCL objects in non-trivial cases.
For example, if there is an implicit array that contains another array and a boolean value it is extremely unclear how to iterate over
such an object. Safe iterators are desinged to define two sorts of iteration:
1. Iteration over complex objects with expanding all values
2. Iteration over complex objects without expanding of values
The following example demonstrates the difference between these two types of iteration:
~~~
key = 1;
key = [2, 3, 4];
Iteration with expansion:
1, 2, 3, 4
Iteration without expansion:
1, [2, 3, 4]
~~~
UCL defines the following functions to manage safe iterators:
- `ucl_object_iterate_new` - creates new safe iterator
- `ucl_object_iterate_reset` - resets iterator to a new object
- `ucl_object_iterate_safe` - safely iterate the object inside iterator
- `ucl_object_iterate_free` - free memory associated with the safe iterator
Please note that unlike unsafe iterators, safe iterators *must* be explicitly initialized and freed.
An assert is likely generated if you use uninitialized or `NULL` iterator in all safe iterators functions.
~~~C
ucl_object_iter_t it;
const ucl_object_t *cur;
it = ucl_object_iterate_new (obj);
while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
/* Do something */
}
/* Switch to another object */
it = ucl_object_iterate_reset (it, another_obj);
while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
/* Do something else */
}
ucl_object_iterate_free (it);
~~~
# Validation functions
Currently, there is only one validation function called `ucl_object_validate`. It performs validation of object using the specified schema. This function is defined as following:

View File

@ -1,4 +1,4 @@
.TH "LIBUCL" "3" "July 26, 2014" "Libucl manual" ""
.TH "LIBUCL" "3" "27 December, 2014" "Libucl manual" ""
.SH NAME
.PP
\f[B]ucl_parser_new\f[], \f[B]ucl_parser_register_macro\f[],
@ -528,8 +528,9 @@ Iteration are used to iterate over UCL compound types: arrays and
objects.
Moreover, iterations could be performed over the keys with multiple
values (implicit arrays).
To iterate over an object, an array or a key with multiple values there
is a function \f[C]ucl_iterate_object\f[].
There are two types of iterators API: old and unsafe one via
\f[C]ucl_iterate_object\f[] and the proposed interface of safe
iterators.
.SS ucl_iterate_object
.IP
.nf
@ -578,6 +579,75 @@ while\ ((obj\ =\ ucl_iterate_object\ (top,\ &it,\ true)))\ {
}
\f[]
.fi
.SS Safe iterators API
.PP
Safe iterators are defined to clarify iterating over UCL objects and
simplify flattening of UCL objects in non\-trivial cases.
For example, if there is an implicit array that contains another array
and a boolean value it is extremely unclear how to iterate over such an
object.
Safe iterators are desinged to define two sorts of iteration:
.IP "1." 3
Iteration over complex objects with expanding all values
.IP "2." 3
Iteration over complex objects without expanding of values
.PP
The following example demonstrates the difference between these two
types of iteration:
.IP
.nf
\f[C]
key\ =\ 1;
key\ =\ [2,\ 3,\ 4];
Iteration\ with\ expansion:
1,\ 2,\ 3,\ 4
Iteration\ without\ expansion:
1,\ [2,\ 3,\ 4]
\f[]
.fi
.PP
UCL defines the following functions to manage safe iterators:
.IP \[bu] 2
\f[C]ucl_object_iterate_new\f[] \- creates new safe iterator
.IP \[bu] 2
\f[C]ucl_object_iterate_reset\f[] \- resets iterator to a new object
.IP \[bu] 2
\f[C]ucl_object_iterate_safe\f[] \- safely iterate the object inside
iterator
.IP \[bu] 2
\f[C]ucl_object_iterate_free\f[] \- free memory associated with the safe
iterator
.PP
Please note that unlike unsafe iterators, safe iterators \f[I]must\f[]
be explicitly initialized and freed.
An assert is likely generated if you use uninitialized or \f[C]NULL\f[]
iterator in all safe iterators functions.
.IP
.nf
\f[C]
ucl_object_iter_t\ it;
const\ ucl_object_t\ *cur;
it\ =\ ucl_object_iterate_new\ (obj);
while\ ((cur\ =\ ucl_object_iterate_safe\ (it,\ true))\ !=\ NULL)\ {
\ \ \ \ /*\ Do\ something\ */
}
/*\ Switch\ to\ another\ object\ */
it\ =\ ucl_object_iterate_reset\ (it,\ another_obj);
while\ ((cur\ =\ ucl_object_iterate_safe\ (it,\ true))\ !=\ NULL)\ {
\ \ \ \ /*\ Do\ something\ else\ */
}
ucl_object_iterate_free\ (it);
\f[]
.fi
.SH VALIDATION FUNCTIONS
.PP
Currently, there is only one validation function called

View File

@ -1,6 +1,6 @@
% LIBUCL(3) Libucl manual
% Vsevolod Stakhov <vsevolod@highsecure.ru>
% July 26, 2014
% %%date%%
# Name

View File

@ -192,7 +192,7 @@ typedef struct ucl_object_s {
int64_t iv; /**< Int value of an object */
const char *sv; /**< String value of an object */
double dv; /**< Double value of an object */
struct ucl_object_s *av; /**< Array */
void *av; /**< Array */
void *ov; /**< Object */
void* ud; /**< Opaque user data */
} value;
@ -715,6 +715,37 @@ typedef void* ucl_object_iter_t;
*/
UCL_EXTERN const ucl_object_t* ucl_iterate_object (const ucl_object_t *obj,
ucl_object_iter_t *iter, bool expand_values);
/**
* Create new safe iterator for the specified object
* @param obj object to iterate
* @return new iterator object that should be used with safe iterators API only
*/
UCL_EXTERN ucl_object_iter_t ucl_object_iterate_new (const ucl_object_t *obj)
UCL_WARN_UNUSED_RESULT;
/**
* Reset initialized iterator to a new object
* @param obj new object to iterate
* @return modified iterator object
*/
UCL_EXTERN ucl_object_iter_t ucl_object_iterate_reset (ucl_object_iter_t it,
const ucl_object_t *obj);
/**
* Get the next object from the `obj`. This fucntion iterates over arrays, objects
* and implicit arrays
* @param iter safe iterator
* @return the next object in sequence
*/
UCL_EXTERN const ucl_object_t* ucl_object_iterate_safe (ucl_object_iter_t iter,
bool expand_values);
/**
* Free memory associated with the safe iterator
* @param it safe iterator object
*/
UCL_EXTERN void ucl_object_iterate_free (ucl_object_iter_t it);
/** @} */
@ -854,6 +885,13 @@ UCL_EXTERN ucl_object_t* ucl_parser_get_object (struct ucl_parser *parser);
* @param parser parser object
*/
UCL_EXTERN const char *ucl_parser_get_error(struct ucl_parser *parser);
/**
* Clear the error in the parser
* @param parser parser object
*/
UCL_EXTERN void ucl_parser_clear_error(struct ucl_parser *parser);
/**
* Free ucl parser object
* @param parser parser object

627
contrib/libucl/klib/khash.h Normal file
View File

@ -0,0 +1,627 @@
/* The MIT License
Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/*
An example:
#include "khash.h"
KHASH_MAP_INIT_INT(32, char)
int main() {
int ret, is_missing;
khiter_t k;
khash_t(32) *h = kh_init(32);
k = kh_put(32, h, 5, &ret);
kh_value(h, k) = 10;
k = kh_get(32, h, 10);
is_missing = (k == kh_end(h));
k = kh_get(32, h, 5);
kh_del(32, h, k);
for (k = kh_begin(h); k != kh_end(h); ++k)
if (kh_exist(h, k)) kh_value(h, k) = 1;
kh_destroy(32, h);
return 0;
}
*/
/*
2013-05-02 (0.2.8):
* Use quadratic probing. When the capacity is power of 2, stepping function
i*(i+1)/2 guarantees to traverse each bucket. It is better than double
hashing on cache performance and is more robust than linear probing.
In theory, double hashing should be more robust than quadratic probing.
However, my implementation is probably not for large hash tables, because
the second hash function is closely tied to the first hash function,
which reduce the effectiveness of double hashing.
Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php
2011-12-29 (0.2.7):
* Minor code clean up; no actual effect.
2011-09-16 (0.2.6):
* The capacity is a power of 2. This seems to dramatically improve the
speed for simple keys. Thank Zilong Tan for the suggestion. Reference:
- http://code.google.com/p/ulib/
- http://nothings.org/computer/judy/
* Allow to optionally use linear probing which usually has better
performance for random input. Double hashing is still the default as it
is more robust to certain non-random input.
* Added Wang's integer hash function (not used by default). This hash
function is more robust to certain non-random input.
2011-02-14 (0.2.5):
* Allow to declare global functions.
2009-09-26 (0.2.4):
* Improve portability
2008-09-19 (0.2.3):
* Corrected the example
* Improved interfaces
2008-09-11 (0.2.2):
* Improved speed a little in kh_put()
2008-09-10 (0.2.1):
* Added kh_clear()
* Fixed a compiling error
2008-09-02 (0.2.0):
* Changed to token concatenation which increases flexibility.
2008-08-31 (0.1.2):
* Fixed a bug in kh_get(), which has not been tested previously.
2008-08-31 (0.1.1):
* Added destructor
*/
#ifndef __AC_KHASH_H
#define __AC_KHASH_H
/*!
@header
Generic hash table library.
*/
#define AC_VERSION_KHASH_H "0.2.8"
#include <stdlib.h>
#include <string.h>
#include <limits.h>
/* compiler specific configuration */
#if UINT_MAX == 0xffffffffu
typedef unsigned int khint32_t;
#elif ULONG_MAX == 0xffffffffu
typedef unsigned long khint32_t;
#endif
#if ULONG_MAX == ULLONG_MAX
typedef unsigned long khint64_t;
#else
typedef unsigned long long khint64_t;
#endif
#ifndef kh_inline
#ifdef _MSC_VER
#define kh_inline __inline
#else
#define kh_inline inline
#endif
#endif /* kh_inline */
#ifndef kh_unused
# ifdef __GNUC__
# define kh_unused(x) __attribute__((__unused__)) x
# else
# define kh_unused(x) x
# endif
#endif
typedef khint32_t khint_t;
typedef khint_t khiter_t;
#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1)))
#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1)))
#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
#ifndef kroundup32
#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
#endif
#ifndef kcalloc
#define kcalloc(N,Z) calloc(N,Z)
#endif
#ifndef kmalloc
#define kmalloc(Z) malloc(Z)
#endif
#ifndef krealloc
#define krealloc(P,Z) realloc(P,Z)
#endif
#ifndef kfree
#define kfree(P) free(P)
#endif
static const double __ac_HASH_UPPER = 0.77;
#define __KHASH_TYPE(name, khkey_t, khval_t) \
typedef struct kh_##name##_s { \
khint_t n_buckets, size, n_occupied, upper_bound; \
khint32_t *flags; \
khkey_t *keys; \
khval_t *vals; \
} kh_##name##_t;
#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \
extern kh_##name##_t * kh_init_##name(void); \
extern void kh_destroy_##name(kh_##name##_t *h); \
extern void kh_clear_##name(kh_##name##_t *h); \
extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
extern void kh_del_##name(kh_##name##_t *h, khint_t x);
#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
SCOPE kh_##name##_t *kh_init_##name(void) { \
return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \
} \
SCOPE void kh_destroy_##name(kh_##name##_t *h) \
{ \
if (h) { \
kfree((void *)h->keys); kfree(h->flags); \
kfree((void *)h->vals); \
kfree(h); \
} \
} \
SCOPE void kh_unused(kh_clear_##name)(kh_##name##_t *h) \
{ \
if (h && h->flags) { \
memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
h->size = h->n_occupied = 0; \
} \
} \
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
{ \
if (h->n_buckets) { \
khint_t k, i, last, mask, step = 0; \
mask = h->n_buckets - 1; \
k = __hash_func(key); i = k & mask; \
last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
i = (i + (++step)) & mask; \
if (i == last) return h->n_buckets; \
} \
return __ac_iseither(h->flags, i)? h->n_buckets : i; \
} else return 0; \
} \
SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
{ /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
khint32_t *new_flags = 0; \
khint_t j = 1; \
{ \
kroundup32(new_n_buckets); \
if (new_n_buckets < 4) new_n_buckets = 4; \
if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
else { /* hash table size to be changed (shrink or expand); rehash */ \
new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (!new_flags) return -1; \
memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (h->n_buckets < new_n_buckets) { /* expand */ \
khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
if (!new_keys) { kfree(new_flags); return -1; } \
h->keys = new_keys; \
if (kh_is_map) { \
khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
if (!new_vals) { kfree(new_flags); return -1; } \
h->vals = new_vals; \
} \
} /* otherwise shrink */ \
} \
} \
if (j) { /* rehashing is needed */ \
for (j = 0; j != h->n_buckets; ++j) { \
if (__ac_iseither(h->flags, j) == 0) { \
khkey_t key = h->keys[j]; \
khval_t val; \
khint_t new_mask; \
new_mask = new_n_buckets - 1; \
if (kh_is_map) val = h->vals[j]; \
__ac_set_isdel_true(h->flags, j); \
while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
khint_t k, i, step = 0; \
k = __hash_func(key); \
i = k & new_mask; \
while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
__ac_set_isempty_false(new_flags, i); \
if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
{ khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \
__ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
} else { /* write the element and jump out of the loop */ \
h->keys[i] = key; \
if (kh_is_map) h->vals[i] = val; \
break; \
} \
} \
} \
} \
if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
} \
kfree(h->flags); /* free the working space */ \
h->flags = new_flags; \
h->n_buckets = new_n_buckets; \
h->n_occupied = h->size; \
h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
} \
return 0; \
} \
SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
{ \
khint_t x; \
if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
if (h->n_buckets > (h->size<<1)) { \
if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
*ret = -1; return h->n_buckets; \
} \
} else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
*ret = -1; return h->n_buckets; \
} \
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
{ \
khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \
else { \
last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
if (__ac_isdel(h->flags, i)) site = i; \
i = (i + (++step)) & mask; \
if (i == last) { x = site; break; } \
} \
if (x == h->n_buckets) { \
if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
else x = i; \
} \
} \
} \
if (__ac_isempty(h->flags, x)) { /* not present at all */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; ++h->n_occupied; \
*ret = 1; \
} else if (__ac_isdel(h->flags, x)) { /* deleted */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; \
*ret = 2; \
} else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
return x; \
} \
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \
{ \
if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
__ac_set_isdel_true(h->flags, x); \
--h->size; \
} \
}
#define KHASH_DECLARE(name, khkey_t, khval_t) \
__KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_PROTOTYPES(name, khkey_t, khval_t)
#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
__KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
/* --- BEGIN OF HASH FUNCTIONS --- */
/*! @function
@abstract Integer hash function
@param key The integer [khint32_t]
@return The hash value [khint_t]
*/
#define kh_int_hash_func(key) (khint32_t)(key)
/*! @function
@abstract Integer comparison function
*/
#define kh_int_hash_equal(a, b) ((a) == (b))
/*! @function
@abstract 64-bit integer hash function
@param key The integer [khint64_t]
@return The hash value [khint_t]
*/
#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11)
/*! @function
@abstract 64-bit integer comparison function
*/
#define kh_int64_hash_equal(a, b) ((a) == (b))
/*! @function
@abstract const char* hash function
@param s Pointer to a null terminated string
@return The hash value
*/
static kh_inline khint_t __ac_X31_hash_string(const char *s)
{
khint_t h = (khint_t)*s;
if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s;
return h;
}
/*! @function
@abstract Another interface to const char* hash function
@param key Pointer to a null terminated string [const char*]
@return The hash value [khint_t]
*/
#define kh_str_hash_func(key) __ac_X31_hash_string(key)
/*! @function
@abstract Const char* comparison function
*/
#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0)
static kh_inline khint_t __ac_Wang_hash(khint_t key)
{
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
#define kh_int_hash_func2(k) __ac_Wang_hash((khint_t)key)
/* --- END OF HASH FUNCTIONS --- */
/* Other convenient macros... */
/*!
@abstract Type of the hash table.
@param name Name of the hash table [symbol]
*/
#define khash_t(name) kh_##name##_t
/*! @function
@abstract Initiate a hash table.
@param name Name of the hash table [symbol]
@return Pointer to the hash table [khash_t(name)*]
*/
#define kh_init(name) kh_init_##name()
/*! @function
@abstract Destroy a hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
*/
#define kh_destroy(name, h) kh_destroy_##name(h)
/*! @function
@abstract Reset a hash table without deallocating memory.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
*/
#define kh_clear(name, h) kh_clear_##name(h)
/*! @function
@abstract Resize a hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param s New size [khint_t]
*/
#define kh_resize(name, h, s) kh_resize_##name(h, s)
/*! @function
@abstract Insert a key to the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Key [type of keys]
@param r Extra return code: -1 if the operation failed;
0 if the key is present in the hash table;
1 if the bucket is empty (never used); 2 if the element in
the bucket has been deleted [int*]
@return Iterator to the inserted element [khint_t]
*/
#define kh_put(name, h, k, r) kh_put_##name(h, k, r)
/*! @function
@abstract Retrieve a key from the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Key [type of keys]
@return Iterator to the found element, or kh_end(h) if the element is absent [khint_t]
*/
#define kh_get(name, h, k) kh_get_##name(h, k)
/*! @function
@abstract Remove a key from the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Iterator to the element to be deleted [khint_t]
*/
#define kh_del(name, h, k) kh_del_##name(h, k)
/*! @function
@abstract Test whether a bucket contains data.
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return 1 if containing data; 0 otherwise [int]
*/
#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))
/*! @function
@abstract Get key given an iterator
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return Key [type of keys]
*/
#define kh_key(h, x) ((h)->keys[x])
/*! @function
@abstract Get value given an iterator
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return Value [type of values]
@discussion For hash sets, calling this results in segfault.
*/
#define kh_val(h, x) ((h)->vals[x])
/*! @function
@abstract Alias of kh_val()
*/
#define kh_value(h, x) ((h)->vals[x])
/*! @function
@abstract Get the start iterator
@param h Pointer to the hash table [khash_t(name)*]
@return The start iterator [khint_t]
*/
#define kh_begin(h) (khint_t)(0)
/*! @function
@abstract Get the end iterator
@param h Pointer to the hash table [khash_t(name)*]
@return The end iterator [khint_t]
*/
#define kh_end(h) ((h)->n_buckets)
/*! @function
@abstract Get the number of elements in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@return Number of elements in the hash table [khint_t]
*/
#define kh_size(h) ((h)->size)
/*! @function
@abstract Get the number of buckets in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@return Number of buckets in the hash table [khint_t]
*/
#define kh_n_buckets(h) ((h)->n_buckets)
/*! @function
@abstract Iterate over the entries in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@param kvar Variable to which key will be assigned
@param vvar Variable to which value will be assigned
@param code Block of code to execute
*/
#define kh_foreach(h, kvar, vvar, code) { khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h,__i)) continue; \
(kvar) = kh_key(h,__i); \
(vvar) = kh_val(h,__i); \
code; \
} }
/*! @function
@abstract Iterate over the values in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@param vvar Variable to which value will be assigned
@param code Block of code to execute
*/
#define kh_foreach_value(h, vvar, code) { khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h,__i)) continue; \
(vvar) = kh_val(h,__i); \
code; \
} }
/* More conenient interfaces */
/*! @function
@abstract Instantiate a hash set containing integer keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_INT(name) \
KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
/*! @function
@abstract Instantiate a hash map containing integer keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_INT(name, khval_t) \
KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
/*! @function
@abstract Instantiate a hash map containing 64-bit integer keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_INT64(name) \
KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
/*! @function
@abstract Instantiate a hash map containing 64-bit integer keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_INT64(name, khval_t) \
KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal)
typedef const char *kh_cstr_t;
/*! @function
@abstract Instantiate a hash map containing const char* keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_STR(name) \
KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
/*! @function
@abstract Instantiate a hash map containing const char* keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_STR(name, khval_t) \
KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
#endif /* __AC_KHASH_H */

103
contrib/libucl/klib/kvec.h Normal file
View File

@ -0,0 +1,103 @@
/* The MIT License
Copyright (c) 2008, by Attractive Chaos <attractor@live.co.uk>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/*
An example:
#include "kvec.h"
int main() {
kvec_t(int) array;
kv_init(array);
kv_push(int, array, 10); // append
kv_a(int, array, 20) = 5; // dynamic
kv_A(array, 20) = 4; // static
kv_destroy(array);
return 0;
}
*/
/*
2008-09-22 (0.1.0):
* The initial version.
*/
#ifndef AC_KVEC_H
#define AC_KVEC_H
#include <stdlib.h>
#define kv_roundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
#define kvec_t(type) struct { size_t n, m; type *a; }
#define kv_init(v) ((v).n = (v).m = 0, (v).a = 0)
#define kv_destroy(v) free((v).a)
#define kv_A(v, i) ((v).a[(i)])
#define kv_pop(v) ((v).a[--(v).n])
#define kv_size(v) ((v).n)
#define kv_max(v) ((v).m)
#define kv_resize(type, v, s) ((v).m = (s), (v).a = (type*)realloc((v).a, sizeof(type) * (v).m))
#define kv_grow_factor 1.5
#define kv_grow(type, v) ((v).m = ((v).m > 1 ? (v).m * kv_grow_factor : 2), \
(v).a = (type*)realloc((v).a, sizeof(type) * (v).m))
#define kv_copy(type, v1, v0) do { \
if ((v1).m < (v0).n) kv_resize(type, v1, (v0).n); \
(v1).n = (v0).n; \
memcpy((v1).a, (v0).a, sizeof(type) * (v0).n); \
} while (0) \
#define kv_push(type, v, x) do { \
if ((v).n == (v).m) { \
kv_grow(type, v); \
} \
(v).a[(v).n++] = (x); \
} while (0)
#define kv_prepend(type, v, x) do { \
if ((v).n == (v).m) { \
kv_grow(type, v); \
} \
memmove((v).a + 1, (v).a, sizeof(type) * (v).n); \
(v).a[0] = (x); \
(v).n ++; \
} while (0)
#define kv_concat(type, v1, v0) do { \
if ((v1).m < (v0).n + (v1).n) kv_resize(type, v1, (v0).n + (v1).n); \
memcpy((v1).a + (v1).n, (v0).a, sizeof(type) * ((v0).n + (v1).n)); \
(v1).n = (v0).n + (v1).n; \
} while (0)
#define kv_del(type, v, i) do { \
if ((i) < (v).n) { \
memmove((v).a + (i), (v).a + ((i) + 1), sizeof(type) * ((v).n - (i) - 1)); \
(v).n --; \
} \
} while (0)
#endif

View File

@ -1,4 +0,0 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View File

@ -1,606 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_lua.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PROG_LUA[([MINIMUM-VERSION], [TOO-BIG-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
# AX_LUA_HEADERS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
# AX_LUA_LIBS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
# AX_LUA_READLINE[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
#
# DESCRIPTION
#
# Detect a Lua interpreter, optionally specifying a minimum and maximum
# version number. Set up important Lua paths, such as the directories in
# which to install scripts and modules (shared libraries).
#
# Also detect Lua headers and libraries. The Lua version contained in the
# header is checked to match the Lua interpreter version exactly. When
# searching for Lua libraries, the version number is used as a suffix.
# This is done with the goal of supporting multiple Lua installs (5.1 and
# 5.2 side-by-side).
#
# A note on compatibility with previous versions: This file has been
# mostly rewritten for serial 18. Most developers should be able to use
# these macros without needing to modify configure.ac. Care has been taken
# to preserve each macro's behavior, but there are some differences:
#
# 1) AX_WITH_LUA is deprecated; it now expands to the exact same thing as
# AX_PROG_LUA with no arguments.
#
# 2) AX_LUA_HEADERS now checks that the version number defined in lua.h
# matches the interpreter version. AX_LUA_HEADERS_VERSION is therefore
# unnecessary, so it is deprecated and does not expand to anything.
#
# 3) The configure flag --with-lua-suffix no longer exists; the user
# should instead specify the LUA precious variable on the command line.
# See the AX_PROG_LUA description for details.
#
# Please read the macro descriptions below for more information.
#
# This file was inspired by Andrew Dalke's and James Henstridge's
# python.m4 and Tom Payne's, Matthieu Moy's, and Reuben Thomas's ax_lua.m4
# (serial 17). Basically, this file is a mash-up of those two files. I
# like to think it combines the best of the two!
#
# AX_PROG_LUA: Search for the Lua interpreter, and set up important Lua
# paths. Adds precious variable LUA, which may contain the path of the Lua
# interpreter. If LUA is blank, the user's path is searched for an
# suitable interpreter.
#
# If MINIMUM-VERSION is supplied, then only Lua interpreters with a
# version number greater or equal to MINIMUM-VERSION will be accepted. If
# TOO-BIG- VERSION is also supplied, then only Lua interpreters with a
# version number greater or equal to MINIMUM-VERSION and less than
# TOO-BIG-VERSION will be accepted.
#
# The Lua version number, LUA_VERSION, is found from the interpreter, and
# substituted. LUA_PLATFORM is also found, but not currently supported (no
# standard representation).
#
# Finally, the macro finds four paths:
#
# luadir Directory to install Lua scripts.
# pkgluadir $luadir/$PACKAGE
# luaexecdir Directory to install Lua modules.
# pkgluaexecdir $luaexecdir/$PACKAGE
#
# These paths a found based on $prefix, $exec_prefix, Lua's package.path,
# and package.cpath. The first path of package.path beginning with $prefix
# is selected as luadir. The first path of package.cpath beginning with
# $exec_prefix is used as luaexecdir. This should work on all reasonable
# Lua installations. If a path cannot be determined, a default path is
# used. Of course, the user can override these later when invoking make.
#
# luadir Default: $prefix/share/lua/$LUA_VERSION
# luaexecdir Default: $exec_prefix/lib/lua/$LUA_VERSION
#
# These directories can be used by Automake as install destinations. The
# variable name minus 'dir' needs to be used as a prefix to the
# appropriate Automake primary, e.g. lua_SCRIPS or luaexec_LIBRARIES.
#
# If an acceptable Lua interpreter is found, then ACTION-IF-FOUND is
# performed, otherwise ACTION-IF-NOT-FOUND is preformed. If ACTION-IF-NOT-
# FOUND is blank, then it will default to printing an error. To prevent
# the default behavior, give ':' as an action.
#
# AX_LUA_HEADERS: Search for Lua headers. Requires that AX_PROG_LUA be
# expanded before this macro. Adds precious variable LUA_INCLUDE, which
# may contain Lua specific include flags, e.g. -I/usr/include/lua5.1. If
# LUA_INCLUDE is blank, then this macro will attempt to find suitable
# flags.
#
# LUA_INCLUDE can be used by Automake to compile Lua modules or
# executables with embedded interpreters. The *_CPPFLAGS variables should
# be used for this purpose, e.g. myprog_CPPFLAGS = $(LUA_INCLUDE).
#
# This macro searches for the header lua.h (and others). The search is
# performed with a combination of CPPFLAGS, CPATH, etc, and LUA_INCLUDE.
# If the search is unsuccessful, then some common directories are tried.
# If the headers are then found, then LUA_INCLUDE is set accordingly.
#
# The paths automatically searched are:
#
# * /usr/include/luaX.Y
# * /usr/include/lua/X.Y
# * /usr/include/luaXY
# * /usr/local/include/luaX.Y
# * /usr/local/include/lua-X.Y
# * /usr/local/include/lua/X.Y
# * /usr/local/include/luaXY
#
# (Where X.Y is the Lua version number, e.g. 5.1.)
#
# The Lua version number found in the headers is always checked to match
# the Lua interpreter's version number. Lua headers with mismatched
# version numbers are not accepted.
#
# If headers are found, then ACTION-IF-FOUND is performed, otherwise
# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then
# it will default to printing an error. To prevent the default behavior,
# set the action to ':'.
#
# AX_LUA_LIBS: Search for Lua libraries. Requires that AX_PROG_LUA be
# expanded before this macro. Adds precious variable LUA_LIB, which may
# contain Lua specific linker flags, e.g. -llua5.1. If LUA_LIB is blank,
# then this macro will attempt to find suitable flags.
#
# LUA_LIB can be used by Automake to link Lua modules or executables with
# embedded interpreters. The *_LIBADD and *_LDADD variables should be used
# for this purpose, e.g. mymod_LIBADD = $(LUA_LIB).
#
# This macro searches for the Lua library. More technically, it searches
# for a library containing the function lua_load. The search is performed
# with a combination of LIBS, LIBRARY_PATH, and LUA_LIB.
#
# If the search determines that some linker flags are missing, then those
# flags will be added to LUA_LIB.
#
# If libraries are found, then ACTION-IF-FOUND is performed, otherwise
# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then
# it will default to printing an error. To prevent the default behavior,
# set the action to ':'.
#
# AX_LUA_READLINE: Search for readline headers and libraries. Requires the
# AX_LIB_READLINE macro, which is provided by ax_lib_readline.m4 from the
# Autoconf Archive.
#
# If a readline compatible library is found, then ACTION-IF-FOUND is
# performed, otherwise ACTION-IF-NOT-FOUND is performed.
#
# LICENSE
#
# Copyright (c) 2014 Reuben Thomas <rrt@sc3d.org>
# Copyright (c) 2013 Tim Perkins <tprk77@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 23
dnl =========================================================================
dnl AX_PROG_LUA([MINIMUM-VERSION], [TOO-BIG-VERSION],
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl =========================================================================
AC_DEFUN([AX_PROG_LUA],
[
dnl Make LUA a precious variable.
AC_ARG_VAR([LUA], [The Lua interpreter, e.g. /usr/bin/lua5.1])
dnl Find a Lua interpreter.
m4_define_default([_AX_LUA_INTERPRETER_LIST],
[lua lua5.2 lua52 lua5.1 lua51 lua50])
m4_if([$1], [],
[ dnl No version check is needed. Find any Lua interpreter.
AS_IF([test "x$LUA" = 'x'],
[AC_PATH_PROGS([LUA], [_AX_LUA_INTERPRETER_LIST], [:])])
ax_display_LUA='lua'
dnl At least check if this is a Lua interpreter.
AC_MSG_CHECKING([if $LUA is a Lua interpreter])
_AX_LUA_CHK_IS_INTRP([$LUA],
[AC_MSG_RESULT([yes])],
[ AC_MSG_RESULT([no])
AC_MSG_ERROR([not a Lua interpreter])
])
],
[ dnl A version check is needed.
AS_IF([test "x$LUA" != 'x'],
[ dnl Check if this is a Lua interpreter.
AC_MSG_CHECKING([if $LUA is a Lua interpreter])
_AX_LUA_CHK_IS_INTRP([$LUA],
[AC_MSG_RESULT([yes])],
[ AC_MSG_RESULT([no])
AC_MSG_ERROR([not a Lua interpreter])
])
dnl Check the version.
m4_if([$2], [],
[_ax_check_text="whether $LUA version >= $1"],
[_ax_check_text="whether $LUA version >= $1, < $2"])
AC_MSG_CHECKING([$_ax_check_text])
_AX_LUA_CHK_VER([$LUA], [$1], [$2],
[AC_MSG_RESULT([yes])],
[ AC_MSG_RESULT([no])
AC_MSG_ERROR([version is out of range for specified LUA])])
ax_display_LUA=$LUA
],
[ dnl Try each interpreter until we find one that satisfies VERSION.
m4_if([$2], [],
[_ax_check_text="for a Lua interpreter with version >= $1"],
[_ax_check_text="for a Lua interpreter with version >= $1, < $2"])
AC_CACHE_CHECK([$_ax_check_text],
[ax_cv_pathless_LUA],
[ for ax_cv_pathless_LUA in _AX_LUA_INTERPRETER_LIST none; do
test "x$ax_cv_pathless_LUA" = 'xnone' && break
_AX_LUA_CHK_IS_INTRP([$ax_cv_pathless_LUA], [], [continue])
_AX_LUA_CHK_VER([$ax_cv_pathless_LUA], [$1], [$2], [break])
done
])
dnl Set $LUA to the absolute path of $ax_cv_pathless_LUA.
AS_IF([test "x$ax_cv_pathless_LUA" = 'xnone'],
[LUA=':'],
[AC_PATH_PROG([LUA], [$ax_cv_pathless_LUA])])
ax_display_LUA=$ax_cv_pathless_LUA
])
])
AS_IF([test "x$LUA" = 'x:'],
[ dnl Run any user-specified action, or abort.
m4_default([$4], [AC_MSG_ERROR([cannot find suitable Lua interpreter])])
],
[ dnl Query Lua for its version number.
AC_CACHE_CHECK([for $ax_display_LUA version], [ax_cv_lua_version],
[ ax_cv_lua_version=`$LUA -e 'print(_VERSION:match "(%d+%.%d+)")'` ])
AS_IF([test "x$ax_cv_lua_version" = 'x'],
[AC_MSG_ERROR([invalid Lua version number])])
AC_SUBST([LUA_VERSION], [$ax_cv_lua_version])
AC_SUBST([LUA_SHORT_VERSION], [`echo "$LUA_VERSION" | sed 's|\.||'`])
dnl The following check is not supported:
dnl At times (like when building shared libraries) you may want to know
dnl which OS platform Lua thinks this is.
AC_CACHE_CHECK([for $ax_display_LUA platform], [ax_cv_lua_platform],
[ax_cv_lua_platform=`$LUA -e "print('unknown')"`])
AC_SUBST([LUA_PLATFORM], [$ax_cv_lua_platform])
dnl Use the values of $prefix and $exec_prefix for the corresponding
dnl values of LUA_PREFIX and LUA_EXEC_PREFIX. These are made distinct
dnl variables so they can be overridden if need be. However, the general
dnl consensus is that you shouldn't need this ability.
AC_SUBST([LUA_PREFIX], ['${prefix}'])
AC_SUBST([LUA_EXEC_PREFIX], ['${exec_prefix}'])
dnl Lua provides no way to query the script directory, and instead
dnl provides LUA_PATH. However, we should be able to make a safe educated
dnl guess. If the built-in search path contains a directory which is
dnl prefixed by $prefix, then we can store scripts there. The first
dnl matching path will be used.
AC_CACHE_CHECK([for $ax_display_LUA script directory],
[ax_cv_lua_luadir],
[ AS_IF([test "x$prefix" = 'xNONE'],
[ax_lua_prefix=$ac_default_prefix],
[ax_lua_prefix=$prefix])
dnl Initialize to the default path.
ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION"
dnl Try to find a path with the prefix.
_AX_LUA_FND_PRFX_PTH([$LUA], [$ax_lua_prefix], [package.path])
AS_IF([test "x$ax_lua_prefixed_path" != 'x'],
[ dnl Fix the prefix.
_ax_strip_prefix=`echo "$ax_lua_prefix" | sed 's|.|.|g'`
ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \
sed "s,^$_ax_strip_prefix,$LUA_PREFIX,"`
])
])
AC_SUBST([luadir], [$ax_cv_lua_luadir])
AC_SUBST([pkgluadir], [\${luadir}/$PACKAGE])
dnl Lua provides no way to query the module directory, and instead
dnl provides LUA_PATH. However, we should be able to make a safe educated
dnl guess. If the built-in search path contains a directory which is
dnl prefixed by $exec_prefix, then we can store modules there. The first
dnl matching path will be used.
AC_CACHE_CHECK([for $ax_display_LUA module directory],
[ax_cv_lua_luaexecdir],
[ AS_IF([test "x$exec_prefix" = 'xNONE'],
[ax_lua_exec_prefix=$ax_lua_prefix],
[ax_lua_exec_prefix=$exec_prefix])
dnl Initialize to the default path.
ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION"
dnl Try to find a path with the prefix.
_AX_LUA_FND_PRFX_PTH([$LUA],
[$ax_lua_exec_prefix], [package.cpathd])
AS_IF([test "x$ax_lua_prefixed_path" != 'x'],
[ dnl Fix the prefix.
_ax_strip_prefix=`echo "$ax_lua_exec_prefix" | sed 's|.|.|g'`
ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \
sed "s,^$_ax_strip_prefix,$LUA_EXEC_PREFIX,"`
])
])
AC_SUBST([luaexecdir], [$ax_cv_lua_luaexecdir])
AC_SUBST([pkgluaexecdir], [\${luaexecdir}/$PACKAGE])
dnl Run any user specified action.
$3
])
])
dnl AX_WITH_LUA is now the same thing as AX_PROG_LUA.
AC_DEFUN([AX_WITH_LUA],
[
AC_MSG_WARN([[$0 is deprecated, please use AX_PROG_LUA]])
AX_PROG_LUA
])
dnl =========================================================================
dnl _AX_LUA_CHK_IS_INTRP(PROG, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
dnl =========================================================================
AC_DEFUN([_AX_LUA_CHK_IS_INTRP],
[
dnl Just print _VERSION because all Lua interpreters have this global.
AS_IF([$1 -e "print('Hello ' .. _VERSION .. '!')" &>/dev/null],
[$2], [$3])
])
dnl =========================================================================
dnl _AX_LUA_CHK_VER(PROG, MINIMUM-VERSION, [TOO-BIG-VERSION],
dnl [ACTION-IF-TRUE], [ACTION-IF-FALSE])
dnl =========================================================================
AC_DEFUN([_AX_LUA_CHK_VER],
[
AS_IF([$1 2>/dev/null -e '
function norm (v) i,j=v:match "(%d+)%.(%d+)" return 100 * i + j end
v=norm (_VERSION)
os.exit ((v >= norm ("$2") and ("$3" == "" or v < norm ("$3"))) and 0 or 1)'],
[$4], [$5])
])
dnl =========================================================================
dnl _AX_LUA_FND_PRFX_PTH(PROG, PREFIX, LUA-PATH-VARIABLE)
dnl =========================================================================
AC_DEFUN([_AX_LUA_FND_PRFX_PTH],
[
dnl Invokes the Lua interpreter PROG to print the path variable
dnl LUA-PATH-VARIABLE, usually package.path or package.cpath. Paths are
dnl then matched against PREFIX. The first path to begin with PREFIX is set
dnl to ax_lua_prefixed_path.
ax_lua_prefixed_path=''
_ax_package_paths=`$1 -e 'print($3)' 2>/dev/null | sed 's|;|\n|g'`
dnl Try the paths in order, looking for the prefix.
for _ax_package_path in $_ax_package_paths; do
dnl Copy the path, up to the use of a Lua wildcard.
_ax_path_parts=`echo "$_ax_package_path" | sed 's|/|\n|g'`
_ax_reassembled=''
for _ax_path_part in $_ax_path_parts; do
echo "$_ax_path_part" | grep '\?' >/dev/null && break
_ax_reassembled="$_ax_reassembled/$_ax_path_part"
done
dnl Check the path against the prefix.
_ax_package_path=$_ax_reassembled
if echo "$_ax_package_path" | grep "^$2" >/dev/null; then
dnl Found it.
ax_lua_prefixed_path=$_ax_package_path
break
fi
done
])
dnl =========================================================================
dnl AX_LUA_HEADERS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl =========================================================================
AC_DEFUN([AX_LUA_HEADERS],
[
dnl Check for LUA_VERSION.
AC_MSG_CHECKING([if LUA_VERSION is defined])
AS_IF([test "x$LUA_VERSION" != 'x'],
[AC_MSG_RESULT([yes])],
[ AC_MSG_RESULT([no])
AC_MSG_ERROR([cannot check Lua headers without knowing LUA_VERSION])
])
dnl Make LUA_INCLUDE a precious variable.
AC_ARG_VAR([LUA_INCLUDE], [The Lua includes, e.g. -I/usr/include/lua5.1])
dnl Some default directories to search.
LUA_SHORT_VERSION=`echo "$LUA_VERSION" | sed 's|\.||'`
m4_define_default([_AX_LUA_INCLUDE_LIST],
[ /usr/include/lua$LUA_VERSION \
/usr/include/lua/$LUA_VERSION \
/usr/include/lua$LUA_SHORT_VERSION \
/usr/local/include/lua$LUA_VERSION \
/usr/local/include/lua-$LUA_VERSION \
/usr/local/include/lua/$LUA_VERSION \
/usr/local/include/lua$LUA_SHORT_VERSION \
])
dnl Try to find the headers.
_ax_lua_saved_cppflags=$CPPFLAGS
CPPFLAGS="$CPPFLAGS $LUA_INCLUDE"
AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h])
CPPFLAGS=$_ax_lua_saved_cppflags
dnl Try some other directories if LUA_INCLUDE was not set.
AS_IF([test "x$LUA_INCLUDE" = 'x' &&
test "x$ac_cv_header_lua_h" != 'xyes'],
[ dnl Try some common include paths.
for _ax_include_path in _AX_LUA_INCLUDE_LIST; do
test ! -d "$_ax_include_path" && continue
AC_MSG_CHECKING([for Lua headers in])
AC_MSG_RESULT([$_ax_include_path])
AS_UNSET([ac_cv_header_lua_h])
AS_UNSET([ac_cv_header_lualib_h])
AS_UNSET([ac_cv_header_lauxlib_h])
AS_UNSET([ac_cv_header_luaconf_h])
_ax_lua_saved_cppflags=$CPPFLAGS
CPPFLAGS="$CPPFLAGS -I$_ax_include_path"
AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h])
CPPFLAGS=$_ax_lua_saved_cppflags
AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'],
[ LUA_INCLUDE="-I$_ax_include_path"
break
])
done
])
AS_IF([test "x$ac_cv_header_lua_h" = 'xyes' && test "x$cross_compiling" != 'xyes'],
[ dnl Make a program to print LUA_VERSION defined in the header.
dnl TODO This probably shouldn't be a runtime test.
AC_CACHE_CHECK([for Lua header version],
[ax_cv_lua_header_version],
[ _ax_lua_saved_cppflags=$CPPFLAGS
CPPFLAGS="$CPPFLAGS $LUA_INCLUDE"
AC_RUN_IFELSE(
[ AC_LANG_SOURCE([[
#include <lua.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char ** argv)
{
if(argc > 1) printf("%s", LUA_VERSION);
exit(EXIT_SUCCESS);
}
]])
],
[ ax_cv_lua_header_version=`./conftest$EXEEXT p | \
sed "s|^Lua \(.*\)|\1|" | \
grep -o "^@<:@0-9@:>@\+\\.@<:@0-9@:>@\+"`
],
[ax_cv_lua_header_version='unknown'])
CPPFLAGS=$_ax_lua_saved_cppflags
])
dnl Compare this to the previously found LUA_VERSION.
AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION])
AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"],
[ AC_MSG_RESULT([yes])
ax_header_version_match='yes'
],
[ AC_MSG_RESULT([no])
ax_header_version_match='no'
])
],
[
ax_header_version_match='yes'
])
dnl Was LUA_INCLUDE specified?
AS_IF([test "x$ax_header_version_match" != 'xyes' &&
test "x$LUA_INCLUDE" != 'x'],
[AC_MSG_ERROR([cannot find headers for specified LUA_INCLUDE])])
dnl Test the final result and run user code.
AS_IF([test "x$ax_header_version_match" = 'xyes'], [$1],
[m4_default([$2], [AC_MSG_ERROR([cannot find Lua includes])])])
])
dnl AX_LUA_HEADERS_VERSION no longer exists, use AX_LUA_HEADERS.
AC_DEFUN([AX_LUA_HEADERS_VERSION],
[
AC_MSG_WARN([[$0 is deprecated, please use AX_LUA_HEADERS]])
])
dnl =========================================================================
dnl AX_LUA_LIBS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl =========================================================================
AC_DEFUN([AX_LUA_LIBS],
[
dnl TODO Should this macro also check various -L flags?
dnl Check for LUA_VERSION.
AC_MSG_CHECKING([if LUA_VERSION is defined])
AS_IF([test "x$LUA_VERSION" != 'x'],
[AC_MSG_RESULT([yes])],
[ AC_MSG_RESULT([no])
AC_MSG_ERROR([cannot check Lua libs without knowing LUA_VERSION])
])
dnl Make LUA_LIB a precious variable.
AC_ARG_VAR([LUA_LIB], [The Lua library, e.g. -llua5.1])
AS_IF([test "x$LUA_LIB" != 'x'],
[ dnl Check that LUA_LIBS works.
_ax_lua_saved_libs=$LIBS
LIBS="$LIBS $LUA_LIB"
AC_SEARCH_LIBS([lua_load], [],
[_ax_found_lua_libs='yes'],
[_ax_found_lua_libs='no'])
LIBS=$_ax_lua_saved_libs
dnl Check the result.
AS_IF([test "x$_ax_found_lua_libs" != 'xyes'],
[AC_MSG_ERROR([cannot find libs for specified LUA_LIB])])
],
[ dnl First search for extra libs.
_ax_lua_extra_libs=''
_ax_lua_saved_libs=$LIBS
LIBS="$LIBS $LUA_LIB"
AC_SEARCH_LIBS([exp], [m])
AC_SEARCH_LIBS([dlopen], [dl])
LIBS=$_ax_lua_saved_libs
AS_IF([test "x$ac_cv_search_exp" != 'xno' &&
test "x$ac_cv_search_exp" != 'xnone required'],
[_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp"])
AS_IF([test "x$ac_cv_search_dlopen" != 'xno' &&
test "x$ac_cv_search_dlopen" != 'xnone required'],
[_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen"])
dnl Try to find the Lua libs.
_ax_lua_saved_libs=$LIBS
LIBS="$LIBS $LUA_LIB"
AC_SEARCH_LIBS([lua_load],
[ lua$LUA_VERSION \
lua$LUA_SHORT_VERSION \
lua-$LUA_VERSION \
lua-$LUA_SHORT_VERSION \
lua],
[_ax_found_lua_libs='yes'],
[_ax_found_lua_libs='no'],
[$_ax_lua_extra_libs])
LIBS=$_ax_lua_saved_libs
AS_IF([test "x$ac_cv_search_lua_load" != 'xno' &&
test "x$ac_cv_search_lua_load" != 'xnone required'],
[LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs"])
])
dnl Test the result and run user code.
AS_IF([test "x$_ax_found_lua_libs" = 'xyes'], [$1],
[m4_default([$2], [AC_MSG_ERROR([cannot find Lua libs])])])
])
dnl =========================================================================
dnl AX_LUA_READLINE([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl =========================================================================
AC_DEFUN([AX_LUA_READLINE],
[
AX_LIB_READLINE
AS_IF([test "x$ac_cv_header_readline_readline_h" != 'x' &&
test "x$ac_cv_header_readline_history_h" != 'x'],
[ LUA_LIBS_CFLAGS="-DLUA_USE_READLINE $LUA_LIBS_CFLAGS"
$1
],
[$2])
])

View File

@ -1,6 +1,7 @@
libucl_common_cflags= -I$(top_srcdir)/src \
-I$(top_srcdir)/include \
-I$(top_srcdir)/uthash \
-I$(top_srcdir)/klib \
-Wall -W -Wno-unused-parameter -Wno-pointer-sign
lib_LTLIBRARIES= libucl.la
libucl_la_SOURCES= ucl_emitter.c \

View File

@ -250,6 +250,7 @@ ucl_emitter_common_start_array (struct ucl_emitter_context *ctx,
const ucl_object_t *obj, bool print_key, bool compact)
{
const ucl_object_t *cur;
ucl_object_iter_t iter = NULL;
const struct ucl_emitter_functions *func = ctx->func;
bool first = true;
@ -266,18 +267,22 @@ ucl_emitter_common_start_array (struct ucl_emitter_context *ctx,
if (obj->type == UCL_ARRAY) {
/* explicit array */
cur = obj->value.av;
while ((cur = ucl_iterate_object (obj, &iter, true)) != NULL) {
ucl_emitter_common_elt (ctx, cur, first, false, compact);
first = false;
}
}
else {
/* implicit array */
cur = obj;
while (cur) {
ucl_emitter_common_elt (ctx, cur, first, false, compact);
first = false;
cur = cur->next;
}
}
while (cur) {
ucl_emitter_common_elt (ctx, cur, first, false, compact);
first = false;
cur = cur->next;
}
}
/**

View File

@ -289,6 +289,7 @@ ucl_fd_append_character (unsigned char c, size_t len, void *ud)
else {
memset (buf, c, len);
if (write (fd, buf, len) == -1) {
free(buf);
return -1;
}
free (buf);

View File

@ -23,119 +23,331 @@
#include "ucl_internal.h"
#include "ucl_hash.h"
#include "utlist.h"
#include "khash.h"
#include "kvec.h"
struct ucl_hash_elt {
const ucl_object_t *obj;
size_t ar_idx;
};
struct ucl_hash_struct {
void *hash;
kvec_t(const ucl_object_t *) ar;
bool caseless;
};
static inline uint32_t
ucl_hash_func (const ucl_object_t *o)
{
return XXH32 (o->key, o->keylen, 0xdeadbeef);
}
static inline int
ucl_hash_equal (const ucl_object_t *k1, const ucl_object_t *k2)
{
if (k1->keylen == k2->keylen) {
return strncmp (k1->key, k2->key, k1->keylen) == 0;
}
return 0;
}
KHASH_INIT (ucl_hash_node, const ucl_object_t *, struct ucl_hash_elt, 1,
ucl_hash_func, ucl_hash_equal)
static inline uint32_t
ucl_hash_caseless_func (const ucl_object_t *o)
{
void *xxh = XXH32_init (0xdeadbeef);
char hash_buf[64], *c;
const char *p;
ssize_t remain = o->keylen;
p = o->key;
c = &hash_buf[0];
while (remain > 0) {
*c++ = tolower (*p++);
if (c - &hash_buf[0] == sizeof (hash_buf)) {
XXH32_update (xxh, hash_buf, sizeof (hash_buf));
c = &hash_buf[0];
}
remain --;
}
if (c - &hash_buf[0] != 0) {
XXH32_update (xxh, hash_buf, c - &hash_buf[0]);
}
return XXH32_digest (xxh);
}
static inline int
ucl_hash_caseless_equal (const ucl_object_t *k1, const ucl_object_t *k2)
{
if (k1->keylen == k2->keylen) {
return strncasecmp (k1->key, k2->key, k1->keylen) == 0;
}
return 0;
}
KHASH_INIT (ucl_hash_caseless_node, const ucl_object_t *, struct ucl_hash_elt, 1,
ucl_hash_caseless_func, ucl_hash_caseless_equal)
ucl_hash_t*
ucl_hash_create (void)
ucl_hash_create (bool ignore_case)
{
ucl_hash_t *new;
new = UCL_ALLOC (sizeof (ucl_hash_t));
if (new != NULL) {
new->buckets = NULL;
kv_init (new->ar);
new->caseless = ignore_case;
if (ignore_case) {
khash_t(ucl_hash_caseless_node) *h = kh_init (ucl_hash_caseless_node);
new->hash = (void *)h;
}
else {
khash_t(ucl_hash_node) *h = kh_init (ucl_hash_node);
new->hash = (void *)h;
}
}
return new;
}
void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func)
{
ucl_hash_node_t *elt, *tmp;
const ucl_object_t *cur, *otmp;
const ucl_object_t *cur, *tmp;
HASH_ITER (hh, hashlin->buckets, elt, tmp) {
HASH_DELETE (hh, hashlin->buckets, elt);
if (func) {
DL_FOREACH_SAFE (elt->data, cur, otmp) {
/* Need to deconst here */
func (__DECONST (ucl_object_t *, cur));
if (hashlin == NULL) {
return;
}
if (func != NULL) {
/* Iterate over the hash first */
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
hashlin->hash;
khiter_t k;
for (k = kh_begin (h); k != kh_end (h); ++k) {
if (kh_exist (h, k)) {
cur = (kh_value (h, k)).obj;
while (cur != NULL) {
tmp = cur->next;
func (__DECONST (ucl_object_t *, cur));
cur = tmp;
}
}
}
UCL_FREE (sizeof (ucl_hash_node_t), elt);
}
UCL_FREE (sizeof (ucl_hash_t), hashlin);
if (hashlin->caseless) {
khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
hashlin->hash;
kh_destroy (ucl_hash_caseless_node, h);
}
else {
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
hashlin->hash;
kh_destroy (ucl_hash_node, h);
}
kv_destroy (hashlin->ar);
UCL_FREE (sizeof (*hashlin), hashlin);
}
void
ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
const char *key, unsigned keylen)
{
ucl_hash_node_t *node;
khiter_t k;
int ret;
struct ucl_hash_elt *elt;
node = UCL_ALLOC (sizeof (ucl_hash_node_t));
node->data = obj;
HASH_ADD_KEYPTR (hh, hashlin->buckets, key, keylen, node);
if (hashlin == NULL) {
return;
}
if (hashlin->caseless) {
khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
hashlin->hash;
k = kh_put (ucl_hash_caseless_node, h, obj, &ret);
if (ret > 0) {
elt = &kh_value (h, k);
kv_push (const ucl_object_t *, hashlin->ar, obj);
elt->obj = obj;
elt->ar_idx = kv_size (hashlin->ar) - 1;
}
}
else {
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
hashlin->hash;
k = kh_put (ucl_hash_node, h, obj, &ret);
if (ret > 0) {
elt = &kh_value (h, k);
kv_push (const ucl_object_t *, hashlin->ar, obj);
elt->obj = obj;
elt->ar_idx = kv_size (hashlin->ar) - 1;
}
}
}
void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old,
const ucl_object_t *new)
{
ucl_hash_node_t *node;
khiter_t k;
int ret;
struct ucl_hash_elt elt, *pelt;
HASH_FIND (hh, hashlin->buckets, old->key, old->keylen, node);
if (node != NULL) {
/* Direct replacement */
node->data = new;
node->hh.key = new->key;
node->hh.keylen = new->keylen;
if (hashlin == NULL) {
return;
}
if (hashlin->caseless) {
khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
hashlin->hash;
k = kh_put (ucl_hash_caseless_node, h, old, &ret);
if (ret == 0) {
elt = kh_value (h, k);
kh_del (ucl_hash_caseless_node, h, k);
k = kh_put (ucl_hash_caseless_node, h, new, &ret);
pelt = &kh_value (h, k);
pelt->obj = new;
pelt->ar_idx = elt.ar_idx;
kv_A (hashlin->ar, elt.ar_idx) = new;
}
}
else {
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
hashlin->hash;
k = kh_put (ucl_hash_node, h, old, &ret);
if (ret == 0) {
elt = kh_value (h, k);
kh_del (ucl_hash_node, h, k);
k = kh_put (ucl_hash_node, h, new, &ret);
pelt = &kh_value (h, k);
pelt->obj = new;
pelt->ar_idx = elt.ar_idx;
kv_A (hashlin->ar, elt.ar_idx) = new;
}
}
}
struct ucl_hash_real_iter {
const ucl_object_t **cur;
const ucl_object_t **end;
};
const void*
ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter)
{
ucl_hash_node_t *elt = *iter;
struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *)(*iter);
const ucl_object_t *ret = NULL;
if (elt == NULL) {
if (hashlin == NULL || hashlin->buckets == NULL) {
return NULL;
}
elt = hashlin->buckets;
if (elt == NULL) {
return NULL;
}
}
else if (elt == hashlin->buckets) {
if (hashlin == NULL) {
return NULL;
}
*iter = elt->hh.next ? elt->hh.next : hashlin->buckets;
return elt->data;
if (it == NULL) {
it = UCL_ALLOC (sizeof (*it));
it->cur = &hashlin->ar.a[0];
it->end = it->cur + hashlin->ar.n;
}
if (it->cur < it->end) {
ret = *it->cur++;
}
else {
UCL_FREE (sizeof (*it), it);
*iter = NULL;
return NULL;
}
*iter = it;
return ret;
}
bool
ucl_hash_iter_has_next (ucl_hash_iter_t iter)
ucl_hash_iter_has_next (ucl_hash_t *hashlin, ucl_hash_iter_t iter)
{
ucl_hash_node_t *elt = iter;
struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *)(iter);
return (elt == NULL || elt->hh.prev != NULL);
return it->cur < it->end - 1;
}
const ucl_object_t*
ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen)
{
ucl_hash_node_t *found;
khiter_t k;
const ucl_object_t *ret = NULL;
ucl_object_t search;
struct ucl_hash_elt *elt;
search.key = key;
search.keylen = keylen;
if (hashlin == NULL) {
return NULL;
}
HASH_FIND (hh, hashlin->buckets, key, keylen, found);
if (found) {
return found->data;
if (hashlin->caseless) {
khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
hashlin->hash;
k = kh_get (ucl_hash_caseless_node, h, &search);
if (k != kh_end (h)) {
elt = &kh_value (h, k);
ret = elt->obj;
}
}
return NULL;
else {
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
hashlin->hash;
k = kh_get (ucl_hash_node, h, &search);
if (k != kh_end (h)) {
elt = &kh_value (h, k);
ret = elt->obj;
}
}
return ret;
}
void
ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)
{
ucl_hash_node_t *found;
khiter_t k;
struct ucl_hash_elt *elt;
HASH_FIND (hh, hashlin->buckets, obj->key, obj->keylen, found);
if (hashlin == NULL) {
return;
}
if (found) {
HASH_DELETE (hh, hashlin->buckets, found);
UCL_FREE (sizeof (ucl_hash_node_t), found);
if (hashlin->caseless) {
khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
hashlin->hash;
k = kh_get (ucl_hash_caseless_node, h, obj);
if (k != kh_end (h)) {
elt = &kh_value (h, k);
kv_A (hashlin->ar, elt->ar_idx) = NULL;
kh_del (ucl_hash_caseless_node, h, k);
}
}
else {
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
hashlin->hash;
k = kh_get (ucl_hash_node, h, obj);
if (k != kh_end (h)) {
elt = &kh_value (h, k);
kv_A (hashlin->ar, elt->ar_idx) = NULL;
kh_del (ucl_hash_node, h, k);
}
}
}

View File

@ -25,15 +25,11 @@
#define __UCL_HASH_H
#include "ucl.h"
#include "uthash.h"
/******************************************************************************/
typedef struct ucl_hash_node_s
{
const ucl_object_t *data;
UT_hash_handle hh;
} ucl_hash_node_t;
struct ucl_hash_node_s;
typedef struct ucl_hash_node_s ucl_hash_node_t;
typedef int ucl_hash_cmp_func (const void* void_a, const void* void_b);
typedef void ucl_hash_free_func (void *ptr);
@ -43,16 +39,14 @@ typedef void* ucl_hash_iter_t;
/**
* Linear chained hashtable.
*/
typedef struct ucl_hash_struct
{
ucl_hash_node_t *buckets; /**< array of hash buckets. One list for each hash modulus. */
} ucl_hash_t;
struct ucl_hash_struct;
typedef struct ucl_hash_struct ucl_hash_t;
/**
* Initializes the hashtable.
*/
ucl_hash_t* ucl_hash_create (void);
ucl_hash_t* ucl_hash_create (bool ignore_case);
/**
* Deinitializes the hashtable.
@ -94,6 +88,6 @@ const void* ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter);
/**
* Check whether an iterator has next element
*/
bool ucl_hash_iter_has_next (ucl_hash_iter_t iter);
bool ucl_hash_iter_has_next (ucl_hash_t *hashlin, ucl_hash_iter_t iter);
#endif

View File

@ -339,14 +339,17 @@ ucl_hash_search_obj (ucl_hash_t* hashlin, ucl_object_t *obj)
return (const ucl_object_t *)ucl_hash_search (hashlin, obj->key, obj->keylen);
}
static inline ucl_hash_t *
ucl_hash_insert_object (ucl_hash_t *hashlin, const ucl_object_t *obj) UCL_WARN_UNUSED_RESULT;
static inline ucl_hash_t * ucl_hash_insert_object (ucl_hash_t *hashlin,
const ucl_object_t *obj,
bool ignore_case) UCL_WARN_UNUSED_RESULT;
static inline ucl_hash_t *
ucl_hash_insert_object (ucl_hash_t *hashlin, const ucl_object_t *obj)
ucl_hash_insert_object (ucl_hash_t *hashlin,
const ucl_object_t *obj,
bool ignore_case)
{
if (hashlin == NULL) {
hashlin = ucl_hash_create ();
hashlin = ucl_hash_create (ignore_case);
}
ucl_hash_insert (hashlin, obj, obj->key, obj->keylen);

View File

@ -570,7 +570,7 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra
else {
obj->type = UCL_OBJECT;
}
obj->value.ov = ucl_hash_create ();
obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
parser->state = UCL_STATE_KEY;
}
else {
@ -975,7 +975,7 @@ ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
else {
if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) {
/* Just add to the explicit array */
DL_APPEND (top->value.av, elt);
ucl_array_append (top, elt);
}
else {
/* Convert to an array */
@ -984,8 +984,8 @@ ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
nobj->key = top->key;
nobj->keylen = top->keylen;
nobj->flags |= UCL_OBJECT_MULTIVALUE;
DL_APPEND (nobj->value.av, top);
DL_APPEND (nobj->value.av, elt);
ucl_array_append (nobj, top);
ucl_array_append (nobj, elt);
ucl_hash_insert (cont, nobj, nobj->key, nobj->keylen);
}
}
@ -1016,6 +1016,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
ucl_chunk_skipc (chunk, p);
parser->prev_state = parser->state;
parser->state = UCL_STATE_MACRO_NAME;
*end_of_object = false;
return true;
}
while (p < chunk->end) {
@ -1195,7 +1196,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
nobj->keylen = keylen;
tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj));
if (tobj == NULL) {
container = ucl_hash_insert_object (container, nobj);
container = ucl_hash_insert_object (container, nobj,
parser->flags & UCL_PARSER_KEY_LOWERCASE);
nobj->prev = nobj;
nobj->next = NULL;
parser->stack->obj->len ++;
@ -1363,14 +1365,16 @@ ucl_get_value_object (struct ucl_parser *parser)
{
ucl_object_t *t, *obj = NULL;
if (parser == NULL || parser->stack == NULL || parser->stack->obj == NULL) {
return NULL;
}
if (parser->stack->obj->type == UCL_ARRAY) {
/* Object must be allocated */
obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
t = parser->stack->obj->value.av;
DL_APPEND (t, obj);
t = parser->stack->obj;
ucl_array_append (t, obj);
parser->cur_obj = obj;
parser->stack->obj->value.av = t;
parser->stack->obj->len ++;
}
else {
/* Object has been already allocated */

View File

@ -525,15 +525,16 @@ ucl_schema_validate_array (const ucl_object_t *schema,
ucl_object_iter_t iter = NULL, piter = NULL;
bool ret = true, allow_additional = true, need_unique = false;
int64_t minmax;
unsigned int idx = 0;
while (ret && (elt = ucl_iterate_object (schema, &iter, true)) != NULL) {
if (strcmp (ucl_object_key (elt), "items") == 0) {
if (elt->type == UCL_ARRAY) {
found = obj->value.av;
found = ucl_array_head (obj);
while (ret && (it = ucl_iterate_object (elt, &piter, true)) != NULL) {
if (found) {
ret = ucl_schema_validate (it, found, false, err, root);
found = found->next;
found = ucl_array_find_index (obj, ++idx);
}
}
if (found != NULL) {
@ -608,14 +609,14 @@ ucl_schema_validate_array (const ucl_object_t *schema,
ret = false;
}
else if (additional_schema != NULL) {
elt = first_unvalidated;
elt = ucl_array_find_index (obj, idx);
while (elt) {
if (!ucl_schema_validate (additional_schema, elt, false,
err, root)) {
ret = false;
break;
}
elt = elt->next;
elt = ucl_array_find_index (obj, idx ++);
}
}
}
@ -741,7 +742,7 @@ ucl_schema_resolve_ref_component (const ucl_object_t *cur,
"reference %s is invalid, invalid item number", refc);
return NULL;
}
res = cur->value.av;
res = ucl_array_head (cur);
i = 0;
while (res != NULL) {
if (i == num) {

View File

@ -24,13 +24,21 @@
#include "ucl.h"
#include "ucl_internal.h"
#include "ucl_chartable.h"
#include "kvec.h"
#ifndef _WIN32
#include <glob.h>
#endif
#ifdef HAVE_LIBGEN_H
#include <libgen.h> /* For dirname */
#endif
typedef kvec_t(ucl_object_t *) ucl_array_t;
#define UCL_ARRAY_GET(ar, obj) ucl_array_t *ar = \
(ucl_array_t *)((obj) != NULL ? (obj)->value.av : NULL)
#ifdef HAVE_OPENSSL
#include <openssl/err.h>
#include <openssl/sha.h>
@ -68,6 +76,11 @@
#define MAP_FAILED ((void *) -1)
#endif
#ifdef _WIN32
#include <limits.h>
#define NBBY CHAR_BIT
#endif
static void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset)
{
void *map = NULL;
@ -195,15 +208,27 @@ ucl_object_dtor_unref (ucl_object_t *obj)
static void
ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor)
{
ucl_object_t *sub, *tmp;
ucl_object_t *tmp, *sub;
while (obj != NULL) {
if (obj->type == UCL_ARRAY) {
sub = obj->value.av;
while (sub != NULL) {
tmp = sub->next;
dtor (sub);
sub = tmp;
UCL_ARRAY_GET (vec, obj);
unsigned int i;
if (vec != NULL) {
for (i = 0; i < vec->n; i ++) {
sub = kv_A (*vec, i);
if (sub != NULL) {
tmp = sub;
while (sub) {
tmp = sub->next;
dtor (sub);
sub = tmp;
}
}
}
kv_destroy (*vec);
UCL_FREE (sizeof (*vec), vec);
}
}
else if (obj->type == UCL_OBJECT) {
@ -455,6 +480,15 @@ ucl_parser_get_error(struct ucl_parser *parser)
return utstring_body(parser->err);
}
UCL_EXTERN void
ucl_parser_clear_error(struct ucl_parser *parser)
{
if (parser != NULL && parser->err != NULL) {
utstring_free(parser->err);
parser->err = NULL;
}
}
UCL_EXTERN bool
ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
{
@ -933,10 +967,10 @@ ucl_include_file (const unsigned char *data, size_t len,
const unsigned char *p = data, *end = data + len;
bool need_glob = false;
int cnt = 0;
glob_t globbuf;
char glob_pattern[PATH_MAX];
size_t i;
#ifndef _WIN32
if (!allow_glob) {
return ucl_include_file_single (data, len, parser, check_signature,
must_exist, priority);
@ -951,6 +985,7 @@ ucl_include_file (const unsigned char *data, size_t len,
p ++;
}
if (need_glob) {
glob_t globbuf;
memset (&globbuf, 0, sizeof (globbuf));
ucl_strlcpy (glob_pattern, (const char *)data, sizeof (glob_pattern));
if (glob (glob_pattern, 0, NULL, &globbuf) != 0) {
@ -978,7 +1013,13 @@ ucl_include_file (const unsigned char *data, size_t len,
must_exist, priority);
}
}
#else
/* Win32 compilers do not support globbing. Therefore, for Win32,
treat allow_glob/need_glob as a NOOP and just return */
return ucl_include_file_single (data, len, parser, check_signature,
must_exist, priority);
#endif
return true;
}
@ -1394,7 +1435,7 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
}
if (top->value.ov == NULL) {
top->value.ov = ucl_hash_create ();
top->value.ov = ucl_hash_create (false);
}
if (keylen == 0) {
@ -1427,7 +1468,7 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt));
if (found == NULL) {
top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false);
top->len ++;
if (replace) {
ret = false;
@ -1444,7 +1485,7 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
ucl_object_insert_key_common (elt, found, found->key,
found->keylen, copy_key, false, false);
ucl_hash_delete (top->value.ov, found);
top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false);
}
else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) {
/* Insert new to old */
@ -1568,7 +1609,7 @@ ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen));
if (found == NULL) {
/* The key does not exist */
top->value.ov = ucl_hash_insert_object (top->value.ov, cp);
top->value.ov = ucl_hash_insert_object (top->value.ov, cp, false);
top->len ++;
}
else {
@ -1610,7 +1651,7 @@ ucl_object_find_key (const ucl_object_t *obj, const char *key)
const ucl_object_t*
ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values)
{
const ucl_object_t *elt;
const ucl_object_t *elt = NULL;
if (obj == NULL || iter == NULL) {
return NULL;
@ -1621,19 +1662,25 @@ ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expan
case UCL_OBJECT:
return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter);
break;
case UCL_ARRAY:
elt = *iter;
if (elt == NULL) {
elt = obj->value.av;
if (elt == NULL) {
return NULL;
case UCL_ARRAY: {
unsigned int idx;
UCL_ARRAY_GET (vec, obj);
idx = (unsigned int)(uintptr_t)(*iter);
if (vec != NULL) {
while (idx < kv_size (*vec)) {
if ((elt = kv_A (*vec, idx)) != NULL) {
idx ++;
break;
}
idx ++;
}
*iter = (void *)(uintptr_t)idx;
}
else if (elt == obj->value.av) {
return NULL;
}
*iter = elt->next ? elt->next : obj->value.av;
return elt;
break;
}
default:
/* Go to linear iteration */
break;
@ -1654,6 +1701,95 @@ ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expan
return NULL;
}
const char safe_iter_magic[4] = {'u', 'i', 't', 'e'};
struct ucl_object_safe_iter {
char magic[4]; /* safety check */
const ucl_object_t *impl_it; /* implicit object iteration */
ucl_object_iter_t expl_it; /* explicit iteration */
};
#define UCL_SAFE_ITER(ptr) (struct ucl_object_safe_iter *)(ptr)
#define UCL_SAFE_ITER_CHECK(it) do { \
assert (it != NULL); \
assert (memcmp (it->magic, safe_iter_magic, sizeof (it->magic)) == 0); \
} while (0)
ucl_object_iter_t
ucl_object_iterate_new (const ucl_object_t *obj)
{
struct ucl_object_safe_iter *it;
it = UCL_ALLOC (sizeof (*it));
if (it != NULL) {
memcpy (it->magic, safe_iter_magic, sizeof (it->magic));
it->expl_it = NULL;
it->impl_it = obj;
}
return (ucl_object_iter_t)it;
}
ucl_object_iter_t
ucl_object_iterate_reset (ucl_object_iter_t it, const ucl_object_t *obj)
{
struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
UCL_SAFE_ITER_CHECK (rit);
rit->impl_it = obj;
rit->expl_it = NULL;
return it;
}
const ucl_object_t*
ucl_object_iterate_safe (ucl_object_iter_t it, bool expand_values)
{
struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
const ucl_object_t *ret = NULL;
UCL_SAFE_ITER_CHECK (rit);
if (rit->impl_it == NULL) {
return NULL;
}
if (rit->impl_it->type == UCL_OBJECT || rit->impl_it->type == UCL_ARRAY) {
ret = ucl_iterate_object (rit->impl_it, &rit->expl_it, true);
if (ret == NULL) {
/* Need to switch to another implicit object in chain */
rit->impl_it = rit->impl_it->next;
rit->expl_it = NULL;
return ucl_object_iterate_safe (it, expand_values);
}
}
else {
/* Just iterate over the implicit array */
ret = rit->impl_it;
rit->impl_it = rit->impl_it->next;
if (expand_values) {
/* We flatten objects if need to expand values */
if (ret->type == UCL_OBJECT || ret->type == UCL_ARRAY) {
return ucl_object_iterate_safe (it, expand_values);
}
}
}
return ret;
}
void
ucl_object_iterate_free (ucl_object_iter_t it)
{
struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
UCL_SAFE_ITER_CHECK (rit);
UCL_FREE (sizeof (*rit), it);
}
const ucl_object_t *
ucl_lookup_path (const ucl_object_t *top, const char *path_in) {
const ucl_object_t *o = NULL, *found;
@ -1733,6 +1869,17 @@ ucl_object_new_full (ucl_type_t type, unsigned priority)
new->next = NULL;
new->prev = new;
ucl_object_set_priority (new, priority);
if (type == UCL_ARRAY) {
new->value.av = UCL_ALLOC (sizeof (ucl_array_t));
if (new->value.av) {
memset (new->value.av, 0, sizeof (ucl_array_t));
UCL_ARRAY_GET (vec, new);
/* Preallocate some space for arrays */
kv_resize (ucl_object_t *, *vec, 8);
}
}
}
}
else {
@ -1826,23 +1973,20 @@ ucl_object_frombool (bool bv)
bool
ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
{
ucl_object_t *head;
UCL_ARRAY_GET (vec, top);
if (elt == NULL || top == NULL) {
return false;
}
head = top->value.av;
if (head == NULL) {
top->value.av = elt;
elt->prev = elt;
if (vec == NULL) {
vec = UCL_ALLOC (sizeof (*vec));
kv_init (*vec);
top->value.av = (void *)vec;
}
else {
elt->prev = head->prev;
head->prev->next = elt;
head->prev = elt;
}
elt->next = NULL;
kv_push (ucl_object_t *, *vec, elt);
top->len ++;
return true;
@ -1851,24 +1995,23 @@ ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
bool
ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
{
ucl_object_t *head;
UCL_ARRAY_GET (vec, top);
if (elt == NULL || top == NULL) {
return false;
}
head = top->value.av;
if (head == NULL) {
top->value.av = elt;
elt->prev = elt;
if (vec == NULL) {
vec = UCL_ALLOC (sizeof (*vec));
kv_init (*vec);
top->value.av = (void *)vec;
kv_push (ucl_object_t *, *vec, elt);
}
else {
elt->prev = head->prev;
head->prev = elt;
/* Slow O(n) algorithm */
kv_prepend (ucl_object_t *, *vec, elt);
}
elt->next = head;
top->value.av = elt;
top->len ++;
return true;
@ -1877,21 +2020,29 @@ ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
bool
ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
{
ucl_object_t *cur, *tmp, *cp;
unsigned i;
ucl_object_t **obj;
UCL_ARRAY_GET (v1, top);
UCL_ARRAY_GET (v2, elt);
if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) {
return false;
}
DL_FOREACH_SAFE (elt->value.av, cur, tmp) {
kv_concat (ucl_object_t *, *v1, *v2);
for (i = v2->n; i < v1->n; i ++) {
obj = &kv_A (*v1, i);
if (*obj == NULL) {
continue;
}
top->len ++;
if (copy) {
cp = ucl_object_copy (cur);
*obj = ucl_object_copy (*obj);
}
else {
cp = ucl_object_ref (cur);
}
if (cp != NULL) {
ucl_array_append (top, cp);
ucl_object_ref (*obj);
}
}
@ -1901,82 +2052,85 @@ ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
ucl_object_t *
ucl_array_delete (ucl_object_t *top, ucl_object_t *elt)
{
ucl_object_t *head;
UCL_ARRAY_GET (vec, top);
ucl_object_t *ret = NULL;
unsigned i;
if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
return NULL;
}
head = top->value.av;
if (elt->prev == elt) {
top->value.av = NULL;
}
else if (elt == head) {
elt->next->prev = elt->prev;
top->value.av = elt->next;
}
else {
elt->prev->next = elt->next;
if (elt->next) {
elt->next->prev = elt->prev;
}
else {
head->prev = elt->prev;
for (i = 0; i < vec->n; i ++) {
if (kv_A (*vec, i) == elt) {
kv_del (ucl_object_t *, *vec, i);
ret = elt;
top->len --;
break;
}
}
elt->next = NULL;
elt->prev = elt;
top->len --;
return elt;
return ret;
}
const ucl_object_t *
ucl_array_head (const ucl_object_t *top)
{
UCL_ARRAY_GET (vec, top);
if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
return NULL;
}
return top->value.av;
return (vec->n > 0 ? vec->a[0] : NULL);
}
const ucl_object_t *
ucl_array_tail (const ucl_object_t *top)
{
UCL_ARRAY_GET (vec, top);
if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
return NULL;
}
return top->value.av->prev;
return (vec->n > 0 ? vec->a[vec->n - 1] : NULL);
}
ucl_object_t *
ucl_array_pop_last (ucl_object_t *top)
{
return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_tail (top)));
UCL_ARRAY_GET (vec, top);
ucl_object_t **obj, *ret = NULL;
if (vec != NULL && vec->n > 0) {
obj = &kv_A (*vec, vec->n - 1);
ret = *obj;
kv_del (ucl_object_t *, *vec, vec->n - 1);
top->len --;
}
return ret;
}
ucl_object_t *
ucl_array_pop_first (ucl_object_t *top)
{
return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_head (top)));
UCL_ARRAY_GET (vec, top);
ucl_object_t **obj, *ret = NULL;
if (vec != NULL && vec->n > 0) {
obj = &kv_A (*vec, 0);
ret = *obj;
kv_del (ucl_object_t *, *vec, 0);
top->len --;
}
return ret;
}
const ucl_object_t *
ucl_array_find_index (const ucl_object_t *top, unsigned int index)
{
ucl_object_iter_t it = NULL;
const ucl_object_t *ret;
UCL_ARRAY_GET (vec, top);
if (top == NULL || top->type != UCL_ARRAY || top->len == 0 ||
(index + 1) > top->len) {
return NULL;
}
while ((ret = ucl_iterate_object (top, &it, true)) != NULL) {
if (index == 0) {
return ret;
}
--index;
if (vec != NULL && vec->n > 0 && index < vec->n) {
return kv_A (*vec, index);
}
return NULL;
@ -1986,22 +2140,15 @@ ucl_object_t *
ucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt,
unsigned int index)
{
ucl_object_t *cur, *tmp;
UCL_ARRAY_GET (vec, top);
ucl_object_t *ret = NULL;
if (top == NULL || top->type != UCL_ARRAY || elt == NULL ||
top->len == 0 || (index + 1) > top->len) {
return NULL;
if (vec != NULL && vec->n > 0 && index < vec->n) {
ret = kv_A (*vec, index);
kv_A (*vec, index) = elt;
}
DL_FOREACH_SAFE (top->value.av, cur, tmp) {
if (index == 0) {
DL_REPLACE_ELEM (top->value.av, cur, elt);
return cur;
}
--index;
}
return NULL;
return ret;
}
ucl_object_t *
@ -2314,7 +2461,7 @@ ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)
switch (o1->type) {
case UCL_STRING:
if (o1->len == o2->len) {
if (o1->len == o2->len && o1->len > 0) {
ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2));
}
else {
@ -2330,17 +2477,28 @@ ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)
ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2);
break;
case UCL_ARRAY:
if (o1->len == o2->len) {
it1 = o1->value.av;
it2 = o2->value.av;
if (o1->len == o2->len && o1->len > 0) {
UCL_ARRAY_GET (vec1, o1);
UCL_ARRAY_GET (vec2, o2);
unsigned i;
/* Compare all elements in both arrays */
while (it1 != NULL && it2 != NULL) {
ret = ucl_object_compare (it1, it2);
if (ret != 0) {
break;
for (i = 0; i < vec1->n; i ++) {
it1 = kv_A (*vec1, i);
it2 = kv_A (*vec2, i);
if (it1 == NULL && it2 != NULL) {
return -1;
}
else if (it2 == NULL && it1 != NULL) {
return 1;
}
else if (it1 != NULL && it2 != NULL) {
ret = ucl_object_compare (it1, it2);
if (ret != 0) {
break;
}
}
it1 = it1->next;
it2 = it2->next;
}
}
else {
@ -2348,7 +2506,7 @@ ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)
}
break;
case UCL_OBJECT:
if (o1->len == o2->len) {
if (o1->len == o2->len && o1->len > 0) {
while ((it1 = ucl_iterate_object (o1, &iter, true)) != NULL) {
it2 = ucl_object_find_key (o2, ucl_object_key (it1));
if (it2 == NULL) {
@ -2377,11 +2535,14 @@ void
ucl_object_array_sort (ucl_object_t *ar,
int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2))
{
UCL_ARRAY_GET (vec, ar);
if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) {
return;
}
DL_SORT (ar->value.av, cmp);
qsort (vec->a, vec->n, sizeof (ucl_object_t *),
(int (*)(const void *, const void *))cmp);
}
#define PRIOBITS 4

View File

@ -0,0 +1,8 @@
# Bad comments case
section {
# key = value;
}
.include(try=true) "./1.in"
key = value;

View File

@ -0,0 +1,4 @@
section {
}
key = "value";

View File

@ -5,5 +5,5 @@ rm /tmp/_ucl_test_schema.out ||true
for i in ${TEST_DIR}/schema/*.json ; do
_name=`basename $i`
printf "running schema test suite $_name... "
$PROG >> /tmp/_ucl_test_schema.out < $i && ( echo "OK" ) || ( echo "Fail" )
$PROG >> /tmp/_ucl_test_schema.out < $i && ( echo "OK" ) || ( echo "Fail" ; exit 1 )
done

View File

@ -30,7 +30,8 @@ int
main (int argc, char **argv)
{
ucl_object_t *obj, *cur, *ar, *ref;
const ucl_object_t *found;
ucl_object_iter_t it;
const ucl_object_t *found, *it_obj;
FILE *out;
unsigned char *emitted;
const char *fname_out = NULL;
@ -59,7 +60,7 @@ main (int argc, char **argv)
cur = ucl_object_fromstring_common ("value1", 0, UCL_STRING_TRIM);
ucl_object_insert_key (obj, cur, "key0", 0, false);
cur = ucl_object_fromdouble (0.1);
ucl_object_replace_key (obj, cur, "key0", 0, false);
assert (ucl_object_replace_key (obj, cur, "key0", 0, false));
/* Create some strings */
cur = ucl_object_fromstring_common (" test string ", 0, UCL_STRING_TRIM);
@ -139,6 +140,33 @@ main (int argc, char **argv)
found = ucl_lookup_path (obj, "key9..key1");
assert (found == NULL);
/* Test iteration */
it = ucl_object_iterate_new (obj);
it_obj = ucl_object_iterate_safe (it, true);
/* key0 = 0.1 */
assert (ucl_object_type (it_obj) == UCL_FLOAT);
it_obj = ucl_object_iterate_safe (it, true);
/* key1 = "" */
assert (ucl_object_type (it_obj) == UCL_STRING);
it_obj = ucl_object_iterate_safe (it, true);
/* key2 = "" */
assert (ucl_object_type (it_obj) == UCL_STRING);
it_obj = ucl_object_iterate_safe (it, true);
/* key3 = "" */
assert (ucl_object_type (it_obj) == UCL_STRING);
it_obj = ucl_object_iterate_safe (it, true);
/* key4 = ([float, int, float], boolean) */
ucl_object_iterate_reset (it, it_obj);
it_obj = ucl_object_iterate_safe (it, true);
assert (ucl_object_type (it_obj) == UCL_FLOAT);
it_obj = ucl_object_iterate_safe (it, true);
assert (ucl_object_type (it_obj) == UCL_INT);
it_obj = ucl_object_iterate_safe (it, true);
assert (ucl_object_type (it_obj) == UCL_FLOAT);
it_obj = ucl_object_iterate_safe (it, true);
assert (ucl_object_type (it_obj) == UCL_BOOLEAN);
ucl_object_iterate_free (it);
emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG);
fprintf (out, "%s\n", emitted);

View File

@ -79,6 +79,8 @@ perform_test (const ucl_object_t *schema, const ucl_object_t *obj,
ucl_object_tostring (description),
ucl_object_toboolean (valid) ? "valid" : "invalid",
err->msg);
fprintf (stdout, "%s\n", ucl_object_emit (data, UCL_EMIT_CONFIG));
fprintf (stdout, "%s\n", ucl_object_emit (schema, UCL_EMIT_CONFIG));
return false;
}

View File

@ -39,7 +39,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdarg.h>
#ifndef oom
#define oom() exit(-1)
#define oom abort
#endif
typedef struct {
@ -54,8 +54,8 @@ do { \
if (((s)->n - (s)->i) < (size_t)(amt)) { \
(s)->d = (char*)realloc((s)->d, (s)->n + amt); \
if ((s)->d == NULL) oom(); \
(s)->n += amt; \
if ((s)->pd) *((s)->pd) = (s)->d; \
else {(s)->n += amt; \
if ((s)->pd) *((s)->pd) = (s)->d;} \
} \
} while(0)
@ -82,7 +82,7 @@ do { \
do { \
s = (UT_string*)calloc(1, sizeof(UT_string)); \
if (!s) oom(); \
utstring_init(s); \
else utstring_init(s); \
} while(0)
#define utstring_renew(s) \

View File

@ -46,7 +46,7 @@ ucl_obj_dump (const ucl_object_t *obj, unsigned int shift)
if (obj->key != NULL) {
printf ("%skey: \"%s\"\n", pre, ucl_object_key (obj));
}
printf ("%sref: %hd\n", pre, obj->ref);
printf ("%sref: %u\n", pre, obj->ref);
printf ("%slen: %u\n", pre, obj->len);
printf ("%sprev: %p\n", pre, obj->prev);
printf ("%snext: %p\n", pre, obj->next);
@ -61,7 +61,10 @@ ucl_obj_dump (const ucl_object_t *obj, unsigned int shift)
else if (obj->type == UCL_ARRAY) {
printf ("%stype: UCL_ARRAY\n", pre);
printf ("%svalue: %p\n", pre, obj->value.av);
ucl_obj_dump (obj->value.av, shift + 2);
it_obj = NULL;
while ((cur = ucl_iterate_object (obj, &it_obj, true))) {
ucl_obj_dump (cur, shift + 2);
}
}
else if (obj->type == UCL_INT) {
printf ("%stype: UCL_INT\n", pre);
@ -96,7 +99,7 @@ int
main(int argc, char **argv)
{
const char *fn = NULL;
char inbuf[8192];
unsigned char inbuf[8192];
struct ucl_parser *parser;
int k, ret = 0, r = 0;
ucl_object_t *obj = NULL;

View File

@ -18,9 +18,10 @@ SRCS= ucl_emitter_streamline.c \
LIBADD= m
WARNS= 1
WARNS= 2
CFLAGS+= -I${LIBUCL}/include \
-I${LIBUCL}/src \
-I${LIBUCL}/uthash
-I${LIBUCL}/uthash \
-I${LIBUCL}/klib
.include <bsd.lib.mk>