aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaptiste Daroussin <bapt@FreeBSD.org>2015-03-02 21:35:31 +0000
committerBaptiste Daroussin <bapt@FreeBSD.org>2015-03-02 21:35:31 +0000
commit513f8791d85bbaf75cea6a942f689a9fc128805e (patch)
treeec41d84b201fb3620a1d96fc8d2c7fd86cef6b63
parent1eea90048f8f0e6360171d254c1f60f41a090814 (diff)
downloadsrc-513f8791d85bbaf75cea6a942f689a9fc128805e.tar.gz
src-513f8791d85bbaf75cea6a942f689a9fc128805e.zip
Update libucl to git version 8d3b186
Notes
Notes: svn path=/vendor/libucl/dist/; revision=279546
-rw-r--r--ChangeLog.md12
-rw-r--r--Makefile.am2
-rw-r--r--README.md16
-rw-r--r--cmake/CMakeLists.txt1
-rw-r--r--configure.ac6
-rw-r--r--doc/Makefile.am3
-rw-r--r--doc/api.md58
-rw-r--r--doc/libucl.376
-rw-r--r--doc/pandoc.template2
-rw-r--r--include/ucl.h40
-rw-r--r--klib/khash.h627
-rw-r--r--klib/kvec.h103
-rw-r--r--m4/.gitignore4
-rw-r--r--m4/ax_lua.m4606
-rw-r--r--src/Makefile.am1
-rw-r--r--src/ucl_emitter.c17
-rw-r--r--src/ucl_emitter_utils.c1
-rw-r--r--src/ucl_hash.c312
-rw-r--r--src/ucl_hash.h18
-rw-r--r--src/ucl_internal.h11
-rw-r--r--src/ucl_parser.c22
-rw-r--r--src/ucl_schema.c11
-rw-r--r--src/ucl_util.c393
-rw-r--r--tests/basic/14.in8
-rw-r--r--tests/basic/14.res4
-rwxr-xr-xtests/schema.test2
-rw-r--r--tests/test_generate.c32
-rw-r--r--tests/test_schema.c2
-rw-r--r--uthash/utstring.h8
29 files changed, 1560 insertions, 838 deletions
diff --git a/ChangeLog.md b/ChangeLog.md
index 0df5e072222e..093ff97a842d 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -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
diff --git a/Makefile.am b/Makefile.am
index ece5b97df488..957e3a2b0f3c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
diff --git a/README.md b/README.md
index 235cfb6595df..797278ba932a 100644
--- a/README.md
+++ b/README.md
@@ -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
+ ....
};
```
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index 3c57db53784a..e84f61905c58 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -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
diff --git a/configure.ac b/configure.ac
index 32db73ad0fdd..be6f6522f121 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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])
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 7e57a829f807..a90a6fa44cc6 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -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 \ No newline at end of file
diff --git a/doc/api.md b/doc/api.md
index 174c7ff47060..75b954bb302c 100644
--- a/doc/api.md
+++ b/doc/api.md
@@ -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:
diff --git a/doc/libucl.3 b/doc/libucl.3
index e319a0d3f932..ec5046325700 100644
--- a/doc/libucl.3
+++ b/doc/libucl.3
@@ -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
diff --git a/doc/pandoc.template b/doc/pandoc.template
index 6d5f0277ae40..2effe1a157ef 100644
--- a/doc/pandoc.template
+++ b/doc/pandoc.template
@@ -1,6 +1,6 @@
% LIBUCL(3) Libucl manual
% Vsevolod Stakhov <vsevolod@highsecure.ru>
-% July 26, 2014
+% %%date%%
# Name
diff --git a/include/ucl.h b/include/ucl.h
index 1aac6a25332c..823ac8d3bfc9 100644
--- a/include/ucl.h
+++ b/include/ucl.h
@@ -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
diff --git a/klib/khash.h b/klib/khash.h
new file mode 100644
index 000000000000..afc3ce3ef0dc
--- /dev/null
+++ b/klib/khash.h
@@ -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 */
diff --git a/klib/kvec.h b/klib/kvec.h
new file mode 100644
index 000000000000..b5cce8508f8e
--- /dev/null
+++ b/klib/kvec.h
@@ -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
diff --git a/m4/.gitignore b/m4/.gitignore
deleted file mode 100644
index 5e7d2734cfc6..000000000000
--- a/m4/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-# Ignore everything in this directory
-*
-# Except this file
-!.gitignore
diff --git a/m4/ax_lua.m4 b/m4/ax_lua.m4
deleted file mode 100644
index 7662f4f22d1b..000000000000
--- a/m4/ax_lua.m4
+++ /dev/null
@@ -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])
-])
diff --git a/src/Makefile.am b/src/Makefile.am
index 417d34e161ca..c3f0c9fffb60 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -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 \
diff --git a/src/ucl_emitter.c b/src/ucl_emitter.c
index 8134d09c1a65..9ddf3584a25b 100644
--- a/src/ucl_emitter.c
+++ b/src/ucl_emitter.c
@@ -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;
- }
+
}
/**
diff --git a/src/ucl_emitter_utils.c b/src/ucl_emitter_utils.c
index da412097ffbc..91cad78bcbf6 100644
--- a/src/ucl_emitter_utils.c
+++ b/src/ucl_emitter_utils.c
@@ -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);
diff --git a/src/ucl_hash.c b/src/ucl_hash.c
index ea55491ed504..275e84d478aa 100644
--- a/src/ucl_hash.c
+++ b/src/ucl_hash.c
@@ -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;
-
- 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));
+ const ucl_object_t *cur, *tmp;
+
+ 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;
+
+ if (hashlin == NULL) {
+ return;
+ }
- node = UCL_ALLOC (sizeof (ucl_hash_node_t));
- node->data = obj;
- HASH_ADD_KEYPTR (hh, hashlin->buckets, key, keylen, node);
+ 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;
- }
+ if (hashlin == NULL) {
+ return NULL;
+ }
+
+ 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 if (elt == hashlin->buckets) {
+ else {
+ UCL_FREE (sizeof (*it), it);
+ *iter = NULL;
return NULL;
}
- *iter = elt->hh.next ? elt->hh.next : hashlin->buckets;
- return elt->data;
+ *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);
+ }
}
}
diff --git a/src/ucl_hash.h b/src/ucl_hash.h
index ddbfdba19ce8..64c83eac8bc1 100644
--- a/src/ucl_hash.h
+++ b/src/ucl_hash.h
@@ -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
diff --git a/src/ucl_internal.h b/src/ucl_internal.h
index 2f75872b7bb8..bdbe691d092b 100644
--- a/src/ucl_internal.h
+++ b/src/ucl_internal.h
@@ -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);
diff --git a/src/ucl_parser.c b/src/ucl_parser.c
index 0d118d84b75a..75acba8ecbd3 100644
--- a/src/ucl_parser.c
+++ b/src/ucl_parser.c
@@ -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 */
diff --git a/src/ucl_schema.c b/src/ucl_schema.c
index faffe8613ce7..834b62accb5f 100644
--- a/src/ucl_schema.c
+++ b/src/ucl_schema.c
@@ -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) {
diff --git a/src/ucl_util.c b/src/ucl_util.c
index 41702e941f5b..41e012bf15bb 100644
--- a/src/ucl_util.c
+++ b/src/ucl_util.c
@@ -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;
-
- if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
- return NULL;
- }
- head = top->value.av;
+ UCL_ARRAY_GET (vec, top);
+ ucl_object_t *ret = NULL;
+ unsigned i;
- 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;
-
- if (top == NULL || top->type != UCL_ARRAY || top->len == 0 ||
- (index + 1) > top->len) {
- return NULL;
- }
+ UCL_ARRAY_GET (vec, top);
- 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
diff --git a/tests/basic/14.in b/tests/basic/14.in
new file mode 100644
index 000000000000..62d2e6059296
--- /dev/null
+++ b/tests/basic/14.in
@@ -0,0 +1,8 @@
+# Bad comments case
+
+section {
+# key = value;
+}
+.include(try=true) "./1.in"
+
+key = value;
diff --git a/tests/basic/14.res b/tests/basic/14.res
new file mode 100644
index 000000000000..f803349a6000
--- /dev/null
+++ b/tests/basic/14.res
@@ -0,0 +1,4 @@
+section {
+}
+key = "value";
+
diff --git a/tests/schema.test b/tests/schema.test
index 0f2c252945c7..fd26804fa295 100755
--- a/tests/schema.test
+++ b/tests/schema.test
@@ -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
diff --git a/tests/test_generate.c b/tests/test_generate.c
index aad92b51fb0e..f09eabb839fe 100644
--- a/tests/test_generate.c
+++ b/tests/test_generate.c
@@ -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);
diff --git a/tests/test_schema.c b/tests/test_schema.c
index 7acebb84b934..4f075dae8d68 100644
--- a/tests/test_schema.c
+++ b/tests/test_schema.c
@@ -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;
}
diff --git a/uthash/utstring.h b/uthash/utstring.h
index f11f34b77e75..b4399484c70e 100644
--- a/uthash/utstring.h
+++ b/uthash/utstring.h
@@ -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) \