diff --git a/BASE.md b/BASE.md
new file mode 100644
index 0000000..fd27fb9
--- /dev/null
+++ b/BASE.md
@@ -0,0 +1,157 @@
+# EJDB 2.0
+
+[](https://tlg.name/ejdb2)
+[](https://github.com/Softmotions/ejdb/blob/master/LICENSE)
+
+
+EJDB2 is an embeddable JSON database engine published under MIT license.
+
+[The Story of the IT-depression, birds and EJDB 2.0](https://medium.com/@adamansky/ejdb2-41670e80897c)
+
+* C11 API
+* Single file database
+* Online backups support
+* 500K library size for Android
+* [iOS](https://github.com/Softmotions/EJDB2Swift) / [Android](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_android/test) / [React Native](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_react_native) / [Flutter](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_flutter) integration
+* Simple but powerful query language (JQL) as well as support of the following standards:
+ * [rfc6902](https://tools.ietf.org/html/rfc6902) JSON Patch
+ * [rfc7386](https://tools.ietf.org/html/rfc7386) JSON Merge patch
+ * [rfc6901](https://tools.ietf.org/html/rfc6901) JSON Path
+* [Support of collection joins](#jql-collection-joins)
+* Powered by [iowow.io](http://iowow.io) - The persistent key/value storage engine
+* Provides HTTP REST/Websockets network endpoints with help of [facil.io](http://facil.io)
+* JSON documents are stored in using fast and compact [binn](https://github.com/liteserver/binn) binary format
+
+---
+* [Native language bindings](#native-language-bindings)
+* Supported platforms
+ * [OSX](#osx)
+ * [iOS](https://github.com/Softmotions/EJDB2Swift)
+ * [Linux](#linux)
+ * [Android](#android)
+ * [Windows](#windows)
+* **[JQL query language](#jql)**
+ * [Grammar](#jql-grammar)
+ * [Quick into](#jql-quick-introduction)
+ * [Data modification](#jql-data-modification)
+ * [Projections](#jql-projections)
+ * [Collection joins](#jql-collection-joins)
+ * [Sorting](#jql-sorting)
+ * [Query options](#jql-options)
+* [Indexes and performance](#jql-indexes-and-performance-tips)
+* [Network API](#http-restwebsocket-api-endpoint)
+ * [HTTP API](#http-api)
+ * [Websockets API](#websocket-api)
+* [C API](#c-api)
+* [License](#license)
+---
+
+## EJDB2 platforms matrix
+
+| | Linux | macOS | iOS | Android | Windows |
+| --- | --- | --- | --- | --- | --- |
+| C library | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark:1 |
+| NodeJS | :heavy_check_mark: | :heavy_check_mark: | | | :x:3 |
+| DartVM | :heavy_check_mark: | :heavy_check_mark:2 | | | :x:3 |
+| Flutter | | | :heavy_check_mark: | :heavy_check_mark: | |
+| React Native | | | :x:4 | :heavy_check_mark: | |
+| Swift | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | |
+| Java | :heavy_check_mark: | :heavy_check_mark: | | :heavy_check_mark: | :heavy_check_mark:2 |
+
+
+ `[1]` No HTTP/Websocket support [#257](https://github.com/Softmotions/ejdb/issues/257)
+ `[2]` Binaries are not distributed with dart `pub.` You can build it [manually](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_node#how-build-it-manually)
+ `[3]` Can be build, but needed a linkage with windows node/dart `libs`.
+ `[4]` Porting in progress [#273](https://github.com/Softmotions/ejdb/issues/273)
+
+
+## Native language bindings
+
+* [NodeJS](https://www.npmjs.com/package/ejdb2_node)
+* [Dart](https://pub.dartlang.org/packages/ejdb2_dart)
+* [Java](https://github.com/Softmotions/ejdb/blob/master/src/bindings/ejdb2_jni/README.md)
+* [Android support](#android)
+* [Swift | iOS](https://github.com/Softmotions/EJDB2Swift)
+* [React Native](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_react_native)
+* [Flutter](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_flutter)
+
+### Unofficial EJDB2 language bindings
+
+* .Net
+ * https://github.com/kmvi/ejdb2-csharp
+* Haskell
+ * https://github.com/cescobaz/ejdb2haskell
+ * https://hackage.haskell.org/package/ejdb2-binding
+* [Pharo](https://pharo.org)
+ * https://github.com/pharo-nosql/pharo-ejdb
+* Lua
+ * https://github.com/chriku/ejdb-lua
+
+## Status
+
+* **EJDB 2.0 core engine is well tested and used in various heavily loaded deployments**
+* Tested on `Linux` and `OSX` platforms. [Limited Windows support](./WINDOWS.md)
+* Old EJDB 1.x version can be found in separate [ejdb_1.x](https://github.com/Softmotions/ejdb/tree/ejdb_1.x) branch.
+ We are not maintaining ejdb 1.x.
+
+## Use cases
+
+* Softmotions trading robots platform
+* [Gimme - a social toy tokens exchange mobile application.](https://play.google.com/store/apps/details?id=com.softmotions.gimme) EJDB2 is used both on mobile and server sides.
+
+Are you using EJDB? [Let me know!](mailto:info@softmotions.com)
+
+## macOS / OSX
+
+EJDB2 code ported and tested on `High Sierra` / `Mojave` / `Catalina`
+
+See also [EJDB2 Swift binding](https://github.com/Softmotions/EJDB2Swift) for OSX, iOS and Linux
+
+```
+brew install ejdb
+```
+
+or
+
+```
+mkdir build && cd build
+cmake .. -DCMAKE_BUILD_TYPE=Release
+make install
+```
+
+## Linux
+### Ubuntu/Debian
+#### PPA repository
+
+```sh
+sudo add-apt-repository ppa:adamansky/ejdb2
+sudo apt-get update
+sudo apt-get install ejdb2
+```
+
+#### Building debian packages
+
+cmake v3.15 or higher required
+
+```sh
+mkdir build && cd build
+cmake .. -DCMAKE_BUILD_TYPE=Release -DPACKAGE_DEB=ON
+make package
+```
+
+#### RPM based Linux distributions
+```sh
+mkdir build && cd build
+cmake .. -DCMAKE_BUILD_TYPE=Release -DPACKAGE_RPM=ON
+make package
+```
+
+## Windows
+EJDB2 can be cross-compiled for windows
+
+**Note:** HTTP/Websocket network API is disabled and not supported
+on Windows until port of http://facil.io library (#257)
+
+Nodejs/Dart bindings not yet ported to Windows.
+
+**[Cross-compilation Guide for Windows](./WINDOWS.md)**
diff --git a/BUILD.gn b/BUILD.gn
new file mode 100644
index 0000000..647645e
--- /dev/null
+++ b/BUILD.gn
@@ -0,0 +1,129 @@
+#Copyright (c) 2019-2021 Huawei Device Co., Ltd.
+#Licensed under the Apache License, Version 2.0 (the "License");
+#you may not use this file except in compliance with the License.
+#You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+#Unless required by applicable law or agreed to in writing, software
+#distributed under the License is distributed on an "AS IS" BASIS,
+#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#See the License for the specific language governing permissions and
+#limitations under the License.
+
+import("//build/ohos.gni")
+
+iowow_src_dir = "//third_party/iowow/src"
+action("copy_iowow_header") {
+ visibility = [ ":*" ]
+ script = "copy_iowow_header.py"
+ inputs = []
+ outputs = [
+ "$target_gen_dir/ejdb2/iowow/basedefs.h",
+ "$target_gen_dir/ejdb2/iowow/iowow.h",
+ "$target_gen_dir/ejdb2/iowow/iwarr.h",
+ "$target_gen_dir/ejdb2/iowow/iwbits.h",
+ "$target_gen_dir/ejdb2/iowow/iwconv.h",
+ "$target_gen_dir/ejdb2/iowow/iwdlsnr.h",
+ "$target_gen_dir/ejdb2/iowow/iwexfile.h",
+ "$target_gen_dir/ejdb2/iowow/iwfile.h",
+ "$target_gen_dir/ejdb2/iowow/iwfsmfile.h",
+ "$target_gen_dir/ejdb2/iowow/iwhmap.h",
+ "$target_gen_dir/ejdb2/iowow/iwkv.h",
+ "$target_gen_dir/ejdb2/iowow/iwlog.h",
+ "$target_gen_dir/ejdb2/iowow/iwp.h",
+ "$target_gen_dir/ejdb2/iowow/iwpool.h",
+ "$target_gen_dir/ejdb2/iowow/iwrdb.h",
+ "$target_gen_dir/ejdb2/iowow/iwsha2.h",
+ "$target_gen_dir/ejdb2/iowow/iwstree.h",
+ "$target_gen_dir/ejdb2/iowow/iwstw.h",
+ "$target_gen_dir/ejdb2/iowow/iwth.h",
+ "$target_gen_dir/ejdb2/iowow/iwtp.h",
+ "$target_gen_dir/ejdb2/iowow/iwutils.h",
+ "$target_gen_dir/ejdb2/iowow/iwuuid.h",
+ "$target_gen_dir/ejdb2/iowow/iwxstr.h",
+ "$target_gen_dir/ejdb2/iowow/murmur3.h",
+ ]
+ args = [
+ "--src-dir",
+ rebase_path(iowow_src_dir),
+ "--dst-dir",
+ rebase_path("$target_gen_dir/ejdb2/iowow"),
+ ]
+}
+
+config("ejdb_config") {
+ include_dirs = [
+ "src",
+ "src/jbi",
+ "src/jbl",
+ "src/jql",
+ "src/util",
+ "$target_gen_dir",
+ ]
+
+ cflags = [
+ "-DNDEBUG",
+ "-O3",
+ "-Wall",
+ "-Wextra",
+ "-Wfatal-errors",
+ "-Wno-implicit-fallthrough",
+ "-Wno-missing-braces",
+ "-Wno-missing-field-initializers",
+ "-Wno-shorten-64-to-32",
+ "-Wno-sign-compare",
+ "-Wno-unknown-pragmas",
+ "-Wno-unused-function",
+ "-Wno-unused-parameter",
+ "-fPIC",
+ "-fsigned-char",
+ "-pedantic",
+ "-std=gnu11",
+ ]
+
+ defines = [
+ "IW_64",
+ "IW_API_EXPORTS",
+
+ #"JB_HAVE_QSORT_R",
+ "JB_PTHREADS",
+ "_DEFAULT_SOURCE",
+ "_FILE_OFFSET_BITS=64",
+ "_LARGEFILE_SOURCE",
+ "_XOPEN_SOURCE=600",
+ ]
+}
+
+ohos_shared_library("ejdb") {
+ configs = [ ":ejdb_config" ]
+
+ public_configs = [ ":ejdb_config" ]
+
+ sources = [
+ "src/ejdb2.c",
+ "src/jbi/jbi_consumer.c",
+ "src/jbi/jbi_dup_scanner.c",
+ "src/jbi/jbi_full_scanner.c",
+ "src/jbi/jbi_pk_scanner.c",
+ "src/jbi/jbi_selection.c",
+ "src/jbi/jbi_sorter_consumer.c",
+ "src/jbi/jbi_uniq_scanner.c",
+ "src/jbi/jbi_util.c",
+ "src/jbl/binn.c",
+ "src/jbl/jbl.c",
+ "src/jbl/jbl_json.c",
+ "src/jql/jql.c",
+ "src/jql/jqp.c",
+ "src/util/lwre.c",
+ "src/util/utf8proc.c",
+ ]
+
+ deps = [
+ ":copy_iowow_header",
+ "//third_party/iowow:iowow",
+ ]
+
+ part_name = "hiview"
+ subsystem_name = "hiviewdfx"
+}
diff --git a/CAPI.md b/CAPI.md
new file mode 100644
index 0000000..08bbc39
--- /dev/null
+++ b/CAPI.md
@@ -0,0 +1,98 @@
+# C API
+
+EJDB can be embedded into any `C/C++` application.
+`C API` documented in the following headers:
+
+* [ejdb.h](https://github.com/Softmotions/ejdb/blob/master/src/ejdb2.h) Main API functions
+* [jbl.h](https://github.com/Softmotions/ejdb/blob/master/src/jbl/jbl.h) JSON documents management API
+* [jql.h](https://github.com/Softmotions/ejdb/blob/master/src/jql/jql.h) Query building API
+
+Example application:
+```c
+#include
+
+#define CHECK(rc_) \
+ if (rc_) { \
+ iwlog_ecode_error3(rc_); \
+ return 1; \
+ }
+
+static iwrc documents_visitor(EJDB_EXEC *ctx, const EJDB_DOC doc, int64_t *step) {
+ // Print document to stderr
+ return jbl_as_json(doc->raw, jbl_fstream_json_printer, stderr, JBL_PRINT_PRETTY);
+}
+
+int main() {
+
+ EJDB_OPTS opts = {
+ .kv = {
+ .path = "example.db",
+ .oflags = IWKV_TRUNC
+ }
+ };
+ EJDB db; // EJDB2 storage handle
+ int64_t id; // Document id placeholder
+ JQL q = 0; // Query instance
+ JBL jbl = 0; // Json document
+
+ iwrc rc = ejdb_init();
+ CHECK(rc);
+
+ rc = ejdb_open(&opts, &db);
+ CHECK(rc);
+
+ // First record
+ rc = jbl_from_json(&jbl, "{\"name\":\"Bianca\", \"age\":4}");
+ RCGO(rc, finish);
+ rc = ejdb_put_new(db, "parrots", jbl, &id);
+ RCGO(rc, finish);
+ jbl_destroy(&jbl);
+
+ // Second record
+ rc = jbl_from_json(&jbl, "{\"name\":\"Darko\", \"age\":8}");
+ RCGO(rc, finish);
+ rc = ejdb_put_new(db, "parrots", jbl, &id);
+ RCGO(rc, finish);
+ jbl_destroy(&jbl);
+
+ // Now execute a query
+ rc = jql_create(&q, "parrots", "/[age > :age]");
+ RCGO(rc, finish);
+
+ EJDB_EXEC ux = {
+ .db = db,
+ .q = q,
+ .visitor = documents_visitor
+ };
+
+ // Set query placeholder value.
+ // Actual query will be /[age > 3]
+ rc = jql_set_i64(q, "age", 0, 3);
+ RCGO(rc, finish);
+
+ // Now execute the query
+ rc = ejdb_exec(&ux);
+
+finish:
+ jql_destroy(&q);
+ jbl_destroy(&jbl);
+ ejdb_close(&db);
+ CHECK(rc);
+ return 0;
+}
+```
+
+Compile and run:
+```
+gcc -std=gnu11 -Wall -pedantic -c -o example1.o example1.c
+gcc -o example1 example1.o -lejdb2
+
+./example1
+{
+ "name": "Darko",
+ "age": 8
+}{
+ "name": "Bianca",
+ "age": 4
+}
+```
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..f5a20f7
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,204 @@
+cmake_minimum_required(VERSION 3.5)
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
+include(CMakeToolsHelpers OPTIONAL)
+set(DEB_CHANGELOG_REQUIRED ON)
+set(DEB_CHANGELOG "${CMAKE_CURRENT_SOURCE_DIR}/Changelog")
+unset(CHANGELOG_LAST_VERSION)
+unset(CHANGELOG_LAST_MESSAGE)
+include(DebChangelog)
+
+set(PROJECT_NAME "ejdb2")
+project(${PROJECT_NAME} C)
+
+set(PROJECT_VENDOR "Softmotions (https://softmotions.com)")
+set(PROJECT_WEBSITE "http://ejdb.org")
+set(PROJECT_MAINTAINER "Anton Adamansky ")
+set(PROJECT_DESCRIPTION_SUMMARY
+ "Embeddable JSON database engine with network support (EJDB2).")
+set(PROJECT_DESCRIPTION
+ "Embeddable JSON database engine with network support (EJDB2).")
+set(CHANGELOG_MESSAGE ${CHANGELOG_LAST_MESSAGE})
+set(PROJECT_PPA "ppa:adamansky/ejdb2")
+set(PROJECT_PPA_USER "adamansky")
+set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO")
+set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "")
+
+set(PROJECT_VERSION_MAJOR ${CHANGELOG_LAST_VERSION_MAJOR})
+set(PROJECT_VERSION_MINOR ${CHANGELOG_LAST_VERSION_MINOR})
+set(PROJECT_VERSION_PATCH ${CHANGELOG_LAST_VERSION_PATCH})
+set(PROJECT_VERSION
+ ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
+set(${PROJECT_NAME}_VERSION ${PROJECT_VERSION})
+set(${PROJECT_NAME}_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
+set(${PROJECT_NAME}_VERSION_MINOR ${PROJECT_VERSION_MINOR})
+set(${PROJECT_NAME}_VERSION_PATCH ${PROJECT_VERSION_PATCH})
+
+option(BUILD_SHARED_LIBS "Build shared libraries" ON)
+option(ENABLE_HTTP "Enable HTTP endpoint and standalone server (jbs)" ON)
+option(BUILD_TESTS "Build test cases" OFF)
+option(ASAN "Turn on address sanitizer" OFF)
+option(BUILD_EXAMPLES "Build example projects" ON)
+option(BUILD_BENCHMARKS "Build benchmarks" OFF)
+option(BUILD_JNI_BINDING "Build Java native binding" OFF)
+option(BUILD_ANDROID_LIBS "Build Android libs" OFF)
+option(BUILD_DART_BINDING "Build Dart VM binding" OFF)
+option(BUILD_NODEJS_BINDING "Build Node.js binding" OFF)
+option(BUILD_REACT_NATIVE_BINDING "Build React Native binding" OFF)
+option(BUILD_FLUTTER_BINDING "Build Flutter binding" OFF)
+option(BUILD_SWIFT_BINDING "Build Swift binding" OFF)
+option(PACKAGE_DEB "Build .deb instalation packages" OFF)
+option(PACKAGE_RPM "Build .rpm instalation packages" OFF)
+option(PACKAGE_TGZ "Build .tgz package archive" ON)
+option(PACKAGE_ZIP "Build .zip package archive" ON)
+option(ENABLE_PPA "Enable PPA package build" OFF)
+option(UPLOAD_PPA "Upload debian packages to the launchpad ppa repository" OFF)
+
+set(PPA_DEBIAN_VERSION
+ "ppa1"
+ CACHE STRING "PPA version suffix for debian packages")
+
+set(PROJECT_PPA_DISTRIB_TARGET
+ "focal;bionic;xenial"
+ CACHE STRING "Ubuntu PPA distribution names")
+
+set(ANDROID_ABIS
+ "x86;x86_64;arm64-v8a;armeabi-v7a"
+ CACHE STRING "Android ABI list")
+
+set(ANDROID_AVD
+ "TestingAVD"
+ CACHE STRING "Android virtual device name for tests")
+
+set(CPACK_SET_DESTDIR ON)
+
+if(POLICY CMP0042)
+ cmake_policy(SET CMP0042 NEW)
+endif(POLICY CMP0042)
+
+if(POLICY CMP0087)
+ cmake_policy(SET CMP0087 NEW)
+endif(POLICY CMP0087)
+
+if(BUILD_REACT_NATIVE_BINDING
+ OR BUILD_FLUTTER_BINDING
+ OR BUILD_ANDROID_LIBS)
+ set(ENABLE_HTTP OFF)
+ set(BUILD_ANDROID_LIBS ON)
+endif()
+
+if(ANDROID_ABI OR IOS)
+ set(ENABLE_HTTP OFF)
+endif()
+
+if(DEFINED CMAKE_TOOLCHAIN_FILE)
+ get_filename_component(_CMAKE_TOOLCHAIN_FILE ${CMAKE_TOOLCHAIN_FILE} ABSOLUTE)
+ set(CMAKE_TOOLCHAIN_FILE ${_CMAKE_TOOLCHAIN_FILE})
+endif()
+
+include(GitRevision)
+include(GNUInstallDirs)
+include(ProjectUtils)
+
+macro_ensure_out_of_source_build(
+ "${CMAKE_PROJECT_NAME} requires an out of source build.")
+
+if(BUILD_TESTS)
+ include(CTest)
+ find_package(CUnit REQUIRED)
+endif(BUILD_TESTS)
+
+if(UPLOAD_PPA)
+ set(ENABLE_PPA ON)
+ set(PACKAGE_DEB ON)
+endif(UPLOAD_PPA)
+
+set(CPACK_GENERATORS)
+if(PACKAGE_TGZ)
+ list(APPEND CPACK_GENERATORS "TGZ")
+endif()
+if(PACKAGE_ZIP)
+ list(APPEND CPACK_GENERATORS "ZIP")
+endif()
+if(PACKAGE_DEB)
+ list(APPEND CPACK_GENERATORS "DEB")
+endif()
+if(PACKAGE_RPM)
+ list(APPEND CPACK_GENERATORS "RPM")
+endif()
+
+if(NOT
+ (CPACK_GENERATORS
+ AND (BUILD_JNI_BINDING
+ OR BUILD_DART_BINDING
+ OR BUILD_NODEJS_BINDING)))
+ set(DO_INSTALL_CORE ON)
+endif()
+
+add_subdirectory(man)
+
+if(NOT ENABLE_PPA)
+ add_subdirectory(src)
+endif()
+
+if(CPACK_GENERATORS)
+ set(CPACK_GENERATOR "${CPACK_GENERATORS}")
+ set(CPACK_SOURCE_IGNORE_FILES
+ "/src/bindings/ejdb2_android"
+ "/src/bindings/ejdb2_dart"
+ "/src/bindings/ejdb2_flutter"
+ "/src/bindings/ejdb2_node"
+ "/src/bindings/ejdb2_react_native"
+ "/src/bindings/ejdb2_swift"
+ "/mxe/"
+ "/build/"
+ "/target/"
+ "/tools/"
+ "/docker/"
+ "/node_modules/"
+ "/cmake-.*/"
+ "/Makefile$"
+ "hints\\\\.txt$"
+ "/\\\\.clang/"
+ "/\\\\.codelite/"
+ "/\\\\.git/"
+ "/\\\\.idea/"
+ "/\\\\.settings/"
+ "/\\\\.vscode/"
+ "\\\\.classpath$"
+ "\\\\.editorconfig$"
+ "\\\\.iml$"
+ "\\\\.ipr$"
+ "\\\\.log$"
+ "\\\\.mk$"
+ "\\\\.project$"
+ "\\\\.workspace$"
+ "\\\\.astylerc$"
+ "uncrustify\\\\.cfg")
+ set(PROJECT_ARCH "${CMAKE_SYSTEM_PROCESSOR}")
+ add_subdirectory(installer)
+endif(CPACK_GENERATORS)
+
+message("${PROJECT_NAME} GIT_REVISION: ${GIT_REVISION}")
+message("${PROJECT_NAME} CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
+message("${PROJECT_NAME} CPACK_GENERATORS: ${CPACK_GENERATORS}")
+message("${PROJECT_NAME} CMAKE_GENERATOR: ${CMAKE_GENERATOR}")
+
+if(MXE_HOME)
+ message("${PROJECT_NAME} MXE_HOME: ${MXE_HOME}")
+endif()
+
+if(CMAKE_SYSTEM_NAME)
+ message("${PROJECT_NAME} CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
+endif()
+message("${PROJECT_NAME} CPU: ${CMAKE_SYSTEM_PROCESSOR}")
+
+if(CMAKE_SIZEOF_VOID_P)
+ message("${PROJECT_NAME} SIZEOF *VOID: ${CMAKE_SIZEOF_VOID_P}")
+endif()
+message("${PROJECT_NAME} PROJECT: ${CHANGELOG_LAST_LINE}")
+
+if(CHANGELOG_MESSAGE)
+ message("${PROJECT_NAME} CHANGELOG_MESSAGE:\n ${CHANGELOG_MESSAGE}")
+endif()
diff --git a/Changelog b/Changelog
new file mode 100644
index 0000000..2ff2c01
--- /dev/null
+++ b/Changelog
@@ -0,0 +1,457 @@
+ejdb2 (2.0.59) testing; urgency=medium
+
+ * Fixed some uninitialized data issues with `jbl_clone()`
+ * Added ejdb_put_new_jbn() (ejdb2.h)
+ * jbs: Default database file name changed from db.jb to ejdb2.db
+ * Added jbl_from_json_printf_va(), jbn_from_json_printf_va() (jbl.h)
+ * Project code reformatted using uncrustify
+ * Updated copyright headers
+ * Removed dependency on some glibc specific features
+ * Added jbl_object_copy_to() (ejdb2.h)
+ * Added new convenient methods (ejdb2.h)
+ - ejdb_patch_jbn()
+ - ejdb_patch_jbl()
+ - ejdb_merge_or_put_jbn()
+ - ejdb_merge_or_put_jbl()
+
+ -- Anton Adamansky Sun, 21 Mar 2021 22:17:40 +0700
+
+ejdb2 (2.0.58) testing; urgency=medium
+
+ * New versioning scheme is used for ejdb2 bindings.
+ * Fixed pub publish issues with dart and flutter bindings.
+ * Upgraded to iwkv v1.4.10
+
+ -- Anton Adamansky Tue, 22 Dec 2020 22:33:24 +0700
+
+ejdb2 (2.0.57) testing; urgency=medium
+
+ * Added new non standard JSON `swap` operation.
+ * bugfix: Incorrect behavior of JSON patch `move` operation.
+ * Added --trylock option to jbs
+ * jbs server CLI should be able to load access token from file (#219)
+ * bugfix: Updated to iowow v1.4.10 with fix https://github.com/Softmotions/iowow/issues/35
+ * enhancement: EJDB2 Java binding improvements.
+
+ -- Anton Adamansky Thu, 17 Dec 2020 23:12:37 +0700
+
+ejdb2 (2.0.56) testing; urgency=medium
+
+ * EJDB2 Java binding improvements.
+ * Added EJDB2 Maven example project and maven repository deployment.
+
+ -- Anton Adamansky Thu, 10 Dec 2020 00:27:09 +0700
+
+ejdb2 (2.0.55) testing; urgency=medium
+
+ * EJDB2 Java binding now in Ubuntu ppa:adamansky/ejdb2
+ * Build scripts refactoring.
+ * Reduced number of WS server threads to half of available CPU Cores.
+
+ -- Anton Adamansky Sun, 06 Dec 2020 22:16:20 +0700
+
+ejdb2 (2.0.54) testing; urgency=medium
+
+ * CRITICAL: Fixed incorrect behavior of `_jbl_cmp_atomic_values`
+ which leads to inconsitent number indexes processing.
+ * Transfered `-DASAN` to `AddIOWOW` CMake module.
+
+ -- Anton Adamansky Thu, 19 Nov 2020 23:33:44 +0700
+
+ejdb2 (2.0.53) testing; urgency=medium
+
+ * Upgraded to iowow v1.4.9
+ * Eliminate duplicated documents from non-inique index scanning
+ * Add prefix matching operator ~ (#292)
+
+ -- Anton Adamansky Wed, 18 Nov 2020 16:00:16 +0700
+
+ejdb2 (2.0.52) testing; urgency=medium
+
+ * Fixed serios bug concerning non-unique indexes, details: (#291)
+ * Dart binding: support of the latest Dart pub
+ * Added `jbn_add_item_null()` (jbl.h)
+ * SIGSEGV, Segmentation fault (#287)
+ * Upgraded to facil.io 0.7.5
+ * Code cleanup
+
+ -- Anton Adamansky Sun, 08 Nov 2020 22:04:58 +0700
+
+ejdb2 (2.0.51) testing; urgency=medium
+
+ * Upgraded to iowow v1.4.7
+ * Added `jbl_from_json_printf()` and `jbn_from_json_printf()` (jbl.h)
+ * Added JQL `upsert` operation
+ * Typo fixed (jbl.c)
+ * `jbl_get_str()` now returns `const char*` (jbl.h)
+ * Added `jbl_set_user_data()` (jbl.h)
+ * Removed disable int compression feature from binn implementation (binn.c)
+
+ -- Anton Adamansky Mon, 21 Sep 2020 12:45:01 +0700
+
+ejdb2 (2.0.50) testing; urgency=medium
+
+ * Better floating point numbers comparison in `jbn_compare_nodes()` (jbl.h)
+ * Fixed error in `jbn_copy_path()` if some source property doesn't exist (jbl.h)
+ * Added `jbn_length()` (jbl.h)
+ * Added `lwre.h` to set of public headers
+ * Added `node_out` for every `jbn_add_item_X()` (jbl.h)
+ * Fixed compilation error on clang-10
+ * Fixed ejdb2_jni to be java-8 compatible
+ * Fixed ejdb2_jni to be headless JDK compatible
+
+ -- Anton Adamansky Wed, 24 Jun 2020 20:42:46 +0700
+
+ejdb2 (2.0.49) testing; urgency=medium
+
+ * Added ability to specify array of primary key values in `/=:?` query clause.
+
+ -- Anton Adamansky Sun, 17 May 2020 01:21:02 +0700
+
+ejdb2 (2.0.48) testing; urgency=medium
+
+ * Implemented collection JOINs (#280)
+
+ -- Anton Adamansky Fri, 15 May 2020 14:22:08 +0700
+
+ejdb2 (2.0.47) testing; urgency=medium
+
+ * Added ability to specify constraints on internal primary key in query (#281)
+ * Added `jbn_copy_paths` (jbl.h)
+
+ -- Anton Adamansky Fri, 08 May 2020 23:23:53 +0700
+
+ejdb2 (2.0.46) testing; urgency=medium
+
+ * Upgraded to iowow v1.4.4
+ * Added `jbn_paths_compare()` (jbl.h)
+ * Added `no_src_clone` parameter `jbn_copy_path` (jbl.h)
+
+ -- Anton Adamansky Sat, 02 May 2020 19:43:36 +0700
+
+ejdb2 (2.0.45) testing; urgency=medium
+
+ * Fixed errors found by PVS studio
+ * Added two variants of `jbn_detach` (jbl.h)
+ * Added non standard JSON patch operation: `add_create` (jbl.h)
+ * Added `jbl_from_node` (jbl.h)
+ * Added `jbn_copy_path` (jbl.h)
+ * Added `jbn_add_item_obj` (jbl.h)
+ * Added `jbn_add_item_arr` (jbl.h)
+ * Minor refactoring of jbl module
+ * Added a set of jbn_add_x (jbl.h)
+
+ -- Anton Adamansky Fri, 24 Apr 2020 02:20:32 +0700
+
+ejdb2 (2.0.44) testing; urgency=medium
+
+ * Fixed missing parent pointer link in `_jbl_add_item` (jbl_json.c).
+ * Added `jbn_clone()` (jbl.h)
+ * Added checks for max nesting level of JSON objects, 1000 by default.
+ * Added `jbl_clone(JBL src, JBL *targetp)` (jbl.h)
+ * Added `jbl_merge_patch_jbl(JBL jbl, JBL patch)` (jbl.h)
+ * Added `jbl_set_string_printf()` (jbl.h)
+ * Added `jbl_structure_size()` (jbl.h)
+ * Better error handling of `kh_put()`
+ * Added `jbl_clone_into_pool(JBL src, IWPOOL *pool, JBL *targetp)` (jbl.h)
+ * Added jbn_path_compare, jbn_path_compare_str, jbn_path_compare_bool,
+ jbn_path_compare_i64, jbn_path_compare_f64 (jbl.h)
+
+ -- Anton Adamansky Mon, 20 Apr 2020 16:24:41 +0700
+
+ejdb2 (2.0.43) testing; urgency=medium
+
+ * Upgraded to iowow v1.4.1
+
+ -- Anton Adamansky Sat, 07 Mar 2020 23:39:40 +0700
+
+ejdb2 (2.0.42) testing; urgency=medium
+
+ * Upgraded to iowow v1.4.0
+
+ -- Anton Adamansky Sat, 07 Mar 2020 11:16:10 +0700
+
+ejdb2 (2.0.41) testing; urgency=medium
+
+ * Fixed race condition on database open on slow devices
+
+ -- Anton Adamansky Tue, 18 Feb 2020 18:55:57 +0700
+
+ejdb2 (2.0.40) testing; urgency=medium
+
+ * Added `jbl_object_get_i64`, `jbl_object_get_f64`,
+ `jbl_object_get_bool`, `jbl_object_get_str`
+ * Minor fixes in index selection rules
+ * Added `jbl_type_t jbl_object_get_type(JBL jbl, const char *key)` (jbl.h)
+ * Upgraded to iowow 1.3.37
+
+ -- Anton Adamansky Mon, 17 Feb 2020 23:38:24 +0700
+
+ejdb2 (2.0.39) testing; urgency=medium
+
+ * Added iwrc jbn_at(JBL_NODE node, const char *path, JBL_NODE *res)
+ * Added iwrc jbn_at2(JBL_NODE node, JBL_PTR jp, JBL_NODE *res)
+ * Added `jbl_set_int64`, `jbl_set_f64`, `jbl_set_string`, `jbl_set_nested` (jbl.h)
+ * Added `jbl_set_bool`, `jbl_set_null` (jbl.h)
+ * Added `jbl_set_empty_array`, `jbl_set_empty_object` (jbl.h)
+ * Safer `jql_destroy` (jql.h)
+ * Added `jql_set_json_jbl` (jql.h)
+ * Added `ejdb_count` (ejdb2.h)
+ * Fixed `_jbl_create_patch` issues
+
+ -- Anton Adamansky Wed, 22 Jan 2020 16:13:20 +0700
+
+ejdb2 (2.0.38) testing; urgency=medium
+
+ * FIXED: In the case of apply/projection `ejdb_list` returned old (not updated) documents
+ * Added `iwrc ejdb_get_iwkv(EJDB db, IWKV *kvp)` (ejdb2.h)
+ * Added non standart JSON patch extension: `increment`
+
+ -- Anton Adamansky Fri, 17 Jan 2020 18:23:56 +0700
+
+ejdb2 (2.0.37) testing; urgency=medium
+
+ * Upgraded to iowow v1.3.35
+ * Fixed wal related durability issue
+
+ -- Anton Adamansky Wed, 15 Jan 2020 13:19:06 +0700
+
+ejdb2 (2.0.36) testing; urgency=medium
+
+ * Implemented Swift language binding #267
+ * Ported to iOS
+ * Upgraded to iowow 1.3.34
+ * Upgraded to facil.io 0.7.4
+ * Improved ejdb2.h documentation
+
+ -- Anton Adamansky Mon, 06 Jan 2020 23:20:38 +0700
+
+ejdb2 (2.0.35) testing; urgency=medium
+
+ * FIXED: JQL apply ignores value set by placeholder (#269)
+
+ -- Anton Adamansky Tue, 10 Dec 2019 21:12:43 +0700
+
+ejdb2 (2.0.34) testing; urgency=medium
+
+ * Reduced library size by 400K: stripped off unused utf8proc data
+
+ -- Anton Adamansky Thu, 05 Dec 2019 12:01:59 +0700
+
+ejdb2 (2.0.33) testing; urgency=medium
+
+ * Added ejdb_merge_or_put atomic method #268
+ * Added getOrNull to node/react bindings
+
+ -- Anton Adamansky Wed, 04 Dec 2019 17:34:01 +0700
+
+ejdb2 (2.0.32) testing; urgency=medium
+
+ * Upgraded to iowow v1.3.31
+
+ -- Anton Adamansky Wed, 04 Dec 2019 17:33:20 +0700
+
+ejdb2 (2.0.31) testing; urgency=medium
+
+ * Upgraded to iowow v1.3.30
+
+ -- Anton Adamansky Tue, 19 Nov 2019 20:40:29 +0700
+
+ejdb2 (2.0.30) testing; urgency=medium
+
+ * Upgraded to iowow v1.3.29
+
+ -- Anton Adamansky Fri, 15 Nov 2019 13:55:03 +0700
+
+ejdb2 (2.0.29) testing; urgency=medium
+
+ * Upgraded to iowow v1.3.27
+ * React Native binding implemented (Android)
+
+ -- Anton Adamansky Mon, 04 Nov 2019 21:52:07 +0700
+
+ejdb2 (2.0.28) testing; urgency=medium
+
+ * Upgraded to facil.io v0.7.3
+ * JBS server functions removed from ejdb2 target libs
+
+ -- Anton Adamansky Fri, 27 Sep 2019 18:26:57 +0700
+
+ejdb2 (2.0.27) testing; urgency=medium
+
+ * Upgraded to iowow v1.3.25 with critical fixes
+
+ -- Anton Adamansky Thu, 29 Aug 2019 12:46:41 +0700
+
+ejdb2 (2.0.26) testing; urgency=medium
+
+ * Upgraded to iowow v1.3.24
+
+ -- Anton Adamansky Thu, 22 Aug 2019 02:16:50 +0700
+
+ejdb2 (2.0.25) testing; urgency=medium
+
+ * ejdb2_dart: Fixed memory leak in dart binding
+ * Upgraded to iowow 1.3.23
+
+ -- Anton Adamansky Sat, 17 Aug 2019 21:27:29 +0700
+
+ejdb2 (2.0.24) testing; urgency=medium
+
+ * Strip shared libraries for release builds.
+
+ -- Anton Adamansky Thu, 25 Jul 2019 21:09:00 +0700
+
+ejdb2 (2.0.23) testing; urgency=medium
+
+ * BUG: Fixed incorrect behavior of `jbi_ftoa`
+
+ -- Anton Adamansky Fri, 19 Jul 2019 05:55:16 +0700
+
+ejdb2 (2.0.22) testing; urgency=medium
+
+ * Limited windows support without HTTP/Websocket network API (#237)
+ * `static_assert` is set to `_Static_assert` if not defined
+ * All uses of `iwftoa` replaced by `jbi_ftoa`
+
+ -- Anton Adamansky Thu, 18 Jul 2019 19:27:26 +0700
+
+ejdb2 (2.0.21) testing; urgency=medium
+
+ * Added `ejdb_rename_collection` method (#254)
+
+ -- Anton Adamansky Fri, 12 Jul 2019 12:39:32 +0700
+
+ejdb2 (2.0.20) testing; urgency=medium
+
+ * Node.js binding (#248)
+ * Added git revision hash getter `ejdb_git_revision()` (ejdb2.h)
+ * Better error reporting on failed memory allocations
+
+ -- Anton Adamansky Wed, 03 Jul 2019 19:36:46 +0700
+
+ejdb2 (2.0.19) testing; urgency=medium
+
+ * Upgraded to iowow v1.3.20 with critical fixes
+
+ -- Anton Adamansky Thu, 13 Jun 2019 22:04:27 +0700
+
+ejdb2 (2.0.18) testing; urgency=medium
+
+ * Limit one time file allocation step to 2G iowow v1.3.18
+ * Added Docker image (#249)
+ * Better qsort_t detection, build ok with `musl`
+
+ -- Anton Adamansky Wed, 12 Jun 2019 16:48:57 +0700
+
+ejdb2 (2.0.17) testing; urgency=medium
+
+ * Added `inverse` JQL query option.
+
+ -- Anton Adamansky Wed, 05 Jun 2019 23:15:09 +0700
+
+ejdb2 (2.0.16) testing; urgency=medium
+
+ * Allowed dash and underscope chars in collection names specified in query: `[@collection_name]/query`.
+ * Fixed minor typo in ejdb2_jni/src/CMakeLists.txt
+
+ -- Anton Adamansky Wed, 05 Jun 2019 19:14:38 +0700
+
+ejdb2 (2.0.15) testing; urgency=medium
+
+ * Security: a heap-overflow vulnerability was fixed in the WebSocket parser of facil.io library
+
+ -- Anton Adamansky Mon, 27 May 2019 13:33:03 +0700
+
+ejdb2 (2.0.14) testing; urgency=medium
+
+ * Android support
+ * Test cases for Android JNI binding
+
+ -- Anton Adamansky Fri, 17 May 2019 00:57:11 +0700
+ejdb2 (2.0.13) testing; urgency=medium
+
+ * Upgraded to iowow_1.3.17 with critical fixes
+
+ -- Anton Adamansky Fri, 03 May 2019 18:27:10 +0700
+
+ejdb2 (2.0.12) testing; urgency=medium
+
+ * Upgraded to iowow_1.3.16 with critical fixes
+
+ -- Anton Adamansky Fri, 03 May 2019 11:59:56 +0700
+
+ejdb2 (2.0.11) testing; urgency=medium
+
+ * Upgraded to iowow_1.3.15 with critical fixes
+
+ -- Anton Adamansky Wed, 01 May 2019 23:34:20 +0700
+
+ejdb2 (2.0.10) testing; urgency=medium
+
+ * CRITICAL: Fixed unexpected database file truncation and data loss on close.
+ * Upgraded to iowow 1.3.14
+
+ -- Anton Adamansky Sat, 27 Apr 2019 01:12:15 +0700
+
+ejdb2 (2.0.9) testing; urgency=medium
+
+ * Upgraded to iowow 1.3.13
+ * Building Native JNI binding on Android
+ * ejdb2_dart: Added notFound,invalidQuery to EJDB2Error
+
+ -- Anton Adamansky Thu, 25 Apr 2019 17:47:16 +0700
+
+ejdb2 (2.0.8) testing; urgency=medium
+
+ * Remove redundant memory coping in ejdb_put()
+
+ -- Anton Adamansky Sun, 21 Apr 2019 14:38:08 +0700
+
+ejdb2 (2.0.7) testing; urgency=medium
+
+ * Fixed deadlock condition with OSX pthread rwlocks.
+ * Phreads `PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP` is used by default
+
+ -- Anton Adamansky Sun, 21 Apr 2019 12:20:27 +0700
+
+ejdb2 (2.0.6) testing; urgency=medium
+
+ * Java JNI binding implemented (#243)
+ * Stability: `jql_create` takes own copy of `coll` argument
+ * Documentation improvements
+
+ -- Anton Adamansky Fri, 19 Apr 2019 17:30:12 +0700
+
+ejdb2 (2.0.5) testing; urgency=medium
+
+ * Library ported to OSX
+ * Library ported to Android NDK (#244)
+
+ -- Anton Adamansky Mon, 15 Apr 2019 11:28:30 +0700
+
+ejdb2 (2.0.4) testing; urgency=medium
+
+ * Landed DartVM binding https://pub.dartlang.org/packages/ejdb2_dart
+ * Minors API enhancements
+
+ -- Anton Adamansky Tue, 09 Apr 2019 01:55:42 +0700
+
+ejdb2 (2.0.3) testing; urgency=medium
+
+ * Fixed #238 Disable network access for PPA Lunchpad builds
+ * Removed gcc `-fvisibility=hidden` from shared lib flag
+
+ -- Anton Adamansky Wed, 03 Apr 2019 17:39:52 +0700
+
+ejdb2 (2.0.1) testing; urgency=medium
+
+ * Because we are static linked to iowow its header files included under `include/ejdb2/iowow`
+
+ -- Anton Adamansky Tue, 02 Apr 2019 12:38:32 +0700
+
+ejdb2 (2.0.0) testing; urgency=medium
+
+ * Initial beta release
+
+ -- Anton Adamansky Mon, 01 Apr 2019 20:21:27 +0700
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..5319d1e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2012-2021 Softmotions Ltd
+
+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.
\ No newline at end of file
diff --git a/README.en.md b/README.en.md
deleted file mode 100644
index 9a2404b..0000000
--- a/README.en.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# third_party_ejdb
-
-#### Description
-{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
-
-#### Software Architecture
-Software architecture description
-
-#### Installation
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Instructions
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Contribution
-
-1. Fork the repository
-2. Create Feat_xxx branch
-3. Commit your code
-4. Create Pull Request
-
-
-#### Gitee Feature
-
-1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
-2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
-3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
-4. The most valuable open source project [GVP](https://gitee.com/gvp)
-5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
-6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
diff --git a/README.md b/README.md
index e21eb7c..dff074c 100644
--- a/README.md
+++ b/README.md
@@ -1,39 +1,1345 @@
-# third_party_ejdb
+# EJDB 2.0
-#### 介绍
-{**以下是 Gitee 平台说明,您可以替换此简介**
-Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
-无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
+[](https://tlg.name/ejdb2)
+[](https://github.com/Softmotions/ejdb/blob/master/LICENSE)
+
-#### 软件架构
-软件架构说明
+EJDB2 is an embeddable JSON database engine published under MIT license.
+
+[The Story of the IT-depression, birds and EJDB 2.0](https://medium.com/@adamansky/ejdb2-41670e80897c)
+
+* C11 API
+* Single file database
+* Online backups support
+* 500K library size for Android
+* [iOS](https://github.com/Softmotions/EJDB2Swift) / [Android](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_android/test) / [React Native](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_react_native) / [Flutter](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_flutter) integration
+* Simple but powerful query language (JQL) as well as support of the following standards:
+ * [rfc6902](https://tools.ietf.org/html/rfc6902) JSON Patch
+ * [rfc7386](https://tools.ietf.org/html/rfc7386) JSON Merge patch
+ * [rfc6901](https://tools.ietf.org/html/rfc6901) JSON Path
+* [Support of collection joins](#jql-collection-joins)
+* Powered by [iowow.io](http://iowow.io) - The persistent key/value storage engine
+* Provides HTTP REST/Websockets network endpoints with help of [facil.io](http://facil.io)
+* JSON documents are stored in using fast and compact [binn](https://github.com/liteserver/binn) binary format
+
+---
+* [Native language bindings](#native-language-bindings)
+* Supported platforms
+ * [OSX](#osx)
+ * [iOS](https://github.com/Softmotions/EJDB2Swift)
+ * [Linux](#linux)
+ * [Android](#android)
+ * [Windows](#windows)
+* **[JQL query language](#jql)**
+ * [Grammar](#jql-grammar)
+ * [Quick into](#jql-quick-introduction)
+ * [Data modification](#jql-data-modification)
+ * [Projections](#jql-projections)
+ * [Collection joins](#jql-collection-joins)
+ * [Sorting](#jql-sorting)
+ * [Query options](#jql-options)
+* [Indexes and performance](#jql-indexes-and-performance-tips)
+* [Network API](#http-restwebsocket-api-endpoint)
+ * [HTTP API](#http-api)
+ * [Websockets API](#websocket-api)
+* [C API](#c-api)
+* [License](#license)
+---
+
+## EJDB2 platforms matrix
+
+| | Linux | macOS | iOS | Android | Windows |
+| --- | --- | --- | --- | --- | --- |
+| C library | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark:1 |
+| NodeJS | :heavy_check_mark: | :heavy_check_mark: | | | :x:3 |
+| DartVM | :heavy_check_mark: | :heavy_check_mark:2 | | | :x:3 |
+| Flutter | | | :heavy_check_mark: | :heavy_check_mark: | |
+| React Native | | | :x:4 | :heavy_check_mark: | |
+| Swift | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | |
+| Java | :heavy_check_mark: | :heavy_check_mark: | | :heavy_check_mark: | :heavy_check_mark:2 |
-#### 安装教程
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### 使用说明
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### 参与贡献
-
-1. Fork 本仓库
-2. 新建 Feat_xxx 分支
-3. 提交代码
-4. 新建 Pull Request
+ `[1]` No HTTP/Websocket support [#257](https://github.com/Softmotions/ejdb/issues/257)
+ `[2]` Binaries are not distributed with dart `pub.` You can build it [manually](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_node#how-build-it-manually)
+ `[3]` Can be build, but needed a linkage with windows node/dart `libs`.
+ `[4]` Porting in progress [#273](https://github.com/Softmotions/ejdb/issues/273)
-#### 特技
+## Native language bindings
+
+* [NodeJS](https://www.npmjs.com/package/ejdb2_node)
+* [Dart](https://pub.dartlang.org/packages/ejdb2_dart)
+* [Java](https://github.com/Softmotions/ejdb/blob/master/src/bindings/ejdb2_jni/README.md)
+* [Android support](#android)
+* [Swift | iOS](https://github.com/Softmotions/EJDB2Swift)
+* [React Native](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_react_native)
+* [Flutter](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_flutter)
+
+### Unofficial EJDB2 language bindings
+
+* .Net
+ * https://github.com/kmvi/ejdb2-csharp
+* Haskell
+ * https://github.com/cescobaz/ejdb2haskell
+ * https://hackage.haskell.org/package/ejdb2-binding
+* [Pharo](https://pharo.org)
+ * https://github.com/pharo-nosql/pharo-ejdb
+* Lua
+ * https://github.com/chriku/ejdb-lua
+
+## Status
+
+* **EJDB 2.0 core engine is well tested and used in various heavily loaded deployments**
+* Tested on `Linux` and `OSX` platforms. [Limited Windows support](./WINDOWS.md)
+* Old EJDB 1.x version can be found in separate [ejdb_1.x](https://github.com/Softmotions/ejdb/tree/ejdb_1.x) branch.
+ We are not maintaining ejdb 1.x.
+
+## Use cases
+
+* Softmotions trading robots platform
+* [Gimme - a social toy tokens exchange mobile application.](https://play.google.com/store/apps/details?id=com.softmotions.gimme) EJDB2 is used both on mobile and server sides.
+
+Are you using EJDB? [Let me know!](mailto:info@softmotions.com)
+
+## macOS / OSX
+
+EJDB2 code ported and tested on `High Sierra` / `Mojave` / `Catalina`
+
+See also [EJDB2 Swift binding](https://github.com/Softmotions/EJDB2Swift) for OSX, iOS and Linux
+
+```
+brew install ejdb
+```
+
+or
+
+```
+mkdir build && cd build
+cmake .. -DCMAKE_BUILD_TYPE=Release
+make install
+```
+
+## Linux
+### Ubuntu/Debian
+#### PPA repository
+
+```sh
+sudo add-apt-repository ppa:adamansky/ejdb2
+sudo apt-get update
+sudo apt-get install ejdb2
+```
+
+#### Building debian packages
+
+cmake v3.15 or higher required
+
+```sh
+mkdir build && cd build
+cmake .. -DCMAKE_BUILD_TYPE=Release -DPACKAGE_DEB=ON
+make package
+```
+
+#### RPM based Linux distributions
+```sh
+mkdir build && cd build
+cmake .. -DCMAKE_BUILD_TYPE=Release -DPACKAGE_RPM=ON
+make package
+```
+
+## Windows
+EJDB2 can be cross-compiled for windows
+
+**Note:** HTTP/Websocket network API is disabled and not supported
+on Windows until port of http://facil.io library (#257)
+
+Nodejs/Dart bindings not yet ported to Windows.
+
+**[Cross-compilation Guide for Windows](./WINDOWS.md)**
+
+
+
+# Android
+
+* [Flutter binding](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_flutter)
+* [React Native binding](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_react_native)
+
+## Sample Android application
+
+* https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_android/test
+
+* https://github.com/Softmotions/ejdb_android_todo_app
+
+
+# JQL
+
+EJDB query language (JQL) syntax inspired by ideas behind XPath and Unix shell pipes.
+It designed for easy querying and updating sets of JSON documents.
+
+## JQL grammar
+
+JQL parser created created by
+[peg/leg — recursive-descent parser generators for C](http://piumarta.com/software/peg/) Here is the formal parser grammar: https://github.com/Softmotions/ejdb/blob/master/src/jql/jqp.leg
+
+## Non formal JQL grammar adapted for brief overview
+
+Notation used below is based on SQL syntax description:
+
+Rule | Description
+--- | ---
+`' '` | String in single quotes denotes unquoted string literal as part of query.
+{ a | b } | Curly brackets enclose two or more required alternative choices, separated by vertical bars.
+[ ] | Square brackets indicate an optional element or clause. Multiple elements or clauses are separated by vertical bars.
+| | Vertical bars separate two or more alternative syntax elements.
+... | Ellipses indicate that the preceding element can be repeated. The repetition is unlimited unless otherwise indicated.
+( ) | Parentheses are grouping symbols.
+Unquoted word in lower case| Denotes semantic of some query part. For example: `placeholder_name` - name of any placeholder.
+```
+QUERY = FILTERS [ '|' APPLY ] [ '|' PROJECTIONS ] [ '|' OPTS ];
+
+STR = { quoted_string | unquoted_string };
+
+JSONVAL = json_value;
+
+PLACEHOLDER = { ':'placeholder_name | '?' }
+
+FILTERS = FILTER [{ and | or } [ not ] FILTER];
+
+ FILTER = [@collection_name]/NODE[/NODE]...;
+
+ NODE = { '*' | '**' | NODE_EXPRESSION | STR };
+
+ NODE_EXPRESSION = '[' NODE_EXPR_LEFT OP NODE_EXPR_RIGHT ']'
+ [{ and | or } [ not ] NODE_EXPRESSION]...;
+
+ OP = [ '!' ] { '=' | '>=' | '<=' | '>' | '<' | ~ }
+ | [ '!' ] { 'eq' | 'gte' | 'lte' | 'gt' | 'lt' }
+ | [ not ] { 'in' | 'ni' | 're' };
+
+ NODE_EXPR_LEFT = { '*' | '**' | STR | NODE_KEY_EXPR };
+
+ NODE_KEY_EXPR = '[' '*' OP NODE_EXPR_RIGHT ']'
+
+ NODE_EXPR_RIGHT = JSONVAL | STR | PLACEHOLDER
+
+APPLY = { 'apply' | 'upsert' } { PLACEHOLDER | json_object | json_array } | 'del'
+
+OPTS = { 'skip' n | 'limit' n | 'count' | 'noidx' | 'inverse' | ORDERBY }...
+
+ ORDERBY = { 'asc' | 'desc' } PLACEHOLDER | json_path
+
+PROJECTIONS = PROJECTION [ {'+' | '-'} PROJECTION ]
+
+ PROJECTION = 'all' | json_path
+
+```
+
+* `json_value`: Any valid JSON value: object, array, string, bool, number.
+* `json_path`: Simplified JSON pointer. Eg.: `/foo/bar` or `/foo/"bar with spaces"/`
+* `*` in context of `NODE`: Any JSON object key name at particular nesting level.
+* `**` in context of `NODE`: Any JSON object key name at arbitrary nesting level.
+* `*` in context of `NODE_EXPR_LEFT`: Key name at specific level.
+* `**` in context of `NODE_EXPR_LEFT`: Nested array value of array element under specific key.
+
+## JQL quick introduction
+
+Lets play with some very basic data and queries.
+For simplicity we will use ejdb websocket network API which provides us a kind of interactive CLI. The same job can be done using pure `C` API too (`ejdb2.h jql.h`).
+
+NOTE: Take a look into [JQL test cases](https://github.com/Softmotions/ejdb/blob/master/src/jql/tests/jql_test1.c) for more examples.
+
+```json
+{
+ "firstName": "John",
+ "lastName": "Doe",
+ "age": 28,
+ "pets": [
+ {"name": "Rexy rex", "kind": "dog", "likes": ["bones", "jumping", "toys"]},
+ {"name": "Grenny", "kind": "parrot", "likes": ["green color", "night", "toys"]}
+ ]
+}
+```
+Save json as `sample.json` then upload it the `family` collection:
+
+```sh
+# Start HTTP/WS server protected by some access token
+./jbs -a 'myaccess01'
+8 Mar 16:15:58.601 INFO: HTTP/WS endpoint at localhost:9191
+```
+
+Server can be accessed using HTTP or Websocket endpoint. [More info](https://github.com/Softmotions/ejdb/blob/master/src/jbr/README.md)
+
+```sh
+curl -d '@sample.json' -H'X-Access-Token:myaccess01' -X POST http://localhost:9191/family
+```
+
+We can play around using interactive [wscat](https://www.npmjs.com/package/@softmotions/wscat) websocket client.
+
+```sh
+wscat -H 'X-Access-Token:myaccess01' -c http://localhost:9191
+connected (press CTRL+C to quit)
+> k info
+< k {
+ "version": "2.0.0",
+ "file": "db.jb",
+ "size": 8192,
+ "collections": [
+ {
+ "name": "family",
+ "dbid": 3,
+ "rnum": 1,
+ "indexes": []
+ }
+ ]
+}
+
+> k get family 1
+< k 1 {
+ "firstName": "John",
+ "lastName": "Doe",
+ "age": 28,
+ "pets": [
+ {
+ "name": "Rexy rex",
+ "kind": "dog",
+ "likes": [
+ "bones",
+ "jumping",
+ "toys"
+ ]
+ },
+ {
+ "name": "Grenny",
+ "kind": "parrot",
+ "likes": [
+ "green color",
+ "night",
+ "toys"
+ ]
+ }
+ ]
+}
+```
+
+Note about the `k` prefix before every command; It is an arbitrary key chosen by client and designated to identify particular
+websocket request, this key will be returned with response to request and allows client to
+identify that response for his particular request. [More info](https://github.com/Softmotions/ejdb/blob/master/src/jbr/README.md)
+
+Query command over websocket has the following format:
+
+```
+ query
+```
+
+So we will consider only `` part in this document.
+
+### Get all elements in collection
+```
+k query family /*
+```
+or
+```
+k query family /**
+```
+or specify collection name in query explicitly
+```
+k @family/*
+```
+
+We can execute query by HTTP `POST` request
+```
+curl --data-raw '@family/[firstName = John]' -H'X-Access-Token:myaccess01' -X POST http://localhost:9191
+
+1 {"firstName":"John","lastName":"Doe","age":28,"pets":[{"name":"Rexy rex","kind":"dog","likes":["bones","jumping","toys"]},{"name":"Grenny","kind":"parrot","likes":["green color","night","toys"]}]}
+```
+
+### Set the maximum number of elements in result set
+
+```
+k @family/* | limit 10
+```
+
+### Get documents where specified json path exists
+
+Element at index `1` exists in `likes` array within a `pets` sub-object
+```
+> k query family /pets/*/likes/1
+< k 1 {"firstName":"John"...
+```
+
+Element at index `1` exists in `likes` array at any `likes` nesting level
+```
+> k query family /**/likes/1
+< k 1 {"firstName":"John"...
+```
+
+**From this point and below I will omit websocket specific prefix `k query family` and
+consider only JQL queries.**
+
+
+### Get documents by primary key
+
+In order to get documents by primary key the following options are available:
+
+1. Use API call `ejdb_get()`
+ ```ts
+ const doc = await db.get('users', 112);
+ ```
+
+1. Use the special query construction: `/=:?` or `@collection/=:?`
+
+Get document from `users` collection with primary key `112`
+```
+> k @users/=112
+```
+
+Update tags array for document in `jobs` collection (TypeScript):
+```ts
+ await db.createQuery('@jobs/ = :? | apply :? | count')
+ .setNumber(0, id)
+ .setJSON(1, { tags })
+ .completionPromise();
+```
+
+Array of primary keys can also be used for matching:
+
+```ts
+ await db.createQuery('@jobs/ = :?| apply :? | count')
+ .setJSON(0, [23, 1, 2])
+ .setJSON(1, { tags })
+ .completionPromise();
+```
+
+### Matching JSON entry values
+
+Below is a set of self explaining queries:
+
+```
+/pets/*/[name = "Rexy rex"]
+
+/pets/*/[name eq "Rexy rex"]
+
+/pets/*/[name = "Rexy rex" or name = Grenny]
+```
+Note about quotes around words with spaces.
+
+Get all documents where owner `age` greater than `20` and have some pet who like `bones` or `toys`
+```
+/[age > 20] and /pets/*/likes/[** in ["bones", "toys"]]
+```
+Here `**` denotes some element in `likes` array.
+
+`ni` is the inverse operator to `in`.
+Get documents where `bones` somewhere in `likes` array.
+```
+/pets/*/[likes ni "bones"]
+```
+
+We can create more complicated filters
+```
+( /[age <= 20] or /[lastName re "Do.*"] )
+ and /pets/*/likes/[** in ["bones", "toys"]]
+```
+Note about grouping parentheses and regular expression matching using `re` operator.
+
+`~` is a prefix matching operator (Since ejdb `v2.0.53`).
+Prefix matching can benefit from using indexes.
+
+Get documents where `/lastName` starts with `"Do"`.
+```
+/[lastName ~ Do]
+```
+
+### Arrays and maps can be matched as is
+
+Filter documents with `likes` array exactly matched to `["bones","jumping","toys"]`
+```
+/**/[likes = ["bones","jumping","toys"]]
+```
+Matching algorithms for arrays and maps are different:
+
+* Array elements are matched from start to end. In equal arrays
+ all values at the same index should be equal.
+* Object maps matching consists of the following steps:
+ * Lexicographically sort object keys in both maps.
+ * Do matching keys and its values starting from the lowest key.
+ * If all corresponding keys and values in one map are fully matched to ones in other
+ and vice versa, maps considered to be equal.
+ For example: `{"f":"d","e":"j"}` and `{"e":"j","f":"d"}` are equal maps.
+
+### Conditions on key names
+
+Find JSON document having `firstName` key at root level.
+```
+/[* = "firstName"]
+```
+I this context `*` denotes a key name.
+
+You can use conditions on key name and key value at the same time:
+```
+/[[* = "firstName"] = John]
+```
+
+Key name can be either `firstName` or `lastName` but should have `John` value in any case.
+```
+/[[* in ["firstName", "lastName"]] = John]
+```
+
+It may be useful in queries with dynamic placeholders (C API):
+```
+/[[* = :keyName] = :keyValue]
+```
+
+## JQL data modification
+
+`APPLY` section responsible for modification of documents content.
+
+```
+APPLY = ({'apply' | `upsert`} { PLACEHOLDER | json_object | json_array }) | 'del'
+```
+
+JSON patch specs conformed to `rfc7386` or `rfc6902` specifications followed after `apply` keyword.
+
+Let's add `address` object to all matched document
+```
+/[firstName = John] | apply {"address":{"city":"New York", "street":""}}
+```
+
+If JSON object is an argument of `apply` section it will be treated as merge match (`rfc7386`) otherwise
+it should be array which denotes `rfc6902` JSON patch. Placeholders also supported by `apply` section.
+```
+/* | apply :?
+```
+
+Set the street name in `address`
+```
+/[firstName = John] | apply [{"op":"replace", "path":"/address/street", "value":"Fifth Avenue"}]
+```
+
+Add `Neo` fish to the set of John's `pets`
+```
+/[firstName = John]
+| apply [{"op":"add", "path":"/pets/-", "value": {"name":"Neo", "kind":"fish"}}]
+```
+
+`upsert` updates existing document by given json argument used as merge patch
+ or inserts provided json argument as new document instance.
+
+```
+/[firstName = John] | upsert {"firstName": "John", "address":{"city":"New York"}}
+```
+
+### Non standard JSON patch extensions
+
+#### increment
+
+Increments numeric value identified by JSON path by specified value.
+
+Example:
+```
+ Document: {"foo": 1}
+ Patch: [{"op": "increment", "path": "/foo", "value": 2}]
+ Result: {"foo": 3}
+```
+#### add_create
+
+Same as JSON patch `add` but creates intermediate object nodes for missing JSON path segments.
+
+Example:
+```
+Document: {"foo": {"bar": 1}}
+Patch: [{"op": "add_create", "path": "/foo/zaz/gaz", "value": 22}]
+Result: {"foo":{"bar":1,"zaz":{"gaz":22}}}
+```
+
+Example:
+```
+Document: {"foo": {"bar": 1}}
+Patch: [{"op": "add_create", "path": "/foo/bar/gaz", "value": 22}]
+Result: Error since element pointed by /foo/bar is not an object
+```
+
+#### swap
+
+Swaps two values of JSON document starting from `from` path.
+
+Swapping rules
+
+1. If value pointed by `from` not exists error will be raised.
+1. If value pointed by `path` not exists it will be set by value from `from` path,
+ then object pointed by `from` path will be removed.
+1. If both values pointed by `from` and `path` are presented they will be swapped.
+
+Example:
+
+```
+Document: {"foo": ["bar"], "baz": {"gaz": 11}}
+Patch: [{"op": "swap", "from": "/foo/0", "path": "/baz/gaz"}]
+Result: {"foo": [11], "baz": {"gaz": "bar"}}
+```
+
+Example (Demo of rule 2):
+
+```
+Document: {"foo": ["bar"], "baz": {"gaz": 11}}
+Patch: [{"op": "swap", "from": "/foo/0", "path": "/baz/zaz"}]
+Result: {"foo":[],"baz":{"gaz":11,"zaz":"bar"}}
+```
+
+### Removing documents
+
+Use `del` keyword to remove matched elements from collection:
+```
+/FILTERS | del
+```
+
+Example:
+```
+> k add family {"firstName":"Jack"}
+< k 2
+> k query family /[firstName re "Ja.*"]
+< k 2 {"firstName":"Jack"}
+
+# Remove selected elements from collection
+> k query family /[firstName=Jack] | del
+< k 2 {"firstName":"Jack"}
+```
+
+## JQL projections
+
+```
+PROJECTIONS = PROJECTION [ {'+' | '-'} PROJECTION ]
+
+ PROJECTION = 'all' | json_path | join_clause
+```
+
+Projection allows to get only subset of JSON document excluding not needed data.
+
+Lets add one more document to our collection:
+
+```sh
+$ cat << EOF | curl -d @- -H'X-Access-Token:myaccess01' -X POST http://localhost:9191/family
+{
+"firstName":"Jack",
+"lastName":"Parker",
+"age":35,
+"pets":[{"name":"Sonic", "kind":"mouse", "likes":[]}]
+}
+EOF
+```
+Now query only pet owners firstName and lastName from collection.
+
+```
+> k query family /* | /{firstName,lastName}
+
+< k 3 {"firstName":"Jack","lastName":"Parker"}
+< k 1 {"firstName":"John","lastName":"Doe"}
+< k
+```
+
+Add `pets` array for every document
+```
+> k query family /* | /{firstName,lastName} + /pets
+
+< k 3 {"firstName":"Jack","lastName":"Parker","pets":[...
+< k 1 {"firstName":"John","lastName":"Doe","pets":[...
+```
+
+Exclude only `pets` field from documents
+```
+> k query family /* | all - /pets
+
+< k 3 {"firstName":"Jack","lastName":"Parker","age":35}
+< k 1 {"firstName":"John","lastName":"Doe","age":28,"address":{"city":"New York","street":"Fifth Avenue"}}
+< k
+```
+Here `all` keyword used denoting whole document.
+
+Get `age` and the first pet in `pets` array.
+```
+> k query family /[age > 20] | /age + /pets/0
+
+< k 3 {"age":35,"pets":[{"name":"Sonic","kind":"mouse","likes":[]}]}
+< k 1 {"age":28,"pets":[{"name":"Rexy rex","kind":"dog","likes":["bones","jumping","toys"]}]}
+< k
+```
+
+## JQL collection joins
+
+Join materializes reference to document to a real document objects which will replace reference inplace.
+
+Documents are joined by their primary keys only.
+
+Reference keys should be stored in referrer document as number or string field.
+
+Joins can be specified as part of projection expression
+in the following form:
+
+```
+/.../field k add artists {"name":"Leonardo Da Vinci", "years":[1452,1519]}
+< k 1
+> k add paintings {"name":"Mona Lisa", "year":1490, "origin":"Italy", "artist": 1}
+< k 1
+> k add paintings {"name":"Madonna Litta - Madonna And The Child", "year":1490, "origin":"Italy", "artist": 1}
+< k 2
+
+# Lists paintings documents
+
+> k @paintings/*
+< k 2 {"name":"Madonna Litta - Madonna And The Child","year":1490,"origin":"Italy","artist":1}
+< k 1 {"name":"Mona Lisa","year":1490,"origin":"Italy","artist":1}
+< k
+>
+
+# Do simple join with artists collection
+
+> k @paintings/* | /artist k @paintings/* | /artist
+
+# Same results as above:
+
+> k @paintings/* | /{name, artist k add paintings {"name":"Mona Lisa2", "year":1490, "origin":"Italy", "artist": 9999}
+< k 3
+> k @paintings/* | /artist k add family {"firstName":"John", "lastName":"Ryan", "age":39}
+< k 4
+```
+
+```
+> k query family /* | /{firstName,lastName,age} | asc /firstName desc /age
+< k 3 {"firstName":"Jack","lastName":"Parker","age":35}
+< k 4 {"firstName":"John","lastName":"Ryan","age":39}
+< k 1 {"firstName":"John","lastName":"Doe","age":28}
+< k
+```
+
+`asc, desc` instructions may use indexes defined for collection to avoid a separate documents sorting stage.
+
+## JQL Options
+
+```
+OPTS = { 'skip' n | 'limit' n | 'count' | 'noidx' | 'inverse' | ORDERBY }...
+```
+
+* `skip n` Skip first `n` records before first element in result set
+* `limit n` Set max number of documents in result set
+* `count` Returns only `count` of matched documents
+ ```
+ > k query family /* | count
+ < k 3
+ < k
+ ```
+* `noidx` Do not use any indexes for query execution.
+* `inverse` By default query scans documents from most recently added to older ones.
+ This option inverts scan direction to opposite and activates `noidx` mode.
+ Has no effect if query has `asc/desc` sorting clauses.
+
+## JQL Indexes and performance tips
+
+Database index can be build for any JSON field path containing values of number or string type.
+Index can be an `unique` ‐ not allowing value duplication and `non unique`.
+The following index mode bit mask flags are used (defined in `ejdb2.h`):
+
+Index mode | Description
+--- | ---
+0x01 EJDB_IDX_UNIQUE | Index is unique
+0x04 EJDB_IDX_STR | Index for JSON `string` field value type
+0x08 EJDB_IDX_I64 | Index for `8 bytes width` signed integer field values
+0x10 EJDB_IDX_F64 | Index for `8 bytes width` signed floating point field values.
+
+For example unique index of string type will be specified by `EJDB_IDX_UNIQUE | EJDB_IDX_STR` = `0x05`.
+Index can be defined for only one value type located under specific path in json document.
+
+Lets define non unique string index for `/lastName` path:
+```
+> k idx family 4 /lastName
+< k
+```
+Index selection for queries based on set of heuristic rules.
+
+You can always check index usage by issuing `explain` command in WS API:
+```
+> k explain family /[lastName=Doe] and /[age!=27]
+< k explain [INDEX] MATCHED STR|3 /lastName EXPR1: 'lastName = Doe' INIT: IWKV_CURSOR_EQ
+[INDEX] SELECTED STR|3 /lastName EXPR1: 'lastName = Doe' INIT: IWKV_CURSOR_EQ
+ [COLLECTOR] PLAIN
+```
+
+The following statements are taken into account when using EJDB2 indexes:
+* Only one index can be used for particular query execution
+* If query consist of `or` joined part at top level or contains `negated` expressions at the top level
+ of query expression - indexes will not be in use at all.
+ So no indexes below:
+ ```
+ /[lastName != Andy]
+
+ /[lastName = "John"] or /[lastName = Peter]
+
+ ```
+ But will be used `/lastName` index defined above
+ ```
+ /[lastName = Doe]
+
+ /[lastName = Doe] and /[age = 28]
+
+ /[lastName = Doe] and not /[age = 28]
+
+ /[lastName = Doe] and /[age != 28]
+ ```
+* The following operators are supported by indexes (ejdb 2.0.x):
+ * `eq, =`
+ * `gt, >`
+ * `gte, >=`
+ * `lt, <`
+ * `lte, <=`
+ * `in`
+ * `~` (Prefix matching since ejdb 2.0.53)
+
+* `ORDERBY` clauses may use indexes to avoid result set sorting.
+* Array fields can also be indexed. Let's outline typical use case: indexing of some entity tags:
+ ```
+ > k add books {"name":"Mastering Ultra", "tags":["ultra", "language", "bestseller"]}
+ < k 1
+ > k add books {"name":"Learn something in 24 hours", "tags":["bestseller"]}
+ < k 2
+ > k query books /*
+ < k 2 {"name":"Learn something in 24 hours","tags":["bestseller"]}
+ < k 1 {"name":"Mastering Ultra","tags":["ultra","language","bestseller"]}
+ < k
+ ```
+ Create string index for `/tags`
+ ```
+ > k idx books 4 /tags
+ < k
+ ```
+ Filter books by `bestseller` tag and show index usage in query:
+ ```
+ > k explain books /tags/[** in ["bestseller"]]
+ < k explain [INDEX] MATCHED STR|4 /tags EXPR1: '** in ["bestseller"]' INIT: IWKV_CURSOR_EQ
+ [INDEX] SELECTED STR|4 /tags EXPR1: '** in ["bestseller"]' INIT: IWKV_CURSOR_EQ
+ [COLLECTOR] PLAIN
+
+ < k 1 {"name":"Mastering Ultra","tags":["ultra","language","bestseller"]}
+ < k 2 {"name":"Learn something in 24 hours","tags":["bestseller"]}
+ < k
+ ```
+
+### Performance tip: Physical ordering of documents
+
+All documents in collection are sorted by their primary key in `descending` order.
+So if you use auto generated keys (`ejdb_put_new`) you may be sure what documents fetched as result of
+full scan query will be ordered according to the time of insertion in descendant order,
+unless you don't use query sorting, indexes or `inverse` keyword.
+
+### Performance tip: Brute force scan vs indexed access
+
+In many cases, using index may drop down the overall query performance.
+Because index collection contains only document references (`id`) and engine may perform
+an addition document fetching by its primary key to finish query matching.
+So for not so large collections a brute scan may perform better than scan using indexes.
+However, exact matching operations: `eq`, `in` and `sorting` by natural index order
+will benefit from index in most cases.
+
+
+### Performance tip: Get rid of unnecessary document data
+
+If you'd like update some set of documents with `apply` or `del` operations
+but don't want fetching all of them as result of query - just add `count`
+modifier to the query to get rid of unnecessary data transferring and json data conversion.
+
+
+
+# HTTP REST/Websocket API endpoint
+
+EJDB engine provides the ability to start a separate HTTP/Websocket endpoint worker exposing network API for quering and data modifications.
+
+The easiest way to expose database over the network is using the standalone `jbs` server. (Of course if you plan to avoid `C API` integration).
+
+## jbs server
+
+```
+jbs -h
+
+EJDB 2.0.0 standalone REST/Websocket server. http://ejdb.org
+
+ --file <> Database file path. Default: db.jb
+ -f <> (same as --file)
+ --port ## HTTP port number listen to. Default: 9191
+ -p ## (same as --port)
+ --bind <> Address server listen. Default: localhost
+ -b <> (same as --bind)
+ --access <> Server access token matched to 'X-Access-Token' HTTP header value
+ -a <> (same as --access)
+ --trunc Cleanup existing database file on open
+ -t (same as --trunc)
+ --wal Use write ahead logging (WAL). Must be set for data durability.
+ -w (same as --wal)
+
+Advanced options
+ --sbz ## Max sorting buffer size. If exceeded, an overflow temp file for data will be created. Default: 16777216, min: 1048576
+ --dsz ## Initial size of buffer to process/store document on queries. Preferable average size of document. Default: 65536, min: 16384
+ --bsz ## Max HTTP/WS API document body size. Default: 67108864, min: 524288
+
+Use any of the following input formats:
+ -arg -arg= -arg
+
+Use the -h, -help or -? to get this information again.
+```
+
+## HTTP API
+
+Access to HTTP endpoint can be protected by a token specified with `--access`
+command flag or by C API `EJDB_HTTP` options. If access token specified on server, client must provide `X-Access-Token` HTTP header value. If token is required and not provided by client the `401` HTTP code will be reported. If access token is not matched to the token provided the `403` HTTP code will be returned.
+For any other errors server will respond with `500` error code.
+
+## REST API
+
+### POST /{collection}
+Add a new document to the `collection`.
+* `200` success. Body: a new document identifier as `int64` number
+
+### PUT /{collection}/{id}
+Replaces/store document under specific numeric `id`
+* `200` on success. Empty body
+
+### DELETE /{collection}/{id}
+Removes document identified by `id` from a `collection`
+* `200` on success. Empty body
+* `404` if document not found
+
+### PATCH /{collection}/{id}
+Patch a document identified by `id` by [rfc7396](https://tools.ietf.org/html/rfc7396),
+[rfc6902](https://tools.ietf.org/html/rfc6902) data.
+* `200` on success. Empty body
+
+### GET | HEAD /{collections}/{id}
+Retrieve document identified by `id` from a `collection`.
+* `200` on success. Body: JSON document text.
+ * `content-type:application/json`
+ * `content-length:`
+* `404` if document not found
+
+### POST /
+Query a collection by provided query as POST body.
+Body of query should contains collection name in use in the first filter element: `@collection_name/...`
+Request headers:
+* `X-Hints` comma separated extra hints to ejdb2 database engine.
+ * `explain` Show query execution plan before first element in result set separated by `--------------------` line.
+Response:
+* Response data transfered using [HTTP chunked transfer encoding](https://en.wikipedia.org/wiki/Chunked_transfer_encoding)
+* `200` on success.
+* JSON documents separated by `\n` in the following format:
+ ```
+ \r\n\t
+ ...
+ ```
+
+Example:
+
+```
+curl -v --data-raw '@family/[age > 18]' -H 'X-Access-Token:myaccess01' http://localhost:9191
+* Rebuilt URL to: http://localhost:9191/
+* Trying 127.0.0.1...
+* TCP_NODELAY set
+* Connected to localhost (127.0.0.1) port 9191 (#0)
+> POST / HTTP/1.1
+> Host: localhost:9191
+> User-Agent: curl/7.58.0
+> Accept: */*
+> X-Access-Token:myaccess01
+> Content-Length: 18
+> Content-Type: application/x-www-form-urlencoded
+>
+* upload completely sent off: 18 out of 18 bytes
+< HTTP/1.1 200 OK
+< connection:keep-alive
+< content-type:application/json
+< transfer-encoding:chunked
+<
+
+4 {"firstName":"John","lastName":"Ryan","age":39}
+3 {"firstName":"Jack","lastName":"Parker","age":35,"pets":[{"name":"Sonic","kind":"mouse","likes":[]}]}
+1 {"firstName":"John","lastName":"Doe","age":28,"pets":[{"name":"Rexy rex","kind":"dog","likes":["bones","jumping","toys"]},{"name":"Grenny","kind":"parrot","likes":["green color","night","toys"]}],"address":{"city":"New York","street":"Fifth Avenue"}}
+* Connection #0 to host localhost left intact
+```
+
+```
+curl --data-raw '@family/[lastName = "Ryan"]' -H 'X-Access-Token:myaccess01' -H 'X-Hints:explain' http://localhost:9191
+[INDEX] MATCHED STR|3 /lastName EXPR1: 'lastName = "Ryan"' INIT: IWKV_CURSOR_EQ
+[INDEX] SELECTED STR|3 /lastName EXPR1: 'lastName = "Ryan"' INIT: IWKV_CURSOR_EQ
+ [COLLECTOR] PLAIN
+--------------------
+4 {"firstName":"John","lastName":"Ryan","age":39}
+```
+
+### OPTIONS /
+Fetch ejdb JSON metadata and available HTTP methods in `Allow` response header.
+Example:
+```
+curl -X OPTIONS -H 'X-Access-Token:myaccess01' http://localhost:9191/
+{
+ "version": "2.0.0",
+ "file": "db.jb",
+ "size": 16384,
+ "collections": [
+ {
+ "name": "family",
+ "dbid": 3,
+ "rnum": 3,
+ "indexes": [
+ {
+ "ptr": "/lastName",
+ "mode": 4,
+ "idbf": 64,
+ "dbid": 4,
+ "rnum": 3
+ }
+ ]
+ }
+ ]
+}
+```
+
+## Websocket API
+
+EJDB supports simple text based protocol over HTTP websocket protocol.
+You can use interactive websocket CLI tool [wscat](https://www.npmjs.com/package/@softmotions/wscat) to communicate with server by hands.
+
+### Commands
+
+#### ?
+Will respond with the following help text message:
+```
+wscat -H 'X-Access-Token:myaccess01' -c http://localhost:9191
+> ?
+<
+ info
+ get
+ set
+ add
+ del
+ patch
+ idx
+ rmi
+ rmc
+ query
+ explain
+
+>
+```
+
+Note about `` prefix before every command; It is an arbitrary key chosen by client and designated to identify particular websocket request, this key will be returned with response to request and allows client to identify that response for his particular request.
+
+Errors are returned in the following format:
+```
+ ERROR:
+```
+
+#### ` info`
+Get database metadatas as JSON document.
+
+#### ` get `
+Retrieve document identified by `id` from a `collection`.
+If document is not found `IWKV_ERROR_NOTFOUND` will be returned.
+
+Example:
+```
+> k get family 3
+< k 3 {
+ "firstName": "Jack",
+ "lastName": "Parker",
+ "age": 35,
+ "pets": [
+ {
+ "name": "Sonic",
+ "kind": "mouse",
+ "likes": []
+ }
+ ]
+}
+```
+If document not found we will get error:
+```
+> k get family 55
+< k ERROR: Key not found. (IWKV_ERROR_NOTFOUND)
+>
+```
+
+#### ` set `
+Replaces/add document under specific numeric `id`.
+`Collection` will be created automatically if not exists.
+
+#### ` add `
+Add new document to `` New `id` of document will be generated
+and returned as response. `Collection> will be created automatically if not exists.
+
+Example:
+```
+> k add mycollection {"foo":"bar"}
+< k 1
+> k add mycollection {"foo":"bar"}
+< k 2
+>
+```
+
+#### ` del `
+Remove document identified by `id` from the `collection`.
+If document is not found `IWKV_ERROR_NOTFOUND` will be returned.
+
+#### ` patch `
+Apply [rfc7396](https://tools.ietf.org/html/rfc7396) or
+[rfc6902](https://tools.ietf.org/html/rfc6902) patch to the document identified by `id`.
+If document is not found `IWKV_ERROR_NOTFOUND` will be returned.
+
+#### ` query `
+Execute query on documents in specified `collection`.
+**Response:** A set of WS messages with document boidies terminated by the last
+message with empty body.
+```
+> k query family /* | /firstName
+< k 4 {"firstName":"John"}
+< k 3 {"firstName":"Jack"}
+< k 1 {"firstName":"John"}
+< k
+```
+Note about last message: `` with no body.
+
+#### ` explain `
+Same as ` query ` but the first response message will
+be prefixed by ` explain` and contains query execution plan.
+
+Example:
+```
+> k explain family /* | /firstName
+< k explain [INDEX] NO [COLLECTOR] PLAIN
+
+< k 4 {"firstName":"John"}
+< k 3 {"firstName":"Jack"}
+< k 1 {"firstName":"John"}
+< k
+```
+
+####
+Execute query text. Body of query should contains collection name in use in the first filter element: `@collection_name/...`. Behavior is the same as for: ` query `
+
+#### ` idx `
+Ensure index with specified `mode` (bitmask flag) for given json `path` and `collection`.
+Collection will be created if not exists.
+
+Index mode | Description
+--- | ---
+0x01 EJDB_IDX_UNIQUE | Index is unique
+0x04 EJDB_IDX_STR | Index for JSON `string` field value type
+0x08 EJDB_IDX_I64 | Index for `8 bytes width` signed integer field values
+0x10 EJDB_IDX_F64 | Index for `8 bytes width` signed floating point field values.
+
+##### Example
+Set unique string index `(0x01 & 0x04) = 5` on `/name` JSON field:
+```
+k idx mycollection 5 /name
+```
+
+#### ` rmi `
+Remove index with specified `mode` (bitmask flag) for given json `path` and `collection`.
+Return error if given index not found.
+
+#### ` rmc `
+Remove collection and all of its data.
+Note: If `collection` is not found no errors will be reported.
+
+
+
+
+# Docker support
+
+If you have [Docker]("https://www.docker.com/") installed, you can build a Docker image and run it in a container
+
+```
+cd docker
+docker build -t ejdb2 .
+docker run -d -p 9191:9191 --name myEJDB ejdb2 --access myAccessKey
+```
+
+or get an image of `ejdb2` directly from the Docker Hub
+
+```
+docker run -d -p 9191:9191 --name myEJDB softmotions/ejdb2 --access myAccessKey
+```
+
+
+# C API
+
+EJDB can be embedded into any `C/C++` application.
+`C API` documented in the following headers:
+
+* [ejdb.h](https://github.com/Softmotions/ejdb/blob/master/src/ejdb2.h) Main API functions
+* [jbl.h](https://github.com/Softmotions/ejdb/blob/master/src/jbl/jbl.h) JSON documents management API
+* [jql.h](https://github.com/Softmotions/ejdb/blob/master/src/jql/jql.h) Query building API
+
+Example application:
+```c
+#include
+
+#define CHECK(rc_) \
+ if (rc_) { \
+ iwlog_ecode_error3(rc_); \
+ return 1; \
+ }
+
+static iwrc documents_visitor(EJDB_EXEC *ctx, const EJDB_DOC doc, int64_t *step) {
+ // Print document to stderr
+ return jbl_as_json(doc->raw, jbl_fstream_json_printer, stderr, JBL_PRINT_PRETTY);
+}
+
+int main() {
+
+ EJDB_OPTS opts = {
+ .kv = {
+ .path = "example.db",
+ .oflags = IWKV_TRUNC
+ }
+ };
+ EJDB db; // EJDB2 storage handle
+ int64_t id; // Document id placeholder
+ JQL q = 0; // Query instance
+ JBL jbl = 0; // Json document
+
+ iwrc rc = ejdb_init();
+ CHECK(rc);
+
+ rc = ejdb_open(&opts, &db);
+ CHECK(rc);
+
+ // First record
+ rc = jbl_from_json(&jbl, "{\"name\":\"Bianca\", \"age\":4}");
+ RCGO(rc, finish);
+ rc = ejdb_put_new(db, "parrots", jbl, &id);
+ RCGO(rc, finish);
+ jbl_destroy(&jbl);
+
+ // Second record
+ rc = jbl_from_json(&jbl, "{\"name\":\"Darko\", \"age\":8}");
+ RCGO(rc, finish);
+ rc = ejdb_put_new(db, "parrots", jbl, &id);
+ RCGO(rc, finish);
+ jbl_destroy(&jbl);
+
+ // Now execute a query
+ rc = jql_create(&q, "parrots", "/[age > :age]");
+ RCGO(rc, finish);
+
+ EJDB_EXEC ux = {
+ .db = db,
+ .q = q,
+ .visitor = documents_visitor
+ };
+
+ // Set query placeholder value.
+ // Actual query will be /[age > 3]
+ rc = jql_set_i64(q, "age", 0, 3);
+ RCGO(rc, finish);
+
+ // Now execute the query
+ rc = ejdb_exec(&ux);
+
+finish:
+ jql_destroy(&q);
+ jbl_destroy(&jbl);
+ ejdb_close(&db);
+ CHECK(rc);
+ return 0;
+}
+```
+
+Compile and run:
+```
+gcc -std=gnu11 -Wall -pedantic -c -o example1.o example1.c
+gcc -o example1 example1.o -lejdb2
+
+./example1
+{
+ "name": "Darko",
+ "age": 8
+}{
+ "name": "Bianca",
+ "age": 4
+}
+```
+
+# License
+```
+
+MIT License
+
+Copyright (c) 2012-2021 Softmotions Ltd
+
+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.
+```
-1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
-2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
-3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
-4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
-5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
-6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
diff --git a/WINDOWS.md b/WINDOWS.md
new file mode 100644
index 0000000..9e5ffb5
--- /dev/null
+++ b/WINDOWS.md
@@ -0,0 +1,50 @@
+# Windows cross compilation
+
+**Note:** HTTP/Websocket network API is disabled and not supported
+on Windows until porting of http://facil.io library
+
+Nodejs/Dart bindings not yet ported to Windows.
+
+## Prerequisites
+
+```sh
+sudo apt-get install bison flex libtool ruby scons intltool libtool-bin p7zip-full wine
+```
+
+## Build
+
+### Prepare MXE
+
+```sh
+git submodule update --init
+```
+
+`nano ./mxe/settings.mk`:
+
+```
+JOBS := 1
+MXE_TARGETS := x86_64-w64-mingw32.static
+LOCAL_PKG_LIST := cunit libiberty
+.DEFAULT local-pkg-list:
+local-pkg-list: $(LOCAL_PKG_LIST)
+```
+
+```
+cd ./mxe
+make
+```
+
+### Cross compilation
+
+```bash
+mkdir ./build
+cd ./build
+
+export MXE_HOME=/mxe
+
+cmake .. -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_TOOLCHAIN_FILE=../win64-tc.cmake \
+ -DENABLE_HTTP=OFF
+
+make package
+```
\ No newline at end of file
diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 0000000..903f3fc
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1,3 @@
+analyzer:
+ exclude:
+ - build/**
\ No newline at end of file
diff --git a/cmake/Modules/AddFacil.cmake b/cmake/Modules/AddFacil.cmake
new file mode 100644
index 0000000..a6d3af6
--- /dev/null
+++ b/cmake/Modules/AddFacil.cmake
@@ -0,0 +1,86 @@
+include(ExternalProject)
+
+if (${CMAKE_VERSION} VERSION_LESS "3.8.0")
+ set(_UPDATE_DISCONNECTED 0)
+else()
+ set(_UPDATE_DISCONNECTED 1)
+endif()
+
+set(FACIL_SOURCE_DIR "${CMAKE_BINARY_DIR}/src/extern_facil")
+set(FACIL_BINARY_DIR "${CMAKE_BINARY_DIR}/src/extern_facil")
+set(FACIL_INCLUDE_DIR "${FACIL_BINARY_DIR}/lib/facil")
+set(FACIL_LIBRARY_DIR "${FACIL_BINARY_DIR}")
+
+if("${FACIL_URL}" STREQUAL "")
+ if(EXISTS ${CMAKE_SOURCE_DIR}/facil.zip)
+ set(FACIL_URL ${CMAKE_SOURCE_DIR}/facil.zip)
+ else()
+ set(FACIL_URL https://github.com/Softmotions/facil.io/archive/master.zip)
+ endif()
+endif()
+
+message("FACIL_URL: ${FACIL_URL}")
+
+set(CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+ -DCMAKE_C_FLAGS=-fPIC -fvisibility=hidden)
+
+foreach(extra
+ CMAKE_C_COMPILER
+ CMAKE_TOOLCHAIN_FILE
+ ANDROID_PLATFORM
+ ANDROID_ABI
+ TEST_TOOL_CMD
+ PLATFORM
+ ENABLE_BITCODE
+ ENABLE_ARC
+ ENABLE_VISIBILITY
+ ENABLE_STRICT_TRY_COMPILE
+ ARCHS)
+ if(DEFINED ${extra})
+ list(APPEND CMAKE_ARGS "-D${extra}=${${extra}}")
+ endif()
+endforeach()
+message("FACIL CMAKE_ARGS: ${CMAKE_ARGS}")
+
+ExternalProject_Add(
+ extern_facil
+ URL ${FACIL_URL}
+ DOWNLOAD_NAME facil.zip
+ TIMEOUT 360
+ # Remove in-source makefile to avoid clashing
+ PATCH_COMMAND rm -f ./makefile
+ PREFIX ${CMAKE_BINARY_DIR}
+ BUILD_IN_SOURCE ON
+ GIT_PROGRESS ON
+ UPDATE_COMMAND ""
+ INSTALL_COMMAND ""
+ UPDATE_DISCONNECTED ${_UPDATE_DISCONNECTED}
+ LOG_DOWNLOAD OFF
+ LOG_UPDATE OFF
+ LOG_BUILD OFF
+ LOG_CONFIGURE OFF
+ LOG_INSTALL OFF
+ CMAKE_ARGS ${CMAKE_ARGS}
+ BUILD_BYPRODUCTS "${FACIL_LIBRARY_DIR}/libfacil.io.a"
+)
+
+add_library(facil_s STATIC IMPORTED GLOBAL)
+set_target_properties(
+ facil_s
+ PROPERTIES
+ IMPORTED_LOCATION "${FACIL_LIBRARY_DIR}/libfacil.io.a"
+)
+add_dependencies(facil_s extern_facil)
+
+if (DO_INSTALL_CORE)
+ install(FILES "${FACIL_LIBRARY_DIR}/libfacil.io.a"
+ RENAME "libfacilio-1.a"
+ DESTINATION ${CMAKE_INSTALL_LIBDIR})
+endif()
+
+list(APPEND PROJECT_LLIBRARIES facil_s)
+list(APPEND PROJECT_INCLUDE_DIRS "${FACIL_INCLUDE_DIR}"
+ "${FACIL_INCLUDE_DIR}/fiobj"
+ "${FACIL_INCLUDE_DIR}/http"
+ "${FACIL_INCLUDE_DIR}/cli"
+ "${FACIL_INCLUDE_DIR}/tls")
diff --git a/cmake/Modules/AddIOWOW.cmake b/cmake/Modules/AddIOWOW.cmake
new file mode 100644
index 0000000..854bbaf
--- /dev/null
+++ b/cmake/Modules/AddIOWOW.cmake
@@ -0,0 +1,84 @@
+include(ExternalProject)
+
+if (${CMAKE_VERSION} VERSION_LESS "3.8.0")
+ set(_UPDATE_DISCONNECTED 0)
+else()
+ set(_UPDATE_DISCONNECTED 1)
+endif()
+
+set(IOWOW_INCLUDE_DIR "${CMAKE_BINARY_DIR}/include")
+
+if("${IOWOW_URL}" STREQUAL "")
+ if(EXISTS ${CMAKE_SOURCE_DIR}/iowow.zip)
+ set(IOWOW_URL ${CMAKE_SOURCE_DIR}/iowow.zip)
+ else()
+ set(IOWOW_URL https://github.com/Softmotions/iowow/archive/master.zip)
+ endif()
+endif()
+
+message("IOWOW_URL: ${IOWOW_URL}")
+
+if (IOS)
+ set(BYPRODUCT "${CMAKE_BINARY_DIR}/lib/libiowow-1.a")
+else()
+ set(BYPRODUCT "${CMAKE_BINARY_DIR}/src/extern_iowow-build/src/libiowow-1.a")
+endif()
+
+set(CMAKE_ARGS -DOWNER_PROJECT_NAME=${PROJECT_NAME}
+ -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+ -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}
+ -DASAN=${ASAN}
+ -DBUILD_SHARED_LIBS=OFF
+ -DBUILD_EXAMPLES=OFF)
+
+foreach(extra
+ CMAKE_C_COMPILER
+ CMAKE_TOOLCHAIN_FILE
+ ANDROID_PLATFORM
+ ANDROID_ABI
+ TEST_TOOL_CMD
+ PLATFORM
+ ENABLE_BITCODE
+ ENABLE_ARC
+ ENABLE_VISIBILITY
+ ENABLE_STRICT_TRY_COMPILE
+ ARCHS)
+ if(DEFINED ${extra})
+ list(APPEND CMAKE_ARGS "-D${extra}=${${extra}}")
+ endif()
+endforeach()
+message("IOWOW CMAKE_ARGS: ${CMAKE_ARGS}")
+
+ExternalProject_Add(
+ extern_iowow
+ URL ${IOWOW_URL}
+ DOWNLOAD_NAME iowow.zip
+ TIMEOUT 360
+ PREFIX ${CMAKE_BINARY_DIR}
+ BUILD_IN_SOURCE OFF
+ UPDATE_COMMAND ""
+ UPDATE_DISCONNECTED ${_UPDATE_DISCONNECTED}
+ LOG_DOWNLOAD OFF
+ LOG_UPDATE OFF
+ LOG_BUILD OFF
+ LOG_CONFIGURE OFF
+ LOG_INSTALL OFF
+ CMAKE_ARGS ${CMAKE_ARGS}
+ BUILD_BYPRODUCTS ${BYPRODUCT}
+)
+
+add_library(iowow_s STATIC IMPORTED GLOBAL)
+set_target_properties(
+ iowow_s
+ PROPERTIES
+ IMPORTED_LOCATION ${BYPRODUCT}
+)
+add_dependencies(iowow_s extern_iowow)
+
+if (DO_INSTALL_CORE)
+ install(FILES "${BYPRODUCT}"
+ DESTINATION ${CMAKE_INSTALL_LIBDIR})
+endif()
+
+list(APPEND PROJECT_LLIBRARIES iowow_s m)
+list(APPEND PROJECT_INCLUDE_DIRS "${IOWOW_INCLUDE_DIR}")
diff --git a/cmake/Modules/CMakeFindJavaCommon.cmake b/cmake/Modules/CMakeFindJavaCommon.cmake
new file mode 100644
index 0000000..46b6280
--- /dev/null
+++ b/cmake/Modules/CMakeFindJavaCommon.cmake
@@ -0,0 +1,31 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# Do not include this module directly from code outside CMake!
+set(_JAVA_HOME "")
+if(JAVA_HOME AND IS_DIRECTORY "${JAVA_HOME}")
+ set(_JAVA_HOME "${JAVA_HOME}")
+ set(_JAVA_HOME_EXPLICIT 1)
+else()
+ set(_ENV_JAVA_HOME "")
+ if(DEFINED ENV{JAVA_HOME})
+ file(TO_CMAKE_PATH "$ENV{JAVA_HOME}" _ENV_JAVA_HOME)
+ endif()
+ if(_ENV_JAVA_HOME AND IS_DIRECTORY "${_ENV_JAVA_HOME}")
+ set(_JAVA_HOME "${_ENV_JAVA_HOME}")
+ set(_JAVA_HOME_EXPLICIT 1)
+ else()
+ set(_CMD_JAVA_HOME "")
+ if(APPLE AND EXISTS /usr/libexec/java_home)
+ execute_process(COMMAND /usr/libexec/java_home
+ OUTPUT_VARIABLE _CMD_JAVA_HOME OUTPUT_STRIP_TRAILING_WHITESPACE)
+ endif()
+ if(_CMD_JAVA_HOME AND IS_DIRECTORY "${_CMD_JAVA_HOME}")
+ set(_JAVA_HOME "${_CMD_JAVA_HOME}")
+ set(_JAVA_HOME_EXPLICIT 0)
+ endif()
+ unset(_CMD_JAVA_HOME)
+ endif()
+ unset(_ENV_JAVA_HOME)
+endif()
diff --git a/cmake/Modules/DebChangelog.cmake b/cmake/Modules/DebChangelog.cmake
new file mode 100644
index 0000000..706d1b7
--- /dev/null
+++ b/cmake/Modules/DebChangelog.cmake
@@ -0,0 +1,54 @@
+## -*- mode:cmake; coding:utf-8; -*-
+# Set output:
+# CHANGELOG_LAST_LINE
+# CHANGELOG_LAST_VERSION - Last changelog version
+# CHANGELOG_LAST_VERSION_MAJOR - Last changelog major version
+# CHANGELOG_LAST_VERSION_MINOR - Last changelog minor version
+# CHANGELOG_LAST_VERSION_PATCH - Last changelog patch version
+# CHANGELOG_LAST_MESSAGE - Last changelog description
+
+if (NOT DEB_CHANGELOG)
+ set(DEB_CHANGELOG "${CMAKE_SOURCE_DIR}/Changelog")
+endif()
+
+if (NOT EXISTS ${DEB_CHANGELOG})
+ if (DEB_CHANGELOG_REQUIRED)
+ message(FATAL_ERROR "Missing required project changelog file: ${DEB_CHANGELOG}")
+ else()
+ message("Missing project changelog file: ${DEB_CHANGELOG}")
+ return()
+ endif()
+endif()
+message(STATUS "Using project changelog file: ${DEB_CHANGELOG}")
+
+file(STRINGS "${DEB_CHANGELOG}" _DEBCHANGELOGN)
+
+foreach(CLINE IN LISTS _DEBCHANGELOGN)
+ if (NOT CHANGELOG_LAST_VERSION)
+ #ejdb (1.2.6) testing; urgency=low
+ string(REGEX MATCH "^[A-Za-z0-9_].*[ \t]+\\((([0-9]+)\\.([0-9]+)\\.([0-9]+))\\)[ \t]+[A-Za-z]+;[ \t].*" _MATCHED "${CLINE}")
+ if (_MATCHED)
+ set(CHANGELOG_LAST_LINE "${_MATCHED}")
+ set(CHANGELOG_LAST_VERSION "${CMAKE_MATCH_1}")
+ set(CHANGELOG_LAST_VERSION_MAJOR "${CMAKE_MATCH_2}")
+ set(CHANGELOG_LAST_VERSION_MINOR "${CMAKE_MATCH_3}")
+ set(CHANGELOG_LAST_VERSION_PATCH "${CMAKE_MATCH_4}")
+ endif()
+ elseif(NOT CHANGELOG_LAST_MESSAGE)
+ string(REGEX MATCH "^[A-Za-z0-9_].*[ \t]+\\((([0-9]+)\\.([0-9]+)\\.([0-9]+))\\)[ \t]+[A-Za-z]+;[ \t].*" _MATCHED "${CLINE}")
+ if (_MATCHED)
+ string(STRIP "${_CDESC}" CHANGELOG_LAST_MESSAGE)
+ return()
+ endif()
+ if (CLINE)
+ string(REGEX MATCH "^[ \t]*\\-\\-[ \t]+" _MATCHED "${CLINE}")
+ if (_MATCHED)
+ string(STRIP "${_CDESC}" CHANGELOG_LAST_MESSAGE)
+ return()
+ endif()
+ set(_CDESC "${_CDESC}\n${CLINE}")
+ endif()
+ endif()
+endforeach(CLINE)
+
+message(FATAL_ERROR "Invalid changelog file: ${DEB_CHANGELOG}")
diff --git a/cmake/Modules/FindCUnit.cmake b/cmake/Modules/FindCUnit.cmake
new file mode 100644
index 0000000..a0cf0e8
--- /dev/null
+++ b/cmake/Modules/FindCUnit.cmake
@@ -0,0 +1,24 @@
+# Find the CUnit headers and libraries
+#
+# CUNIT_INCLUDE_DIRS - The CUnit include directory (directory where CUnit/CUnit.h was found)
+# CUNIT_LIBRARIES - The libraries needed to use CUnit
+# CUNIT_FOUND - True if CUnit found in system
+
+
+FIND_PATH(CUNIT_INCLUDE_DIR NAMES CUnit/CUnit.h)
+MARK_AS_ADVANCED(CUNIT_INCLUDE_DIR)
+
+FIND_LIBRARY(CUNIT_LIBRARY NAMES
+ cunit
+ libcunit
+ cunitlib
+)
+MARK_AS_ADVANCED(CUNIT_LIBRARY)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(CUnit DEFAULT_MSG CUNIT_LIBRARY CUNIT_INCLUDE_DIR)
+
+IF(CUNIT_FOUND)
+ SET(CUNIT_LIBRARIES ${CUNIT_LIBRARY})
+ SET(CUNIT_INCLUDE_DIRS ${CUNIT_INCLUDE_DIR})
+ENDIF(CUNIT_FOUND)
diff --git a/cmake/Modules/FindIOWOW.cmake b/cmake/Modules/FindIOWOW.cmake
new file mode 100644
index 0000000..d93dfd0
--- /dev/null
+++ b/cmake/Modules/FindIOWOW.cmake
@@ -0,0 +1,39 @@
+# Find the IOWOW headers and libraries, attemting to import IOWOW exported targets,
+#
+# IOWOW_INCLUDE_DIRS - The IOWOW include directory
+# IOWOW_LIBRARIES - The libraries needed to use IOWOW
+# IOWOW_FOUND - True if IOWOW found in system
+
+find_path(IOWOW_INCLUDE_DIR NAMES iowow/iowow.h)
+mark_as_advanced(IOWOW_INCLUDE_DIR)
+find_library(IOWOW_LIBRARY NAMES
+ iowow
+ libiowow
+ iowowlib
+)
+mark_as_advanced(IOWOW_LIBRARY)
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(IOWOW DEFAULT_MSG IOWOW_LIBRARY IOWOW_INCLUDE_DIR)
+
+if(IOWOW_FOUND)
+ set(IOWOW_LIBRARIES ${IOWOW_LIBRARY})
+ set(IOWOW_INCLUDE_DIRS ${IOWOW_INCLUDE_DIR})
+ find_path(IOWOW_EXPORTS_DIR
+ NAMES "iowow/iowow-exports.cmake"
+ PATHS /usr/share /usr/local/share)
+ mark_as_advanced(IOWOW_EXPORTS_DIR)
+ if(IOWOW_EXPORTS_DIR)
+ if(EXISTS ${IOWOW_EXPORTS_DIR}/iowow/iowow-exports.cmake)
+ include(${IOWOW_EXPORTS_DIR}/iowow/iowow-exports.cmake)
+ message("-- Imported ${IOWOW_EXPORTS_DIR}/iowow/iowow-exports.cmake")
+ endif()
+ if(EXISTS ${IOWOW_EXPORTS_DIR}/iowow/iowow-static-exports.cmake)
+ include(${IOWOW_EXPORTS_DIR}/iowow/iowow-static-exports.cmake)
+ message("-- Imported ${IOWOW_EXPORTS_DIR}/iowow/iowow-static-exports.cmake")
+ endif()
+ endif(IOWOW_EXPORTS_DIR)
+elseif(IOWOW_FIND_REQUIRED)
+ message(FATAL_ERROR "Could not find libiowow.")
+endif(IOWOW_FOUND)
+
+
diff --git a/cmake/Modules/FindJNI.cmake b/cmake/Modules/FindJNI.cmake
new file mode 100644
index 0000000..2a4bf7f
--- /dev/null
+++ b/cmake/Modules/FindJNI.cmake
@@ -0,0 +1,406 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindJNI
+-------
+
+Find Java Native Interface (JNI) libraries.
+
+JNI enables Java code running in a Java Virtual Machine (JVM) to call
+and be called by native applications and libraries written in other
+languages such as C, C++.
+
+This module finds if Java is installed and determines where the
+include files and libraries are. It also determines what the name of
+the library is. The caller may set variable ``JAVA_HOME`` to specify a
+Java installation prefix explicitly.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module sets the following result variables:
+
+``JNI_INCLUDE_DIRS``
+ the include dirs to use
+``JNI_LIBRARIES``
+ the libraries to use (JAWT and JVM)
+``JNI_FOUND``
+ TRUE if JNI headers and libraries were found.
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+The following cache variables are also available to set or use:
+
+``JAVA_AWT_LIBRARY``
+ the path to the Java AWT Native Interface (JAWT) library
+``JAVA_JVM_LIBRARY``
+ the path to the Java Virtual Machine (JVM) library
+``JAVA_INCLUDE_PATH``
+ the include path to jni.h
+``JAVA_INCLUDE_PATH2``
+ the include path to jni_md.h and jniport.h
+#]=======================================================================]
+
+# Expand {libarch} occurrences to java_libarch subdirectory(-ies) and set ${_var}
+macro(java_append_library_directories _var)
+ # Determine java arch-specific library subdir
+ # Mostly based on openjdk/jdk/make/common/shared/Platform.gmk as of openjdk
+ # 1.6.0_18 + icedtea patches. However, it would be much better to base the
+ # guess on the first part of the GNU config.guess platform triplet.
+ if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
+ if(CMAKE_LIBRARY_ARCHITECTURE STREQUAL "x86_64-linux-gnux32")
+ set(_java_libarch "x32" "amd64" "i386")
+ else()
+ set(_java_libarch "amd64" "i386")
+ endif()
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$")
+ set(_java_libarch "i386")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^alpha")
+ set(_java_libarch "alpha")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm")
+ # Subdir is "arm" for both big-endian (arm) and little-endian (armel).
+ set(_java_libarch "arm" "aarch32")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips")
+ # mips* machines are bi-endian mostly so processor does not tell
+ # endianness of the underlying system.
+ set(_java_libarch "${CMAKE_SYSTEM_PROCESSOR}"
+ "mips" "mipsel" "mipseb" "mipsr6" "mipsr6el"
+ "mips64" "mips64el" "mips64r6" "mips64r6el"
+ "mipsn32" "mipsn32el" "mipsn32r6" "mipsn32r6el")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64le")
+ set(_java_libarch "ppc64" "ppc64le")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64")
+ set(_java_libarch "ppc64" "ppc")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)")
+ set(_java_libarch "ppc" "ppc64")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^sparc")
+ # Both flavours can run on the same processor
+ set(_java_libarch "${CMAKE_SYSTEM_PROCESSOR}" "sparc" "sparcv9")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(parisc|hppa)")
+ set(_java_libarch "parisc" "parisc64")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^s390")
+ # s390 binaries can run on s390x machines
+ set(_java_libarch "${CMAKE_SYSTEM_PROCESSOR}" "s390" "s390x")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^sh")
+ set(_java_libarch "sh")
+ else()
+ set(_java_libarch "${CMAKE_SYSTEM_PROCESSOR}")
+ endif()
+
+ # Append default list architectures if CMAKE_SYSTEM_PROCESSOR was empty or
+ # system is non-Linux (where the code above has not been well tested)
+ if(NOT _java_libarch OR NOT (CMAKE_SYSTEM_NAME MATCHES "Linux"))
+ list(APPEND _java_libarch "i386" "amd64" "ppc")
+ endif()
+
+ # Sometimes ${CMAKE_SYSTEM_PROCESSOR} is added to the list to prefer
+ # current value to a hardcoded list. Remove possible duplicates.
+ list(REMOVE_DUPLICATES _java_libarch)
+
+ foreach(_path ${ARGN})
+ if(_path MATCHES "{libarch}")
+ foreach(_libarch ${_java_libarch})
+ string(REPLACE "{libarch}" "${_libarch}" _newpath "${_path}")
+ if(EXISTS ${_newpath})
+ list(APPEND ${_var} "${_newpath}")
+ endif()
+ endforeach()
+ else()
+ if(EXISTS ${_path})
+ list(APPEND ${_var} "${_path}")
+ endif()
+ endif()
+ endforeach()
+endmacro()
+
+include(CMakeFindJavaCommon)
+
+# Save CMAKE_FIND_FRAMEWORK
+if(DEFINED CMAKE_FIND_FRAMEWORK)
+ set(_JNI_CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK})
+else()
+ unset(_JNI_CMAKE_FIND_FRAMEWORK)
+endif()
+
+if(_JAVA_HOME_EXPLICIT)
+ set(CMAKE_FIND_FRAMEWORK NEVER)
+endif()
+
+set(JAVA_AWT_LIBRARY_DIRECTORIES)
+if(_JAVA_HOME)
+ JAVA_APPEND_LIBRARY_DIRECTORIES(JAVA_AWT_LIBRARY_DIRECTORIES
+ ${_JAVA_HOME}/jre/lib/{libarch}
+ ${_JAVA_HOME}/jre/lib
+ ${_JAVA_HOME}/lib/{libarch}
+ ${_JAVA_HOME}/lib
+ ${_JAVA_HOME}
+ )
+endif()
+
+if (WIN32)
+ set (_JNI_HINTS)
+ execute_process(COMMAND REG QUERY HKLM\\SOFTWARE\\JavaSoft\\JDK /f "." /k
+ RESULT_VARIABLE _JNI_RESULT
+ OUTPUT_VARIABLE _JNI_VERSIONS
+ ERROR_QUIET)
+ if (NOT _JNI_RESULT)
+ string (REGEX MATCHALL "HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\JavaSoft\\\\JDK\\\\[0-9.]+" _JNI_VERSIONS "${_JNI_VERSIONS}")
+ if (_JNI_VERSIONS)
+ # sort versions. Most recent first
+ ## handle version 9 apart from other versions to get correct ordering
+ set (_JNI_V9 ${_JNI_VERSIONS})
+ list (FILTER _JNI_VERSIONS EXCLUDE REGEX "JDK\\\\9")
+ list (SORT _JNI_VERSIONS)
+ list (REVERSE _JNI_VERSIONS)
+ list (FILTER _JNI_V9 INCLUDE REGEX "JDK\\\\9")
+ list (SORT _JNI_V9)
+ list (REVERSE _JNI_V9)
+ list (APPEND _JNI_VERSIONS ${_JNI_V9})
+ foreach (_JNI_HINT IN LISTS _JNI_VERSIONS)
+ list(APPEND _JNI_HINTS "[${_JNI_HINT};JavaHome]")
+ endforeach()
+ endif()
+ endif()
+
+ foreach (_JNI_HINT IN LISTS _JNI_HINTS)
+ list(APPEND JAVA_AWT_LIBRARY_DIRECTORIES "${_JNI_HINT}/lib")
+ endforeach()
+
+ get_filename_component(java_install_version
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit;CurrentVersion]" NAME)
+
+ list(APPEND JAVA_AWT_LIBRARY_DIRECTORIES
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\11;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\10;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.9;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.8;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.7;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.6;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.5;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/lib"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\${java_install_version};JavaHome]/lib"
+ )
+endif()
+
+JAVA_APPEND_LIBRARY_DIRECTORIES(JAVA_AWT_LIBRARY_DIRECTORIES
+ /usr/lib/jvm/java/lib
+ /usr/lib/java/jre/lib/{libarch}
+ /usr/lib/jvm/jre/lib/{libarch}
+ /usr/local/lib/java/jre/lib/{libarch}
+ /usr/local/share/java/jre/lib/{libarch}
+ # Debian specific paths for default JVM
+ /usr/lib/jvm/default-java/jre/lib/{libarch}
+ /usr/lib/jvm/default-java/jre/lib
+ /usr/lib/jvm/default-java/lib
+ # Arch Linux specific paths for default JVM
+ /usr/lib/jvm/default/jre/lib/{libarch}
+ /usr/lib/jvm/default/lib/{libarch}
+ # SuSE specific paths for default JVM
+ /usr/lib64/jvm/java/jre/lib/{libarch}
+ /usr/lib64/jvm/jre/lib/{libarch}
+ /usr/lib/jvm/java-11-openjdk-{libarch}/jre/lib/{libarch} # Ubuntu 18.04 LTS
+ /usr/lib/jvm/java-11-oracle/lib/{libarch}
+ /usr/lib/jvm/java-10-openjdk-{libarch}/jre/lib/{libarch}
+ /usr/lib/jvm/java-10-oracle/lib/{libarch}
+ /usr/lib/jvm/java-9-openjdk-{libarch}/jre/lib/{libarch}
+ /usr/lib/jvm/java-9-oracle/lib/{libarch}
+ /usr/lib/jvm/java-8-openjdk-{libarch}/jre/lib/{libarch} # Ubuntu 15.10
+ /usr/lib/jvm/java-8-oracle/lib/{libarch}
+ # Ubuntu specific paths for default JVM
+ /usr/lib/jvm/java-7-openjdk-{libarch}/jre/lib/{libarch} # Ubuntu 15.10
+ /usr/lib/jvm/java-7-oracle/lib/{libarch}
+ /usr/lib/jvm/java-6-openjdk-{libarch}/jre/lib/{libarch} # Ubuntu 15.10
+ /usr/lib/jvm/java-6-oracle/lib/{libarch}
+ /usr/lib/jvm/java-6-sun/jre/lib/{libarch}
+ /usr/lib/jvm/java-6-sun-1.6.0.00/jre/lib/{libarch} # can this one be removed according to #8821 ? Alex
+ /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre/lib/{libarch} # fedora
+ /usr/lib/jvm/java-6-openjdk/jre/lib/{libarch}
+ # OpenBSD specific paths for default JVM
+ /usr/local/jdk-1.8.0/jre/lib/{libarch}
+ /usr/local/jre-1.8.0/lib/{libarch}
+ /usr/local/jdk-1.7.0/jre/lib/{libarch}
+ /usr/local/jre-1.7.0/lib/{libarch}
+ /usr/local/jdk-1.6.0/jre/lib/{libarch}
+ /usr/local/jre-1.6.0/lib/{libarch}
+ )
+
+set(JAVA_JVM_LIBRARY_DIRECTORIES)
+foreach(dir ${JAVA_AWT_LIBRARY_DIRECTORIES})
+ list(APPEND JAVA_JVM_LIBRARY_DIRECTORIES
+ "${dir}"
+ "${dir}/client"
+ "${dir}/server"
+ # IBM SDK, Java Technology Edition, specific paths
+ "${dir}/j9vm"
+ "${dir}/default"
+ )
+endforeach()
+
+set(JAVA_AWT_INCLUDE_DIRECTORIES)
+if(_JAVA_HOME)
+ list(APPEND JAVA_AWT_INCLUDE_DIRECTORIES ${_JAVA_HOME}/include)
+endif()
+if (WIN32)
+ foreach (_JNI_HINT IN LISTS _JNI_HINTS)
+ list(APPEND JAVA_AWT_INCLUDE_DIRECTORIES "${_JNI_HINT}/include")
+ endforeach()
+ list(APPEND JAVA_AWT_INCLUDE_DIRECTORIES
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\11;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\10;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.9;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.8;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.7;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.6;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.5;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/include"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\${java_install_version};JavaHome]/include"
+ )
+endif()
+
+JAVA_APPEND_LIBRARY_DIRECTORIES(JAVA_AWT_INCLUDE_DIRECTORIES
+ /usr/lib/java/include
+ /usr/local/lib/java/include
+ /usr/lib/jvm/java/include
+ /usr/lib/jvm/java-11-openjdk-{libarch}/include
+ /usr/lib/jvm/java-11-oracle/include
+ /usr/lib/jvm/java-10-openjdk-{libarch}/include
+ /usr/lib/jvm/java-10-oracle/include
+ /usr/lib/jvm/java-9-openjdk-{libarch}/include
+ /usr/lib/jvm/java-9-oracle/include
+ /usr/lib/jvm/java-8-openjdk-{libarch}/include
+ /usr/lib/jvm/java-8-oracle/include
+ /usr/lib/jvm/java-7-openjdk-{libarch}/include
+ /usr/lib/jvm/java-7-oracle/include
+ /usr/lib/jvm/java-6-openjdk-{libarch}/include
+ /usr/lib/jvm/java-6-openjdk/include
+ /usr/lib/jvm/java-6-oracle/include
+ /usr/lib/jvm/java-6-sun/include
+ /usr/local/share/java/include
+ # Debian specific path for default JVM
+ /usr/lib/jvm/default-java/include
+ # Arch specific path for default JVM
+ /usr/lib/jvm/default/include
+ # OpenBSD specific path for default JVM
+ /usr/local/jdk-1.8.0/include
+ /usr/local/jdk-1.7.0/include
+ /usr/local/jdk-1.6.0/include
+ # SuSE specific paths for default JVM
+ /usr/lib64/jvm/java/include
+ )
+
+foreach(JAVA_PROG "${JAVA_RUNTIME}" "${JAVA_COMPILE}" "${JAVA_ARCHIVE}")
+ get_filename_component(jpath "${JAVA_PROG}" PATH)
+ foreach(JAVA_INC_PATH ../include ../java/include ../share/java/include)
+ if(EXISTS ${jpath}/${JAVA_INC_PATH})
+ list(APPEND JAVA_AWT_INCLUDE_DIRECTORIES "${jpath}/${JAVA_INC_PATH}")
+ endif()
+ endforeach()
+ foreach(JAVA_LIB_PATH
+ ../lib ../jre/lib ../jre/lib/i386
+ ../java/lib ../java/jre/lib ../java/jre/lib/i386
+ ../share/java/lib ../share/java/jre/lib ../share/java/jre/lib/i386)
+ if(EXISTS ${jpath}/${JAVA_LIB_PATH})
+ list(APPEND JAVA_AWT_LIBRARY_DIRECTORIES "${jpath}/${JAVA_LIB_PATH}")
+ endif()
+ endforeach()
+endforeach()
+
+if(APPLE)
+ if(CMAKE_FIND_FRAMEWORK STREQUAL "ONLY")
+ set(_JNI_SEARCHES FRAMEWORK)
+ elseif(CMAKE_FIND_FRAMEWORK STREQUAL "NEVER")
+ set(_JNI_SEARCHES NORMAL)
+ elseif(CMAKE_FIND_FRAMEWORK STREQUAL "LAST")
+ set(_JNI_SEARCHES NORMAL FRAMEWORK)
+ else()
+ set(_JNI_SEARCHES FRAMEWORK NORMAL)
+ endif()
+ set(_JNI_FRAMEWORK_JVM NAMES JavaVM)
+ set(_JNI_FRAMEWORK_JAWT "${_JNI_FRAMEWORK_JVM}")
+else()
+ set(_JNI_SEARCHES NORMAL)
+endif()
+
+set(_JNI_NORMAL_JVM
+ NAMES jvm
+ PATHS ${JAVA_JVM_LIBRARY_DIRECTORIES}
+ )
+
+set(_JNI_NORMAL_JAWT
+ NAMES jawt
+ PATHS ${JAVA_AWT_LIBRARY_DIRECTORIES}
+ )
+
+foreach(search ${_JNI_SEARCHES})
+ find_library(JAVA_JVM_LIBRARY ${_JNI_${search}_JVM})
+ find_library(JAVA_AWT_LIBRARY ${_JNI_${search}_JAWT})
+ if(JAVA_JVM_LIBRARY)
+ break()
+ endif()
+endforeach()
+unset(_JNI_SEARCHES)
+unset(_JNI_FRAMEWORK_JVM)
+unset(_JNI_FRAMEWORK_JAWT)
+unset(_JNI_NORMAL_JVM)
+unset(_JNI_NORMAL_JAWT)
+
+# Find headers matching the library.
+if("${JAVA_JVM_LIBRARY};${JAVA_AWT_LIBRARY};" MATCHES "(/JavaVM.framework|-framework JavaVM);")
+ set(CMAKE_FIND_FRAMEWORK ONLY)
+else()
+ set(CMAKE_FIND_FRAMEWORK NEVER)
+endif()
+
+# add in the include path
+find_path(JAVA_INCLUDE_PATH jni.h
+ ${JAVA_AWT_INCLUDE_DIRECTORIES}
+)
+
+find_path(JAVA_INCLUDE_PATH2 NAMES jni_md.h jniport.h
+ PATHS
+ ${JAVA_INCLUDE_PATH}
+ ${JAVA_INCLUDE_PATH}/darwin
+ ${JAVA_INCLUDE_PATH}/win32
+ ${JAVA_INCLUDE_PATH}/linux
+ ${JAVA_INCLUDE_PATH}/freebsd
+ ${JAVA_INCLUDE_PATH}/openbsd
+ ${JAVA_INCLUDE_PATH}/solaris
+ ${JAVA_INCLUDE_PATH}/hp-ux
+ ${JAVA_INCLUDE_PATH}/alpha
+ ${JAVA_INCLUDE_PATH}/aix
+)
+
+# Restore CMAKE_FIND_FRAMEWORK
+if(DEFINED _JNI_CMAKE_FIND_FRAMEWORK)
+ set(CMAKE_FIND_FRAMEWORK ${_JNI_CMAKE_FIND_FRAMEWORK})
+ unset(_JNI_CMAKE_FIND_FRAMEWORK)
+else()
+ unset(CMAKE_FIND_FRAMEWORK)
+endif()
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(JNI DEFAULT_MSG JAVA_AWT_LIBRARY
+ JAVA_JVM_LIBRARY
+ JAVA_INCLUDE_PATH
+ JAVA_INCLUDE_PATH2)
+
+mark_as_advanced(
+ JAVA_AWT_LIBRARY
+ JAVA_JVM_LIBRARY
+ JAVA_INCLUDE_PATH
+ JAVA_INCLUDE_PATH2
+)
+
+set(JNI_LIBRARIES
+ ${JAVA_AWT_LIBRARY}
+ ${JAVA_JVM_LIBRARY}
+)
+
+set(JNI_INCLUDE_DIRS
+ ${JAVA_INCLUDE_PATH}
+ ${JAVA_INCLUDE_PATH2}
+)
diff --git a/cmake/Modules/FindJava.cmake b/cmake/Modules/FindJava.cmake
new file mode 100644
index 0000000..46c4293
--- /dev/null
+++ b/cmake/Modules/FindJava.cmake
@@ -0,0 +1,359 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindJava
+--------
+
+Find Java
+
+This module finds if Java is installed and determines where the
+include files and libraries are. The caller may set variable ``JAVA_HOME``
+to specify a Java installation prefix explicitly.
+
+See also the :module:`FindJNI` module to find Java Native Interface (JNI).
+
+Specify one or more of the following components as you call this find module. See example below.
+
+::
+
+ Runtime = Java Runtime Environment used to execute Java byte-compiled applications
+ Development = Development tools (java, javac, javah, jar and javadoc), includes Runtime component
+ IdlJ = Interface Description Language (IDL) to Java compiler
+ JarSigner = Signer and verifier tool for Java Archive (JAR) files
+
+
+This module sets the following result variables:
+
+::
+
+ Java_JAVA_EXECUTABLE = the full path to the Java runtime
+ Java_JAVAC_EXECUTABLE = the full path to the Java compiler
+ Java_JAVAH_EXECUTABLE = the full path to the Java header generator
+ Java_JAVADOC_EXECUTABLE = the full path to the Java documentation generator
+ Java_IDLJ_EXECUTABLE = the full path to the Java idl compiler
+ Java_JAR_EXECUTABLE = the full path to the Java archiver
+ Java_JARSIGNER_EXECUTABLE = the full path to the Java jar signer
+ Java_VERSION_STRING = Version of java found, eg. 1.6.0_12
+ Java_VERSION_MAJOR = The major version of the package found.
+ Java_VERSION_MINOR = The minor version of the package found.
+ Java_VERSION_PATCH = The patch version of the package found.
+ Java_VERSION_TWEAK = The tweak version of the package found (after '_')
+ Java_VERSION = This is set to: $major[.$minor[.$patch[.$tweak]]]
+
+
+
+The minimum required version of Java can be specified using the
+:command:`find_package` syntax, e.g.
+
+.. code-block:: cmake
+
+ find_package(Java 1.8)
+
+NOTE: ``${Java_VERSION}`` and ``${Java_VERSION_STRING}`` are not guaranteed to
+be identical. For example some java version may return:
+``Java_VERSION_STRING = 1.8.0_17`` and ``Java_VERSION = 1.8.0.17``
+
+another example is the Java OEM, with: ``Java_VERSION_STRING = 1.8.0-oem``
+and ``Java_VERSION = 1.8.0``
+
+For these components the following variables are set:
+
+::
+
+ Java_FOUND - TRUE if all components are found.
+ Java__FOUND - TRUE if is found.
+
+
+
+Example Usages:
+
+::
+
+ find_package(Java)
+ find_package(Java 1.8 REQUIRED)
+ find_package(Java COMPONENTS Runtime)
+ find_package(Java COMPONENTS Development)
+#]=======================================================================]
+
+include(CMakeFindJavaCommon)
+
+# The HINTS option should only be used for values computed from the system.
+set(_JAVA_HINTS)
+if(_JAVA_HOME)
+ list(APPEND _JAVA_HINTS ${_JAVA_HOME}/bin)
+endif()
+if (WIN32)
+ macro (_JAVA_GET_INSTALLED_VERSIONS _KIND)
+ execute_process(COMMAND REG QUERY HKLM\\SOFTWARE\\JavaSoft\\${_KIND}
+ RESULT_VARIABLE _JAVA_RESULT
+ OUTPUT_VARIABLE _JAVA_VERSIONS
+ ERROR_QUIET)
+ if (NOT _JAVA_RESULT)
+ string (REGEX MATCHALL "HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\JavaSoft\\\\${_KIND}\\\\[0-9.]+" _JAVA_VERSIONS "${_JAVA_VERSIONS}")
+ if (_JAVA_VERSIONS)
+ # sort versions. Most recent first
+ ## handle version 9 apart from other versions to get correct ordering
+ set (_JAVA_V9 ${_JAVA_VERSIONS})
+ list (FILTER _JAVA_VERSIONS EXCLUDE REGEX "${_KIND}\\\\9")
+ list (SORT _JAVA_VERSIONS)
+ list (REVERSE _JAVA_VERSIONS)
+ list (FILTER _JAVA_V9 INCLUDE REGEX "${_KIND}\\\\9")
+ list (SORT _JAVA_V9)
+ list (REVERSE _JAVA_V9)
+ list (APPEND _JAVA_VERSIONS ${_JAVA_V9})
+ foreach (_JAVA_HINT IN LISTS _JAVA_VERSIONS)
+ list(APPEND _JAVA_HINTS "[${_JAVA_HINT};JavaHome]/bin")
+ endforeach()
+ endif()
+ endif()
+ endmacro()
+
+ # search for installed versions for version 9 and upper
+ _JAVA_GET_INSTALLED_VERSIONS("JDK")
+ _JAVA_GET_INSTALLED_VERSIONS("JRE")
+
+ list(APPEND _JAVA_HINTS
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.9;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.8;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.7;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.6;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.5;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.9;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.8;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.7;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.6;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.5;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.4;JavaHome]/bin"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.3;JavaHome]/bin"
+ )
+endif()
+
+# Hard-coded guesses should still go in PATHS. This ensures that the user
+# environment can always override hard guesses.
+set(_JAVA_PATHS
+ /usr/lib/java/bin
+ /usr/share/java/bin
+ /usr/local/java/bin
+ /usr/local/java/share/bin
+ /usr/java/j2sdk1.4.2_04
+ /usr/lib/j2sdk1.4-sun/bin
+ /usr/java/j2sdk1.4.2_09/bin
+ /usr/lib/j2sdk1.5-sun/bin
+ /opt/sun-jdk-1.5.0.04/bin
+ /usr/local/jdk-1.7.0/bin
+ /usr/local/jdk-1.6.0/bin
+ )
+find_program(Java_JAVA_EXECUTABLE
+ NAMES java
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
+if(Java_JAVA_EXECUTABLE)
+ execute_process(COMMAND "${Java_JAVA_EXECUTABLE}" -version
+ RESULT_VARIABLE res
+ OUTPUT_VARIABLE var
+ ERROR_VARIABLE var # sun-java output to stderr
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_STRIP_TRAILING_WHITESPACE)
+ if( res )
+ if(var MATCHES "Unable to locate a Java Runtime to invoke|No Java runtime present, requesting install")
+ set(Java_JAVA_EXECUTABLE Java_JAVA_EXECUTABLE-NOTFOUND)
+ elseif(${Java_FIND_REQUIRED})
+ message( FATAL_ERROR "Error executing java -version" )
+ else()
+ message( STATUS "Warning, could not run java -version")
+ endif()
+ else()
+ # Extract version components (up to 4 levels) from "java -version" output.
+ set(_java_version_regex [[(([0-9]+)(\.([0-9]+)(\.([0-9]+)(_([0-9]+))?)?)?.*)]])
+ if(var MATCHES "java version \"${_java_version_regex}\"")
+ # Sun, GCJ, older OpenJDK
+ set(Java_VERSION_STRING "${CMAKE_MATCH_1}")
+ set(Java_VERSION_MAJOR "${CMAKE_MATCH_2}")
+ if (CMAKE_MATCH_4)
+ set(Java_VERSION_MINOR "${CMAKE_MATCH_4}")
+ else()
+ set(Java_VERSION_MINOR 0)
+ endif()
+ if (CMAKE_MATCH_6)
+ set(Java_VERSION_PATCH "${CMAKE_MATCH_6}")
+ else()
+ set(Java_VERSION_PATCH 0)
+ endif()
+ set(Java_VERSION_TWEAK "${CMAKE_MATCH_8}")
+ elseif(var MATCHES "openjdk version \"${_java_version_regex}\"")
+ # OpenJDK
+ set(Java_VERSION_STRING "${CMAKE_MATCH_1}")
+ set(Java_VERSION_MAJOR "${CMAKE_MATCH_2}")
+ if (CMAKE_MATCH_4)
+ set(Java_VERSION_MINOR "${CMAKE_MATCH_4}")
+ else()
+ set(Java_VERSION_MINOR 0)
+ endif()
+ if (CMAKE_MATCH_6)
+ set(Java_VERSION_PATCH "${CMAKE_MATCH_6}")
+ else()
+ set(Java_VERSION_PATCH 0)
+ endif()
+ set(Java_VERSION_TWEAK "${CMAKE_MATCH_8}")
+ elseif(var MATCHES "openjdk version \"([0-9]+)-[A-Za-z]+\"")
+ # OpenJDK 9 early access builds or locally built
+ set(Java_VERSION_STRING "1.${CMAKE_MATCH_1}.0")
+ set(Java_VERSION_MAJOR "1")
+ set(Java_VERSION_MINOR "${CMAKE_MATCH_1}")
+ set(Java_VERSION_PATCH "0")
+ set(Java_VERSION_TWEAK "")
+ elseif(var MATCHES "java full version \"kaffe-${_java_version_regex}\"")
+ # Kaffe style
+ set(Java_VERSION_STRING "${CMAKE_MATCH_1}")
+ set(Java_VERSION_MAJOR "${CMAKE_MATCH_2}")
+ set(Java_VERSION_MINOR "${CMAKE_MATCH_4}")
+ set(Java_VERSION_PATCH "${CMAKE_MATCH_6}")
+ set(Java_VERSION_TWEAK "${CMAKE_MATCH_8}")
+ else()
+ if(NOT Java_FIND_QUIETLY)
+ string(REPLACE "\n" "\n " ver_msg "\n${var}")
+ message(WARNING "Java version not recognized:${ver_msg}\nPlease report.")
+ endif()
+ set(Java_VERSION_STRING "")
+ set(Java_VERSION_MAJOR "")
+ set(Java_VERSION_MINOR "")
+ set(Java_VERSION_PATCH "")
+ set(Java_VERSION_TWEAK "")
+ endif()
+ set(Java_VERSION "${Java_VERSION_MAJOR}")
+ if(NOT "x${Java_VERSION}" STREQUAL "x")
+ foreach(c MINOR PATCH TWEAK)
+ if(NOT "x${Java_VERSION_${c}}" STREQUAL "x")
+ string(APPEND Java_VERSION ".${Java_VERSION_${c}}")
+ else()
+ break()
+ endif()
+ endforeach()
+ endif()
+ endif()
+
+endif()
+
+
+find_program(Java_JAR_EXECUTABLE
+ NAMES jar
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
+find_program(Java_JAVAC_EXECUTABLE
+ NAMES javac
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
+find_program(Java_JAVAH_EXECUTABLE
+ NAMES javah
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
+find_program(Java_JAVADOC_EXECUTABLE
+ NAMES javadoc
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
+find_program(Java_IDLJ_EXECUTABLE
+ NAMES idlj
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
+find_program(Java_JARSIGNER_EXECUTABLE
+ NAMES jarsigner
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
+include(FindPackageHandleStandardArgs)
+if(Java_FIND_COMPONENTS)
+ set(_JAVA_REQUIRED_VARS)
+ foreach(component ${Java_FIND_COMPONENTS})
+ # User just want to execute some Java byte-compiled
+ If(component STREQUAL "Runtime")
+ list(APPEND _JAVA_REQUIRED_VARS Java_JAVA_EXECUTABLE)
+ if(Java_JAVA_EXECUTABLE)
+ set(Java_Runtime_FOUND TRUE)
+ endif()
+ elseif(component STREQUAL "Development")
+ list(APPEND _JAVA_REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAVAC_EXECUTABLE
+ Java_JAR_EXECUTABLE Java_JAVADOC_EXECUTABLE)
+ if(Java_VERSION VERSION_LESS "10")
+ list(APPEND _JAVA_REQUIRED_VARS Java_JAVAH_EXECUTABLE)
+ if(Java_JAVA_EXECUTABLE AND Java_JAVAC_EXECUTABLE
+ AND Java_JAVAH_EXECUTABLE AND Java_JAR_EXECUTABLE AND Java_JAVADOC_EXECUTABLE)
+ set(Java_Development_FOUND TRUE)
+ endif()
+ else()
+ if(Java_JAVA_EXECUTABLE AND Java_JAVAC_EXECUTABLE
+ AND Java_JAR_EXECUTABLE AND Java_JAVADOC_EXECUTABLE)
+ set(Java_Development_FOUND TRUE)
+ endif()
+ endif()
+ elseif(component STREQUAL "IdlJ")
+ list(APPEND _JAVA_REQUIRED_VARS Java_IDLJ_EXECUTABLE)
+ if(Java_IDLJ_EXECUTABLE)
+ set(Java_IdlJ_FOUND TRUE)
+ endif()
+ elseif(component STREQUAL "JarSigner")
+ list(APPEND _JAVA_REQUIRED_VARS Java_JARSIGNER_EXECUTABLE)
+ if(Java_JARSIGNER_EXECUTABLE)
+ set(Java_JarSigner_FOUND TRUE)
+ endif()
+ else()
+ message(FATAL_ERROR "Comp: ${component} is not handled")
+ endif()
+ endforeach()
+ list (REMOVE_DUPLICATES _JAVA_REQUIRED_VARS)
+ find_package_handle_standard_args(Java
+ REQUIRED_VARS ${_JAVA_REQUIRED_VARS} HANDLE_COMPONENTS
+ VERSION_VAR Java_VERSION
+ )
+ if(Java_FOUND)
+ foreach(component ${Java_FIND_COMPONENTS})
+ set(Java_${component}_FOUND TRUE)
+ endforeach()
+ endif()
+else()
+ # Check for Development
+ if(Java_VERSION VERSION_LESS "10")
+ find_package_handle_standard_args(Java
+ REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
+ Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE
+ VERSION_VAR Java_VERSION_STRING
+ )
+ else()
+ find_package_handle_standard_args(Java
+ REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
+ Java_JAVADOC_EXECUTABLE
+ VERSION_VAR Java_VERSION_STRING
+ )
+ endif()
+endif()
+
+
+mark_as_advanced(
+ Java_JAVA_EXECUTABLE
+ Java_JAR_EXECUTABLE
+ Java_JAVAC_EXECUTABLE
+ Java_JAVAH_EXECUTABLE
+ Java_JAVADOC_EXECUTABLE
+ Java_IDLJ_EXECUTABLE
+ Java_JARSIGNER_EXECUTABLE
+ )
+
+# LEGACY
+set(JAVA_RUNTIME ${Java_JAVA_EXECUTABLE})
+set(JAVA_ARCHIVE ${Java_JAR_EXECUTABLE})
+set(JAVA_COMPILE ${Java_JAVAC_EXECUTABLE})
diff --git a/cmake/Modules/FindLibIberty.cmake b/cmake/Modules/FindLibIberty.cmake
new file mode 100644
index 0000000..e291c4c
--- /dev/null
+++ b/cmake/Modules/FindLibIberty.cmake
@@ -0,0 +1,40 @@
+# - Find Iberty
+# This module finds libiberty.
+#
+# It sets the following variables:
+# IBERTY_LIBRARIES - The libiberty library to link against.
+
+# For Debian <= wheezy, use libiberty_pic.a from binutils-dev
+# For Debian >= jessie, use libiberty.a from libiberty-dev
+# For all RHEL/Fedora, use libiberty.a from binutils-devel
+FIND_LIBRARY( IBERTY_LIBRARIES
+ NAMES iberty_pic iberty
+ HINTS ${IBERTY_LIBRARIES}
+ PATHS
+ /usr/lib
+ /usr/lib64
+ /usr/local/lib
+ /usr/local/lib64
+ /opt/local/lib
+ /opt/local/lib64
+ /sw/lib
+ ENV LIBRARY_PATH
+ ENV LD_LIBRARY_PATH
+ )
+
+IF (IBERTY_LIBRARIES)
+
+ # show which libiberty was found only if not quiet
+ MESSAGE( STATUS "Found libiberty: ${IBERTY_LIBRARIES}")
+
+ SET(IBERTY_FOUND TRUE)
+
+ELSE (IBERTY_LIBRARIES)
+
+ IF (IBERTY_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could not find libiberty. Try to install binutil-devel?")
+ ELSE()
+ MESSAGE(STATUS "Could not find libiberty; downloading binutils and building PIC libiberty.")
+ ENDIF (IBERTY_FIND_REQUIRED)
+
+ENDIF (IBERTY_LIBRARIES)
diff --git a/cmake/Modules/GitRevision.cmake b/cmake/Modules/GitRevision.cmake
new file mode 100644
index 0000000..c18f986
--- /dev/null
+++ b/cmake/Modules/GitRevision.cmake
@@ -0,0 +1,18 @@
+message(STATUS "Resolving GIT Version")
+set(GIT_REVISION "")
+find_package(Git)
+if(GIT_FOUND)
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
+ WORKING_DIRECTORY "${local_dir}"
+ OUTPUT_VARIABLE GIT_REVISION
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ message(STATUS "GIT hash: ${GIT_REVISION}")
+else()
+ message(STATUS "GIT not found")
+endif()
+
+
+
diff --git a/cmake/Modules/ProjectUtils.cmake b/cmake/Modules/ProjectUtils.cmake
new file mode 100644
index 0000000..b4d6923
--- /dev/null
+++ b/cmake/Modules/ProjectUtils.cmake
@@ -0,0 +1,16 @@
+macro(MACRO_ENSURE_OUT_OF_SOURCE_BUILD MSG)
+ string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" insource)
+ get_filename_component(PARENTDIR ${CMAKE_SOURCE_DIR} PATH)
+ string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${PARENTDIR}" insourcesubdir)
+ if(insource OR insourcesubdir)
+ message(FATAL_ERROR "${MSG}")
+ endif(insource OR insourcesubdir)
+endmacro(MACRO_ENSURE_OUT_OF_SOURCE_BUILD)
+
+function(UTILS_LIST_PREPEND var prefix)
+ set(_collector)
+ foreach(n ${ARGN})
+ list(APPEND _collector "${prefix}${n}")
+ endforeach()
+ set(${var} ${_collector} PARENT_SCOPE)
+endfunction(UTILS_LIST_PREPEND)
diff --git a/cmake/Modules/TestQSortR.c b/cmake/Modules/TestQSortR.c
new file mode 100644
index 0000000..2bf7fbe
--- /dev/null
+++ b/cmake/Modules/TestQSortR.c
@@ -0,0 +1,5 @@
+#include
+int main(int argc, char **argv) {
+ qsort_r(0, 0, 0, 0, 0);
+ return 0;
+}
diff --git a/cmake/Modules/TestQsortR.cmake b/cmake/Modules/TestQsortR.cmake
new file mode 100644
index 0000000..3a18ed0
--- /dev/null
+++ b/cmake/Modules/TestQsortR.cmake
@@ -0,0 +1,7 @@
+if (NOT DEFINED HAVE_QSORT_R)
+ try_compile(HAVE_QSORT_R
+ "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/"
+ "${CMAKE_CURRENT_LIST_DIR}/TestQSortR.c")
+endif()
+
+
diff --git a/cmake/Modules/UploadPPA.cmake b/cmake/Modules/UploadPPA.cmake
new file mode 100644
index 0000000..2bed362
--- /dev/null
+++ b/cmake/Modules/UploadPPA.cmake
@@ -0,0 +1,361 @@
+## -*- mode:cmake; coding:utf-8; -*-
+# Copyright (c) 2010 Daniel Pfeifer
+# Changes Copyright (c) 2011 2012 Rüdiger Sonderfeld
+#
+# UploadPPA.cmake is free software. It comes without any warranty,
+# to the extent permitted by applicable law. You can redistribute it
+# and/or modify it under the terms of the Do What The Fuck You Want
+# To Public License, Version 2, as published by Sam Hocevar. See
+# http://sam.zoy.org/wtfpl/COPYING for more details.
+#
+##
+# Documentation
+#
+# This CMake module uploads a project to a PPA. It creates all the files
+# necessary (similar to CPack) and uses debuild(1) and dput(1) to create the
+# package and upload it to a PPA. A PPA is a Personal Package Archive and can
+# be used by Debian/Ubuntu or other apt/deb based distributions to install and
+# update packages from a remote repository.
+# Canonicals Launchpad (http://launchpad.net) is usually used to host PPAs.
+# See https://help.launchpad.net/Packaging/PPA for further information
+# about PPAs.
+#
+# UploadPPA.cmake uses similar settings to CPack and the CPack DEB Generator.
+# Additionally the following variables are used
+#
+# CPACK_DEBIAN_PACKAGE_BUILD_DEPENDS to specify build dependencies
+# (cmake is added as default)
+# CPACK_DEBIAN_RESOURCE_FILE_CHANGELOG should point to a file containing the
+# changelog in debian format. If not set it checks whether a file
+# debian/changelog exists in the source directory or creates a simply changelog
+# file.
+# CPACK_DEBIAN_UPDATE_CHANGELOG if set to True then UploadPPA.cmake adds a new
+# entry to the changelog with the current version number and distribution name
+# (lsb_release -c is used). This can be useful because debuild uses the latest
+# version number from the changelog and the version number set in
+# CPACK_PACKAGE_VERSION. If they mismatch the creation of the package fails.
+#
+## A.Hoarau : CHANGELOG_MESSAGE can be used to pass a custom changelog message
+# Check packages
+#
+# ./configure -DENABLE_PPA=On
+# make dput
+# cd build/Debian/${DISTRI}
+# dpkg-source -x vobsub2srt_1.0pre4-ppa1.dsc
+# cd vobsub2srt-1.0pre4/
+# debuild -i -us -uc -sa -b
+#
+# Check the lintian warnings!
+#
+##
+# TODO
+# I plan to add support for git dch (from git-buildpackage) to auto generate
+# the changelog.
+##
+
+find_program(DEBUILD_EXECUTABLE debuild)
+find_program(DPUT_EXECUTABLE dput)
+
+if(NOT DEBUILD_EXECUTABLE OR NOT DPUT_EXECUTABLE)
+ message(WARNING "Debuild or dput not installed, please run sudo apt-get install devscripts")
+ return()
+endif(NOT DEBUILD_EXECUTABLE OR NOT DPUT_EXECUTABLE)
+
+
+if(NOT PROJECT_PPA_DISTRIB_TARGET)
+execute_process(
+ COMMAND lsb_release -cs
+ OUTPUT_VARIABLE DISTRI
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ set(PROJECT_PPA_DISTRIB_TARGET ${DISTRI})
+ message(STATUS "PROJECT_PPA_DISTRIB_TARGET NOT provided, so using system settings : ${DISTRI}")
+endif()
+
+foreach(DISTRI ${PROJECT_PPA_DISTRIB_TARGET})
+message(STATUS "Building for ${DISTRI}")
+
+# Strip "-dirty" flag from package version.
+# It can be added by, e.g., git describe but it causes trouble with debuild etc.
+string(REPLACE "-dirty" "" CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION})
+message(STATUS "version: ${CPACK_PACKAGE_VERSION}")
+
+# DEBIAN/control
+# debian policy enforce lower case for package name
+# Package: (mandatory)
+IF(NOT CPACK_DEBIAN_PACKAGE_NAME)
+ STRING(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_DEBIAN_PACKAGE_NAME)
+ENDIF(NOT CPACK_DEBIAN_PACKAGE_NAME)
+
+# Section: (recommended)
+IF(NOT CPACK_DEBIAN_PACKAGE_SECTION)
+ SET(CPACK_DEBIAN_PACKAGE_SECTION "devel")
+ENDIF(NOT CPACK_DEBIAN_PACKAGE_SECTION)
+
+# Priority: (recommended)
+IF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY)
+ SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
+ENDIF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY)
+
+if(NOT CPACK_DEBIAN_PACKAGE_MAINTAINER)
+ set(CPACK_DEBIAN_PACKAGE_MAINTAINER ${CPACK_PACKAGE_CONTACT})
+endif()
+
+if(NOT CPACK_PACKAGE_DESCRIPTION AND EXISTS ${CPACK_PACKAGE_DESCRIPTION_FILE})
+ file(STRINGS ${CPACK_PACKAGE_DESCRIPTION_FILE} DESC_LINES)
+ foreach(LINE ${DESC_LINES})
+ set(deb_long_description "${deb_long_description} ${LINE}\n")
+ endforeach(LINE ${DESC_LINES})
+else()
+ # add space before each line
+ string(REPLACE "\n" "\n " deb_long_description " ${CPACK_PACKAGE_DESCRIPTION}")
+endif()
+
+if(PPA_DEBIAN_VERSION)
+ set(DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}-${PPA_DEBIAN_VERSION}~${DISTRI}1")
+elseif(NOT PPA_DEBIAN_VERSION AND NOT PROJECT_PPA_DISTRIB_TARGET)
+ message(WARNING "Variable PPA_DEBIAN_VERSION not set! Building 'native' package!")
+ set(DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}")
+else()
+ set(DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}~${DISTRI}1")
+endif()
+
+message(STATUS "Debian version: ${DEBIAN_PACKAGE_VERSION}")
+
+set(DEBIAN_SOURCE_DIR ${CMAKE_BINARY_DIR}/Debian/${DISTRI}/${CPACK_DEBIAN_PACKAGE_NAME}_${DEBIAN_PACKAGE_VERSION})
+
+##############################################################################
+# debian/control
+
+set(debian_control ${DEBIAN_SOURCE_DIR}/debian/control)
+list(APPEND CPACK_DEBIAN_PACKAGE_BUILD_DEPENDS "cmake" "debhelper (>= 7.0.50)")
+list(REMOVE_DUPLICATES CPACK_DEBIAN_PACKAGE_BUILD_DEPENDS)
+list(SORT CPACK_DEBIAN_PACKAGE_BUILD_DEPENDS)
+string(REPLACE ";" ", " build_depends "${CPACK_DEBIAN_PACKAGE_BUILD_DEPENDS}")
+string(REPLACE ";" ", " bin_depends "${CPACK_DEBIAN_PACKAGE_DEPENDS}")
+file(WRITE ${debian_control}
+ "Source: ${CPACK_DEBIAN_PACKAGE_NAME}\n"
+ "Section: ${CPACK_DEBIAN_PACKAGE_SECTION}\n"
+ "Priority: ${CPACK_DEBIAN_PACKAGE_PRIORITY}\n"
+ "Maintainer: ${CPACK_DEBIAN_PACKAGE_MAINTAINER}\n"
+ "Build-Depends: ${build_depends}\n"
+ "Standards-Version: 3.9.7\n"
+ "Homepage: ${CPACK_DEBIAN_PACKAGE_HOMEPAGE}\n"
+ "\n"
+ "Package: ${CPACK_DEBIAN_PACKAGE_NAME}\n"
+ "Architecture: ${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}\n"
+ "Depends: ${bin_depends}, \${shlibs:Depends}, \${misc:Depends}\n"
+ "Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}\n"
+ "${deb_long_description}"
+ )
+
+file(APPEND ${debian_control}
+ "\n\n"
+ "Package: ${CPACK_DEBIAN_PACKAGE_NAME}-dbg\n"
+ "Priority: extra\n"
+ "Section: debug\n"
+ "Architecture: any\n"
+ "Depends: ${CPACK_DEBIAN_PACKAGE_NAME} (= \${binary:Version}), \${shlibs:Depends}, \${misc:Depends}\n"
+ "Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}\n"
+ "${deb_long_description}"
+ "\n .\n"
+ " This is the debugging symbols for the ${CPACK_DEBIAN_PACKAGE_NAME} library"
+ )
+
+foreach(COMPONENT ${CPACK_COMPONENTS_ALL})
+ string(TOUPPER ${COMPONENT} UPPER_COMPONENT)
+ set(DEPENDS "${CPACK_DEBIAN_PACKAGE_NAME}")
+ foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS})
+ set(DEPENDS "${DEPENDS}, ${CPACK_DEBIAN_PACKAGE_NAME}-${DEP}")
+ endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS})
+ file(APPEND ${debian_control} "\n"
+ "Package: ${CPACK_DEBIAN_PACKAGE_NAME}-${COMPONENT}\n"
+ "Architecture: ${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}\n"
+ "Depends: ${DEPENDS}\n"
+ "Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}"
+ ": ${CPACK_COMPONENT_${UPPER_COMPONENT}_DISPLAY_NAME}\n"
+ "${deb_long_description}"
+ "\n .\n"
+ " ${CPACK_COMPONENT_${UPPER_COMPONENT}_DESCRIPTION}\n"
+ )
+endforeach(COMPONENT ${CPACK_COMPONENTS_ALL})
+
+
+
+##############################################################################
+# debian/copyright
+set(debian_copyright ${DEBIAN_SOURCE_DIR}/debian/copyright)
+configure_file(${CPACK_RESOURCE_FILE_LICENSE} ${debian_copyright} COPYONLY)
+
+##############################################################################
+# debian/rules
+set(debian_rules ${DEBIAN_SOURCE_DIR}/debian/rules)
+
+file(WRITE ${debian_rules}
+ "#!/usr/bin/make -f\n"
+ "\nexport DH_VERBOSE=1"
+ "\n\n%:\n"
+ "\tdh $@ --buildsystem=cmake\n"
+ "\noverride_dh_auto_configure:\n"
+ "\tDESTDIR=\"$(CURDIR)/debian/${CPACK_DEBIAN_PACKAGE_NAME}\" dh_auto_configure -- -DCMAKE_BUILD_TYPE=RelWithDebInfo -DPACKAGE_TGZ=OFF ${DEB_CMAKE_ARGS}"
+ "\n\noverride_dh_auto_install:\n"
+ "\tdh_auto_install --destdir=\"$(CURDIR)/debian/${CPACK_DEBIAN_PACKAGE_NAME}\" --buildsystem=cmake"
+ "\n\noverride_dh_strip:\n"
+ "\tdh_strip --dbg-package=${CPACK_DEBIAN_PACKAGE_NAME}-dbg"
+)
+
+execute_process(COMMAND chmod +x ${debian_rules})
+
+##############################################################################
+# debian/compat
+file(WRITE ${DEBIAN_SOURCE_DIR}/debian/compat "7")
+
+##############################################################################
+# debian/source/format
+file(WRITE ${DEBIAN_SOURCE_DIR}/debian/source/format "3.0 (native)")
+
+##############################################################################
+
+# debian/changelog
+set(debian_changelog ${DEBIAN_SOURCE_DIR}/debian/changelog)
+if(NOT CPACK_DEBIAN_RESOURCE_FILE_CHANGELOG)
+ set(CPACK_DEBIAN_RESOURCE_FILE_CHANGELOG ${CMAKE_SOURCE_DIR}/debian/changelog)
+endif()
+
+# TODO add support for git dch (git-buildpackage)
+if(CHANGELOG_MESSAGE)
+ set(output_changelog_msg ${CHANGELOG_MESSAGE})
+else()
+ set(output_changelog_msg "* Package created with CMake")
+endif(CHANGELOG_MESSAGE)
+message(STATUS "Changelog message : \"${output_changelog_msg}\"")
+if(EXISTS ${CPACK_DEBIAN_RESOURCE_FILE_CHANGELOG})
+ configure_file(${CPACK_DEBIAN_RESOURCE_FILE_CHANGELOG} ${debian_changelog} COPYONLY)
+
+ if(CPACK_DEBIAN_UPDATE_CHANGELOG)
+ file(READ ${debian_changelog} debian_changelog_content)
+ execute_process(
+ COMMAND date -R
+ OUTPUT_VARIABLE DATE_TIME
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ file(WRITE ${debian_changelog}
+ "${CPACK_DEBIAN_PACKAGE_NAME} (${DEBIAN_PACKAGE_VERSION}) ${DISTRI}; urgency=low\n\n"
+ " ${output_changelog_msg}\n\n"
+ " -- ${CPACK_DEBIAN_PACKAGE_MAINTAINER} ${DATE_TIME}\n\n"
+ )
+ file(APPEND ${debian_changelog} ${debian_changelog_content})
+ endif()
+
+else()
+ execute_process(
+ COMMAND date -R
+ OUTPUT_VARIABLE DATE_TIME
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ file(WRITE ${debian_changelog}
+ "${CPACK_DEBIAN_PACKAGE_NAME} (${DEBIAN_PACKAGE_VERSION}) ${DISTRI}; urgency=low\n\n"
+ " ${output_changelog_msg}\n\n"
+ " -- ${CPACK_DEBIAN_PACKAGE_MAINTAINER} ${DATE_TIME}\n"
+ )
+ #configure_file(${debian_changelog} ${CPACK_DEBIAN_RESOURCE_FILE_CHANGELOG} COPYONLY)
+endif()
+
+
+##########################################################################
+# Templates
+
+if (CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA)
+ foreach(CF ${CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA})
+ get_filename_component(CF_NAME ${CF} NAME)
+ message("Writing debian/${CF_NAME}")
+ configure_file(${CF} ${DEBIAN_SOURCE_DIR}/debian/${CF_NAME} @ONLY)
+ endforeach()
+endif(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA)
+
+
+##########################################################################
+# .orig.tar.gz
+#execute_process(COMMAND date +%y%m%d
+# OUTPUT_VARIABLE day_suffix
+# OUTPUT_STRIP_TRAILING_WHITESPACE
+# )
+
+set(CPACK_SOURCE_IGNORE_FILES
+ ${CPACK_SOURCE_IGNORE_FILES}
+ "/build.*/"
+ "/Testing/"
+ "/test/"
+ "/tmp/"
+ "/packaging/"
+ "/debian/"
+ "/node_modules/"
+ "/\\\\.git.*"
+ "/\\\\.idea/"
+ "/\\\\.codelite/"
+ "*~$")
+
+#set(package_file_name "${CPACK_DEBIAN_PACKAGE_NAME}_${DEBIAN_PACKAGE_VERSION}")
+set(package_file_name "${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}")
+
+file(WRITE "${CMAKE_BINARY_DIR}/Debian/${DISTRI}/cpack.cmake"
+ "set(CPACK_GENERATOR TGZ)\n"
+ "set(CPACK_PACKAGE_NAME \"${CPACK_DEBIAN_PACKAGE_NAME}\")\n"
+ "set(CPACK_PACKAGE_VERSION \"${CPACK_PACKAGE_VERSION}\")\n"
+ "set(CPACK_PACKAGE_FILE_NAME \"${package_file_name}.orig\")\n"
+ "set(CPACK_PACKAGE_DESCRIPTION \"${CPACK_PACKAGE_NAME} Source\")\n"
+ "set(CPACK_IGNORE_FILES \"${CPACK_SOURCE_IGNORE_FILES}\")\n"
+ "set(CPACK_INSTALLED_DIRECTORIES \"${CPACK_SOURCE_INSTALLED_DIRECTORIES}\")\n"
+ "set(CPACK_INSTALL_SCRIPT \"${CPACK_SOURCE_INSTALL_SCRIPT}\")\n"
+ "set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)\n"
+ )
+
+set(orig_file "${CMAKE_BINARY_DIR}/Debian/${DISTRI}/${package_file_name}.orig.tar.gz")
+
+add_custom_command(OUTPUT ${orig_file}
+ COMMAND cpack --config ${CMAKE_BINARY_DIR}/Debian/${DISTRI}/cpack.cmake
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debian/${DISTRI}
+ )
+
+add_custom_command(OUTPUT ${DEBIAN_SOURCE_DIR}/CMakeLists.txt
+ COMMAND tar zxf ${orig_file}
+ WORKING_DIRECTORY ${DEBIAN_SOURCE_DIR}
+ DEPENDS ${orig_file}
+ )
+
+##############################################################################
+# debuild -S
+set(DEB_SOURCE_CHANGES
+ ${CPACK_DEBIAN_PACKAGE_NAME}_${DEBIAN_PACKAGE_VERSION}_source.changes
+ )
+
+add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/Debian/${DISTRI}/${DEB_SOURCE_CHANGES}
+ COMMAND ${DEBUILD_EXECUTABLE} --no-tgz-check -S
+ WORKING_DIRECTORY ${DEBIAN_SOURCE_DIR}
+ )
+add_custom_target(debuild_${DISTRI} ALL
+ DEPENDS ${DEBIAN_SOURCE_DIR}/CMakeLists.txt
+ ${CMAKE_BINARY_DIR}/Debian/${DISTRI}/${DEB_SOURCE_CHANGES}
+ )
+##############################################################################
+# dput ppa:your-lp-id/ppa
+message(STATUS "Upload PPA is ${UPLOAD_PPA}")
+if(UPLOAD_PPA)
+ if (EXISTS ${DPUT_CONFIG_IN})
+ set(DPUT_DIST ${DISTRI})
+ configure_file(
+ ${DPUT_CONFIG_IN}
+ ${CMAKE_BINARY_DIR}/Debian/${DISTRI}/dput.cf
+ @ONLY
+ )
+ add_custom_target(dput_${DISTRI} ALL
+ COMMAND ${DPUT_EXECUTABLE} -c ${CMAKE_BINARY_DIR}/Debian/${DISTRI}/dput.cf ${DPUT_HOST} ${DEB_SOURCE_CHANGES}
+ DEPENDS debuild_${DISTRI}
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debian/${DISTRI}
+ )
+ else()
+ add_custom_target(dput_${DISTRI} ALL
+ COMMAND ${DPUT_EXECUTABLE} ${DPUT_HOST} ${DEB_SOURCE_CHANGES}
+ DEPENDS debuild_${DISTRI}
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debian/${DISTRI}
+ )
+ endif()
+endif()
+endforeach(DISTRI)
diff --git a/cmake/Modules/Win32LIBTools.cmake b/cmake/Modules/Win32LIBTools.cmake
new file mode 100644
index 0000000..24448de
--- /dev/null
+++ b/cmake/Modules/Win32LIBTools.cmake
@@ -0,0 +1,53 @@
+if (NOT CMAKE_HOST_UNIX OR NOT WIN32)
+ return()
+endif()
+
+find_program(WINTOOLS_WINE_EXEC wine)
+if (NOT WINTOOLS_WINE_EXEC)
+ message("Wine executable not found! Failed to initiate wintools staff.")
+ return()
+endif()
+
+find_program(WINTOOLS_WGET_EXEC wget)
+if (NOT WINTOOLS_WGET_EXEC)
+ message("Wget executable not found! Failed to initiate wintools staff.")
+ return()
+endif()
+
+set(WINTOOLS_DIR ${CMAKE_BINARY_DIR}/WINTOOLS)
+set(WINTOOLS_DL_ROOT "http://softmotions.com/windev")
+
+if (NOT EXISTS ${WINTOOLS_DIR})
+ file(MAKE_DIRECTORY ${WINTOOLS_DIR})
+endif()
+
+set(WINTOOLS_EXECS)
+foreach (WINTOOLS_EXEC link.exe lib.exe mspdb100.dll)
+ if (NOT EXISTS ${WINTOOLS_DIR}/${WINTOOLS_EXEC})
+ add_custom_command(OUTPUT ${WINTOOLS_DIR}/${WINTOOLS_EXEC}
+ COMMAND ${WINTOOLS_WGET_EXEC} ${WINTOOLS_DL_ROOT}/${WINTOOLS_EXEC} -nv -O${WINTOOLS_DIR}/${WINTOOLS_EXEC}
+ WORKING_DIRECTORY ${WINTOOLS_DIR})
+ list(APPEND WINTOOLS_EXECS ${WINTOOLS_DIR}/${WINTOOLS_EXEC})
+ endif()
+endforeach(WINTOOLS_EXEC)
+
+add_custom_target(wintools_init
+ DEPENDS ${WINTOOLS_EXECS})
+
+if (CMAKE_SIZEOF_VOID_P MATCHES 8)
+ set(WINTOOLS_LIB_MACHINE "X64")
+else()
+ set(WINTOOLS_LIB_MACHINE "X86")
+endif()
+message("${PROJECT_NAME} WINTOOLS_LIB_MACHINE: ${WINTOOLS_LIB_MACHINE}")
+
+macro(add_w32_importlib tgt libname wdir)
+ add_custom_command(
+ TARGET ${tgt}
+ POST_BUILD
+ COMMAND ${WINTOOLS_WINE_EXEC} ${WINTOOLS_DIR}/lib.exe /def:${libname}.def /machine:${WINTOOLS_LIB_MACHINE}
+ WORKING_DIRECTORY ${wdir}
+ )
+endmacro(add_w32_importlib)
+
+
diff --git a/copy_iowow_header.py b/copy_iowow_header.py
new file mode 100755
index 0000000..ca0c495
--- /dev/null
+++ b/copy_iowow_header.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import sys
+import argparse
+import os
+import shutil
+
+def copy_file(src_dir, dst_dir):
+ if not os.path.exists(dst_dir):
+ os.makedirs(dst_dir)
+ headers = [
+ 'basedefs.h',
+ 'fs/iwdlsnr.h',
+ 'fs/iwexfile.h',
+ 'fs/iwfile.h',
+ 'fs/iwfsmfile.h',
+ 'iowow.h',
+ #'kv/iwal.h',
+ 'kv/iwkv.h',
+ #'kv/iwkv_internal.h',
+ #'kv/tests/iwkv_tests.h',
+ 'log/iwlog.h',
+ 'platform/iwp.h',
+ #'platform/win32/mman/mman.h',
+ 'rdb/iwrdb.h',
+ 'tmpl/iwcfg.h',
+ 'utils/iwarr.h',
+ 'utils/iwbits.h',
+ 'utils/iwconv.h',
+ 'utils/iwhmap.h',
+ 'utils/iwpool.h',
+ 'utils/iwsha2.h',
+ 'utils/iwstree.h',
+ 'utils/iwstw.h',
+ 'utils/iwth.h',
+ 'utils/iwutils.h',
+ 'utils/iwuuid.h',
+ 'utils/iwxstr.h',
+ #'utils/kbtree.h',
+ #'utils/khash.h',
+ #'utils/ksort.h',
+ #'utils/mt19937ar.h',
+ 'utils/murmur3.h',
+ #'utils/pthread_spin_lock_shim.h'
+ ]
+ for header in headers:
+ src_file = os.path.join(src_dir, header)
+ file_tags = header.split('/')
+ if (len(file_tags) == 1):
+ des_file = os.path.join(dst_dir, header)
+ else:
+ des_file = os.path.join(dst_dir, file_tags[len(file_tags) - 1])
+ shutil.copy2(src_file, des_file)
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--src-dir', help='source path of iowow header file', required=True)
+ parser.add_argument('--dst-dir', help='destion path of iowow header file', required=True)
+ args = parser.parse_args()
+ print('copy from %s to %s', args.src_dir, args.dst_dir)
+ copy_file(args.src_dir, args.dst_dir)
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 0000000..99b87f4
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,22 @@
+FROM alpine:3.9
+
+MAINTAINER Anton Adamansky
+
+RUN apk add --no-cache cmake gcc binutils libc-dev git ninja
+
+RUN git clone https://github.com/Softmotions/ejdb.git && \
+ mkdir -p ejdb/build
+
+WORKDIR ejdb/build
+
+RUN cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/opt/ejdb2 && \
+ ninja install && \
+ mkdir -p /ejdb2_data
+
+VOLUME ["/ejdb2_data"]
+
+EXPOSE 9191
+
+WORKDIR /ejdb2_data
+
+ENTRYPOINT ["/opt/ejdb2/bin/jbs", "-b", "0.0.0.0"]
diff --git a/docker/README.md b/docker/README.md
new file mode 100644
index 0000000..85962bb
--- /dev/null
+++ b/docker/README.md
@@ -0,0 +1,15 @@
+# Docker support
+
+If you have [Docker]("https://www.docker.com/") installed, you can build a Docker image and run it in a container
+
+```
+cd docker
+docker build -t ejdb2 .
+docker run -d -p 9191:9191 --name myEJDB ejdb2 --access myAccessKey
+```
+
+or get an image of `ejdb2` directly from the Docker Hub
+
+```
+docker run -d -p 9191:9191 --name myEJDB softmotions/ejdb2 --access myAccessKey
+```
\ No newline at end of file
diff --git a/docker/testbed/Dockerfile b/docker/testbed/Dockerfile
new file mode 100644
index 0000000..29ba3a0
--- /dev/null
+++ b/docker/testbed/Dockerfile
@@ -0,0 +1,28 @@
+# EJDB2 testbed docker image
+
+FROM ubuntu:xenial
+
+LABEL maintainer="adamansky@gmail.com"
+
+RUN mkdir /setup
+
+WORKDIR /setup
+COPY ./*.sh ./
+RUN ./setup.sh
+
+VOLUME /home/worker/.jenkins
+VOLUME /home/worker/agent
+
+USER root
+COPY jenkins-agent /usr/local/bin/jenkins-agent
+RUN chmod +x /usr/local/bin/jenkins-agent &&\
+ ln -s /usr/local/bin/jenkins-agent /usr/local/bin/jenkins-slave
+
+USER worker
+WORKDIR /home/worker
+
+ENTRYPOINT ["/usr/local/bin/jenkins-agent"]
+
+
+
+
diff --git a/docker/testbed/jenkins-agent b/docker/testbed/jenkins-agent
new file mode 100755
index 0000000..a809de5
--- /dev/null
+++ b/docker/testbed/jenkins-agent
@@ -0,0 +1,117 @@
+#!/usr/bin/env bash
+
+# The MIT License
+#
+# Copyright (c) 2015-2020, CloudBees, Inc.
+#
+# 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.
+
+# Usage jenkins-agent.sh [options] -url http://jenkins [SECRET] [AGENT_NAME]
+# Optional environment variables :
+# * JENKINS_TUNNEL : HOST:PORT for a tunnel to route TCP traffic to jenkins host, when jenkins can't be directly accessed over network
+# * JENKINS_URL : alternate jenkins URL
+# * JENKINS_SECRET : agent secret, if not set as an argument
+# * JENKINS_AGENT_NAME : agent name, if not set as an argument
+# * JENKINS_AGENT_WORKDIR : agent work directory, if not set by optional parameter -workDir
+# * JENKINS_WEB_SOCKET: true if the connection should be made via WebSocket rather than TCP
+# * JENKINS_DIRECT_CONNECTION: Connect directly to this TCP agent port, skipping the HTTP(S) connection parameter download.
+# Value: ":"
+# * JENKINS_INSTANCE_IDENTITY: The base64 encoded InstanceIdentity byte array of the Jenkins master. When this is set,
+# the agent skips connecting to an HTTP(S) port for connection info.
+# * JENKINS_PROTOCOLS: Specify the remoting protocols to attempt when instanceIdentity is provided.
+
+if [ $# -eq 1 ]; then
+
+ # if `docker run` only has one arguments, we assume user is running alternate command like `bash` to inspect the image
+ exec "$@"
+
+else
+
+ # if -tunnel is not provided, try env vars
+ case "$@" in
+ *"-tunnel "*) ;;
+ *)
+ if [ ! -z "$JENKINS_TUNNEL" ]; then
+ TUNNEL="-tunnel $JENKINS_TUNNEL"
+ fi ;;
+ esac
+
+ # if -workDir is not provided, try env vars
+ if [ ! -z "$JENKINS_AGENT_WORKDIR" ]; then
+ case "$@" in
+ *"-workDir"*) echo "Warning: Work directory is defined twice in command-line arguments and the environment variable" ;;
+ *)
+ WORKDIR="-workDir $JENKINS_AGENT_WORKDIR" ;;
+ esac
+ fi
+
+ if [ -n "$JENKINS_URL" ]; then
+ URL="-url $JENKINS_URL"
+ fi
+
+ if [ -n "$JENKINS_NAME" ]; then
+ JENKINS_AGENT_NAME="$JENKINS_NAME"
+ fi
+
+ if [ "$JENKINS_WEB_SOCKET" = true ]; then
+ WEB_SOCKET=-webSocket
+ fi
+
+ if [ -n "$JENKINS_PROTOCOLS" ]; then
+ PROTOCOLS="-protocols $JENKINS_PROTOCOLS"
+ fi
+
+ if [ -n "$JENKINS_DIRECT_CONNECTION" ]; then
+ DIRECT="-direct $JENKINS_DIRECT_CONNECTION"
+ fi
+
+ if [ -n "$JENKINS_INSTANCE_IDENTITY" ]; then
+ INSTANCE_IDENTITY="-instanceIdentity $JENKINS_INSTANCE_IDENTITY"
+ fi
+
+ # if java home is defined, use it
+ JAVA_BIN="java"
+ if [ "$JAVA_HOME" ]; then
+ JAVA_BIN="$JAVA_HOME/bin/java"
+ fi
+
+ # if both required options are defined, do not pass the parameters
+ OPT_JENKINS_SECRET=""
+ if [ -n "$JENKINS_SECRET" ]; then
+ case "$@" in
+ *"${JENKINS_SECRET}"*) echo "Warning: SECRET is defined twice in command-line arguments and the environment variable" ;;
+ *)
+ OPT_JENKINS_SECRET="${JENKINS_SECRET}" ;;
+ esac
+ fi
+
+ OPT_JENKINS_AGENT_NAME=""
+ if [ -n "$JENKINS_AGENT_NAME" ]; then
+ case "$@" in
+ *"${JENKINS_AGENT_NAME}"*) echo "Warning: AGENT_NAME is defined twice in command-line arguments and the environment variable" ;;
+ *)
+ OPT_JENKINS_AGENT_NAME="${JENKINS_AGENT_NAME}" ;;
+ esac
+ fi
+
+ #TODO: Handle the case when the command-line and Environment variable contain different values.
+ #It is fine it blows up for now since it should lead to an error anyway.
+
+ exec $JAVA_BIN $JAVA_OPTS -cp /usr/share/jenkins/agent.jar hudson.remoting.jnlp.Main -headless $TUNNEL $URL $WORKDIR $WEB_SOCKET $DIRECT $PROTOCOLS $INSTANCE_IDENTITY $OPT_JENKINS_SECRET $OPT_JENKINS_AGENT_NAME "$@"
+fi
diff --git a/docker/testbed/llvm-update-alternatives.sh b/docker/testbed/llvm-update-alternatives.sh
new file mode 100755
index 0000000..9ae4774
--- /dev/null
+++ b/docker/testbed/llvm-update-alternatives.sh
@@ -0,0 +1,76 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+
+function register_clang_version {
+ local version=$1
+ local priority=$2
+
+ update-alternatives \
+ --install /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-${version} ${priority} \
+ --slave /usr/bin/llvm-addr2line llvm-addr2line /usr/bin/llvm-addr2line-${version} \
+ --slave /usr/bin/llvm-ar llvm-ar /usr/bin/llvm-ar-${version} \
+ --slave /usr/bin/llvm-as llvm-as /usr/bin/llvm-as-${version} \
+ --slave /usr/bin/llvm-bcanalyzer llvm-bcanalyzer /usr/bin/llvm-bcanalyzer-${version} \
+ --slave /usr/bin/llvm-cov llvm-cov /usr/bin/llvm-cov-${version} \
+ --slave /usr/bin/llvm-diff llvm-diff /usr/bin/llvm-diff-${version} \
+ --slave /usr/bin/llvm-dis llvm-dis /usr/bin/llvm-dis-${version} \
+ --slave /usr/bin/llvm-dwarfdump llvm-dwarfdump /usr/bin/llvm-dwarfdump-${version} \
+ --slave /usr/bin/llvm-exegesis llvm-exegesis /usr/bin/llvm-exegesis-${version} \
+ --slave /usr/bin/llvm-extract llvm-extract /usr/bin/llvm-extract-${version} \
+ --slave /usr/bin/llvm-link llvm-link /usr/bin/llvm-link-${version} \
+ --slave /usr/bin/llvm-lipo llvm-lipo /usr/bin/llvm-lipo-${version} \
+ --slave /usr/bin/llvm-lto llvm-lto /usr/bin/llvm-lto-${version} \
+ --slave /usr/bin/llvm-lto2 llvm-lto2 /usr/bin/llvm-lto2-${version} \
+ --slave /usr/bin/llvm-mc llvm-mc /usr/bin/llvm-mc-${version} \
+ --slave /usr/bin/llvm-mcmarkup llvm-mcmarkup /usr/bin/llvm-mcmarkup-${version} \
+ --slave /usr/bin/llvm-nm llvm-nm /usr/bin/llvm-nm-${version} \
+ --slave /usr/bin/llvm-objcopy llvm-objcopy /usr/bin/llvm-objcopy-${version} \
+ --slave /usr/bin/llvm-objdump llvm-objdump /usr/bin/llvm-objdump-${version} \
+ --slave /usr/bin/llvm-opt-report llvm-opt-report /usr/bin/llvm-opt-report-${version} \
+ --slave /usr/bin/llvm-pdbutil llvm-pdbutil /usr/bin/llvm-pdbutil-${version} \
+ --slave /usr/bin/llvm-profdata llvm-profdata /usr/bin/llvm-profdata-${version} \
+ --slave /usr/bin/llvm-ranlib llvm-ranlib /usr/bin/llvm-ranlib-${version} \
+ --slave /usr/bin/llvm-rc llvm-rc /usr/bin/llvm-rc-${version} \
+ --slave /usr/bin/llvm-readelf llvm-readelf /usr/bin/llvm-readelf-${version} \
+ --slave /usr/bin/llvm-readobj llvm-readobj /usr/bin/llvm-readobj-${version} \
+ --slave /usr/bin/llvm-rtdyld llvm-rtdyld /usr/bin/llvm-rtdyld-${version} \
+ --slave /usr/bin/llvm-size llvm-size /usr/bin/llvm-size-${version} \
+ --slave /usr/bin/llvm-split llvm-split /usr/bin/llvm-split-${version} \
+ --slave /usr/bin/llvm-stress llvm-stress /usr/bin/llvm-stress-${version} \
+ --slave /usr/bin/llvm-strip llvm-strip /usr/bin/llvm-strip-${version} \
+ --slave /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-${version} \
+ --slave /usr/bin/llvm-tblgen llvm-tblgen /usr/bin/llvm-tblgen-${version} \
+ --slave /usr/bin/llvm-undname llvm-undname /usr/bin/llvm-undname-${version}
+
+ update-alternatives \
+ --install /usr/bin/clang clang /usr/bin/clang-${version} ${priority} \
+ --slave /usr/bin/asan_symbolize asan_symbolize /usr/bin/asan_symbolize-${version} \
+ --slave /usr/bin/c-index-test c-index-test /usr/bin/c-index-test-${version} \
+ --slave /usr/bin/clang++ clang++ /usr/bin/clang++-${version} \
+ --slave /usr/bin/clang-check clang-check /usr/bin/clang-check-${version} \
+ --slave /usr/bin/clang-cl clang-cl /usr/bin/clang-cl-${version} \
+ --slave /usr/bin/clang-cpp clang-cpp /usr/bin/clang-cpp-${version} \
+ --slave /usr/bin/clang-format clang-format /usr/bin/clang-format-${version} \
+ --slave /usr/bin/clang-format-diff clang-format-diff /usr/bin/clang-format-diff-${version} \
+ --slave /usr/bin/clang-import-test clang-import-test /usr/bin/clang-import-test-${version} \
+ --slave /usr/bin/clang-include-fixer clang-include-fixer /usr/bin/clang-include-fixer-${version} \
+ --slave /usr/bin/clang-offload-bundler clang-offload-bundler /usr/bin/clang-offload-bundler-${version} \
+ --slave /usr/bin/clang-query clang-query /usr/bin/clang-query-${version} \
+ --slave /usr/bin/clang-rename clang-rename /usr/bin/clang-rename-${version} \
+ --slave /usr/bin/clang-reorder-fields clang-reorder-fields /usr/bin/clang-reorder-fields-${version} \
+ --slave /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-${version} \
+ --slave /usr/bin/clangd clangd /usr/bin/clangd-${version} \
+ --slave /usr/bin/lld lld /usr/bin/lld-${version} \
+ --slave /usr/bin/lld-link lld-link /usr/bin/lld-link-${version} \
+ --slave /usr/bin/lldb lldb /usr/bin/lldb-${version} \
+ --slave /usr/bin/lldb-argdumper lldb-argdumper /usr/bin/lldb-argdumper-${version} \
+ --slave /usr/bin/lldb-instr lldb-instr /usr/bin/lldb-instr-${version} \
+ --slave /usr/bin/lldb-server lldb-server /usr/bin/lldb-server-${version} \
+ --slave /usr/bin/lldb-vscode lldb-vscode /usr/bin/lldb-vscode-${version} \
+ --slave /usr/bin/lli lli /usr/bin/lli-${version} \
+ --slave /usr/bin/lli-child-target lli-child-target /usr/bin/lli-child-target-${version}
+}
+
+register_clang_version $1 $2
diff --git a/docker/testbed/llvm.sh b/docker/testbed/llvm.sh
new file mode 100755
index 0000000..1fb8c12
--- /dev/null
+++ b/docker/testbed/llvm.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+################################################################################
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+################################################################################
+#
+# This script will install the llvm toolchain on the different
+# Debian and Ubuntu versions
+
+set -eux
+
+# read optional command line argument
+LLVM_VERSION=10
+if [ "$#" -eq 1 ]; then
+ LLVM_VERSION=$1
+fi
+
+DISTRO=$(lsb_release -is)
+VERSION=$(lsb_release -sr)
+DIST_VERSION="${DISTRO}_${VERSION}"
+
+if [[ $EUID -ne 0 ]]; then
+ echo "This script must be run as root!"
+ exit 1
+fi
+
+declare -A LLVM_VERSION_PATTERNS
+LLVM_VERSION_PATTERNS[9]="-9"
+LLVM_VERSION_PATTERNS[10]="-10"
+LLVM_VERSION_PATTERNS[11]="-11"
+
+if [ ! ${LLVM_VERSION_PATTERNS[$LLVM_VERSION]+_} ]; then
+ echo "This script does not support LLVM version $LLVM_VERSION"
+ exit 3
+fi
+
+LLVM_VERSION_STRING=${LLVM_VERSION_PATTERNS[$LLVM_VERSION]}
+
+# find the right repository name for the distro and version
+case "$DIST_VERSION" in
+ Debian_9* ) REPO_NAME="deb http://apt.llvm.org/stretch/ llvm-toolchain-stretch$LLVM_VERSION_STRING main" ;;
+ Debian_10* ) REPO_NAME="deb http://apt.llvm.org/buster/ llvm-toolchain-buster$LLVM_VERSION_STRING main" ;;
+ Debian_unstable ) REPO_NAME="deb http://apt.llvm.org/unstable/ llvm-toolchain$LLVM_VERSION_STRING main" ;;
+ Debian_testing ) REPO_NAME="deb http://apt.llvm.org/unstable/ llvm-toolchain$LLVM_VERSION_STRING main" ;;
+ Ubuntu_16.04 ) REPO_NAME="deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial$LLVM_VERSION_STRING main" ;;
+ Ubuntu_18.04 ) REPO_NAME="deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic$LLVM_VERSION_STRING main" ;;
+ Ubuntu_18.10 ) REPO_NAME="deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic$LLVM_VERSION_STRING main" ;;
+ Ubuntu_19.04 ) REPO_NAME="deb http://apt.llvm.org/disco/ llvm-toolchain-disco$LLVM_VERSION_STRING main" ;;
+ Ubuntu_19.10 ) REPO_NAME="deb http://apt.llvm.org/eoan/ llvm-toolchain-eoan$LLVM_VERSION_STRING main" ;;
+ Ubuntu_20.04 ) REPO_NAME="deb http://apt.llvm.org/focal/ llvm-toolchain-focal$LLVM_VERSION_STRING main" ;;
+ * )
+ echo "Distribution '$DISTRO' in version '$VERSION' is not supported by this script (${DIST_VERSION})."
+ exit 2
+esac
+
+
+# install everything
+wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
+add-apt-repository "${REPO_NAME}"
+apt-get update
+apt-get install -y clang-$LLVM_VERSION lldb-$LLVM_VERSION lld-$LLVM_VERSION clangd-$LLVM_VERSION
diff --git a/docker/testbed/setup.sh b/docker/testbed/setup.sh
new file mode 100755
index 0000000..c2d40a4
--- /dev/null
+++ b/docker/testbed/setup.sh
@@ -0,0 +1,202 @@
+#!/bin/bash
+
+set -e
+set -x
+
+echo "Setup docker host"
+
+SCRIPTPATH="$(
+ cd "$(dirname "$0")"
+ pwd -P
+)"
+cd $SCRIPTPATH
+
+JENKINS_AGENT_VERSION=4.6
+
+dpkg --add-architecture i386
+apt-get update
+apt-get install -y apt-utils software-properties-common apt-transport-https sudo curl wget zip unzip
+apt-get update
+apt-get dist-upgrade -y
+
+wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null
+wget -qO- https://deb.nodesource.com/setup_12.x | bash -
+wget -qO- https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
+wget -qO- https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
+
+apt-add-repository -y 'deb https://apt.kitware.com/ubuntu/ xenial main'
+echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
+wget -qO- https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_unstable.list >/etc/apt/sources.list.d/dart_unstable.list
+
+./llvm.sh 10
+./llvm-update-alternatives.sh 10 1000
+
+apt-get update
+
+echo ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula select true | debconf-set-selections
+
+apt-get install -y \
+ autopoint \
+ binutils \
+ bison \
+ build-essential \
+ ca-certificates \
+ cmake \
+ dart \
+ debhelper \
+ debianutils \
+ devscripts \
+ flex \
+ g++ \
+ gcc \
+ git \
+ gnupg \
+ gperf \
+ intltool \
+ lib32z1 \
+ libc6-dbg \
+ libcunit1-dev \
+ libcurl4-openssl-dev \
+ libgdk-pixbuf2.0-0 \
+ libgdk-pixbuf2.0-dev \
+ libtool \
+ libtool-bin \
+ lzip \
+ make \
+ mc \
+ nano \
+ ninja \
+ nodejs \
+ openjdk-8-jdk-headless \
+ p7zip-full \
+ ruby \
+ scons \
+ wine \
+ yarn
+
+echo 'JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64' >> /etc/environment
+
+mkdir -p /opt
+(
+ cd /opt
+ wget -qO swift.tar.gz https://swift.org/builds/swift-5.2.3-release/ubuntu1604/swift-5.2.3-RELEASE/swift-5.2.3-RELEASE-ubuntu16.04.tar.gz
+ tar -xf ./swift.tar.gz
+ rm -f ./swift.tar.gz
+)
+
+useradd -d /home/worker -m -s /bin/bash worker
+
+sudo -iu worker /bin/bash -i <<"EOF"
+set -e
+set -x
+
+echo 'export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64' >> ~/.profile
+echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.profile
+curl -s "https://get.sdkman.io" | /bin/bash
+EOF
+
+sudo -iu worker /bin/bash -i <<"EOF"
+set -e
+set -x
+
+sdk install gradle 5.4.1
+sdk install maven
+
+echo 'PATH=/usr/lib/dart/bin:$PATH' >> ~/.profile
+echo 'PATH=~/.sdkman/candidates/maven/current/bin:$PATH' >> ~/.profile
+echo 'PATH=~/.sdkman/candidates/gradle/current/bin:$PATH' >> ~/.profile
+echo 'PATH=$PATH:/opt/swift-5.2.3-RELEASE-ubuntu16.04/usr/bin' >> ~/.profile
+echo 'export PATH=$PATH:~/.yarn/bin' >> ~/.profile
+EOF
+
+sudo -iu worker /bin/bash -i <<"EOF"
+set -e
+set -x
+
+wget -O commandlinetools.zip https://dl.google.com/android/repository/commandlinetools-linux-6200805_latest.zip
+unzip commandlinetools.zip -d ./Android
+rm commandlinetools.zip
+
+echo 'export ANDROID_NDK_VERSION=21.1.6352462' >> ~/.profile
+echo 'export ANDROID_HOME=~/Android' >> ~/.profile
+echo 'export ANDROID_SDK_ROOT=${ANDROID_HOME}' >> ~/.profile
+echo 'PATH=$PATH:$ANDROID_HOME/tools' >> ~/.profile
+echo 'PATH=$PATH:$ANDROID_HOME/tools/bin' >> ~/.profile
+echo 'PATH=$PATH:$ANDROID_HOME/platform-tools' >> ~/.profile
+echo 'PATH=~/flutter/bin:$PATH' >> ~/.profile
+echo 'export PATH' >> ~/.profile
+echo 'export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/$ANDROID_NDK_VERSION' >> ~/.profile
+EOF
+
+sudo -iu worker /bin/bash -i <<"EOF"
+set -e
+set -x
+
+yes | sdkmanager --sdk_root=${ANDROID_HOME} --licenses
+sdkmanager --sdk_root=${ANDROID_HOME} \
+ --install \
+ "platform-tools" \
+ "platforms;android-28" \
+ "platforms;android-29" \
+ "ndk;${ANDROID_NDK_VERSION}" \
+ "build-tools;28.0.3" \
+ "build-tools;29.0.3"
+
+sdkmanager --sdk_root=${ANDROID_HOME} tools
+yes | sdkmanager --sdk_root=${ANDROID_HOME} --licenses
+EOF
+
+sudo -iu worker /bin/bash -i <<"EOF"
+set -e
+set -x
+
+git clone https://github.com/flutter/flutter.git -b stable
+flutter config --android-sdk $ANDROID_HOME
+flutter doctor --android-licenses
+flutter precache
+EOF
+
+sudo -iu worker /bin/bash -i <<"EOF"
+set -e
+set -x
+
+mkdir -p ~/tmp && cd ~/tmp
+wget https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2
+tar -xf ./valgrind-3.15.0.tar.bz2
+cd ./valgrind-3.15.0
+./configure --prefix=/home/worker/.local
+make && make install
+cd ~/ && rm -rf ./tmp/*
+EOF
+
+curl --create-dirs -fsSLo /usr/share/jenkins/agent.jar \
+ https://repo.jenkins-ci.org/public/org/jenkins-ci/main/remoting/${JENKINS_AGENT_VERSION}/remoting-${JENKINS_AGENT_VERSION}.jar
+chmod 755 /usr/share/jenkins
+chmod 644 /usr/share/jenkins/agent.jar
+ln -sf /usr/share/jenkins/agent.jar /usr/share/jenkins/slave.jar
+
+sudo -iu worker /bin/bash -i <<"EOF"
+set -e
+set -x
+
+git clone https://github.com/mxe/mxe.git
+cd ./mxe
+echo 'JOBS := 1' > ./settings.mk
+echo 'MXE_TARGETS := x86_64-w64-mingw32.static' >> ./settings.mk
+echo 'LOCAL_PKG_LIST := cunit libiberty' >> ./settings.mk
+echo '.DEFAULT local-pkg-list:' >> ./settings.mk
+echo 'local-pkg-list: $(LOCAL_PKG_LIST)' >> ./settings.mk
+
+make
+echo 'export MXE_HOME=~/mxe' >> ~/.profile
+EOF
+
+sudo -iu worker /bin/bash -i <<"EOF"
+set -e
+set -x
+mkdir -p ~/.jenkins
+mkdir -p ~/agent
+cat ~/.profile
+echo $PATH
+EOF
+
diff --git a/installer/CMakeLists.txt b/installer/CMakeLists.txt
new file mode 100644
index 0000000..03d1629
--- /dev/null
+++ b/installer/CMakeLists.txt
@@ -0,0 +1,5 @@
+if (BUILD_JNI_BINDING)
+ add_subdirectory(jni)
+else()
+ add_subdirectory(core)
+endif()
\ No newline at end of file
diff --git a/installer/core/CMakeLists.txt b/installer/core/CMakeLists.txt
new file mode 100644
index 0000000..867bd0c
--- /dev/null
+++ b/installer/core/CMakeLists.txt
@@ -0,0 +1,62 @@
+set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}")
+set(CPACK_PACKAGE_CONTACT "${PROJECT_MAINTAINER}")
+set(CPACK_PACKAGE_VERSION ${ejdb2_VERSION})
+set(CPACK_PACKAGE_VERSION_MAJOR ${ejdb2_VERSION_MAJOR})
+set(CPACK_PACKAGE_VERSION_MINOR ${ejdb2_VERSION_MINOR})
+set(CPACK_PACKAGE_VERSION_PATCH ${ejdb2_VERSION_PATCH})
+set(CPACK_PACKAGE_VENDOR ${PROJECT_VENDOR})
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${PROJECT_DESCRIPTION_SUMMARY})
+set(CPACK_PACKAGE_DESCRIPTION ${PROJECT_DESCRIPTION})
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
+set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md")
+set(CPACK_RESOURCE_FILE_WELCOME "${CMAKE_SOURCE_DIR}/README.md")
+set(CPACK_PACKAGE_FILE_NAME
+ "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_BUILD_TYPE}-${CMAKE_SYSTEM_NAME}-${PROJECT_ARCH}")
+if (CMAKE_BUILD_TYPE STREQUAL "Release")
+ set(CPACK_STRIP_FILES ON)
+endif ()
+
+set(DEB_CMAKE_ARGS "-DBUILD_SHARED_LIBS=ON")
+
+if (PACKAGE_DEB)
+ execute_process(
+ COMMAND /usr/bin/dpkg --print-architecture
+ OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
+ RESULT_VARIABLE EXECUTE_RESULT
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET
+ )
+ if (EXECUTE_RESULT)
+ message(FATAL_ERROR "dpkg not found: No package generation.")
+ endif ()
+ set(CPACK_DEBIAN_PACKAGE_DESCRIPTION ${CPACK_PACKAGE_DESCRIPTION})
+ set(CPACK_DEBIAN_PACKAGE_HOMEPAGE ${PROJECT_WEBSITE})
+ set(CPACK_DEBIAN_PACKAGE_SECTION libs)
+ set(CPACK_DEBIAN_PACKAGE_PRIORITY optional)
+ #set(CPACK_DEBIAN_PACKAGE_DEPENDS zlib1g)
+ set(CPACK_DEBIAN_PACKAGE_BUILD_DEPENDS pkg-config git devscripts dh-make)
+ if (NOT PPA_DEBIAN_VERSION)
+ set(PPA_DEBIAN_VERSION ppa1)
+ endif ()
+ if (PROJECT_PPA)
+ set(DPUT_HOST ${PROJECT_PPA})
+ endif ()
+ #set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "any")
+ set(CPACK_DEBIAN_RESOURCE_FILE_CHANGELOG ${CMAKE_SOURCE_DIR}/Changelog)
+ set(CPACK_DEBIAN_UPDATE_CHANGELOG ON)
+endif (PACKAGE_DEB)
+
+if (PACKAGE_TGZ)
+ set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
+endif (PACKAGE_TGZ)
+
+include(CPack)
+
+if (ENABLE_PPA)
+ set(CPACK_SOURCE_INSTALL_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/../fetch_libs.cmake")
+ if (NOT PROJECT_PPA_DISTRIB_TARGET)
+ set(PROJECT_PPA_DISTRIB_TARGET focal)
+ endif ()
+ set(DPUT_CONFIG_IN ${CMAKE_CURRENT_SOURCE_DIR}/../debian/dput.cf.in)
+ include(UploadPPA)
+endif ()
diff --git a/installer/debian/dput.cf.in b/installer/debian/dput.cf.in
new file mode 100644
index 0000000..c78437b
--- /dev/null
+++ b/installer/debian/dput.cf.in
@@ -0,0 +1,5 @@
+[ppa]
+fqdn = ppa.launchpad.net
+method = sftp
+login = @PROJECT_PPA_USER@
+incoming = ~%(ppa)s/ubuntu/@DPUT_DIST@
diff --git a/installer/fetch_libs.cmake b/installer/fetch_libs.cmake
new file mode 100644
index 0000000..6f563ab
--- /dev/null
+++ b/installer/fetch_libs.cmake
@@ -0,0 +1,5 @@
+message("DOWNLOAD https://github.com/Softmotions/facil.io/archive/master.zip")
+file(DOWNLOAD https://github.com/Softmotions/facil.io/archive/master.zip ${CMAKE_CURRENT_BINARY_DIR}/facil.zip)
+
+message("DOWNLOAD https://github.com/Softmotions/iowow/archive/master.zip")
+file(DOWNLOAD https://github.com/Softmotions/iowow/archive/master.zip ${CMAKE_CURRENT_BINARY_DIR}/iowow.zip)
diff --git a/installer/jni/CMakeLists.txt b/installer/jni/CMakeLists.txt
new file mode 100644
index 0000000..97fcb85
--- /dev/null
+++ b/installer/jni/CMakeLists.txt
@@ -0,0 +1,73 @@
+file(READ ${CMAKE_SOURCE_DIR}/src/bindings/ejdb2_jni/version.txt
+ EJDB2_JNI_VERSION)
+if(NOT EJDB2_JNI_VERSION)
+ message(
+ FATAL_ERROR
+ "${CMAKE_SOURCE_DIR}/src/bindings/ejdb2_jni/version.txt is not exists")
+endif()
+set(EJDB2_JNI_VERSION "${PROJECT_VERSION}.${EJDB2_JNI_VERSION}")
+
+set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}-java")
+set(CPACK_PACKAGE_CONTACT "${PROJECT_MAINTAINER}")
+set(CPACK_PACKAGE_VERSION ${EJDB2_JNI_VERSION})
+set(CPACK_PACKAGE_VERSION_MAJOR ${ejdb2_VERSION_MAJOR})
+set(CPACK_PACKAGE_VERSION_MINOR ${ejdb2_VERSION_MINOR})
+set(CPACK_PACKAGE_VERSION_PATCH ${ejdb2_VERSION_PATCH})
+set(CPACK_PACKAGE_VENDOR ${PROJECT_VENDOR})
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY
+ "${PROJECT_DESCRIPTION_SUMMARY} Java binding.")
+set(CPACK_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION} Java binding.")
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
+set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md")
+set(CPACK_RESOURCE_FILE_WELCOME "${CMAKE_SOURCE_DIR}/README.md")
+set(CPACK_PACKAGE_FILE_NAME
+ "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_BUILD_TYPE}-${CMAKE_SYSTEM_NAME}-${PROJECT_ARCH}"
+)
+if(CMAKE_BUILD_TYPE STREQUAL "Release")
+ set(CPACK_STRIP_FILES ON)
+endif()
+
+set(DEB_CMAKE_ARGS "-DBUILD_JNI_BINDING=ON")
+
+if(PACKAGE_DEB)
+ execute_process(
+ COMMAND /usr/bin/dpkg --print-architecture
+ OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
+ RESULT_VARIABLE EXECUTE_RESULT
+ OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
+ if(EXECUTE_RESULT)
+ message(FATAL_ERROR "dpkg not found: No package generation.")
+ endif()
+ set(CPACK_DEBIAN_PACKAGE_DESCRIPTION ${CPACK_PACKAGE_DESCRIPTION})
+ set(CPACK_DEBIAN_PACKAGE_HOMEPAGE ${PROJECT_WEBSITE})
+ set(CPACK_DEBIAN_PACKAGE_SECTION libs)
+ set(CPACK_DEBIAN_PACKAGE_PRIORITY optional)
+ # set(CPACK_DEBIAN_PACKAGE_DEPENDS zlib1g)
+ set(CPACK_DEBIAN_PACKAGE_BUILD_DEPENDS pkg-config git devscripts dh-make
+ openjdk-8-jdk)
+ if(NOT PPA_DEBIAN_VERSION)
+ set(PPA_DEBIAN_VERSION ppa1)
+ endif()
+ if(PROJECT_PPA)
+ set(DPUT_HOST ${PROJECT_PPA})
+ endif()
+ # set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "any")
+ set(CPACK_DEBIAN_RESOURCE_FILE_CHANGELOG ${CMAKE_SOURCE_DIR}/Changelog)
+ set(CPACK_DEBIAN_UPDATE_CHANGELOG ON)
+endif(PACKAGE_DEB)
+
+if(PACKAGE_TGZ)
+ set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
+endif(PACKAGE_TGZ)
+
+include(CPack)
+
+if(ENABLE_PPA)
+ set(CPACK_SOURCE_INSTALL_SCRIPT
+ "${CMAKE_CURRENT_SOURCE_DIR}/../fetch_libs.cmake")
+ if(NOT PROJECT_PPA_DISTRIB_TARGET)
+ set(PROJECT_PPA_DISTRIB_TARGET focal)
+ endif()
+ set(DPUT_CONFIG_IN ${CMAKE_CURRENT_SOURCE_DIR}/../debian/dput.cf.in)
+ include(UploadPPA)
+endif()
diff --git a/ios-tc.cmake b/ios-tc.cmake
new file mode 100644
index 0000000..f266dd7
--- /dev/null
+++ b/ios-tc.cmake
@@ -0,0 +1,704 @@
+# This file is part of the ios-cmake project. It was retrieved from
+# https://github.com/cristeab/ios-cmake.git, which is a fork of
+# https://code.google.com/p/ios-cmake/. Which in turn is based off of
+# the Platform/Darwin.cmake and Platform/UnixPaths.cmake files which
+# are included with CMake 2.8.4
+#
+# The ios-cmake project is licensed under the new BSD license.
+#
+# Copyright (c) 2014, Bogdan Cristea and LTE Engineering Software,
+# Kitware, Inc., Insight Software Consortium. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# This file is based off of the Platform/Darwin.cmake and
+# Platform/UnixPaths.cmake files which are included with CMake 2.8.4
+# It has been altered for iOS development.
+#
+# Updated by Alex Stewart (alexs.mac@gmail.com)
+#
+# *****************************************************************************
+# Now maintained by Alexander Widerberg (widerbergaren [at] gmail.com)
+# under the BSD-3-Clause license
+# https://github.com/leetal/ios-cmake
+# *****************************************************************************
+#
+# INFORMATION / HELP
+#
+# The following arguments control the behaviour of this toolchain:
+#
+# PLATFORM: (default "OS")
+# OS = Build for iPhoneOS.
+# OS64 = Build for arm64 iphoneOS.
+# OS64COMBINED = Build for arm64 x86_64 iphoneOS. Combined into FAT STATIC lib (supported on 3.14+ of CMakewith "-G Xcode" argument ONLY)
+# SIMULATOR = Build for x86 i386 iphoneOS Simulator.
+# SIMULATOR64 = Build for x86_64 iphoneOS Simulator.
+# TVOS = Build for arm64 tvOS.
+# TVOSCOMBINED = Build for arm64 x86_64 tvOS. Combined into FAT STATIC lib (supported on 3.14+ of CMake with "-G Xcode" argument ONLY)
+# SIMULATOR_TVOS = Build for x86_64 tvOS Simulator.
+# WATCHOS = Build for armv7k arm64_32 for watchOS.
+# WATCHOSCOMBINED = Build for armv7k arm64_32 x86_64 watchOS. Combined into FAT STATIC lib (supported on 3.14+ of CMake with "-G Xcode" argument ONLY)
+# SIMULATOR_WATCHOS = Build for x86_64 for watchOS Simulator.
+#
+# CMAKE_OSX_SYSROOT: Path to the SDK to use. By default this is
+# automatically determined from PLATFORM and xcodebuild, but
+# can also be manually specified (although this should not be required).
+#
+# CMAKE_DEVELOPER_ROOT: Path to the Developer directory for the platform
+# being compiled for. By default this is automatically determined from
+# CMAKE_OSX_SYSROOT, but can also be manually specified (although this should
+# not be required).
+#
+# DEPLOYMENT_TARGET: Minimum SDK version to target. Default 2.0 on watchOS and 9.0 on tvOS+iOS
+#
+# ENABLE_BITCODE: (1|0) Enables or disables bitcode support. Default 1 (true)
+#
+# ENABLE_ARC: (1|0) Enables or disables ARC support. Default 1 (true, ARC enabled by default)
+#
+# ENABLE_VISIBILITY: (1|0) Enables or disables symbol visibility support. Default 0 (false, visibility hidden by default)
+#
+# ENABLE_STRICT_TRY_COMPILE: (1|0) Enables or disables strict try_compile() on all Check* directives (will run linker
+# to actually check if linking is possible). Default 0 (false, will set CMAKE_TRY_COMPILE_TARGET_TYPE to STATIC_LIBRARY)
+#
+# ARCHS: (armv7 armv7s armv7k arm64 arm64_32 i386 x86_64) If specified, will override the default architectures for the given PLATFORM
+# OS = armv7 armv7s arm64 (if applicable)
+# OS64 = arm64 (if applicable)
+# SIMULATOR = i386
+# SIMULATOR64 = x86_64
+# TVOS = arm64
+# SIMULATOR_TVOS = x86_64 (i386 has since long been deprecated)
+# WATCHOS = armv7k arm64_32 (if applicable)
+# SIMULATOR_WATCHOS = x86_64 (i386 has since long been deprecated)
+#
+# This toolchain defines the following variables for use externally:
+#
+# XCODE_VERSION: Version number (not including Build version) of Xcode detected.
+# SDK_VERSION: Version of SDK being used.
+# CMAKE_OSX_ARCHITECTURES: Architectures being compiled for (generated from PLATFORM).
+#
+# This toolchain defines the following macros for use externally:
+#
+# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE XCODE_VARIANT)
+# A convenience macro for setting xcode specific properties on targets.
+# Available variants are: All, Release, RelWithDebInfo, Debug, MinSizeRel
+# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1" "all").
+#
+# find_host_package (PROGRAM ARGS)
+# A macro used to find executable programs on the host system, not within the
+# environment. Thanks to the android-cmake project for providing the
+# command.
+#
+# ******************************** DEPRECATIONS *******************************
+#
+# IOS_DEPLOYMENT_TARGET: (Deprecated) Alias to DEPLOYMENT_TARGET
+# CMAKE_IOS_DEVELOPER_ROOT: (Deprecated) Alias to CMAKE_DEVELOPER_ROOT
+# IOS_PLATFORM: (Deprecated) Alias to PLATFORM
+# IOS_ARCH: (Deprecated) Alias to ARCHS
+#
+# *****************************************************************************
+#
+
+# Fix for PThread library not in path
+set(CMAKE_THREAD_LIBS_INIT "-lpthread")
+set(CMAKE_HAVE_THREADS_LIBRARY 1)
+set(CMAKE_USE_WIN32_THREADS_INIT 0)
+set(CMAKE_USE_PTHREADS_INIT 1)
+
+# Cache what generator is used
+set(USED_CMAKE_GENERATOR "${CMAKE_GENERATOR}" CACHE STRING "Expose CMAKE_GENERATOR" FORCE)
+
+if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14")
+ set(MODERN_CMAKE YES)
+endif()
+
+# Get the Xcode version being used.
+execute_process(COMMAND xcodebuild -version
+ OUTPUT_VARIABLE XCODE_VERSION
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+string(REGEX MATCH "Xcode [0-9\\.]+" XCODE_VERSION "${XCODE_VERSION}")
+string(REGEX REPLACE "Xcode ([0-9\\.]+)" "\\1" XCODE_VERSION "${XCODE_VERSION}")
+
+######## ALIASES (DEPRECATION WARNINGS)
+
+if(DEFINED IOS_PLATFORM)
+ set(PLATFORM ${IOS_PLATFORM})
+ message(DEPRECATION "IOS_PLATFORM argument is DEPRECATED. Consider using the new PLATFORM argument instead.")
+endif()
+
+if(DEFINED IOS_DEPLOYMENT_TARGET)
+ set(DEPLOYMENT_TARGET ${IOS_DEPLOYMENT_TARGET})
+ message(DEPRECATION "IOS_DEPLOYMENT_TARGET argument is DEPRECATED. Consider using the new DEPLOYMENT_TARGET argument instead.")
+endif()
+
+if(DEFINED CMAKE_IOS_DEVELOPER_ROOT)
+ set(CMAKE_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT})
+ message(DEPRECATION "CMAKE_IOS_DEVELOPER_ROOT argument is DEPRECATED. Consider using the new CMAKE_DEVELOPER_ROOT argument instead.")
+endif()
+
+if(DEFINED IOS_ARCH)
+ set(ARCHS ${IOS_ARCH})
+ message(DEPRECATION "IOS_ARCH argument is DEPRECATED. Consider using the new ARCHS argument instead.")
+endif()
+
+######## END ALIASES
+
+# Unset the FORCE on cache variables if in try_compile()
+set(FORCE_CACHE FORCE)
+get_property(_CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE)
+if(_CMAKE_IN_TRY_COMPILE)
+ unset(FORCE_CACHE)
+endif()
+
+# Default to building for iPhoneOS if not specified otherwise, and we cannot
+# determine the platform from the CMAKE_OSX_ARCHITECTURES variable. The use
+# of CMAKE_OSX_ARCHITECTURES is such that try_compile() projects can correctly
+# determine the value of PLATFORM from the root project, as
+# CMAKE_OSX_ARCHITECTURES is propagated to them by CMake.
+if(NOT DEFINED PLATFORM)
+ if (CMAKE_OSX_ARCHITECTURES)
+ if(CMAKE_OSX_ARCHITECTURES MATCHES ".*arm.*" AND CMAKE_OSX_SYSROOT MATCHES ".*iphoneos.*")
+ set(PLATFORM "OS")
+ elseif(CMAKE_OSX_ARCHITECTURES MATCHES "i386" AND CMAKE_OSX_SYSROOT MATCHES ".*iphonesimulator.*")
+ set(PLATFORM "SIMULATOR")
+ elseif(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64" AND CMAKE_OSX_SYSROOT MATCHES ".*iphonesimulator.*")
+ set(PLATFORM "SIMULATOR64")
+ elseif(CMAKE_OSX_ARCHITECTURES MATCHES "arm64" AND CMAKE_OSX_SYSROOT MATCHES ".*appletvos.*")
+ set(PLATFORM "TVOS")
+ elseif(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64" AND CMAKE_OSX_SYSROOT MATCHES ".*appletvsimulator.*")
+ set(PLATFORM "SIMULATOR_TVOS")
+ elseif(CMAKE_OSX_ARCHITECTURES MATCHES ".*armv7k.*" AND CMAKE_OSX_SYSROOT MATCHES ".*watchos.*")
+ set(PLATFORM "WATCHOS")
+ elseif(CMAKE_OSX_ARCHITECTURES MATCHES "i386" AND CMAKE_OSX_SYSROOT MATCHES ".*watchsimulator.*")
+ set(PLATFORM "SIMULATOR_WATCHOS")
+ endif()
+ endif()
+ if (NOT PLATFORM)
+ set(PLATFORM "OS")
+ endif()
+endif()
+
+set(PLATFORM_INT "${PLATFORM}" CACHE STRING "Type of platform for which the build targets.")
+
+# Handle the case where we are targeting iOS and a version above 10.3.4 (32-bit support dropped officially)
+if(PLATFORM_INT STREQUAL "OS" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4)
+ set(PLATFORM_INT "OS64")
+ message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.")
+elseif(PLATFORM_INT STREQUAL "SIMULATOR" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4)
+ set(PLATFORM_INT "SIMULATOR64")
+ message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.")
+endif()
+
+# Determine the platform name and architectures for use in xcodebuild commands
+# from the specified PLATFORM name.
+if(PLATFORM_INT STREQUAL "OS")
+ set(SDK_NAME iphoneos)
+ if(NOT ARCHS)
+ set(ARCHS armv7 armv7s arm64)
+ endif()
+elseif(PLATFORM_INT STREQUAL "OS64")
+ set(SDK_NAME iphoneos)
+ if(NOT ARCHS)
+ if (XCODE_VERSION VERSION_GREATER 10.0)
+ set(ARCHS arm64) # Add arm64e when Apple have fixed the integration issues with it, libarclite_iphoneos.a is currently missung bitcode markers for example
+ else()
+ set(ARCHS arm64)
+ endif()
+ endif()
+elseif(PLATFORM_INT STREQUAL "OS64COMBINED")
+ set(SDK_NAME iphoneos)
+ if(MODERN_CMAKE)
+ if(NOT ARCHS)
+ if (XCODE_VERSION VERSION_GREATER 10.0)
+ set(ARCHS arm64 x86_64) # Add arm64e when Apple have fixed the integration issues with it, libarclite_iphoneos.a is currently missung bitcode markers for example
+ else()
+ set(ARCHS arm64 x86_64)
+ endif()
+ endif()
+ else()
+ message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the OS64COMBINED setting work")
+ endif()
+elseif(PLATFORM_INT STREQUAL "SIMULATOR")
+ set(SDK_NAME iphonesimulator)
+ if(NOT ARCHS)
+ set(ARCHS i386)
+ endif()
+ message(DEPRECATION "SIMULATOR IS DEPRECATED. Consider using SIMULATOR64 instead.")
+elseif(PLATFORM_INT STREQUAL "SIMULATOR64")
+ set(SDK_NAME iphonesimulator)
+ if(NOT ARCHS)
+ set(ARCHS x86_64)
+ endif()
+elseif(PLATFORM_INT STREQUAL "TVOS")
+ set(SDK_NAME appletvos)
+ if(NOT ARCHS)
+ set(ARCHS arm64)
+ endif()
+elseif (PLATFORM_INT STREQUAL "TVOSCOMBINED")
+ set(SDK_NAME appletvos)
+ if(MODERN_CMAKE)
+ if(NOT ARCHS)
+ set(ARCHS arm64 x86_64)
+ endif()
+ else()
+ message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the TVOSCOMBINED setting work")
+ endif()
+elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS")
+ set(SDK_NAME appletvsimulator)
+ if(NOT ARCHS)
+ set(ARCHS x86_64)
+ endif()
+elseif(PLATFORM_INT STREQUAL "WATCHOS")
+ set(SDK_NAME watchos)
+ if(NOT ARCHS)
+ if (XCODE_VERSION VERSION_GREATER 10.0)
+ set(ARCHS armv7k arm64_32)
+ else()
+ set(ARCHS armv7k)
+ endif()
+ endif()
+elseif(PLATFORM_INT STREQUAL "WATCHOSCOMBINED")
+ set(SDK_NAME watchos)
+ if(MODERN_CMAKE)
+ if(NOT ARCHS)
+ if (XCODE_VERSION VERSION_GREATER 10.0)
+ set(ARCHS armv7k arm64_32 i386)
+ else()
+ set(ARCHS armv7k i386)
+ endif()
+ endif()
+ else()
+ message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the WATCHOSCOMBINED setting work")
+ endif()
+elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS")
+ set(SDK_NAME watchsimulator)
+ if(NOT ARCHS)
+ set(ARCHS i386)
+ endif()
+else()
+ message(FATAL_ERROR "Invalid PLATFORM: ${PLATFORM_INT}")
+endif()
+
+if(MODERN_CMAKE AND PLATFORM_INT MATCHES ".*COMBINED" AND NOT USED_CMAKE_GENERATOR MATCHES "Xcode")
+ message(FATAL_ERROR "The COMBINED options only work with Xcode generator, -G Xcode")
+endif()
+
+# If user did not specify the SDK root to use, then query xcodebuild for it.
+execute_process(COMMAND xcodebuild -version -sdk ${SDK_NAME} Path
+ OUTPUT_VARIABLE CMAKE_OSX_SYSROOT_INT
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+if (NOT DEFINED CMAKE_OSX_SYSROOT_INT AND NOT DEFINED CMAKE_OSX_SYSROOT)
+ message(SEND_ERROR "Please make sure that Xcode is installed and that the toolchain"
+ "is pointing to the correct path. Please run:"
+ "sudo xcode-select -s /Applications/Xcode.app/Contents/Developer"
+ "and see if that fixes the problem for you.")
+ message(FATAL_ERROR "Invalid CMAKE_OSX_SYSROOT: ${CMAKE_OSX_SYSROOT} "
+ "does not exist.")
+elseif(DEFINED CMAKE_OSX_SYSROOT_INT)
+ set(CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "")
+endif()
+
+# Set Xcode property for SDKROOT as well if Xcode generator is used
+if(USED_CMAKE_GENERATOR MATCHES "Xcode")
+ set(CMAKE_OSX_SYSROOT "${SDK_NAME}" CACHE INTERNAL "")
+ if(NOT DEFINED CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM)
+ set(CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "123456789A" CACHE INTERNAL "")
+ endif()
+endif()
+
+# Specify minimum version of deployment target.
+if(NOT DEFINED DEPLOYMENT_TARGET)
+ if (PLATFORM_INT STREQUAL "WATCHOS" OR PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS")
+ # Unless specified, SDK version 2.0 is used by default as minimum target version (watchOS).
+ set(DEPLOYMENT_TARGET "2.0"
+ CACHE STRING "Minimum SDK version to build for." )
+ else()
+ # Unless specified, SDK version 9.0 is used by default as minimum target version (iOS, tvOS).
+ set(DEPLOYMENT_TARGET "9.0"
+ CACHE STRING "Minimum SDK version to build for." )
+ endif()
+ message(STATUS "Using the default min-version since DEPLOYMENT_TARGET not provided!")
+endif()
+
+# Use bitcode or not
+if(NOT DEFINED ENABLE_BITCODE AND NOT ARCHS MATCHES "((^|;|, )(i386|x86_64))+")
+ # Unless specified, enable bitcode support by default
+ message(STATUS "Enabling bitcode support by default. ENABLE_BITCODE not provided!")
+ set(ENABLE_BITCODE TRUE)
+elseif(NOT DEFINED ENABLE_BITCODE)
+ message(STATUS "Disabling bitcode support by default on simulators. ENABLE_BITCODE not provided for override!")
+ set(ENABLE_BITCODE FALSE)
+endif()
+set(ENABLE_BITCODE_INT ${ENABLE_BITCODE} CACHE BOOL "Whether or not to enable bitcode" ${FORCE_CACHE})
+# Use ARC or not
+if(NOT DEFINED ENABLE_ARC)
+ # Unless specified, enable ARC support by default
+ set(ENABLE_ARC TRUE)
+ message(STATUS "Enabling ARC support by default. ENABLE_ARC not provided!")
+endif()
+set(ENABLE_ARC_INT ${ENABLE_ARC} CACHE BOOL "Whether or not to enable ARC" ${FORCE_CACHE})
+# Use hidden visibility or not
+if(NOT DEFINED ENABLE_VISIBILITY)
+ # Unless specified, disable symbols visibility by default
+ set(ENABLE_VISIBILITY FALSE)
+ message(STATUS "Hiding symbols visibility by default. ENABLE_VISIBILITY not provided!")
+endif()
+set(ENABLE_VISIBILITY_INT ${ENABLE_VISIBILITY} CACHE BOOL "Whether or not to hide symbols (-fvisibility=hidden)" ${FORCE_CACHE})
+# Set strict compiler checks or not
+if(NOT DEFINED ENABLE_STRICT_TRY_COMPILE)
+ # Unless specified, disable strict try_compile()
+ set(ENABLE_STRICT_TRY_COMPILE FALSE)
+ message(STATUS "Using NON-strict compiler checks by default. ENABLE_STRICT_TRY_COMPILE not provided!")
+endif()
+set(ENABLE_STRICT_TRY_COMPILE_INT ${ENABLE_STRICT_TRY_COMPILE} CACHE BOOL "Whether or not to use strict compiler checks" ${FORCE_CACHE})
+# Get the SDK version information.
+execute_process(COMMAND xcodebuild -sdk ${CMAKE_OSX_SYSROOT} -version SDKVersion
+ OUTPUT_VARIABLE SDK_VERSION
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+# Find the Developer root for the specific iOS platform being compiled for
+# from CMAKE_OSX_SYSROOT. Should be ../../ from SDK specified in
+# CMAKE_OSX_SYSROOT. There does not appear to be a direct way to obtain
+# this information from xcrun or xcodebuild.
+if (NOT DEFINED CMAKE_DEVELOPER_ROOT AND NOT USED_CMAKE_GENERATOR MATCHES "Xcode")
+ get_filename_component(PLATFORM_SDK_DIR ${CMAKE_OSX_SYSROOT} PATH)
+ get_filename_component(CMAKE_DEVELOPER_ROOT ${PLATFORM_SDK_DIR} PATH)
+
+ if (NOT DEFINED CMAKE_DEVELOPER_ROOT)
+ message(FATAL_ERROR "Invalid CMAKE_DEVELOPER_ROOT: "
+ "${CMAKE_DEVELOPER_ROOT} does not exist.")
+ endif()
+endif()
+# Find the C & C++ compilers for the specified SDK.
+if(NOT CMAKE_C_COMPILER)
+ execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT} -find clang
+ OUTPUT_VARIABLE CMAKE_C_COMPILER
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ message(STATUS "Using C compiler: ${CMAKE_C_COMPILER}")
+endif()
+if(NOT CMAKE_CXX_COMPILER)
+ execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT} -find clang++
+ OUTPUT_VARIABLE CMAKE_CXX_COMPILER
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ message(STATUS "Using CXX compiler: ${CMAKE_CXX_COMPILER}")
+endif()
+# Find (Apple's) libtool.
+execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT} -find libtool
+ OUTPUT_VARIABLE BUILD_LIBTOOL
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+message(STATUS "Using libtool: ${BUILD_LIBTOOL}")
+# Configure libtool to be used instead of ar + ranlib to build static libraries.
+# This is required on Xcode 7+, but should also work on previous versions of
+# Xcode.
+set(CMAKE_C_CREATE_STATIC_LIBRARY
+ "${BUILD_LIBTOOL} -static -o ")
+set(CMAKE_CXX_CREATE_STATIC_LIBRARY
+ "${BUILD_LIBTOOL} -static -o ")
+# Find the toolchain's provided install_name_tool if none is found on the host
+if(NOT CMAKE_INSTALL_NAME_TOOL)
+ execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT} -find install_name_tool
+ OUTPUT_VARIABLE CMAKE_INSTALL_NAME_TOOL_INT
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ set(CMAKE_INSTALL_NAME_TOOL ${CMAKE_INSTALL_NAME_TOOL_INT} CACHE STRING "" ${FORCE_CACHE})
+endif()
+# Get the version of Darwin (OS X) of the host.
+execute_process(COMMAND uname -r
+ OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+if(SDK_NAME MATCHES "iphone")
+ set(CMAKE_SYSTEM_NAME iOS CACHE INTERNAL "" ${FORCE_CACHE})
+endif()
+# CMake 3.14+ support building for iOS, watchOS and tvOS out of the box.
+if(MODERN_CMAKE)
+ if(SDK_NAME MATCHES "appletv")
+ set(CMAKE_SYSTEM_NAME tvOS CACHE INTERNAL "" ${FORCE_CACHE})
+ elseif(SDK_NAME MATCHES "watch")
+ set(CMAKE_SYSTEM_NAME watchOS CACHE INTERNAL "" ${FORCE_CACHE})
+ endif()
+ # Provide flags for a combined FAT library build on newer CMake versions
+ if(PLATFORM_INT MATCHES ".*COMBINED")
+ set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH "NO" CACHE INTERNAL "" ${FORCE_CACHE})
+ set(CMAKE_IOS_INSTALL_COMBINED YES CACHE INTERNAL "" ${FORCE_CACHE})
+ message(STATUS "Will combine built (static) artifacts into FAT lib...")
+ endif()
+elseif(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.10")
+ # Legacy code path prior to CMake 3.14 or fallback if no SDK_NAME specified
+ set(CMAKE_SYSTEM_NAME iOS CACHE INTERNAL "" ${FORCE_CACHE})
+else()
+ # Legacy code path prior to CMake 3.14 or fallback if no SDK_NAME specified
+ set(CMAKE_SYSTEM_NAME Darwin CACHE INTERNAL "" ${FORCE_CACHE})
+endif()
+# Standard settings.
+set(CMAKE_SYSTEM_VERSION ${SDK_VERSION} CACHE INTERNAL "")
+set(UNIX TRUE CACHE BOOL "")
+set(APPLE TRUE CACHE BOOL "")
+set(IOS TRUE CACHE BOOL "")
+set(CMAKE_AR ar CACHE FILEPATH "" FORCE)
+set(CMAKE_RANLIB ranlib CACHE FILEPATH "" FORCE)
+set(CMAKE_STRIP strip CACHE FILEPATH "" FORCE)
+# Set the architectures for which to build.
+set(CMAKE_OSX_ARCHITECTURES ${ARCHS} CACHE STRING "Build architecture for iOS")
+# Change the type of target generated for try_compile() so it'll work when cross-compiling, weak compiler checks
+if(ENABLE_STRICT_TRY_COMPILE_INT)
+ message(STATUS "Using strict compiler checks (default in CMake).")
+else()
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+endif()
+# All iOS/Darwin specific settings - some may be redundant.
+set(CMAKE_MACOSX_BUNDLE YES)
+set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO")
+set(CMAKE_SHARED_LIBRARY_PREFIX "lib")
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
+set(CMAKE_SHARED_MODULE_PREFIX "lib")
+set(CMAKE_SHARED_MODULE_SUFFIX ".so")
+set(CMAKE_C_COMPILER_ABI ELF)
+set(CMAKE_CXX_COMPILER_ABI ELF)
+set(CMAKE_C_HAS_ISYSROOT 1)
+set(CMAKE_CXX_HAS_ISYSROOT 1)
+set(CMAKE_MODULE_EXISTS 1)
+set(CMAKE_DL_LIBS "")
+set(CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
+set(CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ")
+set(CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}")
+set(CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}")
+
+if(ARCHS MATCHES "((^|;|, )(arm64|arm64e|x86_64))+")
+ set(CMAKE_C_SIZEOF_DATA_PTR 8)
+ set(CMAKE_CXX_SIZEOF_DATA_PTR 8)
+ if(ARCHS MATCHES "((^|;|, )(arm64|arm64e))+")
+ set(CMAKE_SYSTEM_PROCESSOR "aarch64")
+ else()
+ set(CMAKE_SYSTEM_PROCESSOR "x86_64")
+ endif()
+else()
+ set(CMAKE_C_SIZEOF_DATA_PTR 4)
+ set(CMAKE_CXX_SIZEOF_DATA_PTR 4)
+ set(CMAKE_SYSTEM_PROCESSOR "arm")
+endif()
+
+# Note that only Xcode 7+ supports the newer more specific:
+# -m${SDK_NAME}-version-min flags, older versions of Xcode use:
+# -m(ios/ios-simulator)-version-min instead.
+if(${CMAKE_VERSION} VERSION_LESS "3.11")
+ if(PLATFORM_INT STREQUAL "OS" OR PLATFORM_INT STREQUAL "OS64")
+ if(XCODE_VERSION VERSION_LESS 7.0)
+ set(SDK_NAME_VERSION_FLAGS
+ "-mios-version-min=${DEPLOYMENT_TARGET}")
+ else()
+ # Xcode 7.0+ uses flags we can build directly from SDK_NAME.
+ set(SDK_NAME_VERSION_FLAGS
+ "-m${SDK_NAME}-version-min=${DEPLOYMENT_TARGET}")
+ endif()
+ elseif(PLATFORM_INT STREQUAL "TVOS")
+ set(SDK_NAME_VERSION_FLAGS
+ "-mtvos-version-min=${DEPLOYMENT_TARGET}")
+ elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS")
+ set(SDK_NAME_VERSION_FLAGS
+ "-mtvos-simulator-version-min=${DEPLOYMENT_TARGET}")
+ elseif(PLATFORM_INT STREQUAL "WATCHOS")
+ set(SDK_NAME_VERSION_FLAGS
+ "-mwatchos-version-min=${DEPLOYMENT_TARGET}")
+ elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS")
+ set(SDK_NAME_VERSION_FLAGS
+ "-mwatchos-simulator-version-min=${DEPLOYMENT_TARGET}")
+ else()
+ # SIMULATOR or SIMULATOR64 both use -mios-simulator-version-min.
+ set(SDK_NAME_VERSION_FLAGS
+ "-mios-simulator-version-min=${DEPLOYMENT_TARGET}")
+ endif()
+else()
+ # Newer versions of CMake sets the version min flags correctly
+ set(CMAKE_OSX_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET} CACHE STRING
+ "Set CMake deployment target" ${FORCE_CACHE})
+endif()
+
+
+if(ENABLE_BITCODE_INT)
+ set(BITCODE "-fembed-bitcode")
+ set(CMAKE_XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE "bitcode" CACHE INTERNAL "")
+ set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "YES" CACHE INTERNAL "")
+else()
+ set(BITCODE "")
+ set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "NO" CACHE INTERNAL "")
+endif()
+
+if(ENABLE_ARC_INT)
+ set(FOBJC_ARC "-fobjc-arc")
+ set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES" CACHE INTERNAL "")
+else()
+ set(FOBJC_ARC "-fno-objc-arc")
+ set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "NO" CACHE INTERNAL "")
+endif()
+
+if(NOT ENABLE_VISIBILITY_INT)
+ set(VISIBILITY "-fvisibility=hidden")
+ set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "YES" CACHE INTERNAL "")
+else()
+ set(VISIBILITY "")
+ set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "NO" CACHE INTERNAL "")
+endif()
+
+if(NOT IOS_TOOLCHAIN_HAS_RUN)
+ #Check if Xcode generator is used, since that will handle these flags automagically
+ if(USED_CMAKE_GENERATOR MATCHES "Xcode")
+ message(STATUS "Not setting any manual command-line buildflags, since Xcode is selected as generator.")
+ else()
+ set(CMAKE_C_FLAGS
+ "${SDK_NAME_VERSION_FLAGS} ${BITCODE} -fobjc-abi-version=2 ${FOBJC_ARC} ${CMAKE_C_FLAGS}")
+ # Hidden visibilty is required for C++ on iOS.
+ set(CMAKE_CXX_FLAGS
+ "${SDK_NAME_VERSION_FLAGS} ${BITCODE} ${VISIBILITY} -fvisibility-inlines-hidden -fobjc-abi-version=2 ${FOBJC_ARC} ${CMAKE_CXX_FLAGS}")
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -O0 -g ${CMAKE_CXX_FLAGS_DEBUG}")
+ set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS} -DNDEBUG -Os -ffast-math ${CMAKE_CXX_FLAGS_MINSIZEREL}")
+ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS} -DNDEBUG -O2 -g -ffast-math ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -DNDEBUG -O3 -ffast-math ${CMAKE_CXX_FLAGS_RELEASE}")
+ set(CMAKE_C_LINK_FLAGS "${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}")
+ set(CMAKE_CXX_LINK_FLAGS "${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}")
+ set(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp")
+
+ # In order to ensure that the updated compiler flags are used in try_compile()
+ # tests, we have to forcibly set them in the CMake cache, not merely set them
+ # in the local scope.
+ set(VARS_TO_FORCE_IN_CACHE
+ CMAKE_C_FLAGS
+ CMAKE_CXX_FLAGS
+ CMAKE_CXX_FLAGS_DEBUG
+ CMAKE_CXX_FLAGS_RELWITHDEBINFO
+ CMAKE_CXX_FLAGS_MINSIZEREL
+ CMAKE_CXX_FLAGS_RELEASE
+ CMAKE_C_LINK_FLAGS
+ CMAKE_CXX_LINK_FLAGS)
+ foreach(VAR_TO_FORCE ${VARS_TO_FORCE_IN_CACHE})
+ set(${VAR_TO_FORCE} "${${VAR_TO_FORCE}}" CACHE STRING "" ${FORCE_CACHE})
+ endforeach()
+ endif()
+
+ ## Print status messages to inform of the current state
+ message(STATUS "Configuring ${SDK_NAME} build for platform: ${PLATFORM_INT}, architecture(s): ${ARCHS}")
+ message(STATUS "Using SDK: ${CMAKE_OSX_SYSROOT_INT}")
+ message(STATUS "Using minimum deployment version: ${DEPLOYMENT_TARGET}"
+ " (SDK version: ${SDK_VERSION})")
+ if(MODERN_CMAKE)
+ message(STATUS "Merging integrated CMake 3.14+ iOS,tvOS,watchOS,macOS toolchain(s) with this toolchain!")
+ endif()
+ if(USED_CMAKE_GENERATOR MATCHES "Xcode")
+ message(STATUS "Using Xcode version: ${XCODE_VERSION}")
+ endif()
+ if(DEFINED SDK_NAME_VERSION_FLAGS)
+ message(STATUS "Using version flags: ${SDK_NAME_VERSION_FLAGS}")
+ endif()
+ message(STATUS "Using a data_ptr size of: ${CMAKE_CXX_SIZEOF_DATA_PTR}")
+ message(STATUS "Using install_name_tool: ${CMAKE_INSTALL_NAME_TOOL}")
+ if(ENABLE_BITCODE_INT)
+ message(STATUS "Enabling bitcode support.")
+ else()
+ message(STATUS "Disabling bitcode support.")
+ endif()
+
+ if(ENABLE_ARC_INT)
+ message(STATUS "Enabling ARC support.")
+ else()
+ message(STATUS "Disabling ARC support.")
+ endif()
+
+ if(NOT ENABLE_VISIBILITY_INT)
+ message(STATUS "Hiding symbols (-fvisibility=hidden).")
+ endif()
+endif()
+
+set(CMAKE_PLATFORM_HAS_INSTALLNAME 1)
+set(CMAKE_SHARED_LINKER_FLAGS "-rpath @executable_path/Frameworks -rpath @loader_path/Frameworks")
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names")
+set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -Wl,-headerpad_max_install_names")
+set(CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,")
+set(CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".tbd" ".dylib" ".so" ".a")
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-install_name")
+
+# Set the find root to the iOS developer roots and to user defined paths.
+set(CMAKE_FIND_ROOT_PATH ${CMAKE_OSX_SYSROOT_INT} ${CMAKE_PREFIX_PATH} CACHE STRING "Root path that will be prepended
+ to all search paths")
+# Default to searching for frameworks first.
+set(CMAKE_FIND_FRAMEWORK FIRST)
+# Set up the default search directories for frameworks.
+set(CMAKE_FRAMEWORK_PATH
+ ${CMAKE_DEVELOPER_ROOT}/Library/PrivateFrameworks
+ ${CMAKE_OSX_SYSROOT_INT}/System/Library/Frameworks
+ ${CMAKE_FRAMEWORK_PATH} CACHE STRING "Frameworks search paths" ${FORCE_CACHE})
+
+set(IOS_TOOLCHAIN_HAS_RUN TRUE CACHE BOOL "Has the CMake toolchain run already?" ${FORCE_CACHE})
+
+# By default, search both the specified iOS SDK and the remainder of the host filesystem.
+if(NOT CMAKE_FIND_ROOT_PATH_MODE_PROGRAM)
+ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH CACHE STRING "" ${FORCE_CACHE})
+endif()
+if(NOT CMAKE_FIND_ROOT_PATH_MODE_LIBRARY)
+ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY CACHE STRING "" ${FORCE_CACHE})
+endif()
+if(NOT CMAKE_FIND_ROOT_PATH_MODE_INCLUDE)
+ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY CACHE STRING "" ${FORCE_CACHE})
+endif()
+if(NOT CMAKE_FIND_ROOT_PATH_MODE_PACKAGE)
+ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY CACHE STRING "" ${FORCE_CACHE})
+endif()
+
+#
+# Some helper-macros below to simplify and beautify the CMakeFile
+#
+
+# This little macro lets you set any Xcode specific property.
+macro(set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE XCODE_RELVERSION)
+ set(XCODE_RELVERSION_I "${XCODE_RELVERSION}")
+ if(XCODE_RELVERSION_I STREQUAL "All")
+ set_property(TARGET ${TARGET} PROPERTY
+ XCODE_ATTRIBUTE_${XCODE_PROPERTY} "${XCODE_VALUE}")
+ else()
+ set_property(TARGET ${TARGET} PROPERTY
+ XCODE_ATTRIBUTE_${XCODE_PROPERTY}[variant=${XCODE_RELVERSION_I}] "${XCODE_VALUE}")
+ endif()
+endmacro(set_xcode_property)
+# This macro lets you find executable programs on the host system.
+macro(find_host_package)
+ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
+ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
+ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE NEVER)
+ set(IOS FALSE)
+ find_package(${ARGN})
+ set(IOS TRUE)
+ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
+ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
+ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
+ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH)
+endmacro(find_host_package)
diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt
new file mode 100644
index 0000000..34b65bc
--- /dev/null
+++ b/man/CMakeLists.txt
@@ -0,0 +1,10 @@
+
+if (DO_INSTALL_CORE)
+
+ install(FILES ejdb2.3 DESTINATION ${CMAKE_INSTALL_MANDIR}/man3
+ COMPONENT doc)
+
+ install(FILES jbs.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1
+ COMPONENT doc)
+
+ endif()
\ No newline at end of file
diff --git a/man/ejdb2.3 b/man/ejdb2.3
new file mode 100644
index 0000000..5650a62
--- /dev/null
+++ b/man/ejdb2.3
@@ -0,0 +1,12 @@
+.TH "EJDB2" 3 "2020-04-01" "Man Page" "EJDB2"
+
+.SH NAME
+EJDB2 \- Embedded JSON Database engine
+
+.SH DESCRIPTION
+.PP
+EJDB2 is an embeddable JSON database engine published under MIT license.
+
+.SH "SEE ALSO"
+.I http://ejdb.org
+EJDB project offcial web site.
diff --git a/man/jbs.1 b/man/jbs.1
new file mode 100644
index 0000000..5097b57
--- /dev/null
+++ b/man/jbs.1
@@ -0,0 +1,12 @@
+.TH "JBS" 1 "2019-04-01" "Man Page" "JBS"
+
+.SH NAME
+EJDB2 standalone HTTP REST/Websocket server.
+
+.SH DESCRIPTION
+.PP
+EJDB2 is an embeddable JSON database engine published under MIT license.
+
+.SH "SEE ALSO"
+.I http://ejdb.org
+EJDB2 project offcial web site.
diff --git a/pvs_studio_analyze.sh b/pvs_studio_analyze.sh
new file mode 100755
index 0000000..6be8850
--- /dev/null
+++ b/pvs_studio_analyze.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+set -e
+
+SCRIPTPATH="$(
+ cd "$(dirname "$0")"
+ pwd -P
+)"
+cd $SCRIPTPATH
+
+if [ ! -d ./build ]; then
+ mkdir ./build
+fi
+
+cd ./build
+cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Release \
+ -DBUILD_JNI_BINDING=ON \
+ -DBUILD_DART_BINDING=ON \
+ -DBUILD_NODEJS_BINDING=ON \
+ && make
+pvs-studio-analyzer analyze -a 45 -l ${HOME}/.config/PVS-Studio/PVS-Studio.lic -j4 -o ./pvs.log
+rm -rf ./pvs_report
+plog-converter -a 'GA:1,2,3;64:1;OP:1,2,3;MISRA:1' -t fullhtml -o ./pvs_report ./pvs.log
diff --git a/release.sh b/release.sh
new file mode 100755
index 0000000..1124c68
--- /dev/null
+++ b/release.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+set -e
+# set -x
+
+SCRIPTPATH="$(
+ cd "$(dirname "$0")"
+ pwd -P
+)"
+cd $SCRIPTPATH
+
+
+readme() {
+ echo "Generating README.md";
+ cat "./BASE.md" > "./README.md"
+ echo -e "\n\n" >> "./README.md"
+ cat "./src/bindings/ejdb2_android/README.md" >> "./README.md"
+ echo -e "\n\n" >> "./README.md"
+ # cat "./src/bindings/ejdb2_swift/EJDB2Swift/README.md" >> "./README.md"
+ # echo -e "\n\n" >> "./README.md"
+ cat "./src/jql/README.md" >> "./README.md"
+ echo -e "\n\n" >> "./README.md"
+ cat "./src/jbr/README.md" >> "./README.md"
+ echo -e "\n\n" >> "./README.md"
+ cat "./docker/README.md" >> "./README.md"
+ echo -e "\n\n" >> "./README.md"
+ cat "./CAPI.md" >> "./README.md"
+ echo -e '\n# License\n```\n' >> "./README.md"
+ cat "./LICENSE" >> "./README.md"
+ echo -e '\n```\n' >> "./README.md"
+}
+
+release_tag() {
+ echo "Creating EJDB2 release"
+ readme
+
+ git pull origin master
+ dch --distribution testing --no-force-save-on-release --release "" -c ./Changelog
+ VERSION=`dpkg-parsechangelog -l./Changelog -SVersion`
+ TAG="v${VERSION}"
+ CHANGESET=`dpkg-parsechangelog -l./Changelog -SChanges | sed '/^ejdb2.*/d' | sed '/^\s*$/d'`
+ git add ./Changelog
+ git add ./README.md
+
+ if ! git diff-index --quiet HEAD --; then
+ git commit -a -m"${TAG} landed"
+ git push origin master
+ fi
+
+ echo "${CHANGESET}" | git tag -f -a -F - "${TAG}"
+ git push origin -f --tags
+}
+
+while [ "$1" != "" ]; do
+ case $1 in
+ "-d" ) readme
+ exit
+ ;;
+ "-r" ) release_tag
+ exit
+ ;;
+ esac
+ shift
+done
+
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..af0bc62
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,383 @@
+if(NOT CMAKE_BUILD_TYPE)
+ message(
+ FATAL_ERROR
+ "Please specify the build type -DCMAKE_BUILD_TYPE=Debug|Release|RelWithDebInfo"
+ )
+endif()
+
+set(MODULES util jbl jql jbi)
+set(PROJECT_LLIBRARIES)
+set(PROJECT_INCLUDE_DIRS)
+set(ALL_SRC)
+set(ALL_HDRS)
+set(PUB_HDRS)
+set(PROJECT_GENERATED_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated)
+list(APPEND PROJECT_INCLUDE_DIRS "${PROJECT_GENERATED_DIR}"
+ "${CMAKE_CURRENT_SOURCE_DIR}")
+
+if(APPLE)
+ option(BUILD_FRAMEWORK "Build an OS X framework" OFF)
+ set(FRAMEWORK_INSTALL_DIR
+ "/Library/Frameworks"
+ CACHE STRING "Directory to install frameworks to.")
+endif()
+
+include(CheckIncludeFile)
+include(CheckIncludeFiles)
+include(CheckLibraryExists)
+include(TestBigEndian)
+
+include(AddIOWOW)
+
+if(ENABLE_HTTP)
+ if(WIN32)
+ message(FATAL_ERROR "ENABLE_HTTP option cannot be used in Windows build")
+ endif()
+ include(AddFacil)
+ add_definitions(-DJB_HTTP)
+ list(APPEND MODULES jbr)
+endif()
+
+if((CMAKE_BUILD_TYPE EQUAL Release) OR (CMAKE_BUILD_TYPE EQUAL RelWithDebInfo))
+ add_definition(-DJB_RELEASE=1)
+endif()
+
+include(TestQsortR)
+if(HAVE_QSORT_R)
+ add_definitions(-DJB_HAVE_QSORT_R)
+endif()
+
+test_big_endian(IS_BIG_ENDIAN)
+if(IS_BIG_ENDIAN EQUAL 1)
+ add_definitions(-DIW_BIGENDIAN=1)
+endif()
+
+if(CMAKE_SIZEOF_VOID_P MATCHES 8)
+ add_definitions(-DIW_64)
+else()
+ add_definitions(-DIW_32)
+endif()
+
+if(BUILD_TESTS)
+ add_definitions(-DIW_TESTS)
+endif()
+
+find_package(Threads REQUIRED CMAKE_THREAD_PREFER_PTHREAD)
+if(CMAKE_USE_WIN32_THREADS_INIT)
+ add_definitions(-DJB_WIN32_THREADS)
+elseif(CMAKE_USE_PTHREADS_INIT)
+ add_definitions(-DJB_PTHREADS)
+else()
+ mesage(FATAL_ERROR "Unable to find suitable threading library")
+endif(CMAKE_USE_WIN32_THREADS_INIT)
+
+if(ANDROID)
+ find_library(LOG_LIB log)
+ if(NOT LOG_LIB)
+ message(FATAL_ERROR "Library 'log' not FOUND")
+ endif()
+ list(APPEND PROJECT_LLIBRARIES "${LOG_LIB}")
+endif()
+
+if(NOT WIN32)
+ list(APPEND PROJECT_LLIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+else()
+ include(Win32LIBTools)
+ check_include_file(windows.h HAVE_WINDOWS_H)
+ if(NOT HAVE_WINDOWS_H)
+ message(FATAL_ERROR "Unable to find windows.h include file")
+ endif()
+
+ set(IBERTY_FIND_REQUIRED ON)
+ include(FindLibIberty)
+ list(APPEND PROJECT_LLIBRARIES ${IBERTY_LIBRARIES})
+
+ check_library_exists(winpthread pthread_exit "" HAVE_WINPTHREAD)
+ if(NOT HAVE_WINPTHREAD)
+ message(FATAL_ERROR "Unable to winpthread lib")
+ endif()
+ list(INSERT PROJECT_LLIBRARIES 0 -lwinpthread)
+ add_definitions(-D_POSIX_THREAD_SAFE_FUNCTIONS)
+endif()
+
+foreach(HF IN ITEMS stdlib stddef stdint stdbool)
+ string(TOUPPER "${HF}" UHF)
+ check_include_file(${HF}.h "JB_HAVE_${UHF}")
+ if(NOT JB_HAVE_${UHF})
+ message(FATAL_ERROR "Include file '${HF}.h' not FOUND")
+ endif()
+endforeach()
+
+add_definitions(-D_XOPEN_SOURCE=600)
+add_definitions(-D_DEFAULT_SOURCE)
+add_definitions(-D_LARGEFILE_SOURCE)
+add_definitions(-D_FILE_OFFSET_BITS=64)
+if(APPLE)
+ add_definitions(-D_DARWIN_C_SOURCE)
+endif(APPLE)
+
+file(GLOB ROOT_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.c)
+list(APPEND ALL_SRC ${ROOT_SRC})
+
+foreach(MODULE IN LISTS MODULES)
+ file(GLOB MODULE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}/*.c)
+ file(GLOB MODULE_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}/*.h)
+ list(APPEND ALL_SRC ${MODULE_SRC})
+ list(APPEND ALL_HDRS ${MODULE_HDRS})
+ list(APPEND PROJECT_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE})
+endforeach(MODULE)
+
+list(
+ APPEND
+ PUB_HDRS
+ ${CMAKE_CURRENT_SOURCE_DIR}/ejdb2.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/jbl/jbl.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/jbr/jbr.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/jql/jql.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/util/lwre.h)
+
+set(CMAKE_C_FLAGS
+ "${CMAKE_C_FLAGS} -std=gnu11 -fsigned-char -pedantic -Wfatal-errors -Wall -Wextra \
+ -Wno-sign-compare -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-function \
+ -Wno-missing-field-initializers -Wno-missing-braces \
+ -Wno-shorten-64-to-32")
+
+if(NOT WIN32)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-implicit-fallthrough -fPIC")
+else()
+ add_definitions(-D__USE_MINGW_ANSI_STDIO)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-pedantic-ms-format")
+ set(CMAKE_EXE_LINKER_FLAGS
+ "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
+endif()
+
+if(ASAN)
+ set(CMAKE_C_ASAN "-fsanitize=address -fno-omit-frame-pointer")
+endif()
+
+set(CMAKE_C_FLAGS_DEBUG
+ "${CMAKE_C_ASAN} -O0 -g -ggdb -Werror -DDEBUG -D_DEBUG -UNDEBUG -Wno-unused-variable"
+)
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_ASAN} -O3 -DNDEBUG")
+# set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-Wl,-s")
+set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELEASE} -g")
+set(CMAKE_C_FLAGS_RELEASEWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
+
+if(CMAKE_COMPILER_IS_GNUCC)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+endif()
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tmpl/ejdb2cfg.h
+ ${PROJECT_GENERATED_DIR}/ejdb2cfg.h)
+file(GLOB PROJECT_GENERATED_HDRS ${PROJECT_GENERATED_DIR}/*.h)
+list(APPEND ALL_HDRS ${PROJECT_GENERATED_HDRS})
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tmpl/libejdb2.pc.in
+ ${PROJECT_GENERATED_DIR}/libejdb2.pc @ONLY)
+
+if(DO_INSTALL_CORE)
+ install(FILES ${PROJECT_GENERATED_DIR}/libejdb2.pc
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+endif()
+
+list(REMOVE_DUPLICATES PROJECT_LLIBRARIES)
+list(REMOVE_DUPLICATES PROJECT_INCLUDE_DIRS)
+include_directories(${PROJECT_INCLUDE_DIRS})
+
+foreach(MODULE IN LISTS MODULES)
+ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}/CMakeLists.txt)
+ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${MODULE})
+ endif()
+ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}/tools/CMakeLists.txt)
+ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}/tools)
+ endif()
+ if(BUILD_TESTS AND EXISTS
+ ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}/tests/CMakeLists.txt)
+ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}/tests)
+ endif()
+ if(BUILD_EXAMPLES
+ AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}/examples/CMakeLists.txt)
+ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}/examples)
+ endif()
+ if(BUILD_BENCHMARKS
+ AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}/benchmark/CMakeLists.txt)
+ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}/benchmark)
+ endif()
+endforeach(MODULE)
+
+if(ENABLE_HTTP)
+ add_subdirectory(jbs)
+endif()
+
+if(BUILD_TESTS)
+ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tests)
+endif()
+
+if(BUILD_EXAMPLES)
+ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/examples)
+endif()
+
+if(BUILD_DART_BINDING)
+ add_subdirectory(bindings/ejdb2_dart)
+endif()
+
+if(BUILD_JNI_BINDING)
+ add_subdirectory(bindings/ejdb2_jni)
+endif()
+
+if(BUILD_NODEJS_BINDING)
+ add_subdirectory(bindings/ejdb2_node)
+endif()
+
+if(BUILD_ANDROID_LIBS)
+ add_subdirectory(bindings/ejdb2_android)
+endif()
+
+if(BUILD_REACT_NATIVE_BINDING)
+ add_subdirectory(bindings/ejdb2_react_native)
+endif()
+
+if(BUILD_FLUTTER_BINDING)
+ add_subdirectory(bindings/ejdb2_flutter)
+endif()
+
+if(BUILD_SWIFT_BINDING)
+ add_subdirectory(bindings/ejdb2_swift)
+endif()
+
+if(NOT BUILD_SHARED_LIBS)
+ add_definitions(-DIW_NODLL)
+ add_library(ejdb2 STATIC ${ALL_SRC})
+ add_library(ejdb2_s ALIAS ejdb2)
+else()
+ add_library(ejdb2 SHARED ${ALL_SRC})
+ add_library(ejdb2_s STATIC ${ALL_SRC})
+endif()
+
+target_link_libraries(ejdb2 ${PROJECT_LLIBRARIES})
+if(BUILD_SHARED_LIBS)
+ target_link_libraries(ejdb2_s ${PROJECT_LLIBRARIES})
+endif()
+
+if(BUILD_SHARED_LIBS)
+ if(WIN32)
+ add_dependencies(ejdb2 wintools_init)
+ set_target_properties(ejdb2 PROPERTIES LINK_FLAGS
+ "-Wl,--output-def,libejdb2.def")
+ add_w32_importlib(ejdb2 libejdb2 ${CMAKE_CURRENT_BINARY_DIR})
+
+ if(DO_INSTALL_CORE)
+ install(
+ FILES ${CMAKE_CURRENT_BINARY_DIR}/libejdb2.def
+ ${CMAKE_CURRENT_BINARY_DIR}/libejdb2.lib
+ ${CMAKE_CURRENT_BINARY_DIR}/libejdb2.exp
+ DESTINATION ${CMAKE_INSTALL_LIBDIR})
+ endif()
+
+ endif()
+ set_target_properties(
+ ejdb2
+ PROPERTIES VERSION ${PROJECT_VERSION}
+ SOVERSION ${PROJECT_VERSION_MAJOR}
+ PUBLIC_HEADER "${PUB_HDRS}"
+ DEFINE_SYMBOL IW_API_EXPORTS)
+
+ if(CMAKE_BUILD_TYPE STREQUAL "Release")
+ add_custom_command(
+ TARGET ejdb2
+ POST_BUILD
+ COMMAND strip -s $)
+ endif()
+
+ set_target_properties(
+ ejdb2_s PROPERTIES VERSION ${PROJECT_VERSION} COMPILE_FLAGS "-DIW_NODLL"
+ OUTPUT_NAME ejdb2-${PROJECT_VERSION_MAJOR})
+else()
+ set_target_properties(
+ ejdb2
+ PROPERTIES VERSION ${PROJECT_VERSION}
+ PUBLIC_HEADER "${PUB_HDRS}"
+ COMPILE_FLAGS "-DIW_NODLL"
+ LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -s"
+ OUTPUT_NAME ejdb2-${PROJECT_VERSION_MAJOR})
+endif()
+
+if(DO_INSTALL_CORE)
+ install(
+ TARGETS ejdb2
+ EXPORT ejdb2-exports
+ FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
+ install(EXPORT ejdb2-exports
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME})
+endif()
+
+if(BUILD_SHARED_LIBS AND DO_INSTALL_CORE)
+ install(
+ TARGETS ejdb2_s
+ EXPORT ejdb2-static-exports
+ FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
+ install(EXPORT ejdb2-static-exports
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME})
+endif()
+
+if(DO_INSTALL_CORE)
+ # Install iowow headers included into ejdb2
+ install(
+ DIRECTORY ${IOWOW_INCLUDE_DIR}/${PROJECT_NAME}/iowow
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}
+ COMPONENT headers
+ FILES_MATCHING
+ PATTERN "*.h")
+ install(FILES ${CMAKE_SOURCE_DIR}/LICENSE ${CMAKE_SOURCE_DIR}/Changelog
+ DESTINATION ${CMAKE_INSTALL_DOCDIR})
+ install(
+ FILES ${CMAKE_SOURCE_DIR}/README.md
+ RENAME README
+ DESTINATION ${CMAKE_INSTALL_DOCDIR})
+
+ export(EXPORT ejdb2-exports)
+ if(BUILD_SHARED_LIBS)
+ export(EXPORT ejdb2-static-exports)
+ endif(BUILD_SHARED_LIBS)
+
+endif()
+
+include(InstallRequiredSystemLibraries)
+
+set(${PROJECT_NAME}_PUB_HDRS
+ ${PUB_HDRS}
+ CACHE INTERNAL "${PROJECT_NAME}: Public headers" FORCE)
+set(${PROJECT_NAME}_INCLUDE_DIRS
+ ${PROJECT_INCLUDE_DIRS}
+ CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
+
+message("")
+message("CMAKE_GENERATOR: ${CMAKE_GENERATOR}")
+message("${PROJECT_NAME} LINK LIBS: ${PROJECT_LLIBRARIES}")
+message("${PROJECT_NAME} ASAN: ${ASAN}")
+message("\n${PROJECT_NAME} INCLUDE DIRS: ${PROJECT_INCLUDE_DIRS}")
+message("\n${PROJECT_NAME} SOURCES: ${ALL_SRC}")
+message("\n${PROJECT_NAME} PUB_HDRS: ${PUB_HDRS}")
+message("\n${PROJECT_NAME} CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
+message("${PROJECT_NAME} ANDROID_ABIS: ${ANDROID_ABIS}")
+message("${PROJECT_NAME} ENABLE_HTTP: ${ENABLE_HTTP}")
+message("${PROJECT_NAME} BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}")
+message("${PROJECT_NAME} BUILD_TESTS: ${BUILD_TESTS}")
+message("${PROJECT_NAME} BUILD_EXAMPLES: ${BUILD_EXAMPLES}")
+message("${PROJECT_NAME} BUILD_BENCHMARKS: ${BUILD_BENCHMARKS}")
+message("${PROJECT_NAME} BUILD_DART_BINDING: ${BUILD_DART_BINDING}")
+message("${PROJECT_NAME} BUILD_ANDROID_LIBS: ${BUILD_ANDROID_LIBS}")
+message("${PROJECT_NAME} BUILD_JNI_BINDING: ${BUILD_JNI_BINDING}")
+message("${PROJECT_NAME} BUILD_NODEJS_BINDING: ${BUILD_NODEJS_BINDING}")
+message(
+ "${PROJECT_NAME} BUILD_REACT_NATIVE_BINDING: ${BUILD_REACT_NATIVE_BINDING}")
+message("${PROJECT_NAME} BUILD_FLUTTER_BINDING: ${BUILD_FLUTTER_BINDING}")
+message("${PROJECT_NAME} BUILD_SWIFT_BINDING: ${BUILD_SWIFT_BINDING}")
diff --git a/src/bindings/ejdb2_android/CMakeLists.txt b/src/bindings/ejdb2_android/CMakeLists.txt
new file mode 100644
index 0000000..6d724ca
--- /dev/null
+++ b/src/bindings/ejdb2_android/CMakeLists.txt
@@ -0,0 +1,36 @@
+if (NOT DEFINED ANDROID_NDK_HOME)
+ if (DEFINED ENV{ANDROID_NDK_HOME})
+ set(ANDROID_NDK_HOME $ENV{ANDROID_NDK_HOME})
+ else ()
+ message(FATAL_ERROR "Missing required ANDROID_NDK_HOME option/env. Use -DANDROID_NDK_HOME=...")
+ endif ()
+endif ()
+
+set(ANDROID_BUILD_DIR "${CMAKE_SOURCE_DIR}/build_android")
+set(ANDROID_LIBS_DIR "${CMAKE_CURRENT_BINARY_DIR}/libs")
+
+foreach (AABI IN ITEMS ${ANDROID_ABIS})
+ list(APPEND ANDROID_ABIS_LIBS "${ANDROID_LIBS_DIR}/${AABI}/libejdb2jni.so")
+ add_custom_target(
+ android_${AABI} ALL
+ BYPRODUCTS ${ANDROID_LIBS_DIR}/${AABI}/libejdb2jni.so
+ COMMAND ${CMAKE_COMMAND} -E remove_directory ${ANDROID_BUILD_DIR}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${ANDROID_BUILD_DIR}
+ COMMAND ${CMAKE_COMMAND} -G ${CMAKE_GENERATOR} -S ${CMAKE_SOURCE_DIR}
+ -B ${ANDROID_BUILD_DIR}
+ -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+ -DBUILD_JNI_BINDING=ON
+ -DENABLE_HTTP=OFF
+ -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake
+ -DANDROID_ABI=${AABI}
+ -DANDROID_PLATFORM=android-21
+ -DANDROID_NATIVE_API_LEVEL=21
+ -DIOWOW_URL=${IOWOW_URL}
+ COMMAND ${CMAKE_COMMAND} --build ${ANDROID_BUILD_DIR}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${ANDROID_LIBS_DIR}/${AABI}
+ COMMAND ${CMAKE_COMMAND} -E copy ${ANDROID_BUILD_DIR}/src/bindings/ejdb2_jni/src/libejdb2jni.so ${ANDROID_LIBS_DIR}/${AABI}
+ COMMAND ${CMAKE_COMMAND} -E copy ${ANDROID_BUILD_DIR}/src/bindings/ejdb2_jni/src/ejdb2.jar ${ANDROID_LIBS_DIR}
+ COMMAND ${CMAKE_COMMAND} -E remove_directory ${ANDROID_BUILD_DIR}
+ VERBATIM
+ )
+endforeach ()
\ No newline at end of file
diff --git a/src/bindings/ejdb2_android/README.md b/src/bindings/ejdb2_android/README.md
new file mode 100644
index 0000000..33ed493
--- /dev/null
+++ b/src/bindings/ejdb2_android/README.md
@@ -0,0 +1,10 @@
+# Android
+
+* [Flutter binding](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_flutter)
+* [React Native binding](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_react_native)
+
+## Sample Android application
+
+* https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_android/test
+
+* https://github.com/Softmotions/ejdb_android_todo_app
\ No newline at end of file
diff --git a/src/bindings/ejdb2_android/test/.gitignore b/src/bindings/ejdb2_android/test/.gitignore
new file mode 100644
index 0000000..5cbce53
--- /dev/null
+++ b/src/bindings/ejdb2_android/test/.gitignore
@@ -0,0 +1,6 @@
+!/gradle/wrapper/gradle-wrapper.jar
+.gradle
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/src/bindings/ejdb2_android/test/README.md b/src/bindings/ejdb2_android/test/README.md
new file mode 100644
index 0000000..523aab9
--- /dev/null
+++ b/src/bindings/ejdb2_android/test/README.md
@@ -0,0 +1,30 @@
+# Android
+
+## Sample Android application
+
+https://github.com/Softmotions/ejdb_android_todo_app
+
+## Android binding showcase and unit tests
+
+```bash
+cd ./src/bindings/ejdb2_android/test
+```
+
+Set local android SDK/NDK path and target `arch` in `local.properties`
+
+```properties
+# Path to Android SDK dir
+sdk.dir=/Android-sdk
+
+# Path to Android NDK dir
+ndk.dir=/Android-sdk/ndk-bundle
+
+# Target abi name: armeabi-v7a, arm64-v8a, x86, x86_64
+abi.name=arm64-v8a
+```
+
+Run Android emulator for the same abi version then:
+
+```bash
+./gradlew connectedAndroidTest
+```
\ No newline at end of file
diff --git a/src/bindings/ejdb2_android/test/build.gradle b/src/bindings/ejdb2_android/test/build.gradle
new file mode 100644
index 0000000..5291ec5
--- /dev/null
+++ b/src/bindings/ejdb2_android/test/build.gradle
@@ -0,0 +1,36 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath "com.android.tools.build:gradle:3.1.0"
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
+
+Properties properties = new Properties()
+if (project.rootProject.file('local.properties').exists()) {
+ def is = project.rootProject.file('local.properties').newDataInputStream()
+ properties.load(is)
+ is.close()
+}
+
+ext {
+ abiName = properties.get("abi.name")
+}
\ No newline at end of file
diff --git a/src/bindings/ejdb2_android/test/ejdb2/.gitignore b/src/bindings/ejdb2_android/test/ejdb2/.gitignore
new file mode 100644
index 0000000..f11a73c
--- /dev/null
+++ b/src/bindings/ejdb2_android/test/ejdb2/.gitignore
@@ -0,0 +1,3 @@
+/build
+/jniLibs
+/libs
\ No newline at end of file
diff --git a/src/bindings/ejdb2_android/test/ejdb2/build.gradle b/src/bindings/ejdb2_android/test/ejdb2/build.gradle
new file mode 100644
index 0000000..647587a
--- /dev/null
+++ b/src/bindings/ejdb2_android/test/ejdb2/build.gradle
@@ -0,0 +1,65 @@
+apply plugin: 'com.android.library'
+
+def props = rootProject.ext
+
+android {
+ compileSdkVersion 21
+ defaultConfig {
+ minSdkVersion 21
+ targetSdkVersion 21
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ externalNativeBuild {
+ cmake {
+ abiFilters props.abiName
+ targets "ejdb2jni"
+ arguments "-DCMAKE_BUILD_TYPE=Release",
+ "-DBUILD_JNI_BINDING=ON",
+ "-DENABLE_HTTP=OFF",
+ "-DBUILD_EXAMPLES=OFF",
+ "-DCMAKE_TOOLCHAIN_FILE=$ndkDirectory/build/cmake/android.toolchain.cmake",
+ "-DANDROID_ABI=$props.abiName",
+ "-DANDROID_PLATFORM=android-21",
+ "-DANDROID_NATIVE_API_LEVEL=21"
+ }
+ }
+ }
+ externalNativeBuild {
+ cmake {
+ path file("../../../../CMakeLists.txt")
+ }
+ }
+}
+
+project.afterEvaluate {
+ if (tasks.findByName("externalNativeBuildDebug")) {
+ javaPreCompileDebug.dependsOn externalNativeBuildDebug
+ externalNativeBuildDebug.doLast {
+ copy {
+ from(".externalNativeBuild/cmake/debug/$props.abiName/src/bindings/ejdb2_jni/src") {
+ include "ejdb2.jar"
+ }
+ into "libs"
+ }
+ }
+ }
+ if (tasks.findByName("externalNativeBuildRelease")) {
+ javaPreCompileRelease.dependsOn externalNativeBuildRelease
+ externalNativeBuildRelease.doLast {
+ copy {
+ from(".externalNativeBuild/cmake/release/$props.abiName/src/bindings/ejdb2_jni/src") {
+ include "ejdb2.jar"
+ }
+ into "libs"
+ }
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: "libs", include: ["*.jar"])
+ testImplementation "junit:junit:4.12"
+ androidTestImplementation "com.android.support.test:runner:1.0.2"
+ androidTestImplementation "com.android.support.test.espresso:espresso-core:3.0.2"
+}
\ No newline at end of file
diff --git a/src/bindings/ejdb2_android/test/ejdb2/src/androidTest/java/com/softmotions/ejdb2/Ejdb2AndroidTest.java b/src/bindings/ejdb2_android/test/ejdb2/src/androidTest/java/com/softmotions/ejdb2/Ejdb2AndroidTest.java
new file mode 100644
index 0000000..3c63298
--- /dev/null
+++ b/src/bindings/ejdb2_android/test/ejdb2/src/androidTest/java/com/softmotions/ejdb2/Ejdb2AndroidTest.java
@@ -0,0 +1,189 @@
+package com.softmotions.ejdb2;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+@RunWith(AndroidJUnit4.class)
+public class Ejdb2AndroidTest {
+
+ private EJDB2 db;
+
+ @Before
+ public void start() {
+ try {
+ File dir = InstrumentationRegistry.getTargetContext().getCacheDir();
+ File path = new File(dir, "test.db");
+ db = new EJDB2Builder(path.getAbsolutePath()).truncate().open();
+ } catch (EJDB2Exception e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+
+ @After
+ public void shutdown() {
+ db.close();
+ }
+
+ @Test
+ public void ejdb2tests() {
+ try {
+ EJDB2Exception exception;
+ String json = "{'foo':'bar'}".replace('\'', '"');
+ String patch = "[{'op':'add', 'path':'/baz', 'value':'qux'}]".replace('\'', '"');
+
+ long id = db.put("c1", json);
+ assertEquals(1L, id);
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ db.get("c1", 1L, bos);
+ assertEquals(bos.toString(), json);
+
+ db.patch("c1", patch, id);
+ bos.reset();
+ db.get("c1", 1L, bos);
+ assertEquals(bos.toString(), "{'foo':'bar','baz':'qux'}".replace('\'', '"'));
+ bos.reset();
+
+ db.del("c1", id);
+
+ exception = null;
+ try {
+ db.get("c1", id, bos);
+ } catch (EJDB2Exception e) {
+ exception = e;
+ }
+ assertNotNull(exception);
+ assertTrue(exception.getMessage().contains("IWKV_ERROR_NOTFOUND"));
+
+ // JQL resources can be closed explicitly or garbage collected
+ JQL q = db.createQuery("@mycoll/*");
+ assertNotNull(q.getDb());
+ assertEquals(q.getCollection(), "mycoll");
+
+ id = db.put("mycoll", "{'foo':'bar'}".replace('\'', '"'));
+ assertEquals(1, id);
+
+ exception = null;
+ try {
+ db.put("mycoll", "{\"");
+ } catch (EJDB2Exception e) {
+ exception = e;
+ }
+ assertTrue(exception != null && exception.getMessage() != null);
+ assertEquals(86005, exception.getCode());
+ assertTrue(exception.getMessage().contains("JBL_ERROR_PARSE_UNQUOTED_STRING"));
+
+ db.put("mycoll", "{'foo':'baz'}".replace('\'', '"'));
+
+ final Map results = new LinkedHashMap<>();
+ q.execute(new JQLCallback() {
+ @Override
+ public long onRecord(long docId, String doc) {
+ assertTrue(docId > 0 && doc != null);
+ results.put(docId, doc);
+ return 1;
+ }
+ });
+ assertEquals(2, results.size());
+ assertEquals(results.get(1L), "{\"foo\":\"bar\"}");
+ assertEquals(results.get(2L), "{\"foo\":\"baz\"}");
+ results.clear();
+
+ try {
+ JQL q2 = db.createQuery("/[foo=:?]", "mycoll").setString(0, "zaz");
+ q2.execute(new JQLCallback() {
+ @Override
+ public long onRecord(long docId, String doc) {
+ results.put(docId, doc);
+ return 1;
+ }
+ });
+ q2.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail();
+ }
+ assertTrue(results.isEmpty());
+
+ try {
+ JQL q2 = db.createQuery("/[foo=:val]", "mycoll").setString("val", "bar");
+ q2.execute(new JQLCallback() {
+ @Override
+ public long onRecord(long docId, String doc) {
+ results.put(docId, doc);
+ return 1;
+ }
+ });
+ q2.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail();
+ }
+ assertEquals(1, results.size());
+ assertEquals(results.get(1L), "{\"foo\":\"bar\"}");
+
+ exception = null;
+ try {
+ db.createQuery("@mycoll/[");
+ } catch (EJDB2Exception e) {
+ exception = e;
+ }
+ assertTrue(exception != null && exception.getMessage() != null);
+ assertEquals(87001, exception.getCode());
+ assertTrue(exception.getMessage().contains("@mycoll/[ <---"));
+
+
+ long count = db.createQuery("@mycoll/* | count").executeScalarInt();
+ assertEquals(2, count);
+
+ q.withExplain().execute();
+ assertTrue(q.getExplainLog().contains("[INDEX] NO [COLLECTOR] PLAIN"));
+
+ json = db.infoAsString();
+ assertNotNull(json);
+ assertTrue(json.contains("{\"name\":\"mycoll\",\"dbid\":4,\"rnum\":2,\"indexes\":[]}"));
+
+ // Indexes
+ db.ensureStringIndex("mycoll", "/foo", true);
+ json = db.infoAsString();
+ assertTrue(json.contains("\"indexes\":[{\"ptr\":\"/foo\",\"mode\":5,\"idbf\":0,\"dbid\":5,\"rnum\":2}]"));
+
+
+ db.patch("mycoll", patch, 2);
+
+ json = db.createQuery("@mycoll/[foo=:?] and /[baz=:?]")
+ .setString(0, "baz")
+ .setString(1, "qux")
+ .firstJson();
+ assertEquals("{\"foo\":\"baz\",\"baz\":\"qux\"}", json);
+
+ json = db.createQuery("@mycoll/[foo re :?]").setRegexp(0, ".*").firstJson();
+ assertEquals("{\"foo\":\"baz\",\"baz\":\"qux\"}", json);
+
+ db.removeStringIndex("mycoll", "/foo", true);
+ json = db.infoAsString();
+ assertTrue(json.contains("{\"name\":\"mycoll\",\"dbid\":4,\"rnum\":2,\"indexes\":[]}"));
+
+ db.removeCollection("mycoll");
+ db.removeCollection("c1");
+ json = db.infoAsString();
+ assertTrue(json.contains("\"collections\":[]"));
+ } catch (UnsupportedEncodingException | EJDB2Exception e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+}
diff --git a/src/bindings/ejdb2_android/test/ejdb2/src/main/AndroidManifest.xml b/src/bindings/ejdb2_android/test/ejdb2/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..c8aa4d8
--- /dev/null
+++ b/src/bindings/ejdb2_android/test/ejdb2/src/main/AndroidManifest.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/bindings/ejdb2_android/test/gradle.properties b/src/bindings/ejdb2_android/test/gradle.properties
new file mode 100644
index 0000000..82618ce
--- /dev/null
+++ b/src/bindings/ejdb2_android/test/gradle.properties
@@ -0,0 +1,15 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
+
diff --git a/src/bindings/ejdb2_android/test/gradle/wrapper/gradle-wrapper.jar b/src/bindings/ejdb2_android/test/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..5c2d1cf
Binary files /dev/null and b/src/bindings/ejdb2_android/test/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/src/bindings/ejdb2_android/test/gradle/wrapper/gradle-wrapper.properties b/src/bindings/ejdb2_android/test/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..f4d7b2b
--- /dev/null
+++ b/src/bindings/ejdb2_android/test/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/src/bindings/ejdb2_android/test/gradlew b/src/bindings/ejdb2_android/test/gradlew
new file mode 100755
index 0000000..b0d6d0a
--- /dev/null
+++ b/src/bindings/ejdb2_android/test/gradlew
@@ -0,0 +1,188 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/src/bindings/ejdb2_android/test/gradlew.bat b/src/bindings/ejdb2_android/test/gradlew.bat
new file mode 100644
index 0000000..9991c50
--- /dev/null
+++ b/src/bindings/ejdb2_android/test/gradlew.bat
@@ -0,0 +1,100 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/src/bindings/ejdb2_android/test/local.properties b/src/bindings/ejdb2_android/test/local.properties
new file mode 100644
index 0000000..23489b9
--- /dev/null
+++ b/src/bindings/ejdb2_android/test/local.properties
@@ -0,0 +1,9 @@
+
+## Path to Android SDK dir
+sdk.dir=/Android-sdk
+
+## Path to Android NDK dir
+ndk.dir=/Android-sdk/ndk-bundle
+
+## Target abi name: armeabi-v7a, arm64-v8a, x86, x86_64
+abi.name=x86
\ No newline at end of file
diff --git a/src/bindings/ejdb2_android/test/settings.gradle b/src/bindings/ejdb2_android/test/settings.gradle
new file mode 100644
index 0000000..c0509d9
--- /dev/null
+++ b/src/bindings/ejdb2_android/test/settings.gradle
@@ -0,0 +1 @@
+include ':ejdb2'
diff --git a/src/bindings/ejdb2_dart/.gitignore b/src/bindings/ejdb2_dart/.gitignore
new file mode 100644
index 0000000..13bb388
--- /dev/null
+++ b/src/bindings/ejdb2_dart/.gitignore
@@ -0,0 +1 @@
+!/.packages
\ No newline at end of file
diff --git a/src/bindings/ejdb2_dart/.packages b/src/bindings/ejdb2_dart/.packages
new file mode 100644
index 0000000..7d676ba
--- /dev/null
+++ b/src/bindings/ejdb2_dart/.packages
@@ -0,0 +1,54 @@
+# Generated by pub on 2020-12-21 22:58:24.542808.
+_fe_analyzer_shared:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-7.0.0/lib/
+analyzer:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/analyzer-0.39.17/lib/
+args:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/args-1.6.0/lib/
+async:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/async-2.5.0-nullsafety.3/lib/
+boolean_selector:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0-nullsafety.3/lib/
+charcode:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/charcode-1.2.0-nullsafety.3/lib/
+cli_util:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/cli_util-0.2.0/lib/
+collection:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0-nullsafety.5/lib/
+convert:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/convert-2.1.1/lib/
+coverage:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/coverage-0.14.0/lib/
+crypto:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/crypto-2.1.5/lib/
+csslib:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/csslib-0.16.2/lib/
+glob:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/glob-1.2.0/lib/
+html:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/html-0.14.0+3/lib/
+http_multi_server:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/http_multi_server-2.2.0/lib/
+http_parser:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/http_parser-3.1.4/lib/
+io:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/io-0.3.4/lib/
+js:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/js-0.6.3-nullsafety.3/lib/
+json_at:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/json_at-2.0.0-nullsafety.1/lib/
+logging:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/logging-0.11.4/lib/
+matcher:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.10-nullsafety.3/lib/
+meta:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/meta-1.3.0-nullsafety.6/lib/
+mime:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/mime-0.9.7/lib/
+node_interop:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/node_interop-1.1.1/lib/
+node_io:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/node_io-1.1.1/lib/
+node_preamble:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/node_preamble-1.4.12/lib/
+package_config:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/package_config-1.9.3/lib/
+path:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/path-1.8.0-nullsafety.3/lib/
+pedantic:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/pedantic-1.10.0-nullsafety.3/lib/
+pool:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/pool-1.5.0-nullsafety.3/lib/
+pub_semver:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/pub_semver-1.4.4/lib/
+quiver:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/quiver-3.0.0-nullsafety.2/lib/
+shelf:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/shelf-0.7.9/lib/
+shelf_packages_handler:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/shelf_packages_handler-2.0.0/lib/
+shelf_static:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/shelf_static-0.2.8/lib/
+shelf_web_socket:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-0.2.3/lib/
+source_map_stack_trace:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/source_map_stack_trace-2.1.0-nullsafety.4/lib/
+source_maps:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.10-nullsafety.3/lib/
+source_span:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/source_span-1.8.0-nullsafety.4/lib/
+stack_trace:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0-nullsafety.6/lib/
+stream_channel:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.0-nullsafety.3/lib/
+string_scanner:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0-nullsafety.3/lib/
+term_glyph:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.0-nullsafety.3/lib/
+test:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/test-1.16.0-nullsafety.13/lib/
+test_api:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/test_api-0.2.19-nullsafety.6/lib/
+test_core:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/test_core-0.3.12-nullsafety.12/lib/
+typed_data:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0-nullsafety.5/lib/
+vm_service:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/vm_service-4.2.0/lib/
+watcher:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/watcher-0.9.7+15/lib/
+web_socket_channel:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-1.1.0/lib/
+webkit_inspection_protocol:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/webkit_inspection_protocol-0.7.3/lib/
+yaml:file:///home/adam/.pub-cache/hosted/pub.dartlang.org/yaml-2.2.1/lib/
+ejdb2_dart:lib/
diff --git a/src/bindings/ejdb2_dart/CHANGELOG.md b/src/bindings/ejdb2_dart/CHANGELOG.md
new file mode 100644
index 0000000..6dd20db
--- /dev/null
+++ b/src/bindings/ejdb2_dart/CHANGELOG.md
@@ -0,0 +1,4 @@
+ejdb_dart (@EJDB2_DART_VERSION@)
+
+- Upgraded to Dart v2.12.x (null safety and native bindings API)
+- Used new versioning scheme: {EJDB_VERSION}{BINDING_VERSION_NUMBER}
\ No newline at end of file
diff --git a/src/bindings/ejdb2_dart/CMakeLists.txt b/src/bindings/ejdb2_dart/CMakeLists.txt
new file mode 100644
index 0000000..af690d7
--- /dev/null
+++ b/src/bindings/ejdb2_dart/CMakeLists.txt
@@ -0,0 +1,91 @@
+# Build dart binding shared library
+
+file(READ ${CMAKE_CURRENT_SOURCE_DIR}/version.txt _VERSION)
+set_property(GLOBAL PROPERTY EJDB2_DART_VERSION_PROPERTY
+ "${PROJECT_VERSION}${_VERSION}")
+set(EJDB2_DART_VERSION "${PROJECT_VERSION}${_VERSION}")
+
+add_library(ejdb2_dart SHARED lib/ejdb2_dart.c)
+target_link_libraries(ejdb2_dart ejdb2_s ${PROJECT_LLIBRARIES})
+
+set(dart_COMPILE_FLAGS " ")
+set(dart_LINK_FLAGS " ")
+
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
+ set(dart_LINK_FLAGS "-dynamic -undefined dynamic_lookup")
+endif()
+
+set(DART_PUB_DIR ${CMAKE_CURRENT_BINARY_DIR}/ejdb2_dart)
+
+configure_file(lib/ejdb2_dart.c ${DART_PUB_DIR}/lib/ejdb2_dart.c COPYONLY)
+configure_file(lib/ejdb2_dart.dart ${DART_PUB_DIR}/lib/ejdb2_dart.dart COPYONLY)
+configure_file(test/ejdb2_dart_test.dart
+ ${DART_PUB_DIR}/test/ejdb2_dart_test.dart COPYONLY)
+configure_file(example/example.dart ${DART_PUB_DIR}/example/example.dart
+ COPYONLY)
+configure_file(example/isolate.dart ${DART_PUB_DIR}/example/isolate.dart
+ COPYONLY)
+
+configure_file(README.md ${DART_PUB_DIR}/README.md COPYONLY)
+configure_file(LICENSE ${DART_PUB_DIR}/LICENSE COPYONLY)
+configure_file(CHANGELOG.md ${DART_PUB_DIR}/CHANGELOG.md @ONLY)
+configure_file(pubspec.yaml.in ${DART_PUB_DIR}/pubspec.yaml @ONLY)
+configure_file(analysis_options.yaml ${DART_PUB_DIR}/analysis_options.yaml
+ COPYONLY)
+configure_file(.packages ${DART_PUB_DIR}/.packages COPYONLY)
+
+set_target_properties(
+ ejdb2_dart
+ PROPERTIES COMPILE_FLAGS ${dart_COMPILE_FLAGS} LINK_FLAGS ${dart_LINK_FLAGS}
+ LIBRARY_OUTPUT_DIRECTORY ${DART_PUB_DIR}/lib)
+
+if(CMAKE_BUILD_TYPE STREQUAL "Release")
+ add_custom_command(
+ TARGET ejdb2_dart
+ POST_BUILD
+ COMMAND strip -s $)
+endif()
+
+set_target_properties(
+ ejdb2_dart
+ PROPERTIES VERSION ${PROJECT_VERSION} OUTPUT_NAME ejdb2dart
+ SOVERSION ${PROJECT_VERSION_MAJOR} DEFINE_SYMBOL IW_API_EXPORTS)
+
+install(
+ TARGETS ejdb2_dart
+ FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
+
+install(FILES ${DART_PUB_DIR}/lib/ejdb2_dart.dart ${DART_PUB_DIR}/README.md
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/dart)
+
+install(FILES ${DART_PUB_DIR}/example/example.dart
+ ${DART_PUB_DIR}/example/isolate.dart
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/dart/example)
+
+if(BUILD_TESTS)
+ find_program(DART_EXEC dart HINTS /usr/bin /usr/local/bin)
+ if(DART_EXEC MATCHES "DART_EXEC-NOTFOUND")
+ message(FATAL_ERROR "`dart` executable not found")
+ endif()
+ find_program(PUB_EXEC pub /usr/bin /usr/local/bin)
+ if(PUB_EXEC MATCHES "PUB_EXEC-NOTFOUND")
+ set(PUB_EXEC ${DART_EXEC} pub)
+ endif()
+
+ add_custom_command(
+ COMMAND ${PUB_EXEC} get
+ OUTPUT ${DART_PUB_DIR}/pubspec.lock
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/pubspec.yaml
+ WORKING_DIRECTORY ${DART_PUB_DIR}
+ VERBATIM)
+ add_custom_target(pub_get ALL DEPENDS ${DART_PUB_DIR}/pubspec.lock)
+
+ add_test(
+ NAME ejdb2dart
+ COMMAND ${DART_EXEC} --enable-asserts ./test/ejdb2_dart_test.dart
+ WORKING_DIRECTORY ${DART_PUB_DIR})
+endif(BUILD_TESTS)
diff --git a/src/bindings/ejdb2_dart/LICENSE b/src/bindings/ejdb2_dart/LICENSE
new file mode 100644
index 0000000..5319d1e
--- /dev/null
+++ b/src/bindings/ejdb2_dart/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2012-2021 Softmotions Ltd
+
+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.
\ No newline at end of file
diff --git a/src/bindings/ejdb2_dart/README.md b/src/bindings/ejdb2_dart/README.md
new file mode 100644
index 0000000..0a79fe3
--- /dev/null
+++ b/src/bindings/ejdb2_dart/README.md
@@ -0,0 +1,49 @@
+# EJDB2 Dart VM native binding
+
+Embeddable JSON Database engine http://ejdb.org Dart binding.
+
+See https://github.com/Softmotions/ejdb/blob/master/README.md
+
+For API usage examples take a look into [/example](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_dart/example) and [/test](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_dart/test) folders.
+
+## Example
+
+```dart
+import 'package:ejdb2_dart/ejdb2_dart.dart';
+
+void main() async {
+ final db = await EJDB2.open('example.db', truncate: true);
+
+ var id = await db.put('parrots', {'name': 'Bianca', 'age': 4});
+ print('Bianca record: ${id}');
+
+ id = await db.put('parrots', {'name': 'Darko', 'age': 8});
+ print('Darko record: ${id}');
+
+ final q = db.createQuery('/[age > :age]', 'parrots');
+ await for (final doc in q.setInt('age', 3).execute()) {
+ print('Found ${doc}');
+ }
+ await db.close();
+}
+```
+
+## Supported platforms
+
+* Linux x64
+* OSX
+
+## How build it manually
+
+Note: native binding requires Dart SDK version >= 2.12.x
+
+``` sh
+git clone https://github.com/Softmotions/ejdb.git
+cd ./ejdb
+mkdir ./build && cd build
+cmake .. -DBUILD_DART_BINDING=ON -DCMAKE_BUILD_TYPE=Release
+make
+cd src/bindings/ejdb2_dart/ejdb2_dart
+pub get
+```
+
diff --git a/src/bindings/ejdb2_dart/analysis_options.yaml b/src/bindings/ejdb2_dart/analysis_options.yaml
new file mode 100644
index 0000000..8f52b68
--- /dev/null
+++ b/src/bindings/ejdb2_dart/analysis_options.yaml
@@ -0,0 +1,157 @@
+analyzer:
+ errors:
+ native_function_body_in_non_sdk_code: ignore
+ strong-mode:
+ implicit-casts: false
+ implicit-dynamic: true
+linter:
+ rules:
+ - always_declare_return_types
+ - always_put_required_named_parameters_first
+ - always_require_non_null_named_parameters
+ - annotate_overrides
+ - avoid_bool_literals_in_conditional_expressions
+ - avoid_catching_errors
+ - avoid_classes_with_only_static_members
+ - avoid_double_and_int_checks
+ - avoid_empty_else
+ - avoid_field_initializers_in_const_classes
+ - avoid_implementing_value_types
+ - avoid_init_to_null
+ - avoid_js_rounded_ints
+ - avoid_null_checks_in_equality_operators
+ - avoid_private_typedef_functions
+ - avoid_relative_lib_imports
+ - avoid_renaming_method_parameters
+ - avoid_return_types_on_setters
+ - avoid_returning_null
+ - avoid_returning_null_for_future
+ - avoid_returning_null_for_void
+ #- avoid_returning_this
+ - avoid_setters_without_getters
+ - avoid_shadowing_type_parameters
+ - avoid_single_cascade_in_expression_statements
+ - avoid_slow_async_io
+ - avoid_types_as_parameter_names
+ - avoid_unused_constructor_parameters
+ - camel_case_extensions
+ - camel_case_types
+ - cancel_subscriptions
+ - comment_references
+ - control_flow_in_finally
+ - curly_braces_in_flow_control_structures
+ - diagnostic_describe_all_properties
+ - directives_ordering
+ - empty_catches
+ - empty_constructor_bodies
+ - empty_statements
+ - file_names
+ - flutter_style_todos
+ - hash_and_equals
+ - implementation_imports
+ - invariant_booleans
+ - iterable_contains_unrelated_type
+ - join_return_with_assignment
+ - library_names
+ - list_remove_unrelated_type
+ - literal_only_boolean_expressions
+ - no_adjacent_strings_in_list
+ - no_duplicate_case_values
+ - null_closures
+ - one_member_abstracts
+ - only_throw_errors
+ - overridden_fields
+ - package_api_docs
+ - package_names
+ - package_prefixed_library_names
+ - prefer_adjacent_string_concatenation
+ - prefer_asserts_in_initializer_lists
+ #- prefer_asserts_with_message
+ - prefer_collection_literals
+ - prefer_conditional_assignment
+ - prefer_const_constructors
+ - prefer_const_declarations
+ - prefer_const_literals_to_create_immutables
+ - prefer_constructors_over_static_methods
+ - prefer_contains
+ - prefer_equal_for_default_values
+ # - prefer_expression_function_bodies
+ - prefer_final_fields
+ - prefer_final_in_for_each
+ - prefer_final_locals
+ - prefer_for_elements_to_map_fromIterable
+ - prefer_foreach
+ - prefer_function_declarations_over_variables
+ - prefer_generic_function_type_aliases
+ - prefer_if_null_operators
+ - prefer_initializing_formals
+ - prefer_inlined_adds
+ - prefer_interpolation_to_compose_strings
+ - prefer_is_empty
+ - prefer_is_not_empty
+ - prefer_iterable_whereType
+ - prefer_mixin
+ - prefer_null_aware_operators
+ - prefer_single_quotes
+ - prefer_spread_collections
+ - prefer_typing_uninitialized_variables
+ - prefer_void_to_null
+ - provide_deprecation_message
+ - recursive_getters
+ - slash_for_doc_comments
+ - sort_child_properties_last
+ - sort_constructors_first
+ - sort_pub_dependencies
+ - sort_unnamed_constructors_first
+ - test_types_in_equals
+ - throw_in_finally
+ - type_init_formals
+ - unawaited_futures
+ - unnecessary_await_in_return
+ - unnecessary_const
+ - unnecessary_getters_setters
+ - unnecessary_lambdas
+ - unnecessary_new
+ - unnecessary_null_aware_assignments
+ - unnecessary_null_in_if_null_operators
+ - unnecessary_overrides
+ - unnecessary_parenthesis
+ - unnecessary_statements
+ - unnecessary_this
+ - unrelated_type_equality_checks
+ - unsafe_html
+ - use_full_hex_values_for_flutter_colors
+ - use_rethrow_when_possible
+ - use_setters_to_change_properties
+ - use_string_buffers
+ - use_to_and_as_if_applicable
+ - valid_regexps
+ - void_checks
+ # - always_put_control_body_on_new_line
+ # - always_specify_types
+ # - avoid_annotating_with_dynamic
+ # - avoid_as
+ # - avoid_catches_without_on_clauses
+ # - avoid_equals_and_hash_code_on_mutable_classes
+ # - avoid_function_literals_in_foreach_calls
+ # - avoid_positional_boolean_parameters
+ # - avoid_print
+ # - avoid_types_on_closure_parameters
+ # - avoid_void_async
+ # - await_only_futures
+ # - cascade_invocations
+ # - close_sinks
+ # - constant_identifier_names
+ # - library_prefixes
+ # - lines_longer_than_80_chars
+ # - non_constant_identifier_names
+ # - omit_local_variable_types
+ # - parameter_assignments
+ # - prefer_const_constructors_in_immutables
+ # - prefer_double_quotes
+ # - prefer_if_elements_to_conditional_expressions
+ # - prefer_int_literals
+ # - public_member_api_docs
+ # - type_annotate_public_apis
+ # - unnecessary_brace_in_string_interps
+ # - use_function_type_syntax_for_parameters
diff --git a/src/bindings/ejdb2_dart/example/example.dart b/src/bindings/ejdb2_dart/example/example.dart
new file mode 100644
index 0000000..95eceee
--- /dev/null
+++ b/src/bindings/ejdb2_dart/example/example.dart
@@ -0,0 +1,17 @@
+import 'package:ejdb2_dart/ejdb2_dart.dart';
+
+void main() async {
+ final db = await EJDB2.open('example.db', truncate: true);
+
+ var id = await db.put('parrots', {'name': 'Bianca', 'age': 4});
+ print('Bianca record: ${id}');
+
+ id = await db.put('parrots', {'name': 'Darko', 'age': 8});
+ print('Darko record: ${id}');
+
+ final q = db.createQuery('/[age > :age]', 'parrots');
+ await for (final doc in q.setInt('age', 3).execute()) {
+ print('Found $doc');
+ }
+ await db.close();
+}
diff --git a/src/bindings/ejdb2_dart/example/isolate.dart b/src/bindings/ejdb2_dart/example/isolate.dart
new file mode 100644
index 0000000..50fbe99
--- /dev/null
+++ b/src/bindings/ejdb2_dart/example/isolate.dart
@@ -0,0 +1,38 @@
+import 'dart:async';
+import 'dart:isolate';
+
+import 'package:ejdb2_dart/ejdb2_dart.dart';
+
+/// Database access from multiple isolates.
+/// Based on isolate example from https://github.com/adamlofts/leveldb_dart
+
+void main() async {
+ final runners = Iterable.generate(5).map((int index) {
+ return Runner.spawn(index);
+ }).toList();
+ await Future.wait(runners.map((Runner r) => r.finish));
+}
+
+Future run(int index) async {
+ print('Thread ${index} write');
+ final db = await EJDB2.open('isolate.db', truncate: true);
+ await db.put('c1', {'index': index});
+ // Sleep 1 second
+ await Future.delayed(const Duration(seconds: 1));
+ final nextKey = (index + 1) % 5;
+ final doc = await db.createQuery('/[index=:?]', 'c1').setInt(0, nextKey).execute().first;
+ print('Thread ${index} read: ${doc}');
+}
+
+class Runner {
+ final Completer _finish = Completer();
+ final RawReceivePort _finishPort = RawReceivePort();
+ Runner.spawn(int index) {
+ _finishPort.handler = (dynamic _) {
+ _finish.complete();
+ _finishPort.close();
+ };
+ Isolate.spawn(run, index, onExit: _finishPort.sendPort);
+ }
+ Future get finish => _finish.future;
+}
diff --git a/src/bindings/ejdb2_dart/lib/dart_api.h b/src/bindings/ejdb2_dart/lib/dart_api.h
new file mode 100644
index 0000000..189a6b7
--- /dev/null
+++ b/src/bindings/ejdb2_dart/lib/dart_api.h
@@ -0,0 +1,3944 @@
+/*
+ * Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+ * for details. All rights reserved. Use of this source code is governed by a
+ * BSD-style license that can be found in the LICENSE file.
+ */
+
+#ifndef RUNTIME_INCLUDE_DART_API_H_
+#define RUNTIME_INCLUDE_DART_API_H_
+
+/** \mainpage Dart Embedding API Reference
+ *
+ * This reference describes the Dart Embedding API, which is used to embed the
+ * Dart Virtual Machine within C/C++ applications.
+ *
+ * This reference is generated from the header include/dart_api.h.
+ */
+
+/* __STDC_FORMAT_MACROS has to be defined before including to
+ * enable platform independent printf format specifiers. */
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
+#endif
+
+#include
+#include
+#include
+
+#ifdef __cplusplus
+#define DART_EXTERN_C extern "C"
+#else
+#define DART_EXTERN_C
+#endif
+
+#if defined(__CYGWIN__)
+#error Tool chain and platform not supported.
+#elif defined(_WIN32)
+#if defined(DART_SHARED_LIB)
+#define DART_EXPORT DART_EXTERN_C __declspec(dllexport)
+#else
+#define DART_EXPORT DART_EXTERN_C
+#endif
+#else
+#if __GNUC__ >= 4
+#if defined(DART_SHARED_LIB)
+#define DART_EXPORT \
+ DART_EXTERN_C __attribute__((visibility("default"))) __attribute((used))
+#else
+#define DART_EXPORT DART_EXTERN_C
+#endif
+#else
+#error Tool chain not supported.
+#endif
+#endif
+
+#if __GNUC__
+#define DART_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#elif _MSC_VER
+#define DART_WARN_UNUSED_RESULT _Check_return_
+#else
+#define DART_WARN_UNUSED_RESULT
+#endif
+
+/*
+ * =======
+ * Handles
+ * =======
+ */
+
+/**
+ * An isolate is the unit of concurrency in Dart. Each isolate has
+ * its own memory and thread of control. No state is shared between
+ * isolates. Instead, isolates communicate by message passing.
+ *
+ * Each thread keeps track of its current isolate, which is the
+ * isolate which is ready to execute on the current thread. The
+ * current isolate may be NULL, in which case no isolate is ready to
+ * execute. Most of the Dart apis require there to be a current
+ * isolate in order to function without error. The current isolate is
+ * set by any call to Dart_CreateIsolateGroup or Dart_EnterIsolate.
+ */
+typedef struct _Dart_Isolate* Dart_Isolate;
+typedef struct _Dart_IsolateGroup* Dart_IsolateGroup;
+
+/**
+ * An object reference managed by the Dart VM garbage collector.
+ *
+ * Because the garbage collector may move objects, it is unsafe to
+ * refer to objects directly. Instead, we refer to objects through
+ * handles, which are known to the garbage collector and updated
+ * automatically when the object is moved. Handles should be passed
+ * by value (except in cases like out-parameters) and should never be
+ * allocated on the heap.
+ *
+ * Most functions in the Dart Embedding API return a handle. When a
+ * function completes normally, this will be a valid handle to an
+ * object in the Dart VM heap. This handle may represent the result of
+ * the operation or it may be a special valid handle used merely to
+ * indicate successful completion. Note that a valid handle may in
+ * some cases refer to the null object.
+ *
+ * --- Error handles ---
+ *
+ * When a function encounters a problem that prevents it from
+ * completing normally, it returns an error handle (See Dart_IsError).
+ * An error handle has an associated error message that gives more
+ * details about the problem (See Dart_GetError).
+ *
+ * There are four kinds of error handles that can be produced,
+ * depending on what goes wrong:
+ *
+ * - Api error handles are produced when an api function is misused.
+ * This happens when a Dart embedding api function is called with
+ * invalid arguments or in an invalid context.
+ *
+ * - Unhandled exception error handles are produced when, during the
+ * execution of Dart code, an exception is thrown but not caught.
+ * Prototypically this would occur during a call to Dart_Invoke, but
+ * it can occur in any function which triggers the execution of Dart
+ * code (for example, Dart_ToString).
+ *
+ * An unhandled exception error provides access to an exception and
+ * stacktrace via the functions Dart_ErrorGetException and
+ * Dart_ErrorGetStackTrace.
+ *
+ * - Compilation error handles are produced when, during the execution
+ * of Dart code, a compile-time error occurs. As above, this can
+ * occur in any function which triggers the execution of Dart code.
+ *
+ * - Fatal error handles are produced when the system wants to shut
+ * down the current isolate.
+ *
+ * --- Propagating errors ---
+ *
+ * When an error handle is returned from the top level invocation of
+ * Dart code in a program, the embedder must handle the error as they
+ * see fit. Often, the embedder will print the error message produced
+ * by Dart_Error and exit the program.
+ *
+ * When an error is returned while in the body of a native function,
+ * it can be propagated up the call stack by calling
+ * Dart_PropagateError, Dart_SetReturnValue, or Dart_ThrowException.
+ * Errors should be propagated unless there is a specific reason not
+ * to. If an error is not propagated then it is ignored. For
+ * example, if an unhandled exception error is ignored, that
+ * effectively "catches" the unhandled exception. Fatal errors must
+ * always be propagated.
+ *
+ * When an error is propagated, any current scopes created by
+ * Dart_EnterScope will be exited.
+ *
+ * Using Dart_SetReturnValue to propagate an exception is somewhat
+ * more convenient than using Dart_PropagateError, and should be
+ * preferred for reasons discussed below.
+ *
+ * Dart_PropagateError and Dart_ThrowException do not return. Instead
+ * they transfer control non-locally using a setjmp-like mechanism.
+ * This can be inconvenient if you have resources that you need to
+ * clean up before propagating the error.
+ *
+ * When relying on Dart_PropagateError, we often return error handles
+ * rather than propagating them from helper functions. Consider the
+ * following contrived example:
+ *
+ * 1 Dart_Handle isLongStringHelper(Dart_Handle arg) {
+ * 2 intptr_t* length = 0;
+ * 3 result = Dart_StringLength(arg, &length);
+ * 4 if (Dart_IsError(result)) {
+ * 5 return result;
+ * 6 }
+ * 7 return Dart_NewBoolean(length > 100);
+ * 8 }
+ * 9
+ * 10 void NativeFunction_isLongString(Dart_NativeArguments args) {
+ * 11 Dart_EnterScope();
+ * 12 AllocateMyResource();
+ * 13 Dart_Handle arg = Dart_GetNativeArgument(args, 0);
+ * 14 Dart_Handle result = isLongStringHelper(arg);
+ * 15 if (Dart_IsError(result)) {
+ * 16 FreeMyResource();
+ * 17 Dart_PropagateError(result);
+ * 18 abort(); // will not reach here
+ * 19 }
+ * 20 Dart_SetReturnValue(result);
+ * 21 FreeMyResource();
+ * 22 Dart_ExitScope();
+ * 23 }
+ *
+ * In this example, we have a native function which calls a helper
+ * function to do its work. On line 5, the helper function could call
+ * Dart_PropagateError, but that would not give the native function a
+ * chance to call FreeMyResource(), causing a leak. Instead, the
+ * helper function returns the error handle to the caller, giving the
+ * caller a chance to clean up before propagating the error handle.
+ *
+ * When an error is propagated by calling Dart_SetReturnValue, the
+ * native function will be allowed to complete normally and then the
+ * exception will be propagated only once the native call
+ * returns. This can be convenient, as it allows the C code to clean
+ * up normally.
+ *
+ * The example can be written more simply using Dart_SetReturnValue to
+ * propagate the error.
+ *
+ * 1 Dart_Handle isLongStringHelper(Dart_Handle arg) {
+ * 2 intptr_t* length = 0;
+ * 3 result = Dart_StringLength(arg, &length);
+ * 4 if (Dart_IsError(result)) {
+ * 5 return result
+ * 6 }
+ * 7 return Dart_NewBoolean(length > 100);
+ * 8 }
+ * 9
+ * 10 void NativeFunction_isLongString(Dart_NativeArguments args) {
+ * 11 Dart_EnterScope();
+ * 12 AllocateMyResource();
+ * 13 Dart_Handle arg = Dart_GetNativeArgument(args, 0);
+ * 14 Dart_SetReturnValue(isLongStringHelper(arg));
+ * 15 FreeMyResource();
+ * 16 Dart_ExitScope();
+ * 17 }
+ *
+ * In this example, the call to Dart_SetReturnValue on line 14 will
+ * either return the normal return value or the error (potentially
+ * generated on line 3). The call to FreeMyResource on line 15 will
+ * execute in either case.
+ *
+ * --- Local and persistent handles ---
+ *
+ * Local handles are allocated within the current scope (see
+ * Dart_EnterScope) and go away when the current scope exits. Unless
+ * otherwise indicated, callers should assume that all functions in
+ * the Dart embedding api return local handles.
+ *
+ * Persistent handles are allocated within the current isolate. They
+ * can be used to store objects across scopes. Persistent handles have
+ * the lifetime of the current isolate unless they are explicitly
+ * deallocated (see Dart_DeletePersistentHandle).
+ * The type Dart_Handle represents a handle (both local and persistent).
+ * The type Dart_PersistentHandle is a Dart_Handle and it is used to
+ * document that a persistent handle is expected as a parameter to a call
+ * or the return value from a call is a persistent handle.
+ *
+ * FinalizableHandles are persistent handles which are auto deleted when
+ * the object is garbage collected. It is never safe to use these handles
+ * unless you know the object is still reachable.
+ *
+ * WeakPersistentHandles are persistent handles which are automatically set
+ * to point Dart_Null when the object is garbage collected. They are not auto
+ * deleted, so it is safe to use them after the object has become unreachable.
+ */
+typedef struct _Dart_Handle* Dart_Handle;
+typedef Dart_Handle Dart_PersistentHandle;
+typedef struct _Dart_WeakPersistentHandle* Dart_WeakPersistentHandle;
+typedef struct _Dart_FinalizableHandle* Dart_FinalizableHandle;
+// These structs are versioned by DART_API_DL_MAJOR_VERSION, bump the
+// version when changing this struct.
+
+typedef void (*Dart_HandleFinalizer)(void* isolate_callback_data, void* peer);
+
+/**
+ * Is this an error handle?
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT bool Dart_IsError(Dart_Handle handle);
+
+/**
+ * Is this an api error handle?
+ *
+ * Api error handles are produced when an api function is misused.
+ * This happens when a Dart embedding api function is called with
+ * invalid arguments or in an invalid context.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT bool Dart_IsApiError(Dart_Handle handle);
+
+/**
+ * Is this an unhandled exception error handle?
+ *
+ * Unhandled exception error handles are produced when, during the
+ * execution of Dart code, an exception is thrown but not caught.
+ * This can occur in any function which triggers the execution of Dart
+ * code.
+ *
+ * See Dart_ErrorGetException and Dart_ErrorGetStackTrace.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT bool Dart_IsUnhandledExceptionError(Dart_Handle handle);
+
+/**
+ * Is this a compilation error handle?
+ *
+ * Compilation error handles are produced when, during the execution
+ * of Dart code, a compile-time error occurs. This can occur in any
+ * function which triggers the execution of Dart code.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT bool Dart_IsCompilationError(Dart_Handle handle);
+
+/**
+ * Is this a fatal error handle?
+ *
+ * Fatal error handles are produced when the system wants to shut down
+ * the current isolate.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT bool Dart_IsFatalError(Dart_Handle handle);
+
+/**
+ * Gets the error message from an error handle.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \return A C string containing an error message if the handle is
+ * error. An empty C string ("") if the handle is valid. This C
+ * String is scope allocated and is only valid until the next call
+ * to Dart_ExitScope.
+*/
+DART_EXPORT const char* Dart_GetError(Dart_Handle handle);
+
+/**
+ * Is this an error handle for an unhandled exception?
+ */
+DART_EXPORT bool Dart_ErrorHasException(Dart_Handle handle);
+
+/**
+ * Gets the exception Object from an unhandled exception error handle.
+ */
+DART_EXPORT Dart_Handle Dart_ErrorGetException(Dart_Handle handle);
+
+/**
+ * Gets the stack trace Object from an unhandled exception error handle.
+ */
+DART_EXPORT Dart_Handle Dart_ErrorGetStackTrace(Dart_Handle handle);
+
+/**
+ * Produces an api error handle with the provided error message.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \param error the error message.
+ */
+DART_EXPORT Dart_Handle Dart_NewApiError(const char* error);
+DART_EXPORT Dart_Handle Dart_NewCompilationError(const char* error);
+
+/**
+ * Produces a new unhandled exception error handle.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \param exception An instance of a Dart object to be thrown or
+ * an ApiError or CompilationError handle.
+ * When an ApiError or CompilationError handle is passed in
+ * a string object of the error message is created and it becomes
+ * the Dart object to be thrown.
+ */
+DART_EXPORT Dart_Handle Dart_NewUnhandledExceptionError(Dart_Handle exception);
+
+/**
+ * Propagates an error.
+ *
+ * If the provided handle is an unhandled exception error, this
+ * function will cause the unhandled exception to be rethrown. This
+ * will proceed in the standard way, walking up Dart frames until an
+ * appropriate 'catch' block is found, executing 'finally' blocks,
+ * etc.
+ *
+ * If the error is not an unhandled exception error, we will unwind
+ * the stack to the next C frame. Intervening Dart frames will be
+ * discarded; specifically, 'finally' blocks will not execute. This
+ * is the standard way that compilation errors (and the like) are
+ * handled by the Dart runtime.
+ *
+ * In either case, when an error is propagated any current scopes
+ * created by Dart_EnterScope will be exited.
+ *
+ * See the additional discussion under "Propagating Errors" at the
+ * beginning of this file.
+ *
+ * \param An error handle (See Dart_IsError)
+ *
+ * \return On success, this function does not return. On failure, the
+ * process is terminated.
+ */
+DART_EXPORT void Dart_PropagateError(Dart_Handle handle);
+
+/**
+ * Converts an object to a string.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \return The converted string if no error occurs during
+ * the conversion. If an error does occur, an error handle is
+ * returned.
+ */
+DART_EXPORT Dart_Handle Dart_ToString(Dart_Handle object);
+
+/**
+ * Checks to see if two handles refer to identically equal objects.
+ *
+ * If both handles refer to instances, this is equivalent to using the top-level
+ * function identical() from dart:core. Otherwise, returns whether the two
+ * argument handles refer to the same object.
+ *
+ * \param obj1 An object to be compared.
+ * \param obj2 An object to be compared.
+ *
+ * \return True if the objects are identically equal. False otherwise.
+ */
+DART_EXPORT bool Dart_IdentityEquals(Dart_Handle obj1, Dart_Handle obj2);
+
+/**
+ * Allocates a handle in the current scope from a persistent handle.
+ */
+DART_EXPORT Dart_Handle Dart_HandleFromPersistent(Dart_PersistentHandle object);
+
+/**
+ * Allocates a handle in the current scope from a weak persistent handle.
+ *
+ * This will be a handle to Dart_Null if the object has been garbage collected.
+ */
+DART_EXPORT Dart_Handle
+Dart_HandleFromWeakPersistent(Dart_WeakPersistentHandle object);
+
+/**
+ * Allocates a persistent handle for an object.
+ *
+ * This handle has the lifetime of the current isolate unless it is
+ * explicitly deallocated by calling Dart_DeletePersistentHandle.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT Dart_PersistentHandle Dart_NewPersistentHandle(Dart_Handle object);
+
+/**
+ * Assign value of local handle to a persistent handle.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \param obj1 A persistent handle whose value needs to be set.
+ * \param obj2 An object whose value needs to be set to the persistent handle.
+ *
+ * \return Success if the persistent handle was set
+ * Otherwise, returns an error.
+ */
+DART_EXPORT void Dart_SetPersistentHandle(Dart_PersistentHandle obj1,
+ Dart_Handle obj2);
+
+/**
+ * Deallocates a persistent handle.
+ *
+ * Requires there to be a current isolate group.
+ */
+DART_EXPORT void Dart_DeletePersistentHandle(Dart_PersistentHandle object);
+
+/**
+ * Allocates a weak persistent handle for an object.
+ *
+ * This handle has the lifetime of the current isolate. The handle can also be
+ * explicitly deallocated by calling Dart_DeleteWeakPersistentHandle.
+ *
+ * If the object becomes unreachable the callback is invoked with the peer as
+ * argument. The callback can be executed on any thread, will have a current
+ * isolate group, but will not have a current isolate. The callback can only
+ * call Dart_DeletePersistentHandle or Dart_DeleteWeakPersistentHandle. This
+ * gives the embedder the ability to cleanup data associated with the object.
+ * The handle will point to the Dart_Null object after the finalizer has been
+ * run. It is illegal to call into the VM with any other Dart_* functions from
+ * the callback. If the handle is deleted before the object becomes
+ * unreachable, the callback is never invoked.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \param object An object.
+ * \param peer A pointer to a native object or NULL. This value is
+ * provided to callback when it is invoked.
+ * \param external_allocation_size The number of externally allocated
+ * bytes for peer. Used to inform the garbage collector.
+ * \param callback A function pointer that will be invoked sometime
+ * after the object is garbage collected, unless the handle has been deleted.
+ * A valid callback needs to be specified it cannot be NULL.
+ *
+ * \return The weak persistent handle or NULL. NULL is returned in case of bad
+ * parameters.
+ */
+DART_EXPORT Dart_WeakPersistentHandle
+Dart_NewWeakPersistentHandle(Dart_Handle object,
+ void* peer,
+ intptr_t external_allocation_size,
+ Dart_HandleFinalizer callback);
+
+/**
+ * Deletes the given weak persistent [object] handle.
+ *
+ * Requires there to be a current isolate group.
+ */
+DART_EXPORT void Dart_DeleteWeakPersistentHandle(
+ Dart_WeakPersistentHandle object);
+
+/**
+ * Updates the external memory size for the given weak persistent handle.
+ *
+ * May trigger garbage collection.
+ */
+DART_EXPORT void Dart_UpdateExternalSize(Dart_WeakPersistentHandle object,
+ intptr_t external_allocation_size);
+
+/**
+ * Allocates a finalizable handle for an object.
+ *
+ * This handle has the lifetime of the current isolate group unless the object
+ * pointed to by the handle is garbage collected, in this case the VM
+ * automatically deletes the handle after invoking the callback associated
+ * with the handle. The handle can also be explicitly deallocated by
+ * calling Dart_DeleteFinalizableHandle.
+ *
+ * If the object becomes unreachable the callback is invoked with the
+ * the peer as argument. The callback can be executed on any thread, will have
+ * an isolate group, but will not have a current isolate. The callback can only
+ * call Dart_DeletePersistentHandle or Dart_DeleteWeakPersistentHandle.
+ * This gives the embedder the ability to cleanup data associated with the
+ * object and clear out any cached references to the handle. All references to
+ * this handle after the callback will be invalid. It is illegal to call into
+ * the VM with any other Dart_* functions from the callback. If the handle is
+ * deleted before the object becomes unreachable, the callback is never
+ * invoked.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \param object An object.
+ * \param peer A pointer to a native object or NULL. This value is
+ * provided to callback when it is invoked.
+ * \param external_allocation_size The number of externally allocated
+ * bytes for peer. Used to inform the garbage collector.
+ * \param callback A function pointer that will be invoked sometime
+ * after the object is garbage collected, unless the handle has been deleted.
+ * A valid callback needs to be specified it cannot be NULL.
+ *
+ * \return The finalizable handle or NULL. NULL is returned in case of bad
+ * parameters.
+ */
+DART_EXPORT Dart_FinalizableHandle
+Dart_NewFinalizableHandle(Dart_Handle object,
+ void* peer,
+ intptr_t external_allocation_size,
+ Dart_HandleFinalizer callback);
+
+/**
+ * Deletes the given finalizable [object] handle.
+ *
+ * The caller has to provide the actual Dart object the handle was created from
+ * to prove the object (and therefore the finalizable handle) is still alive.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT void Dart_DeleteFinalizableHandle(Dart_FinalizableHandle object,
+ Dart_Handle strong_ref_to_object);
+
+/**
+ * Updates the external memory size for the given finalizable handle.
+ *
+ * The caller has to provide the actual Dart object the handle was created from
+ * to prove the object (and therefore the finalizable handle) is still alive.
+ *
+ * May trigger garbage collection.
+ */
+DART_EXPORT void Dart_UpdateFinalizableExternalSize(
+ Dart_FinalizableHandle object,
+ Dart_Handle strong_ref_to_object,
+ intptr_t external_allocation_size);
+
+/*
+ * ==========================
+ * Initialization and Globals
+ * ==========================
+ */
+
+/**
+ * Gets the version string for the Dart VM.
+ *
+ * The version of the Dart VM can be accessed without initializing the VM.
+ *
+ * \return The version string for the embedded Dart VM.
+ */
+DART_EXPORT const char* Dart_VersionString();
+
+typedef struct {
+ const char* library_uri;
+ const char* class_name;
+ const char* function_name;
+} Dart_QualifiedFunctionName;
+
+/**
+ * Isolate specific flags are set when creating a new isolate using the
+ * Dart_IsolateFlags structure.
+ *
+ * Current version of flags is encoded in a 32-bit integer with 16 bits used
+ * for each part.
+ */
+
+#define DART_FLAGS_CURRENT_VERSION (0x0000000c)
+
+typedef struct {
+ int32_t version;
+ bool enable_asserts;
+ bool use_field_guards;
+ bool use_osr;
+ bool obfuscate;
+ Dart_QualifiedFunctionName* entry_points;
+ bool load_vmservice_library;
+ bool copy_parent_code;
+ bool null_safety;
+ bool is_system_isolate;
+} Dart_IsolateFlags;
+
+/**
+ * Initialize Dart_IsolateFlags with correct version and default values.
+ */
+DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags);
+
+/**
+ * An isolate creation and initialization callback function.
+ *
+ * This callback, provided by the embedder, is called when the VM
+ * needs to create an isolate. The callback should create an isolate
+ * by calling Dart_CreateIsolateGroup and load any scripts required for
+ * execution.
+ *
+ * This callback may be called on a different thread than the one
+ * running the parent isolate.
+ *
+ * When the function returns NULL, it is the responsibility of this
+ * function to ensure that Dart_ShutdownIsolate has been called if
+ * required (for example, if the isolate was created successfully by
+ * Dart_CreateIsolateGroup() but the root library fails to load
+ * successfully, then the function should call Dart_ShutdownIsolate
+ * before returning).
+ *
+ * When the function returns NULL, the function should set *error to
+ * a malloc-allocated buffer containing a useful error message. The
+ * caller of this function (the VM) will make sure that the buffer is
+ * freed.
+ *
+ * \param script_uri The uri of the main source file or snapshot to load.
+ * Either the URI of the parent isolate set in Dart_CreateIsolateGroup for
+ * Isolate.spawn, or the argument to Isolate.spawnUri canonicalized by the
+ * library tag handler of the parent isolate.
+ * The callback is responsible for loading the program by a call to
+ * Dart_LoadScriptFromKernel.
+ * \param main The name of the main entry point this isolate will
+ * eventually run. This is provided for advisory purposes only to
+ * improve debugging messages. The main function is not invoked by
+ * this function.
+ * \param package_root Ignored.
+ * \param package_config Uri of the package configuration file (either in format
+ * of .packages or .dart_tool/package_config.json) for this isolate
+ * to resolve package imports against. If this parameter is not passed the
+ * package resolution of the parent isolate should be used.
+ * \param flags Default flags for this isolate being spawned. Either inherited
+ * from the spawning isolate or passed as parameters when spawning the
+ * isolate from Dart code.
+ * \param isolate_data The isolate data which was passed to the
+ * parent isolate when it was created by calling Dart_CreateIsolateGroup().
+ * \param error A structure into which the embedder can place a
+ * C string containing an error message in the case of failures.
+ *
+ * \return The embedder returns NULL if the creation and
+ * initialization was not successful and the isolate if successful.
+ */
+typedef Dart_Isolate (*Dart_IsolateGroupCreateCallback)(
+ const char* script_uri,
+ const char* main,
+ const char* package_root,
+ const char* package_config,
+ Dart_IsolateFlags* flags,
+ void* isolate_data,
+ char** error);
+
+/**
+ * An isolate initialization callback function.
+ *
+ * This callback, provided by the embedder, is called when the VM has created an
+ * isolate within an existing isolate group (i.e. from the same source as an
+ * existing isolate).
+ *
+ * The callback should setup native resolvers and might want to set a custom
+ * message handler via [Dart_SetMessageNotifyCallback] and mark the isolate as
+ * runnable.
+ *
+ * This callback may be called on a different thread than the one
+ * running the parent isolate.
+ *
+ * When the function returns `false`, it is the responsibility of this
+ * function to ensure that `Dart_ShutdownIsolate` has been called.
+ *
+ * When the function returns `false`, the function should set *error to
+ * a malloc-allocated buffer containing a useful error message. The
+ * caller of this function (the VM) will make sure that the buffer is
+ * freed.
+ *
+ * \param child_isolate_data The callback data to associate with the new
+ * child isolate.
+ * \param error A structure into which the embedder can place a
+ * C string containing an error message in the case the initialization fails.
+ *
+ * \return The embedder returns true if the initialization was successful and
+ * false otherwise (in which case the VM will terminate the isolate).
+ */
+typedef bool (*Dart_InitializeIsolateCallback)(void** child_isolate_data,
+ char** error);
+
+/**
+ * An isolate unhandled exception callback function.
+ *
+ * This callback has been DEPRECATED.
+ */
+typedef void (*Dart_IsolateUnhandledExceptionCallback)(Dart_Handle error);
+
+/**
+ * An isolate shutdown callback function.
+ *
+ * This callback, provided by the embedder, is called before the vm
+ * shuts down an isolate. The isolate being shutdown will be the current
+ * isolate. It is safe to run Dart code.
+ *
+ * This function should be used to dispose of native resources that
+ * are allocated to an isolate in order to avoid leaks.
+ *
+ * \param isolate_group_data The same callback data which was passed to the
+ * isolate group when it was created.
+ * \param isolate_data The same callback data which was passed to the isolate
+ * when it was created.
+ */
+typedef void (*Dart_IsolateShutdownCallback)(void* isolate_group_data,
+ void* isolate_data);
+
+/**
+ * An isolate cleanup callback function.
+ *
+ * This callback, provided by the embedder, is called after the vm
+ * shuts down an isolate. There will be no current isolate and it is *not*
+ * safe to run Dart code.
+ *
+ * This function should be used to dispose of native resources that
+ * are allocated to an isolate in order to avoid leaks.
+ *
+ * \param isolate_group_data The same callback data which was passed to the
+ * isolate group when it was created.
+ * \param isolate_data The same callback data which was passed to the isolate
+ * when it was created.
+ */
+typedef void (*Dart_IsolateCleanupCallback)(void* isolate_group_data,
+ void* isolate_data);
+
+/**
+ * An isolate group cleanup callback function.
+ *
+ * This callback, provided by the embedder, is called after the vm
+ * shuts down an isolate group.
+ *
+ * This function should be used to dispose of native resources that
+ * are allocated to an isolate in order to avoid leaks.
+ *
+ * \param isolate_group_data The same callback data which was passed to the
+ * isolate group when it was created.
+ *
+ */
+typedef void (*Dart_IsolateGroupCleanupCallback)(void* isolate_group_data);
+
+/**
+ * A thread death callback function.
+ * This callback, provided by the embedder, is called before a thread in the
+ * vm thread pool exits.
+ * This function could be used to dispose of native resources that
+ * are associated and attached to the thread, in order to avoid leaks.
+ */
+typedef void (*Dart_ThreadExitCallback)();
+
+/**
+ * Callbacks provided by the embedder for file operations. If the
+ * embedder does not allow file operations these callbacks can be
+ * NULL.
+ *
+ * Dart_FileOpenCallback - opens a file for reading or writing.
+ * \param name The name of the file to open.
+ * \param write A boolean variable which indicates if the file is to
+ * opened for writing. If there is an existing file it needs to truncated.
+ *
+ * Dart_FileReadCallback - Read contents of file.
+ * \param data Buffer allocated in the callback into which the contents
+ * of the file are read into. It is the responsibility of the caller to
+ * free this buffer.
+ * \param file_length A variable into which the length of the file is returned.
+ * In the case of an error this value would be -1.
+ * \param stream Handle to the opened file.
+ *
+ * Dart_FileWriteCallback - Write data into file.
+ * \param data Buffer which needs to be written into the file.
+ * \param length Length of the buffer.
+ * \param stream Handle to the opened file.
+ *
+ * Dart_FileCloseCallback - Closes the opened file.
+ * \param stream Handle to the opened file.
+ *
+ */
+typedef void* (*Dart_FileOpenCallback)(const char* name, bool write);
+
+typedef void (*Dart_FileReadCallback)(uint8_t** data,
+ intptr_t* file_length,
+ void* stream);
+
+typedef void (*Dart_FileWriteCallback)(const void* data,
+ intptr_t length,
+ void* stream);
+
+typedef void (*Dart_FileCloseCallback)(void* stream);
+
+typedef bool (*Dart_EntropySource)(uint8_t* buffer, intptr_t length);
+
+/**
+ * Callback provided by the embedder that is used by the vmservice isolate
+ * to request the asset archive. The asset archive must be an uncompressed tar
+ * archive that is stored in a Uint8List.
+ *
+ * If the embedder has no vmservice isolate assets, the callback can be NULL.
+ *
+ * \return The embedder must return a handle to a Uint8List containing an
+ * uncompressed tar archive or null.
+ */
+typedef Dart_Handle (*Dart_GetVMServiceAssetsArchive)();
+
+/**
+ * The current version of the Dart_InitializeFlags. Should be incremented every
+ * time Dart_InitializeFlags changes in a binary incompatible way.
+ */
+#define DART_INITIALIZE_PARAMS_CURRENT_VERSION (0x00000004)
+
+/** Forward declaration */
+struct Dart_CodeObserver;
+
+/**
+ * Callback provided by the embedder that is used by the VM to notify on code
+ * object creation, *before* it is invoked the first time.
+ * This is useful for embedders wanting to e.g. keep track of PCs beyond
+ * the lifetime of the garbage collected code objects.
+ * Note that an address range may be used by more than one code object over the
+ * lifecycle of a process. Clients of this function should record timestamps for
+ * these compilation events and when collecting PCs to disambiguate reused
+ * address ranges.
+ */
+typedef void (*Dart_OnNewCodeCallback)(struct Dart_CodeObserver* observer,
+ const char* name,
+ uintptr_t base,
+ uintptr_t size);
+
+typedef struct Dart_CodeObserver {
+ void* data;
+
+ Dart_OnNewCodeCallback on_new_code;
+} Dart_CodeObserver;
+
+/**
+ * Describes how to initialize the VM. Used with Dart_Initialize.
+ *
+ * \param version Identifies the version of the struct used by the client.
+ * should be initialized to DART_INITIALIZE_PARAMS_CURRENT_VERSION.
+ * \param vm_isolate_snapshot A buffer containing a snapshot of the VM isolate
+ * or NULL if no snapshot is provided. If provided, the buffer must remain
+ * valid until Dart_Cleanup returns.
+ * \param instructions_snapshot A buffer containing a snapshot of precompiled
+ * instructions, or NULL if no snapshot is provided. If provided, the buffer
+ * must remain valid until Dart_Cleanup returns.
+ * \param initialize_isolate A function to be called during isolate
+ * initialization inside an existing isolate group.
+ * See Dart_InitializeIsolateCallback.
+ * \param create_group A function to be called during isolate group creation.
+ * See Dart_IsolateGroupCreateCallback.
+ * \param shutdown A function to be called right before an isolate is shutdown.
+ * See Dart_IsolateShutdownCallback.
+ * \param cleanup A function to be called after an isolate was shutdown.
+ * See Dart_IsolateCleanupCallback.
+ * \param cleanup_group A function to be called after an isolate group is shutdown.
+ * See Dart_IsolateGroupCleanupCallback.
+ * \param get_service_assets A function to be called by the service isolate when
+ * it requires the vmservice assets archive.
+ * See Dart_GetVMServiceAssetsArchive.
+ * \param code_observer An external code observer callback function.
+ * The observer can be invoked as early as during the Dart_Initialize() call.
+ */
+typedef struct {
+ int32_t version;
+ const uint8_t* vm_snapshot_data;
+ const uint8_t* vm_snapshot_instructions;
+ Dart_IsolateGroupCreateCallback create_group;
+ Dart_InitializeIsolateCallback initialize_isolate;
+ Dart_IsolateShutdownCallback shutdown_isolate;
+ Dart_IsolateCleanupCallback cleanup_isolate;
+ Dart_IsolateGroupCleanupCallback cleanup_group;
+ Dart_ThreadExitCallback thread_exit;
+ Dart_FileOpenCallback file_open;
+ Dart_FileReadCallback file_read;
+ Dart_FileWriteCallback file_write;
+ Dart_FileCloseCallback file_close;
+ Dart_EntropySource entropy_source;
+ Dart_GetVMServiceAssetsArchive get_service_assets;
+ bool start_kernel_isolate;
+ Dart_CodeObserver* code_observer;
+} Dart_InitializeParams;
+
+/**
+ * Initializes the VM.
+ *
+ * \param params A struct containing initialization information. The version
+ * field of the struct must be DART_INITIALIZE_PARAMS_CURRENT_VERSION.
+ *
+ * \return NULL if initialization is successful. Returns an error message
+ * otherwise. The caller is responsible for freeing the error message.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_Initialize(
+ Dart_InitializeParams* params);
+
+/**
+ * Cleanup state in the VM before process termination.
+ *
+ * \return NULL if cleanup is successful. Returns an error message otherwise.
+ * The caller is responsible for freeing the error message.
+ *
+ * NOTE: This function must not be called on a thread that was created by the VM
+ * itself.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_Cleanup();
+
+/**
+ * Sets command line flags. Should be called before Dart_Initialize.
+ *
+ * \param argc The length of the arguments array.
+ * \param argv An array of arguments.
+ *
+ * \return NULL if successful. Returns an error message otherwise.
+ * The caller is responsible for freeing the error message.
+ *
+ * NOTE: This call does not store references to the passed in c-strings.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_SetVMFlags(int argc,
+ const char** argv);
+
+/**
+ * Returns true if the named VM flag is of boolean type, specified, and set to
+ * true.
+ *
+ * \param flag_name The name of the flag without leading punctuation
+ * (example: "enable_asserts").
+ */
+DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name);
+
+/*
+ * ========
+ * Isolates
+ * ========
+ */
+
+/**
+ * Creates a new isolate. The new isolate becomes the current isolate.
+ *
+ * A snapshot can be used to restore the VM quickly to a saved state
+ * and is useful for fast startup. If snapshot data is provided, the
+ * isolate will be started using that snapshot data. Requires a core snapshot or
+ * an app snapshot created by Dart_CreateSnapshot or
+ * Dart_CreatePrecompiledSnapshot* from a VM with the same version.
+ *
+ * Requires there to be no current isolate.
+ *
+ * \param script_uri The main source file or snapshot this isolate will load.
+ * The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a child
+ * isolate is created by Isolate.spawn. The embedder should use a URI that
+ * allows it to load the same program into such a child isolate.
+ * \param name A short name for the isolate to improve debugging messages.
+ * Typically of the format 'foo.dart:main()'.
+ * \param isolate_snapshot_data
+ * \param isolate_snapshot_instructions Buffers containing a snapshot of the
+ * isolate or NULL if no snapshot is provided. If provided, the buffers must
+ * remain valid until the isolate shuts down.
+ * \param flags Pointer to VM specific flags or NULL for default flags.
+ * \param isolate_group_data Embedder group data. This data can be obtained
+ * by calling Dart_IsolateGroupData and will be passed to the
+ * Dart_IsolateShutdownCallback, Dart_IsolateCleanupCallback, and
+ * Dart_IsolateGroupCleanupCallback.
+ * \param isolate_data Embedder data. This data will be passed to
+ * the Dart_IsolateGroupCreateCallback when new isolates are spawned from
+ * this parent isolate.
+ * \param error Returns NULL if creation is successful, an error message
+ * otherwise. The caller is responsible for calling free() on the error
+ * message.
+ *
+ * \return The new isolate on success, or NULL if isolate creation failed.
+ */
+DART_EXPORT Dart_Isolate
+Dart_CreateIsolateGroup(const char* script_uri,
+ const char* name,
+ const uint8_t* isolate_snapshot_data,
+ const uint8_t* isolate_snapshot_instructions,
+ Dart_IsolateFlags* flags,
+ void* isolate_group_data,
+ void* isolate_data,
+ char** error);
+/**
+ * Creates a new isolate inside the isolate group of [group_member].
+ *
+ * Requires there to be no current isolate.
+ *
+ * \param group_member An isolate from the same group into which the newly created
+ * isolate should be born into. Other threads may not have entered / enter this
+ * member isolate.
+ * \param name A short name for the isolate for debugging purposes.
+ * \param shutdown_callback A callback to be called when the isolate is being
+ * shutdown (may be NULL).
+ * \param cleanup_callback A callback to be called when the isolate is being
+ * cleaned up (may be NULL).
+ * \param isolate_data The embedder-specific data associated with this isolate.
+ * \param error Set to NULL if creation is successful, set to an error
+ * message otherwise. The caller is responsible for calling free() on the
+ * error message.
+ *
+ * \return The newly created isolate on success, or NULL if isolate creation
+ * failed.
+ *
+ * If successful, the newly created isolate will become the current isolate.
+ */
+DART_EXPORT Dart_Isolate
+Dart_CreateIsolateInGroup(Dart_Isolate group_member,
+ const char* name,
+ Dart_IsolateShutdownCallback shutdown_callback,
+ Dart_IsolateCleanupCallback cleanup_callback,
+ void* child_isolate_data,
+ char** error);
+
+/* TODO(turnidge): Document behavior when there is already a current
+ * isolate. */
+
+/**
+ * Creates a new isolate from a Dart Kernel file. The new isolate
+ * becomes the current isolate.
+ *
+ * Requires there to be no current isolate.
+ *
+ * \param script_uri The main source file or snapshot this isolate will load.
+ * The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a child
+ * isolate is created by Isolate.spawn. The embedder should use a URI that
+ * allows it to load the same program into such a child isolate.
+ * \param name A short name for the isolate to improve debugging messages.
+ * Typically of the format 'foo.dart:main()'.
+ * \param kernel_buffer
+ * \param kernel_buffer_size A buffer which contains a kernel/DIL program. Must
+ * remain valid until isolate shutdown.
+ * \param flags Pointer to VM specific flags or NULL for default flags.
+ * \param isolate_group_data Embedder group data. This data can be obtained
+ * by calling Dart_IsolateGroupData and will be passed to the
+ * Dart_IsolateShutdownCallback, Dart_IsolateCleanupCallback, and
+ * Dart_IsolateGroupCleanupCallback.
+ * \param isolate_data Embedder data. This data will be passed to
+ * the Dart_IsolateGroupCreateCallback when new isolates are spawned from
+ * this parent isolate.
+ * \param error Returns NULL if creation is successful, an error message
+ * otherwise. The caller is responsible for calling free() on the error
+ * message.
+ *
+ * \return The new isolate on success, or NULL if isolate creation failed.
+ */
+DART_EXPORT Dart_Isolate
+Dart_CreateIsolateGroupFromKernel(const char* script_uri,
+ const char* name,
+ const uint8_t* kernel_buffer,
+ intptr_t kernel_buffer_size,
+ Dart_IsolateFlags* flags,
+ void* isolate_group_data,
+ void* isolate_data,
+ char** error);
+/**
+ * Shuts down the current isolate. After this call, the current isolate is NULL.
+ * Any current scopes created by Dart_EnterScope will be exited. Invokes the
+ * shutdown callback and any callbacks of remaining weak persistent handles.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT void Dart_ShutdownIsolate();
+/* TODO(turnidge): Document behavior when there is no current isolate. */
+
+/**
+ * Returns the current isolate. Will return NULL if there is no
+ * current isolate.
+ */
+DART_EXPORT Dart_Isolate Dart_CurrentIsolate();
+
+/**
+ * Returns the callback data associated with the current isolate. This
+ * data was set when the isolate got created or initialized.
+ */
+DART_EXPORT void* Dart_CurrentIsolateData();
+
+/**
+ * Returns the callback data associated with the given isolate. This
+ * data was set when the isolate got created or initialized.
+ */
+DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate);
+
+/**
+ * Returns the current isolate group. Will return NULL if there is no
+ * current isolate group.
+ */
+DART_EXPORT Dart_IsolateGroup Dart_CurrentIsolateGroup();
+
+/**
+ * Returns the callback data associated with the current isolate group. This
+ * data was passed to the isolate group when it was created.
+ */
+DART_EXPORT void* Dart_CurrentIsolateGroupData();
+
+/**
+ * Returns the callback data associated with the specified isolate group. This
+ * data was passed to the isolate when it was created.
+ * The embedder is responsible for ensuring the consistency of this data
+ * with respect to the lifecycle of an isolate group.
+ */
+DART_EXPORT void* Dart_IsolateGroupData(Dart_Isolate isolate);
+
+/**
+ * Returns the debugging name for the current isolate.
+ *
+ * This name is unique to each isolate and should only be used to make
+ * debugging messages more comprehensible.
+ */
+DART_EXPORT Dart_Handle Dart_DebugName();
+
+/**
+ * Returns the ID for an isolate which is used to query the service protocol.
+ *
+ * It is the responsibility of the caller to free the returned ID.
+ */
+DART_EXPORT const char* Dart_IsolateServiceId(Dart_Isolate isolate);
+
+/**
+ * Enters an isolate. After calling this function,
+ * the current isolate will be set to the provided isolate.
+ *
+ * Requires there to be no current isolate. Multiple threads may not be in
+ * the same isolate at once.
+ */
+DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate);
+
+/**
+ * Kills the given isolate.
+ *
+ * This function has the same effect as dart:isolate's
+ * Isolate.kill(priority:immediate).
+ * It can interrupt ordinary Dart code but not native code. If the isolate is
+ * in the middle of a long running native function, the isolate will not be
+ * killed until control returns to Dart.
+ *
+ * Does not require a current isolate. It is safe to kill the current isolate if
+ * there is one.
+ */
+DART_EXPORT void Dart_KillIsolate(Dart_Isolate isolate);
+
+/**
+ * Notifies the VM that the embedder expects |size| bytes of memory have become
+ * unreachable. The VM may use this hint to adjust the garbage collector's
+ * growth policy.
+ *
+ * Multiple calls are interpreted as increasing, not replacing, the estimate of
+ * unreachable memory.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT void Dart_HintFreed(intptr_t size);
+
+/**
+ * Notifies the VM that the embedder expects to be idle until |deadline|. The VM
+ * may use this time to perform garbage collection or other tasks to avoid
+ * delays during execution of Dart code in the future.
+ *
+ * |deadline| is measured in microseconds against the system's monotonic time.
+ * This clock can be accessed via Dart_TimelineGetMicros().
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT void Dart_NotifyIdle(int64_t deadline);
+
+/**
+ * Notifies the VM that the system is running low on memory.
+ *
+ * Does not require a current isolate. Only valid after calling Dart_Initialize.
+ */
+DART_EXPORT void Dart_NotifyLowMemory();
+
+/**
+ * Starts the CPU sampling profiler.
+ */
+DART_EXPORT void Dart_StartProfiling();
+
+/**
+ * Stops the CPU sampling profiler.
+ *
+ * Note that some profile samples might still be taken after this fucntion
+ * returns due to the asynchronous nature of the implementation on some
+ * platforms.
+ */
+DART_EXPORT void Dart_StopProfiling();
+
+/**
+ * Notifies the VM that the current thread should not be profiled until a
+ * matching call to Dart_ThreadEnableProfiling is made.
+ *
+ * NOTE: By default, if a thread has entered an isolate it will be profiled.
+ * This function should be used when an embedder knows a thread is about
+ * to make a blocking call and wants to avoid unnecessary interrupts by
+ * the profiler.
+ */
+DART_EXPORT void Dart_ThreadDisableProfiling();
+
+/**
+ * Notifies the VM that the current thread should be profiled.
+ *
+ * NOTE: It is only legal to call this function *after* calling
+ * Dart_ThreadDisableProfiling.
+ *
+ * NOTE: By default, if a thread has entered an isolate it will be profiled.
+ */
+DART_EXPORT void Dart_ThreadEnableProfiling();
+
+/**
+ * Register symbol information for the Dart VM's profiler and crash dumps.
+ *
+ * This consumes the output of //topaz/runtime/dart/profiler_symbols, which
+ * should be treated as opaque.
+ */
+DART_EXPORT void Dart_AddSymbols(const char* dso_name,
+ void* buffer,
+ intptr_t buffer_size);
+
+/**
+ * Exits an isolate. After this call, Dart_CurrentIsolate will
+ * return NULL.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT void Dart_ExitIsolate();
+/* TODO(turnidge): We don't want users of the api to be able to exit a
+ * "pure" dart isolate. Implement and document. */
+
+/**
+ * Creates a full snapshot of the current isolate heap.
+ *
+ * A full snapshot is a compact representation of the dart vm isolate heap
+ * and dart isolate heap states. These snapshots are used to initialize
+ * the vm isolate on startup and fast initialization of an isolate.
+ * A Snapshot of the heap is created before any dart code has executed.
+ *
+ * Requires there to be a current isolate. Not available in the precompiled
+ * runtime (check Dart_IsPrecompiledRuntime).
+ *
+ * \param buffer Returns a pointer to a buffer containing the
+ * snapshot. This buffer is scope allocated and is only valid
+ * until the next call to Dart_ExitScope.
+ * \param size Returns the size of the buffer.
+ * \param is_core Create a snapshot containing core libraries.
+ * Such snapshot should be agnostic to null safety mode.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateSnapshot(uint8_t** vm_snapshot_data_buffer,
+ intptr_t* vm_snapshot_data_size,
+ uint8_t** isolate_snapshot_data_buffer,
+ intptr_t* isolate_snapshot_data_size,
+ bool is_core);
+
+/**
+ * Returns whether the buffer contains a kernel file.
+ *
+ * \param buffer Pointer to a buffer that might contain a kernel binary.
+ * \param buffer_size Size of the buffer.
+ *
+ * \return Whether the buffer contains a kernel binary (full or partial).
+ */
+DART_EXPORT bool Dart_IsKernel(const uint8_t* buffer, intptr_t buffer_size);
+
+/**
+ * Make isolate runnable.
+ *
+ * When isolates are spawned, this function is used to indicate that
+ * the creation and initialization (including script loading) of the
+ * isolate is complete and the isolate can start.
+ * This function expects there to be no current isolate.
+ *
+ * \param isolate The isolate to be made runnable.
+ *
+ * \return NULL if successful. Returns an error message otherwise. The caller
+ * is responsible for freeing the error message.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_IsolateMakeRunnable(
+ Dart_Isolate isolate);
+
+/*
+ * ==================
+ * Messages and Ports
+ * ==================
+ */
+
+/**
+ * A port is used to send or receive inter-isolate messages
+ */
+typedef int64_t Dart_Port;
+
+/**
+ * ILLEGAL_PORT is a port number guaranteed never to be associated with a valid
+ * port.
+ */
+#define ILLEGAL_PORT ((Dart_Port)0)
+
+/**
+ * A message notification callback.
+ *
+ * This callback allows the embedder to provide an alternate wakeup
+ * mechanism for the delivery of inter-isolate messages. It is the
+ * responsibility of the embedder to call Dart_HandleMessage to
+ * process the message.
+ */
+typedef void (*Dart_MessageNotifyCallback)(Dart_Isolate dest_isolate);
+
+/**
+ * Allows embedders to provide an alternative wakeup mechanism for the
+ * delivery of inter-isolate messages. This setting only applies to
+ * the current isolate.
+ *
+ * Most embedders will only call this function once, before isolate
+ * execution begins. If this function is called after isolate
+ * execution begins, the embedder is responsible for threading issues.
+ */
+DART_EXPORT void Dart_SetMessageNotifyCallback(
+ Dart_MessageNotifyCallback message_notify_callback);
+/* TODO(turnidge): Consider moving this to isolate creation so that it
+ * is impossible to mess up. */
+
+/**
+ * Query the current message notify callback for the isolate.
+ *
+ * \return The current message notify callback for the isolate.
+ */
+DART_EXPORT Dart_MessageNotifyCallback Dart_GetMessageNotifyCallback();
+
+/**
+ * The VM's default message handler supports pausing an isolate before it
+ * processes the first message and right after the it processes the isolate's
+ * final message. This can be controlled for all isolates by two VM flags:
+ *
+ * `--pause-isolates-on-start`
+ * `--pause-isolates-on-exit`
+ *
+ * Additionally, Dart_SetShouldPauseOnStart and Dart_SetShouldPauseOnExit can be
+ * used to control this behaviour on a per-isolate basis.
+ *
+ * When an embedder is using a Dart_MessageNotifyCallback the embedder
+ * needs to cooperate with the VM so that the service protocol can report
+ * accurate information about isolates and so that tools such as debuggers
+ * work reliably.
+ *
+ * The following functions can be used to implement pausing on start and exit.
+ */
+
+/**
+ * If the VM flag `--pause-isolates-on-start` was passed this will be true.
+ *
+ * \return A boolean value indicating if pause on start was requested.
+ */
+DART_EXPORT bool Dart_ShouldPauseOnStart();
+
+/**
+ * Override the VM flag `--pause-isolates-on-start` for the current isolate.
+ *
+ * \param should_pause Should the isolate be paused on start?
+ *
+ * NOTE: This must be called before Dart_IsolateMakeRunnable.
+ */
+DART_EXPORT void Dart_SetShouldPauseOnStart(bool should_pause);
+
+/**
+ * Is the current isolate paused on start?
+ *
+ * \return A boolean value indicating if the isolate is paused on start.
+ */
+DART_EXPORT bool Dart_IsPausedOnStart();
+
+/**
+ * Called when the embedder has paused the current isolate on start and when
+ * the embedder has resumed the isolate.
+ *
+ * \param paused Is the isolate paused on start?
+ */
+DART_EXPORT void Dart_SetPausedOnStart(bool paused);
+
+/**
+ * If the VM flag `--pause-isolates-on-exit` was passed this will be true.
+ *
+ * \return A boolean value indicating if pause on exit was requested.
+ */
+DART_EXPORT bool Dart_ShouldPauseOnExit();
+
+/**
+ * Override the VM flag `--pause-isolates-on-exit` for the current isolate.
+ *
+ * \param should_pause Should the isolate be paused on exit?
+ *
+ */
+DART_EXPORT void Dart_SetShouldPauseOnExit(bool should_pause);
+
+/**
+ * Is the current isolate paused on exit?
+ *
+ * \return A boolean value indicating if the isolate is paused on exit.
+ */
+DART_EXPORT bool Dart_IsPausedOnExit();
+
+/**
+ * Called when the embedder has paused the current isolate on exit and when
+ * the embedder has resumed the isolate.
+ *
+ * \param paused Is the isolate paused on exit?
+ */
+DART_EXPORT void Dart_SetPausedOnExit(bool paused);
+
+/**
+ * Called when the embedder has caught a top level unhandled exception error
+ * in the current isolate.
+ *
+ * NOTE: It is illegal to call this twice on the same isolate without first
+ * clearing the sticky error to null.
+ *
+ * \param error The unhandled exception error.
+ */
+DART_EXPORT void Dart_SetStickyError(Dart_Handle error);
+
+/**
+ * Does the current isolate have a sticky error?
+ */
+DART_EXPORT bool Dart_HasStickyError();
+
+/**
+ * Gets the sticky error for the current isolate.
+ *
+ * \return A handle to the sticky error object or null.
+ */
+DART_EXPORT Dart_Handle Dart_GetStickyError();
+
+/**
+ * Handles the next pending message for the current isolate.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_HandleMessage();
+
+/**
+ * Drains the microtask queue, then blocks the calling thread until the current
+ * isolate recieves a message, then handles all messages.
+ *
+ * \param timeout_millis When non-zero, the call returns after the indicated
+ number of milliseconds even if no message was received.
+ * \return A valid handle if no error occurs, otherwise an error handle.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_WaitForEvent(int64_t timeout_millis);
+
+/**
+ * Handles any pending messages for the vm service for the current
+ * isolate.
+ *
+ * This function may be used by an embedder at a breakpoint to avoid
+ * pausing the vm service.
+ *
+ * This function can indirectly cause the message notify callback to
+ * be called.
+ *
+ * \return true if the vm service requests the program resume
+ * execution, false otherwise
+ */
+DART_EXPORT bool Dart_HandleServiceMessages();
+
+/**
+ * Does the current isolate have pending service messages?
+ *
+ * \return true if the isolate has pending service messages, false otherwise.
+ */
+DART_EXPORT bool Dart_HasServiceMessages();
+
+/**
+ * Processes any incoming messages for the current isolate.
+ *
+ * This function may only be used when the embedder has not provided
+ * an alternate message delivery mechanism with
+ * Dart_SetMessageCallbacks. It is provided for convenience.
+ *
+ * This function waits for incoming messages for the current
+ * isolate. As new messages arrive, they are handled using
+ * Dart_HandleMessage. The routine exits when all ports to the
+ * current isolate are closed.
+ *
+ * \return A valid handle if the run loop exited successfully. If an
+ * exception or other error occurs while processing messages, an
+ * error handle is returned.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_RunLoop();
+
+/**
+ * Lets the VM run message processing for the isolate.
+ *
+ * This function expects there to a current isolate and the current isolate
+ * must not have an active api scope. The VM will take care of making the
+ * isolate runnable (if not already), handles its message loop and will take
+ * care of shutting the isolate down once it's done.
+ *
+ * \param errors_are_fatal Whether uncaught errors should be fatal.
+ * \param on_error_port A port to notify on uncaught errors (or ILLEGAL_PORT).
+ * \param on_exit_port A port to notify on exit (or ILLEGAL_PORT).
+ * \param error A non-NULL pointer which will hold an error message if the call
+ * fails. The error has to be free()ed by the caller.
+ *
+ * \return If successfull the VM takes owernship of the isolate and takes care
+ * of its message loop. If not successful the caller retains owernship of the
+ * isolate.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT bool Dart_RunLoopAsync(
+ bool errors_are_fatal,
+ Dart_Port on_error_port,
+ Dart_Port on_exit_port,
+ char** error);
+
+/* TODO(turnidge): Should this be removed from the public api? */
+
+/**
+ * Gets the main port id for the current isolate.
+ */
+DART_EXPORT Dart_Port Dart_GetMainPortId();
+
+/**
+ * Does the current isolate have live ReceivePorts?
+ *
+ * A ReceivePort is live when it has not been closed.
+ */
+DART_EXPORT bool Dart_HasLivePorts();
+
+/**
+ * Posts a message for some isolate. The message is a serialized
+ * object.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \param port The destination port.
+ * \param object An object from the current isolate.
+ *
+ * \return True if the message was posted.
+ */
+DART_EXPORT bool Dart_Post(Dart_Port port_id, Dart_Handle object);
+
+/**
+ * Returns a new SendPort with the provided port id.
+ *
+ * \param port_id The destination port.
+ *
+ * \return A new SendPort if no errors occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewSendPort(Dart_Port port_id);
+
+/**
+ * Gets the SendPort id for the provided SendPort.
+ * \param port A SendPort object whose id is desired.
+ * \param port_id Returns the id of the SendPort.
+ * \return Success if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_SendPortGetId(Dart_Handle port,
+ Dart_Port* port_id);
+
+/*
+ * ======
+ * Scopes
+ * ======
+ */
+
+/**
+ * Enters a new scope.
+ *
+ * All new local handles will be created in this scope. Additionally,
+ * some functions may return "scope allocated" memory which is only
+ * valid within this scope.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT void Dart_EnterScope();
+
+/**
+ * Exits a scope.
+ *
+ * The previous scope (if any) becomes the current scope.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT void Dart_ExitScope();
+
+/**
+ * The Dart VM uses "zone allocation" for temporary structures. Zones
+ * support very fast allocation of small chunks of memory. The chunks
+ * cannot be deallocated individually, but instead zones support
+ * deallocating all chunks in one fast operation.
+ *
+ * This function makes it possible for the embedder to allocate
+ * temporary data in the VMs zone allocator.
+ *
+ * Zone allocation is possible:
+ * 1. when inside a scope where local handles can be allocated
+ * 2. when processing a message from a native port in a native port
+ * handler
+ *
+ * All the memory allocated this way will be reclaimed either on the
+ * next call to Dart_ExitScope or when the native port handler exits.
+ *
+ * \param size Size of the memory to allocate.
+ *
+ * \return A pointer to the allocated memory. NULL if allocation
+ * failed. Failure might due to is no current VM zone.
+ */
+DART_EXPORT uint8_t* Dart_ScopeAllocate(intptr_t size);
+
+/*
+ * =======
+ * Objects
+ * =======
+ */
+
+/**
+ * Returns the null object.
+ *
+ * \return A handle to the null object.
+ */
+DART_EXPORT Dart_Handle Dart_Null();
+
+/**
+ * Is this object null?
+ */
+DART_EXPORT bool Dart_IsNull(Dart_Handle object);
+
+/**
+ * Returns the empty string object.
+ *
+ * \return A handle to the empty string object.
+ */
+DART_EXPORT Dart_Handle Dart_EmptyString();
+
+/**
+ * Returns types that are not classes, and which therefore cannot be looked up
+ * as library members by Dart_GetType.
+ *
+ * \return A handle to the dynamic, void or Never type.
+ */
+DART_EXPORT Dart_Handle Dart_TypeDynamic();
+DART_EXPORT Dart_Handle Dart_TypeVoid();
+DART_EXPORT Dart_Handle Dart_TypeNever();
+
+/**
+ * Checks if the two objects are equal.
+ *
+ * The result of the comparison is returned through the 'equal'
+ * parameter. The return value itself is used to indicate success or
+ * failure, not equality.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param obj1 An object to be compared.
+ * \param obj2 An object to be compared.
+ * \param equal Returns the result of the equality comparison.
+ *
+ * \return A valid handle if no error occurs during the comparison.
+ */
+DART_EXPORT Dart_Handle Dart_ObjectEquals(Dart_Handle obj1,
+ Dart_Handle obj2,
+ bool* equal);
+
+/**
+ * Is this object an instance of some type?
+ *
+ * The result of the test is returned through the 'instanceof' parameter.
+ * The return value itself is used to indicate success or failure.
+ *
+ * \param object An object.
+ * \param type A type.
+ * \param instanceof Return true if 'object' is an instance of type 'type'.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_ObjectIsType(Dart_Handle object,
+ Dart_Handle type,
+ bool* instanceof);
+
+/**
+ * Query object type.
+ *
+ * \param object Some Object.
+ *
+ * \return true if Object is of the specified type.
+ */
+DART_EXPORT bool Dart_IsInstance(Dart_Handle object);
+DART_EXPORT bool Dart_IsNumber(Dart_Handle object);
+DART_EXPORT bool Dart_IsInteger(Dart_Handle object);
+DART_EXPORT bool Dart_IsDouble(Dart_Handle object);
+DART_EXPORT bool Dart_IsBoolean(Dart_Handle object);
+DART_EXPORT bool Dart_IsString(Dart_Handle object);
+DART_EXPORT bool Dart_IsStringLatin1(Dart_Handle object); /* (ISO-8859-1) */
+DART_EXPORT bool Dart_IsExternalString(Dart_Handle object);
+DART_EXPORT bool Dart_IsList(Dart_Handle object);
+DART_EXPORT bool Dart_IsMap(Dart_Handle object);
+DART_EXPORT bool Dart_IsLibrary(Dart_Handle object);
+DART_EXPORT bool Dart_IsType(Dart_Handle handle);
+DART_EXPORT bool Dart_IsFunction(Dart_Handle handle);
+DART_EXPORT bool Dart_IsVariable(Dart_Handle handle);
+DART_EXPORT bool Dart_IsTypeVariable(Dart_Handle handle);
+DART_EXPORT bool Dart_IsClosure(Dart_Handle object);
+DART_EXPORT bool Dart_IsTypedData(Dart_Handle object);
+DART_EXPORT bool Dart_IsByteBuffer(Dart_Handle object);
+DART_EXPORT bool Dart_IsFuture(Dart_Handle object);
+
+/*
+ * =========
+ * Instances
+ * =========
+ */
+
+/*
+ * For the purposes of the embedding api, not all objects returned are
+ * Dart language objects. Within the api, we use the term 'Instance'
+ * to indicate handles which refer to true Dart language objects.
+ *
+ * TODO(turnidge): Reorganize the "Object" section above, pulling down
+ * any functions that more properly belong here. */
+
+/**
+ * Gets the type of a Dart language object.
+ *
+ * \param instance Some Dart object.
+ *
+ * \return If no error occurs, the type is returned. Otherwise an
+ * error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_InstanceGetType(Dart_Handle instance);
+
+/**
+ * Returns the name for the provided class type.
+ *
+ * \return A valid string handle if no error occurs during the
+ * operation.
+ */
+DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle cls_type);
+
+/**
+ * Returns the name for the provided function or method.
+ *
+ * \return A valid string handle if no error occurs during the
+ * operation.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function);
+
+/**
+ * Returns a handle to the owner of a function.
+ *
+ * The owner of an instance method or a static method is its defining
+ * class. The owner of a top-level function is its defining
+ * library. The owner of the function of a non-implicit closure is the
+ * function of the method or closure that defines the non-implicit
+ * closure.
+ *
+ * \return A valid handle to the owner of the function, or an error
+ * handle if the argument is not a valid handle to a function.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function);
+
+/**
+ * Determines whether a function handle referes to a static function
+ * of method.
+ *
+ * For the purposes of the embedding API, a top-level function is
+ * implicitly declared static.
+ *
+ * \param function A handle to a function or method declaration.
+ * \param is_static Returns whether the function or method is declared static.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function,
+ bool* is_static);
+
+/**
+ * Is this object a closure resulting from a tear-off (closurized method)?
+ *
+ * Returns true for closures produced when an ordinary method is accessed
+ * through a getter call. Returns false otherwise, in particular for closures
+ * produced from local function declarations.
+ *
+ * \param object Some Object.
+ *
+ * \return true if Object is a tear-off.
+ */
+DART_EXPORT bool Dart_IsTearOff(Dart_Handle object);
+
+/**
+ * Retrieves the function of a closure.
+ *
+ * \return A handle to the function of the closure, or an error handle if the
+ * argument is not a closure.
+ */
+DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure);
+
+/**
+ * Returns a handle to the library which contains class.
+ *
+ * \return A valid handle to the library with owns class, null if the class
+ * has no library or an error handle if the argument is not a valid handle
+ * to a class type.
+ */
+DART_EXPORT Dart_Handle Dart_ClassLibrary(Dart_Handle cls_type);
+
+/*
+ * =============================
+ * Numbers, Integers and Doubles
+ * =============================
+ */
+
+/**
+ * Does this Integer fit into a 64-bit signed integer?
+ *
+ * \param integer An integer.
+ * \param fits Returns true if the integer fits into a 64-bit signed integer.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_IntegerFitsIntoInt64(Dart_Handle integer,
+ bool* fits);
+
+/**
+ * Does this Integer fit into a 64-bit unsigned integer?
+ *
+ * \param integer An integer.
+ * \param fits Returns true if the integer fits into a 64-bit unsigned integer.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_IntegerFitsIntoUint64(Dart_Handle integer,
+ bool* fits);
+
+/**
+ * Returns an Integer with the provided value.
+ *
+ * \param value The value of the integer.
+ *
+ * \return The Integer object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewInteger(int64_t value);
+
+/**
+ * Returns an Integer with the provided value.
+ *
+ * \param value The unsigned value of the integer.
+ *
+ * \return The Integer object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewIntegerFromUint64(uint64_t value);
+
+/**
+ * Returns an Integer with the provided value.
+ *
+ * \param value The value of the integer represented as a C string
+ * containing a hexadecimal number.
+ *
+ * \return The Integer object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewIntegerFromHexCString(const char* value);
+
+/**
+ * Gets the value of an Integer.
+ *
+ * The integer must fit into a 64-bit signed integer, otherwise an error occurs.
+ *
+ * \param integer An Integer.
+ * \param value Returns the value of the Integer.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_IntegerToInt64(Dart_Handle integer,
+ int64_t* value);
+
+/**
+ * Gets the value of an Integer.
+ *
+ * The integer must fit into a 64-bit unsigned integer, otherwise an
+ * error occurs.
+ *
+ * \param integer An Integer.
+ * \param value Returns the value of the Integer.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_IntegerToUint64(Dart_Handle integer,
+ uint64_t* value);
+
+/**
+ * Gets the value of an integer as a hexadecimal C string.
+ *
+ * \param integer An Integer.
+ * \param value Returns the value of the Integer as a hexadecimal C
+ * string. This C string is scope allocated and is only valid until
+ * the next call to Dart_ExitScope.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_IntegerToHexCString(Dart_Handle integer,
+ const char** value);
+
+/**
+ * Returns a Double with the provided value.
+ *
+ * \param value A double.
+ *
+ * \return The Double object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewDouble(double value);
+
+/**
+ * Gets the value of a Double
+ *
+ * \param double_obj A Double
+ * \param value Returns the value of the Double.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_DoubleValue(Dart_Handle double_obj, double* value);
+
+/**
+ * Returns a closure of static function 'function_name' in the class 'class_name'
+ * in the exported namespace of specified 'library'.
+ *
+ * \param library Library object
+ * \param cls_type Type object representing a Class
+ * \param function_name Name of the static function in the class
+ *
+ * \return A valid Dart instance if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_GetStaticMethodClosure(Dart_Handle library,
+ Dart_Handle cls_type,
+ Dart_Handle function_name);
+
+/*
+ * ========
+ * Booleans
+ * ========
+ */
+
+/**
+ * Returns the True object.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \return A handle to the True object.
+ */
+DART_EXPORT Dart_Handle Dart_True();
+
+/**
+ * Returns the False object.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \return A handle to the False object.
+ */
+DART_EXPORT Dart_Handle Dart_False();
+
+/**
+ * Returns a Boolean with the provided value.
+ *
+ * \param value true or false.
+ *
+ * \return The Boolean object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewBoolean(bool value);
+
+/**
+ * Gets the value of a Boolean
+ *
+ * \param boolean_obj A Boolean
+ * \param value Returns the value of the Boolean.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_BooleanValue(Dart_Handle boolean_obj, bool* value);
+
+/*
+ * =======
+ * Strings
+ * =======
+ */
+
+/**
+ * Gets the length of a String.
+ *
+ * \param str A String.
+ * \param length Returns the length of the String.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_StringLength(Dart_Handle str, intptr_t* length);
+
+/**
+ * Returns a String built from the provided C string
+ * (There is an implicit assumption that the C string passed in contains
+ * UTF-8 encoded characters and '\0' is considered as a termination
+ * character).
+ *
+ * \param value A C String
+ *
+ * \return The String object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewStringFromCString(const char* str);
+/* TODO(turnidge): Document what happens when we run out of memory
+ * during this call. */
+
+/**
+ * Returns a String built from an array of UTF-8 encoded characters.
+ *
+ * \param utf8_array An array of UTF-8 encoded characters.
+ * \param length The length of the codepoints array.
+ *
+ * \return The String object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewStringFromUTF8(const uint8_t* utf8_array,
+ intptr_t length);
+
+/**
+ * Returns a String built from an array of UTF-16 encoded characters.
+ *
+ * \param utf16_array An array of UTF-16 encoded characters.
+ * \param length The length of the codepoints array.
+ *
+ * \return The String object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewStringFromUTF16(const uint16_t* utf16_array,
+ intptr_t length);
+
+/**
+ * Returns a String built from an array of UTF-32 encoded characters.
+ *
+ * \param utf32_array An array of UTF-32 encoded characters.
+ * \param length The length of the codepoints array.
+ *
+ * \return The String object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewStringFromUTF32(const int32_t* utf32_array,
+ intptr_t length);
+
+/**
+ * Returns a String which references an external array of
+ * Latin-1 (ISO-8859-1) encoded characters.
+ *
+ * \param latin1_array Array of Latin-1 encoded characters. This must not move.
+ * \param length The length of the characters array.
+ * \param peer An external pointer to associate with this string.
+ * \param external_allocation_size The number of externally allocated
+ * bytes for peer. Used to inform the garbage collector.
+ * \param callback A callback to be called when this string is finalized.
+ *
+ * \return The String object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle
+Dart_NewExternalLatin1String(const uint8_t* latin1_array,
+ intptr_t length,
+ void* peer,
+ intptr_t external_allocation_size,
+ Dart_HandleFinalizer callback);
+
+/**
+ * Returns a String which references an external array of UTF-16 encoded
+ * characters.
+ *
+ * \param utf16_array An array of UTF-16 encoded characters. This must not move.
+ * \param length The length of the characters array.
+ * \param peer An external pointer to associate with this string.
+ * \param external_allocation_size The number of externally allocated
+ * bytes for peer. Used to inform the garbage collector.
+ * \param callback A callback to be called when this string is finalized.
+ *
+ * \return The String object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle
+Dart_NewExternalUTF16String(const uint16_t* utf16_array,
+ intptr_t length,
+ void* peer,
+ intptr_t external_allocation_size,
+ Dart_HandleFinalizer callback);
+
+/**
+ * Gets the C string representation of a String.
+ * (It is a sequence of UTF-8 encoded values with a '\0' termination.)
+ *
+ * \param str A string.
+ * \param cstr Returns the String represented as a C string.
+ * This C string is scope allocated and is only valid until
+ * the next call to Dart_ExitScope.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_StringToCString(Dart_Handle str,
+ const char** cstr);
+
+/**
+ * Gets a UTF-8 encoded representation of a String.
+ *
+ * Any unpaired surrogate code points in the string will be converted as
+ * replacement characters (U+FFFD, 0xEF 0xBF 0xBD in UTF-8). If you need
+ * to preserve unpaired surrogates, use the Dart_StringToUTF16 function.
+ *
+ * \param str A string.
+ * \param utf8_array Returns the String represented as UTF-8 code
+ * units. This UTF-8 array is scope allocated and is only valid
+ * until the next call to Dart_ExitScope.
+ * \param length Used to return the length of the array which was
+ * actually used.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_StringToUTF8(Dart_Handle str,
+ uint8_t** utf8_array,
+ intptr_t* length);
+
+/**
+ * Gets the data corresponding to the string object. This function returns
+ * the data only for Latin-1 (ISO-8859-1) string objects. For all other
+ * string objects it returns an error.
+ *
+ * \param str A string.
+ * \param latin1_array An array allocated by the caller, used to return
+ * the string data.
+ * \param length Used to pass in the length of the provided array.
+ * Used to return the length of the array which was actually used.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_StringToLatin1(Dart_Handle str,
+ uint8_t* latin1_array,
+ intptr_t* length);
+
+/**
+ * Gets the UTF-16 encoded representation of a string.
+ *
+ * \param str A string.
+ * \param utf16_array An array allocated by the caller, used to return
+ * the array of UTF-16 encoded characters.
+ * \param length Used to pass in the length of the provided array.
+ * Used to return the length of the array which was actually used.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_StringToUTF16(Dart_Handle str,
+ uint16_t* utf16_array,
+ intptr_t* length);
+
+/**
+ * Gets the storage size in bytes of a String.
+ *
+ * \param str A String.
+ * \param length Returns the storage size in bytes of the String.
+ * This is the size in bytes needed to store the String.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_StringStorageSize(Dart_Handle str, intptr_t* size);
+
+/**
+ * Retrieves some properties associated with a String.
+ * Properties retrieved are:
+ * - character size of the string (one or two byte)
+ * - length of the string
+ * - peer pointer of string if it is an external string.
+ * \param str A String.
+ * \param char_size Returns the character size of the String.
+ * \param str_len Returns the length of the String.
+ * \param peer Returns the peer pointer associated with the String or 0 if
+ * there is no peer pointer for it.
+ * \return Success if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_StringGetProperties(Dart_Handle str,
+ intptr_t* char_size,
+ intptr_t* str_len,
+ void** peer);
+
+/*
+ * =====
+ * Lists
+ * =====
+ */
+
+/**
+ * Returns a List of the desired length.
+ *
+ * \param length The length of the list.
+ *
+ * \return The List object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewList(intptr_t length);
+
+typedef enum {
+ Dart_CoreType_Dynamic,
+ Dart_CoreType_Int,
+ Dart_CoreType_String,
+} Dart_CoreType_Id;
+
+// TODO(bkonyi): convert this to use nullable types once NNBD is enabled.
+/**
+ * Returns a List of the desired length with the desired legacy element type.
+ *
+ * \param element_type_id The type of elements of the list.
+ * \param length The length of the list.
+ *
+ * \return The List object if no error occurs. Otherwise returns an error
+ * handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewListOf(Dart_CoreType_Id element_type_id,
+ intptr_t length);
+
+/**
+ * Returns a List of the desired length with the desired element type.
+ *
+ * \param element_type Handle to a nullable type object. E.g., from
+ * Dart_GetType or Dart_GetNullableType.
+ *
+ * \param length The length of the list.
+ *
+ * \return The List object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewListOfType(Dart_Handle element_type,
+ intptr_t length);
+
+/**
+ * Returns a List of the desired length with the desired element type, filled
+ * with the provided object.
+ *
+ * \param element_type Handle to a type object. E.g., from Dart_GetType.
+ *
+ * \param fill_object Handle to an object of type 'element_type' that will be
+ * used to populate the list. This parameter can only be Dart_Null() if the
+ * length of the list is 0 or 'element_type' is a nullable type.
+ *
+ * \param length The length of the list.
+ *
+ * \return The List object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewListOfTypeFilled(Dart_Handle element_type,
+ Dart_Handle fill_object,
+ intptr_t length);
+
+/**
+ * Gets the length of a List.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param list A List.
+ * \param length Returns the length of the List.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_ListLength(Dart_Handle list, intptr_t* length);
+
+/**
+ * Gets the Object at some index of a List.
+ *
+ * If the index is out of bounds, an error occurs.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param list A List.
+ * \param index A valid index into the List.
+ *
+ * \return The Object in the List at the specified index if no error
+ * occurs. Otherwise returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_ListGetAt(Dart_Handle list, intptr_t index);
+
+/**
+* Gets a range of Objects from a List.
+*
+* If any of the requested index values are out of bounds, an error occurs.
+*
+* May generate an unhandled exception error.
+*
+* \param list A List.
+* \param offset The offset of the first item to get.
+* \param length The number of items to get.
+* \param result A pointer to fill with the objects.
+*
+* \return Success if no error occurs during the operation.
+*/
+DART_EXPORT Dart_Handle Dart_ListGetRange(Dart_Handle list,
+ intptr_t offset,
+ intptr_t length,
+ Dart_Handle* result);
+
+/**
+ * Sets the Object at some index of a List.
+ *
+ * If the index is out of bounds, an error occurs.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param array A List.
+ * \param index A valid index into the List.
+ * \param value The Object to put in the List.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_ListSetAt(Dart_Handle list,
+ intptr_t index,
+ Dart_Handle value);
+
+/**
+ * May generate an unhandled exception error.
+ */
+DART_EXPORT Dart_Handle Dart_ListGetAsBytes(Dart_Handle list,
+ intptr_t offset,
+ uint8_t* native_array,
+ intptr_t length);
+
+/**
+ * May generate an unhandled exception error.
+ */
+DART_EXPORT Dart_Handle Dart_ListSetAsBytes(Dart_Handle list,
+ intptr_t offset,
+ const uint8_t* native_array,
+ intptr_t length);
+
+/*
+ * ====
+ * Maps
+ * ====
+ */
+
+/**
+ * Gets the Object at some key of a Map.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param map A Map.
+ * \param key An Object.
+ *
+ * \return The value in the map at the specified key, null if the map does not
+ * contain the key, or an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_MapGetAt(Dart_Handle map, Dart_Handle key);
+
+/**
+ * Returns whether the Map contains a given key.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param map A Map.
+ *
+ * \return A handle on a boolean indicating whether map contains the key.
+ * Otherwise returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_MapContainsKey(Dart_Handle map, Dart_Handle key);
+
+/**
+ * Gets the list of keys of a Map.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param map A Map.
+ *
+ * \return The list of key Objects if no error occurs. Otherwise returns an
+ * error handle.
+ */
+DART_EXPORT Dart_Handle Dart_MapKeys(Dart_Handle map);
+
+/*
+ * ==========
+ * Typed Data
+ * ==========
+ */
+
+typedef enum {
+ Dart_TypedData_kByteData = 0,
+ Dart_TypedData_kInt8,
+ Dart_TypedData_kUint8,
+ Dart_TypedData_kUint8Clamped,
+ Dart_TypedData_kInt16,
+ Dart_TypedData_kUint16,
+ Dart_TypedData_kInt32,
+ Dart_TypedData_kUint32,
+ Dart_TypedData_kInt64,
+ Dart_TypedData_kUint64,
+ Dart_TypedData_kFloat32,
+ Dart_TypedData_kFloat64,
+ Dart_TypedData_kInt32x4,
+ Dart_TypedData_kFloat32x4,
+ Dart_TypedData_kFloat64x2,
+ Dart_TypedData_kInvalid
+} Dart_TypedData_Type;
+
+/**
+ * Return type if this object is a TypedData object.
+ *
+ * \return kInvalid if the object is not a TypedData object or the appropriate
+ * Dart_TypedData_Type.
+ */
+DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfTypedData(Dart_Handle object);
+
+/**
+ * Return type if this object is an external TypedData object.
+ *
+ * \return kInvalid if the object is not an external TypedData object or
+ * the appropriate Dart_TypedData_Type.
+ */
+DART_EXPORT Dart_TypedData_Type
+Dart_GetTypeOfExternalTypedData(Dart_Handle object);
+
+/**
+ * Returns a TypedData object of the desired length and type.
+ *
+ * \param type The type of the TypedData object.
+ * \param length The length of the TypedData object (length in type units).
+ *
+ * \return The TypedData object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewTypedData(Dart_TypedData_Type type,
+ intptr_t length);
+
+/**
+ * Returns a TypedData object which references an external data array.
+ *
+ * \param type The type of the data array.
+ * \param data A data array. This array must not move.
+ * \param length The length of the data array (length in type units).
+ *
+ * \return The TypedData object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewExternalTypedData(Dart_TypedData_Type type,
+ void* data,
+ intptr_t length);
+
+/**
+ * Returns a TypedData object which references an external data array.
+ *
+ * \param type The type of the data array.
+ * \param data A data array. This array must not move.
+ * \param length The length of the data array (length in type units).
+ * \param peer A pointer to a native object or NULL. This value is
+ * provided to callback when it is invoked.
+ * \param external_allocation_size The number of externally allocated
+ * bytes for peer. Used to inform the garbage collector.
+ * \param callback A function pointer that will be invoked sometime
+ * after the object is garbage collected, unless the handle has been deleted.
+ * A valid callback needs to be specified it cannot be NULL.
+ *
+ * \return The TypedData object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle
+Dart_NewExternalTypedDataWithFinalizer(Dart_TypedData_Type type,
+ void* data,
+ intptr_t length,
+ void* peer,
+ intptr_t external_allocation_size,
+ Dart_HandleFinalizer callback);
+
+/**
+ * Returns a ByteBuffer object for the typed data.
+ *
+ * \param type_data The TypedData object.
+ *
+ * \return The ByteBuffer object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewByteBuffer(Dart_Handle typed_data);
+
+/**
+ * Acquires access to the internal data address of a TypedData object.
+ *
+ * \param object The typed data object whose internal data address is to
+ * be accessed.
+ * \param type The type of the object is returned here.
+ * \param data The internal data address is returned here.
+ * \param len Size of the typed array is returned here.
+ *
+ * Notes:
+ * When the internal address of the object is acquired any calls to a
+ * Dart API function that could potentially allocate an object or run
+ * any Dart code will return an error.
+ *
+ * Any Dart API functions for accessing the data should not be called
+ * before the corresponding release. In particular, the object should
+ * not be acquired again before its release. This leads to undefined
+ * behavior.
+ *
+ * \return Success if the internal data address is acquired successfully.
+ * Otherwise, returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_TypedDataAcquireData(Dart_Handle object,
+ Dart_TypedData_Type* type,
+ void** data,
+ intptr_t* len);
+
+/**
+ * Releases access to the internal data address that was acquired earlier using
+ * Dart_TypedDataAcquireData.
+ *
+ * \param object The typed data object whose internal data address is to be
+ * released.
+ *
+ * \return Success if the internal data address is released successfully.
+ * Otherwise, returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object);
+
+/**
+ * Returns the TypedData object associated with the ByteBuffer object.
+ *
+ * \param byte_buffer The ByteBuffer object.
+ *
+ * \return The TypedData object if no error occurs. Otherwise returns
+ * an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_GetDataFromByteBuffer(Dart_Handle byte_buffer);
+
+/*
+ * ============================================================
+ * Invoking Constructors, Methods, Closures and Field accessors
+ * ============================================================
+ */
+
+/**
+ * Invokes a constructor, creating a new object.
+ *
+ * This function allows hidden constructors (constructors with leading
+ * underscores) to be called.
+ *
+ * \param type Type of object to be constructed.
+ * \param constructor_name The name of the constructor to invoke. Use
+ * Dart_Null() or Dart_EmptyString() to invoke the unnamed constructor.
+ * This name should not include the name of the class.
+ * \param number_of_arguments Size of the arguments array.
+ * \param arguments An array of arguments to the constructor.
+ *
+ * \return If the constructor is called and completes successfully,
+ * then the new object. If an error occurs during execution, then an
+ * error handle is returned.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_New(Dart_Handle type,
+ Dart_Handle constructor_name,
+ int number_of_arguments,
+ Dart_Handle* arguments);
+
+/**
+ * Allocate a new object without invoking a constructor.
+ *
+ * \param type The type of an object to be allocated.
+ *
+ * \return The new object. If an error occurs during execution, then an
+ * error handle is returned.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_Allocate(Dart_Handle type);
+
+/**
+ * Allocate a new object without invoking a constructor, and sets specified
+ * native fields.
+ *
+ * \param type The type of an object to be allocated.
+ * \param num_native_fields The number of native fields to set.
+ * \param native_fields An array containing the value of native fields.
+ *
+ * \return The new object. If an error occurs during execution, then an
+ * error handle is returned.
+ */
+DART_EXPORT Dart_Handle
+Dart_AllocateWithNativeFields(Dart_Handle type,
+ intptr_t num_native_fields,
+ const intptr_t* native_fields);
+
+/**
+ * Invokes a method or function.
+ *
+ * The 'target' parameter may be an object, type, or library. If
+ * 'target' is an object, then this function will invoke an instance
+ * method. If 'target' is a type, then this function will invoke a
+ * static method. If 'target' is a library, then this function will
+ * invoke a top-level function from that library.
+ * NOTE: This API call cannot be used to invoke methods of a type object.
+ *
+ * This function ignores visibility (leading underscores in names).
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param target An object, type, or library.
+ * \param name The name of the function or method to invoke.
+ * \param number_of_arguments Size of the arguments array.
+ * \param arguments An array of arguments to the function.
+ *
+ * \return If the function or method is called and completes
+ * successfully, then the return value is returned. If an error
+ * occurs during execution, then an error handle is returned.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_Invoke(Dart_Handle target,
+ Dart_Handle name,
+ int number_of_arguments,
+ Dart_Handle* arguments);
+/* TODO(turnidge): Document how to invoke operators. */
+
+/**
+ * Invokes a Closure with the given arguments.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \return If no error occurs during execution, then the result of
+ * invoking the closure is returned. If an error occurs during
+ * execution, then an error handle is returned.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_InvokeClosure(Dart_Handle closure,
+ int number_of_arguments,
+ Dart_Handle* arguments);
+
+/**
+ * Invokes a Generative Constructor on an object that was previously
+ * allocated using Dart_Allocate/Dart_AllocateWithNativeFields.
+ *
+ * The 'target' parameter must be an object.
+ *
+ * This function ignores visibility (leading underscores in names).
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param target An object.
+ * \param name The name of the constructor to invoke.
+ * Use Dart_Null() or Dart_EmptyString() to invoke the unnamed constructor.
+ * \param number_of_arguments Size of the arguments array.
+ * \param arguments An array of arguments to the function.
+ *
+ * \return If the constructor is called and completes
+ * successfully, then the object is returned. If an error
+ * occurs during execution, then an error handle is returned.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_InvokeConstructor(Dart_Handle object,
+ Dart_Handle name,
+ int number_of_arguments,
+ Dart_Handle* arguments);
+
+/**
+ * Gets the value of a field.
+ *
+ * The 'container' parameter may be an object, type, or library. If
+ * 'container' is an object, then this function will access an
+ * instance field. If 'container' is a type, then this function will
+ * access a static field. If 'container' is a library, then this
+ * function will access a top-level variable.
+ * NOTE: This API call cannot be used to access fields of a type object.
+ *
+ * This function ignores field visibility (leading underscores in names).
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param container An object, type, or library.
+ * \param name A field name.
+ *
+ * \return If no error occurs, then the value of the field is
+ * returned. Otherwise an error handle is returned.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_GetField(Dart_Handle container, Dart_Handle name);
+
+/**
+ * Sets the value of a field.
+ *
+ * The 'container' parameter may actually be an object, type, or
+ * library. If 'container' is an object, then this function will
+ * access an instance field. If 'container' is a type, then this
+ * function will access a static field. If 'container' is a library,
+ * then this function will access a top-level variable.
+ * NOTE: This API call cannot be used to access fields of a type object.
+ *
+ * This function ignores field visibility (leading underscores in names).
+ *
+ * May generate an unhandled exception error.
+ *
+ * \param container An object, type, or library.
+ * \param name A field name.
+ * \param value The new field value.
+ *
+ * \return A valid handle if no error occurs.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_SetField(Dart_Handle container, Dart_Handle name, Dart_Handle value);
+
+/*
+ * ==========
+ * Exceptions
+ * ==========
+ */
+
+/*
+ * TODO(turnidge): Remove these functions from the api and replace all
+ * uses with Dart_NewUnhandledExceptionError. */
+
+/**
+ * Throws an exception.
+ *
+ * This function causes a Dart language exception to be thrown. This
+ * will proceed in the standard way, walking up Dart frames until an
+ * appropriate 'catch' block is found, executing 'finally' blocks,
+ * etc.
+ *
+ * If an error handle is passed into this function, the error is
+ * propagated immediately. See Dart_PropagateError for a discussion
+ * of error propagation.
+ *
+ * If successful, this function does not return. Note that this means
+ * that the destructors of any stack-allocated C++ objects will not be
+ * called. If there are no Dart frames on the stack, an error occurs.
+ *
+ * \return An error handle if the exception was not thrown.
+ * Otherwise the function does not return.
+ */
+DART_EXPORT Dart_Handle Dart_ThrowException(Dart_Handle exception);
+
+/**
+ * Rethrows an exception.
+ *
+ * Rethrows an exception, unwinding all dart frames on the stack. If
+ * successful, this function does not return. Note that this means
+ * that the destructors of any stack-allocated C++ objects will not be
+ * called. If there are no Dart frames on the stack, an error occurs.
+ *
+ * \return An error handle if the exception was not thrown.
+ * Otherwise the function does not return.
+ */
+DART_EXPORT Dart_Handle Dart_ReThrowException(Dart_Handle exception,
+ Dart_Handle stacktrace);
+
+/*
+ * ===========================
+ * Native fields and functions
+ * ===========================
+ */
+
+/**
+ * Gets the number of native instance fields in an object.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeInstanceFieldCount(Dart_Handle obj,
+ int* count);
+
+/**
+ * Gets the value of a native field.
+ *
+ * TODO(turnidge): Document.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeInstanceField(Dart_Handle obj,
+ int index,
+ intptr_t* value);
+
+/**
+ * Sets the value of a native field.
+ *
+ * TODO(turnidge): Document.
+ */
+DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj,
+ int index,
+ intptr_t value);
+
+/**
+ * The arguments to a native function.
+ *
+ * This object is passed to a native function to represent its
+ * arguments and return value. It allows access to the arguments to a
+ * native function by index. It also allows the return value of a
+ * native function to be set.
+ */
+typedef struct _Dart_NativeArguments* Dart_NativeArguments;
+
+/**
+ * Extracts current isolate group data from the native arguments structure.
+ */
+DART_EXPORT void* Dart_GetNativeIsolateGroupData(Dart_NativeArguments args);
+
+typedef enum {
+ Dart_NativeArgument_kBool = 0,
+ Dart_NativeArgument_kInt32,
+ Dart_NativeArgument_kUint32,
+ Dart_NativeArgument_kInt64,
+ Dart_NativeArgument_kUint64,
+ Dart_NativeArgument_kDouble,
+ Dart_NativeArgument_kString,
+ Dart_NativeArgument_kInstance,
+ Dart_NativeArgument_kNativeFields,
+} Dart_NativeArgument_Type;
+
+typedef struct _Dart_NativeArgument_Descriptor {
+ uint8_t type;
+ uint8_t index;
+} Dart_NativeArgument_Descriptor;
+
+typedef union _Dart_NativeArgument_Value {
+ bool as_bool;
+ int32_t as_int32;
+ uint32_t as_uint32;
+ int64_t as_int64;
+ uint64_t as_uint64;
+ double as_double;
+ struct {
+ Dart_Handle dart_str;
+ void* peer;
+ } as_string;
+ struct {
+ intptr_t num_fields;
+ intptr_t* values;
+ } as_native_fields;
+ Dart_Handle as_instance;
+} Dart_NativeArgument_Value;
+
+enum {
+ kNativeArgNumberPos = 0,
+ kNativeArgNumberSize = 8,
+ kNativeArgTypePos = kNativeArgNumberPos + kNativeArgNumberSize,
+ kNativeArgTypeSize = 8,
+};
+
+#define BITMASK(size) ((1 << size) - 1)
+#define DART_NATIVE_ARG_DESCRIPTOR(type, position) \
+ (((type & BITMASK(kNativeArgTypeSize)) << kNativeArgTypePos) | \
+ (position & BITMASK(kNativeArgNumberSize)))
+
+/**
+ * Gets the native arguments based on the types passed in and populates
+ * the passed arguments buffer with appropriate native values.
+ *
+ * \param args the Native arguments block passed into the native call.
+ * \param num_arguments length of argument descriptor array and argument
+ * values array passed in.
+ * \param arg_descriptors an array that describes the arguments that
+ * need to be retrieved. For each argument to be retrieved the descriptor
+ * contains the argument number (0, 1 etc.) and the argument type
+ * described using Dart_NativeArgument_Type, e.g:
+ * DART_NATIVE_ARG_DESCRIPTOR(Dart_NativeArgument_kBool, 1) indicates
+ * that the first argument is to be retrieved and it should be a boolean.
+ * \param arg_values array into which the native arguments need to be
+ * extracted into, the array is allocated by the caller (it could be
+ * stack allocated to avoid the malloc/free performance overhead).
+ *
+ * \return Success if all the arguments could be extracted correctly,
+ * returns an error handle if there were any errors while extracting the
+ * arguments (mismatched number of arguments, incorrect types, etc.).
+ */
+DART_EXPORT Dart_Handle
+Dart_GetNativeArguments(Dart_NativeArguments args,
+ int num_arguments,
+ const Dart_NativeArgument_Descriptor* arg_descriptors,
+ Dart_NativeArgument_Value* arg_values);
+
+/**
+ * Gets the native argument at some index.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args,
+ int index);
+/* TODO(turnidge): Specify the behavior of an out-of-bounds access. */
+
+/**
+ * Gets the number of native arguments.
+ */
+DART_EXPORT int Dart_GetNativeArgumentCount(Dart_NativeArguments args);
+
+/**
+ * Gets all the native fields of the native argument at some index.
+ * \param args Native arguments structure.
+ * \param arg_index Index of the desired argument in the structure above.
+ * \param num_fields size of the intptr_t array 'field_values' passed in.
+ * \param field_values intptr_t array in which native field values are returned.
+ * \return Success if the native fields where copied in successfully. Otherwise
+ * returns an error handle. On success the native field values are copied
+ * into the 'field_values' array, if the argument at 'arg_index' is a
+ * null object then 0 is copied as the native field values into the
+ * 'field_values' array.
+ */
+DART_EXPORT Dart_Handle
+Dart_GetNativeFieldsOfArgument(Dart_NativeArguments args,
+ int arg_index,
+ int num_fields,
+ intptr_t* field_values);
+
+/**
+ * Gets the native field of the receiver.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeReceiver(Dart_NativeArguments args,
+ intptr_t* value);
+
+/**
+ * Gets a string native argument at some index.
+ * \param args Native arguments structure.
+ * \param arg_index Index of the desired argument in the structure above.
+ * \param peer Returns the peer pointer if the string argument has one.
+ * \return Success if the string argument has a peer, if it does not
+ * have a peer then the String object is returned. Otherwise returns
+ * an error handle (argument is not a String object).
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeStringArgument(Dart_NativeArguments args,
+ int arg_index,
+ void** peer);
+
+/**
+ * Gets an integer native argument at some index.
+ * \param args Native arguments structure.
+ * \param arg_index Index of the desired argument in the structure above.
+ * \param value Returns the integer value if the argument is an Integer.
+ * \return Success if no error occurs. Otherwise returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeIntegerArgument(Dart_NativeArguments args,
+ int index,
+ int64_t* value);
+
+/**
+ * Gets a boolean native argument at some index.
+ * \param args Native arguments structure.
+ * \param arg_index Index of the desired argument in the structure above.
+ * \param value Returns the boolean value if the argument is a Boolean.
+ * \return Success if no error occurs. Otherwise returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeBooleanArgument(Dart_NativeArguments args,
+ int index,
+ bool* value);
+
+/**
+ * Gets a double native argument at some index.
+ * \param args Native arguments structure.
+ * \param arg_index Index of the desired argument in the structure above.
+ * \param value Returns the double value if the argument is a double.
+ * \return Success if no error occurs. Otherwise returns an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeDoubleArgument(Dart_NativeArguments args,
+ int index,
+ double* value);
+
+/**
+ * Sets the return value for a native function.
+ *
+ * If retval is an Error handle, then error will be propagated once
+ * the native functions exits. See Dart_PropagateError for a
+ * discussion of how different types of errors are propagated.
+ */
+DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args,
+ Dart_Handle retval);
+
+DART_EXPORT void Dart_SetWeakHandleReturnValue(Dart_NativeArguments args,
+ Dart_WeakPersistentHandle rval);
+
+DART_EXPORT void Dart_SetBooleanReturnValue(Dart_NativeArguments args,
+ bool retval);
+
+DART_EXPORT void Dart_SetIntegerReturnValue(Dart_NativeArguments args,
+ int64_t retval);
+
+DART_EXPORT void Dart_SetDoubleReturnValue(Dart_NativeArguments args,
+ double retval);
+
+/**
+ * A native function.
+ */
+typedef void (*Dart_NativeFunction)(Dart_NativeArguments arguments);
+
+/**
+ * Native entry resolution callback.
+ *
+ * For libraries and scripts which have native functions, the embedder
+ * can provide a native entry resolver. This callback is used to map a
+ * name/arity to a Dart_NativeFunction. If no function is found, the
+ * callback should return NULL.
+ *
+ * The parameters to the native resolver function are:
+ * \param name a Dart string which is the name of the native function.
+ * \param num_of_arguments is the number of arguments expected by the
+ * native function.
+ * \param auto_setup_scope is a boolean flag that can be set by the resolver
+ * to indicate if this function needs a Dart API scope (see Dart_EnterScope/
+ * Dart_ExitScope) to be setup automatically by the VM before calling into
+ * the native function. By default most native functions would require this
+ * to be true but some light weight native functions which do not call back
+ * into the VM through the Dart API may not require a Dart scope to be
+ * setup automatically.
+ *
+ * \return A valid Dart_NativeFunction which resolves to a native entry point
+ * for the native function.
+ *
+ * See Dart_SetNativeResolver.
+ */
+typedef Dart_NativeFunction (*Dart_NativeEntryResolver)(Dart_Handle name,
+ int num_of_arguments,
+ bool* auto_setup_scope);
+/* TODO(turnidge): Consider renaming to NativeFunctionResolver or
+ * NativeResolver. */
+
+/**
+ * Native entry symbol lookup callback.
+ *
+ * For libraries and scripts which have native functions, the embedder
+ * can provide a callback for mapping a native entry to a symbol. This callback
+ * maps a native function entry PC to the native function name. If no native
+ * entry symbol can be found, the callback should return NULL.
+ *
+ * The parameters to the native reverse resolver function are:
+ * \param nf A Dart_NativeFunction.
+ *
+ * \return A const UTF-8 string containing the symbol name or NULL.
+ *
+ * See Dart_SetNativeResolver.
+ */
+typedef const uint8_t* (*Dart_NativeEntrySymbol)(Dart_NativeFunction nf);
+
+/*
+ * ===========
+ * Environment
+ * ===========
+ */
+
+/**
+ * An environment lookup callback function.
+ *
+ * \param name The name of the value to lookup in the environment.
+ *
+ * \return A valid handle to a string if the name exists in the
+ * current environment or Dart_Null() if not.
+ */
+typedef Dart_Handle (*Dart_EnvironmentCallback)(Dart_Handle name);
+
+/**
+ * Sets the environment callback for the current isolate. This
+ * callback is used to lookup environment values by name in the
+ * current environment. This enables the embedder to supply values for
+ * the const constructors bool.fromEnvironment, int.fromEnvironment
+ * and String.fromEnvironment.
+ */
+DART_EXPORT Dart_Handle
+Dart_SetEnvironmentCallback(Dart_EnvironmentCallback callback);
+
+/**
+ * Sets the callback used to resolve native functions for a library.
+ *
+ * \param library A library.
+ * \param resolver A native entry resolver.
+ *
+ * \return A valid handle if the native resolver was set successfully.
+ */
+DART_EXPORT Dart_Handle
+Dart_SetNativeResolver(Dart_Handle library,
+ Dart_NativeEntryResolver resolver,
+ Dart_NativeEntrySymbol symbol);
+/* TODO(turnidge): Rename to Dart_LibrarySetNativeResolver? */
+
+/**
+ * Returns the callback used to resolve native functions for a library.
+ *
+ * \param library A library.
+ * \param resolver a pointer to a Dart_NativeEntryResolver
+ *
+ * \return A valid handle if the library was found.
+ */
+DART_EXPORT Dart_Handle
+Dart_GetNativeResolver(Dart_Handle library, Dart_NativeEntryResolver* resolver);
+
+/**
+ * Returns the callback used to resolve native function symbols for a library.
+ *
+ * \param library A library.
+ * \param resolver a pointer to a Dart_NativeEntrySymbol.
+ *
+ * \return A valid handle if the library was found.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeSymbol(Dart_Handle library,
+ Dart_NativeEntrySymbol* resolver);
+
+/*
+ * =====================
+ * Scripts and Libraries
+ * =====================
+ */
+
+typedef enum {
+ Dart_kCanonicalizeUrl = 0,
+ Dart_kImportTag,
+ Dart_kKernelTag,
+ Dart_kImportExtensionTag,
+} Dart_LibraryTag;
+
+/**
+ * The library tag handler is a multi-purpose callback provided by the
+ * embedder to the Dart VM. The embedder implements the tag handler to
+ * provide the ability to load Dart scripts and imports.
+ *
+ * -- TAGS --
+ *
+ * Dart_kCanonicalizeUrl
+ *
+ * This tag indicates that the embedder should canonicalize 'url' with
+ * respect to 'library'. For most embedders, the
+ * Dart_DefaultCanonicalizeUrl function is a sufficient implementation
+ * of this tag. The return value should be a string holding the
+ * canonicalized url.
+ *
+ * Dart_kImportTag
+ *
+ * This tag is used to load a library from IsolateMirror.loadUri. The embedder
+ * should call Dart_LoadLibraryFromKernel to provide the library to the VM. The
+ * return value should be an error or library (the result from
+ * Dart_LoadLibraryFromKernel).
+ *
+ * Dart_kKernelTag
+ *
+ * This tag is used to load the intermediate file (kernel) generated by
+ * the Dart front end. This tag is typically used when a 'hot-reload'
+ * of an application is needed and the VM is 'use dart front end' mode.
+ * The dart front end typically compiles all the scripts, imports and part
+ * files into one intermediate file hence we don't use the source/import or
+ * script tags. The return value should be an error or a TypedData containing
+ * the kernel bytes.
+ *
+ * Dart_kImportExtensionTag
+ *
+ * This tag is used to load an external import (shared object file). The
+ * extension path must have the scheme 'dart-ext:'.
+ */
+typedef Dart_Handle (*Dart_LibraryTagHandler)(
+ Dart_LibraryTag tag,
+ Dart_Handle library_or_package_map_url,
+ Dart_Handle url);
+
+/**
+ * Sets library tag handler for the current isolate. This handler is
+ * used to handle the various tags encountered while loading libraries
+ * or scripts in the isolate.
+ *
+ * \param handler Handler code to be used for handling the various tags
+ * encountered while loading libraries or scripts in the isolate.
+ *
+ * \return If no error occurs, the handler is set for the isolate.
+ * Otherwise an error handle is returned.
+ *
+ * TODO(turnidge): Document.
+ */
+DART_EXPORT Dart_Handle
+Dart_SetLibraryTagHandler(Dart_LibraryTagHandler handler);
+
+/**
+ * Handles deferred loading requests. When this handler is invoked, it should
+ * eventually load the deferred loading unit with the given id and call
+ * Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError. It is
+ * recommended that the loading occur asynchronously, but it is permitted to
+ * call Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError before the
+ * handler returns.
+ *
+ * If an error is returned, it will be propogated through
+ * `prefix.loadLibrary()`. This is useful for synchronous
+ * implementations, which must propogate any unwind errors from
+ * Dart_DeferredLoadComplete or Dart_DeferredLoadComplete. Otherwise the handler
+ * should return a non-error such as `Dart_Null()`.
+ */
+typedef Dart_Handle (*Dart_DeferredLoadHandler)(intptr_t loading_unit_id);
+
+/**
+ * Sets the deferred load handler for the current isolate. This handler is
+ * used to handle loading deferred imports in an AppJIT or AppAOT program.
+ */
+DART_EXPORT Dart_Handle
+Dart_SetDeferredLoadHandler(Dart_DeferredLoadHandler handler);
+
+/**
+ * Notifies the VM that a deferred load completed successfully. This function
+ * will eventually cause the corresponding `prefix.loadLibrary()` futures to
+ * complete.
+ *
+ * Requires the current isolate to be the same current isolate during the
+ * invocation of the Dart_DeferredLoadHandler.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_DeferredLoadComplete(intptr_t loading_unit_id,
+ const uint8_t* snapshot_data,
+ const uint8_t* snapshot_instructions);
+
+/**
+ * Notifies the VM that a deferred load failed. This function
+ * will eventually cause the corresponding `prefix.loadLibrary()` futures to
+ * complete with an error.
+ *
+ * If `transient` is true, future invocations of `prefix.loadLibrary()` will
+ * trigger new load requests. If false, futures invocation will complete with
+ * the same error.
+ *
+ * Requires the current isolate to be the same current isolate during the
+ * invocation of the Dart_DeferredLoadHandler.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_DeferredLoadCompleteError(intptr_t loading_unit_id,
+ const char* error_message,
+ bool transient);
+
+/**
+ * Canonicalizes a url with respect to some library.
+ *
+ * The url is resolved with respect to the library's url and some url
+ * normalizations are performed.
+ *
+ * This canonicalization function should be sufficient for most
+ * embedders to implement the Dart_kCanonicalizeUrl tag.
+ *
+ * \param base_url The base url relative to which the url is
+ * being resolved.
+ * \param url The url being resolved and canonicalized. This
+ * parameter is a string handle.
+ *
+ * \return If no error occurs, a String object is returned. Otherwise
+ * an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_DefaultCanonicalizeUrl(Dart_Handle base_url,
+ Dart_Handle url);
+
+/**
+ * Loads the root library for the current isolate.
+ *
+ * Requires there to be no current root library.
+ *
+ * \param buffer A buffer which contains a kernel binary (see
+ * pkg/kernel/binary.md). Must remain valid until isolate group shutdown.
+ * \param buffer_size Length of the passed in buffer.
+ *
+ * \return A handle to the root library, or an error.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_LoadScriptFromKernel(const uint8_t* kernel_buffer, intptr_t kernel_size);
+
+/**
+ * Gets the library for the root script for the current isolate.
+ *
+ * If the root script has not yet been set for the current isolate,
+ * this function returns Dart_Null(). This function never returns an
+ * error handle.
+ *
+ * \return Returns the root Library for the current isolate or Dart_Null().
+ */
+DART_EXPORT Dart_Handle Dart_RootLibrary();
+
+/**
+ * Sets the root library for the current isolate.
+ *
+ * \return Returns an error handle if `library` is not a library handle.
+ */
+DART_EXPORT Dart_Handle Dart_SetRootLibrary(Dart_Handle library);
+
+/**
+ * Lookup or instantiate a legacy type by name and type arguments from a
+ * Library.
+ *
+ * \param library The library containing the class or interface.
+ * \param class_name The class name for the type.
+ * \param number_of_type_arguments Number of type arguments.
+ * For non parametric types the number of type arguments would be 0.
+ * \param type_arguments Pointer to an array of type arguments.
+ * For non parameteric types a NULL would be passed in for this argument.
+ *
+ * \return If no error occurs, the type is returned.
+ * Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_GetType(Dart_Handle library,
+ Dart_Handle class_name,
+ intptr_t number_of_type_arguments,
+ Dart_Handle* type_arguments);
+
+/**
+ * Lookup or instantiate a nullable type by name and type arguments from
+ * Library.
+ *
+ * \param library The library containing the class or interface.
+ * \param class_name The class name for the type.
+ * \param number_of_type_arguments Number of type arguments.
+ * For non parametric types the number of type arguments would be 0.
+ * \param type_arguments Pointer to an array of type arguments.
+ * For non parameteric types a NULL would be passed in for this argument.
+ *
+ * \return If no error occurs, the type is returned.
+ * Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_GetNullableType(Dart_Handle library,
+ Dart_Handle class_name,
+ intptr_t number_of_type_arguments,
+ Dart_Handle* type_arguments);
+
+/**
+ * Lookup or instantiate a non-nullable type by name and type arguments from
+ * Library.
+ *
+ * \param library The library containing the class or interface.
+ * \param class_name The class name for the type.
+ * \param number_of_type_arguments Number of type arguments.
+ * For non parametric types the number of type arguments would be 0.
+ * \param type_arguments Pointer to an array of type arguments.
+ * For non parameteric types a NULL would be passed in for this argument.
+ *
+ * \return If no error occurs, the type is returned.
+ * Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle
+Dart_GetNonNullableType(Dart_Handle library,
+ Dart_Handle class_name,
+ intptr_t number_of_type_arguments,
+ Dart_Handle* type_arguments);
+
+/**
+ * Creates a nullable version of the provided type.
+ *
+ * \param type The type to be converted to a nullable type.
+ *
+ * \return If no error occurs, a nullable type is returned.
+ * Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_TypeToNullableType(Dart_Handle type);
+
+/**
+ * Creates a non-nullable version of the provided type.
+ *
+ * \param type The type to be converted to a non-nullable type.
+ *
+ * \return If no error occurs, a non-nullable type is returned.
+ * Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_TypeToNonNullableType(Dart_Handle type);
+
+/**
+ * A type's nullability.
+ *
+ * \param type A Dart type.
+ * \param result An out parameter containing the result of the check. True if
+ * the type is of the specified nullability, false otherwise.
+ *
+ * \return Returns an error handle if type is not of type Type.
+ */
+DART_EXPORT Dart_Handle Dart_IsNullableType(Dart_Handle type, bool* result);
+DART_EXPORT Dart_Handle Dart_IsNonNullableType(Dart_Handle type, bool* result);
+DART_EXPORT Dart_Handle Dart_IsLegacyType(Dart_Handle type, bool* result);
+
+/**
+ * Lookup a class or interface by name from a Library.
+ *
+ * \param library The library containing the class or interface.
+ * \param class_name The name of the class or interface.
+ *
+ * \return If no error occurs, the class or interface is
+ * returned. Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_GetClass(Dart_Handle library,
+ Dart_Handle class_name);
+/* TODO(asiva): The above method needs to be removed once all uses
+ * of it are removed from the embedder code. */
+
+/**
+ * Returns an import path to a Library, such as "file:///test.dart" or
+ * "dart:core".
+ */
+DART_EXPORT Dart_Handle Dart_LibraryUrl(Dart_Handle library);
+
+/**
+ * Returns a URL from which a Library was loaded.
+ */
+DART_EXPORT Dart_Handle Dart_LibraryResolvedUrl(Dart_Handle library);
+
+/**
+ * \return An array of libraries.
+ */
+DART_EXPORT Dart_Handle Dart_GetLoadedLibraries();
+
+DART_EXPORT Dart_Handle Dart_LookupLibrary(Dart_Handle url);
+/* TODO(turnidge): Consider returning Dart_Null() when the library is
+ * not found to distinguish that from a true error case. */
+
+/**
+ * Report an loading error for the library.
+ *
+ * \param library The library that failed to load.
+ * \param error The Dart error instance containing the load error.
+ *
+ * \return If the VM handles the error, the return value is
+ * a null handle. If it doesn't handle the error, the error
+ * object is returned.
+ */
+DART_EXPORT Dart_Handle Dart_LibraryHandleError(Dart_Handle library,
+ Dart_Handle error);
+
+/**
+ * Called by the embedder to load a partial program. Does not set the root
+ * library.
+ *
+ * \param buffer A buffer which contains a kernel binary (see
+ * pkg/kernel/binary.md). Must remain valid until isolate shutdown.
+ * \param buffer_size Length of the passed in buffer.
+ *
+ * \return A handle to the main library of the compilation unit, or an error.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_LoadLibraryFromKernel(const uint8_t* kernel_buffer,
+ intptr_t kernel_buffer_size);
+
+/**
+ * Returns a flattened list of pairs. The first element in each pair is the
+ * importing library and and the second element is the imported library for each
+ * import in the isolate of a library whose URI's scheme is [scheme].
+ *
+ * Requires there to be a current isolate.
+ *
+ * \return A handle to a list of flattened pairs of importer-importee.
+ */
+DART_EXPORT Dart_Handle Dart_GetImportsOfScheme(Dart_Handle scheme);
+
+/**
+ * Indicates that all outstanding load requests have been satisfied.
+ * This finalizes all the new classes loaded and optionally completes
+ * deferred library futures.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \param complete_futures Specify true if all deferred library
+ * futures should be completed, false otherwise.
+ *
+ * \return Success if all classes have been finalized and deferred library
+ * futures are completed. Otherwise, returns an error.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_FinalizeLoading(bool complete_futures);
+
+/*
+ * =====
+ * Peers
+ * =====
+ */
+
+/**
+ * The peer field is a lazily allocated field intended for storage of
+ * an uncommonly used values. Most instances types can have a peer
+ * field allocated. The exceptions are subtypes of Null, num, and
+ * bool.
+ */
+
+/**
+ * Returns the value of peer field of 'object' in 'peer'.
+ *
+ * \param object An object.
+ * \param peer An out parameter that returns the value of the peer
+ * field.
+ *
+ * \return Returns an error if 'object' is a subtype of Null, num, or
+ * bool.
+ */
+DART_EXPORT Dart_Handle Dart_GetPeer(Dart_Handle object, void** peer);
+
+/**
+ * Sets the value of the peer field of 'object' to the value of
+ * 'peer'.
+ *
+ * \param object An object.
+ * \param peer A value to store in the peer field.
+ *
+ * \return Returns an error if 'object' is a subtype of Null, num, or
+ * bool.
+ */
+DART_EXPORT Dart_Handle Dart_SetPeer(Dart_Handle object, void* peer);
+
+/*
+ * ======
+ * Kernel
+ * ======
+ */
+
+/**
+ * Experimental support for Dart to Kernel parser isolate.
+ *
+ * TODO(hausner): Document finalized interface.
+ *
+ */
+
+// TODO(33433): Remove kernel service from the embedding API.
+
+typedef enum {
+ Dart_KernelCompilationStatus_Unknown = -1,
+ Dart_KernelCompilationStatus_Ok = 0,
+ Dart_KernelCompilationStatus_Error = 1,
+ Dart_KernelCompilationStatus_Crash = 2,
+} Dart_KernelCompilationStatus;
+
+typedef struct {
+ Dart_KernelCompilationStatus status;
+ bool null_safety;
+ char* error;
+ uint8_t* kernel;
+ intptr_t kernel_size;
+} Dart_KernelCompilationResult;
+
+DART_EXPORT bool Dart_IsKernelIsolate(Dart_Isolate isolate);
+DART_EXPORT bool Dart_KernelIsolateIsRunning();
+DART_EXPORT Dart_Port Dart_KernelPort();
+
+/**
+ * Compiles the given `script_uri` to a kernel file.
+ *
+ * \param platform_kernel A buffer containing the kernel of the platform (e.g.
+ * `vm_platform_strong.dill`). The VM does not take ownership of this memory.
+ *
+ * \param platform_kernel_size The length of the platform_kernel buffer.
+ *
+ * \return Returns the result of the compilation.
+ *
+ * On a successful compilation the returned [Dart_KernelCompilationResult] has
+ * a status of [Dart_KernelCompilationStatus_Ok] and the `kernel`/`kernel_size`
+ * fields are set. The caller takes ownership of the malloc()ed buffer.
+ *
+ * On a failed compilation the `error` might be set describing the reason for
+ * the failed compilation. The caller takes ownership of the malloc()ed
+ * error.
+ *
+ * Requires there to be a current isolate.
+ */
+DART_EXPORT Dart_KernelCompilationResult
+Dart_CompileToKernel(const char* script_uri,
+ const uint8_t* platform_kernel,
+ const intptr_t platform_kernel_size,
+ bool incremental_compile,
+ const char* package_config);
+
+typedef struct {
+ const char* uri;
+ const char* source;
+} Dart_SourceFile;
+
+DART_EXPORT Dart_KernelCompilationResult Dart_KernelListDependencies();
+
+/**
+ * Sets the kernel buffer which will be used to load Dart SDK sources
+ * dynamically at runtime.
+ *
+ * \param platform_kernel A buffer containing kernel which has sources for the
+ * Dart SDK populated. Note: The VM does not take ownership of this memory.
+ *
+ * \param platform_kernel_size The length of the platform_kernel buffer.
+ */
+DART_EXPORT void Dart_SetDartLibrarySourcesKernel(
+ const uint8_t* platform_kernel,
+ const intptr_t platform_kernel_size);
+
+/**
+ * Detect the null safety opt-in status.
+ *
+ * When running from source, it is based on the opt-in status of `script_uri`.
+ * When running from a kernel buffer, it is based on the mode used when
+ * generating `kernel_buffer`.
+ * When running from an appJIT or AOT snapshot, it is based on the mode used
+ * when generating `snapshot_data`.
+ *
+ * \param script_uri Uri of the script that contains the source code
+ *
+ * \param package_config Uri of the package configuration file (either in format
+ * of .packages or .dart_tool/package_config.json) for the null safety
+ * detection to resolve package imports against. If this parameter is not
+ * passed the package resolution of the parent isolate should be used.
+ *
+ * \param original_working_directory current working directory when the VM
+ * process was launched, this is used to correctly resolve the path specified
+ * for package_config.
+ *
+ * \param snapshot_data
+ *
+ * \param snapshot_instructions Buffers containing a snapshot of the
+ * isolate or NULL if no snapshot is provided. If provided, the buffers must
+ * remain valid until the isolate shuts down.
+ *
+ * \param kernel_buffer
+ *
+ * \param kernel_buffer_size A buffer which contains a kernel/DIL program. Must
+ * remain valid until isolate shutdown.
+ *
+ * \return Returns true if the null safety is opted in by the input being
+ * run `script_uri`, `snapshot_data` or `kernel_buffer`.
+ *
+ */
+DART_EXPORT bool Dart_DetectNullSafety(const char* script_uri,
+ const char* package_config,
+ const char* original_working_directory,
+ const uint8_t* snapshot_data,
+ const uint8_t* snapshot_instructions,
+ const uint8_t* kernel_buffer,
+ intptr_t kernel_buffer_size);
+
+#define DART_KERNEL_ISOLATE_NAME "kernel-service"
+
+/*
+ * =======
+ * Service
+ * =======
+ */
+
+#define DART_VM_SERVICE_ISOLATE_NAME "vm-service"
+
+/**
+ * Returns true if isolate is the service isolate.
+ *
+ * \param isolate An isolate
+ *
+ * \return Returns true if 'isolate' is the service isolate.
+ */
+DART_EXPORT bool Dart_IsServiceIsolate(Dart_Isolate isolate);
+
+/**
+ * Writes the CPU profile to the timeline as a series of 'instant' events.
+ *
+ * Note that this is an expensive operation.
+ *
+ * \param main_port The main port of the Isolate whose profile samples to write.
+ * \param error An optional error, must be free()ed by caller.
+ *
+ * \return Returns true if the profile is successfully written and false
+ * otherwise.
+ */
+DART_EXPORT bool Dart_WriteProfileToTimeline(Dart_Port main_port, char** error);
+
+/*
+ * ====================
+ * Compilation Feedback
+ * ====================
+ */
+
+/**
+ * Record all functions which have been compiled in the current isolate.
+ *
+ * \param buffer Returns a pointer to a buffer containing the trace.
+ * This buffer is scope allocated and is only valid until the next call to
+ * Dart_ExitScope.
+ * \param size Returns the size of the buffer.
+ * \return Returns an valid handle upon success.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_SaveCompilationTrace(uint8_t** buffer, intptr_t* buffer_length);
+
+/**
+ * Compile all functions from data from Dart_SaveCompilationTrace. Unlike JIT
+ * feedback, this data is fuzzy: loading does not need to happen in the exact
+ * program that was saved, the saver and loader do not need to agree on checked
+ * mode versus production mode or debug/release/product.
+ *
+ * \return Returns an error handle if a compilation error was encountered.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_LoadCompilationTrace(uint8_t* buffer, intptr_t buffer_length);
+
+/**
+ * Record runtime feedback for the current isolate, including type feedback
+ * and usage counters.
+ *
+ * \param buffer Returns a pointer to a buffer containing the trace.
+ * This buffer is scope allocated and is only valid until the next call to
+ * Dart_ExitScope.
+ * \param size Returns the size of the buffer.
+ * \return Returns an valid handle upon success.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_SaveTypeFeedback(uint8_t** buffer, intptr_t* buffer_length);
+
+/**
+ * Compile functions using data from Dart_SaveTypeFeedback. The data must from a
+ * VM with the same version and compiler flags.
+ *
+ * \return Returns an error handle if a compilation error was encountered or a
+ * version mismatch is detected.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_LoadTypeFeedback(uint8_t* buffer, intptr_t buffer_length);
+
+/*
+ * ==============
+ * Precompilation
+ * ==============
+ */
+
+/**
+ * Compiles all functions reachable from entry points and marks
+ * the isolate to disallow future compilation.
+ *
+ * Entry points should be specified using `@pragma("vm:entry-point")`
+ * annotation.
+ *
+ * \return An error handle if a compilation error or runtime error running const
+ * constructors was encountered.
+ */
+DART_EXPORT Dart_Handle Dart_Precompile();
+
+typedef void (*Dart_CreateLoadingUnitCallback)(
+ void* callback_data,
+ intptr_t loading_unit_id,
+ void** write_callback_data,
+ void** write_debug_callback_data);
+typedef void (*Dart_StreamingWriteCallback)(void* callback_data,
+ const uint8_t* buffer,
+ intptr_t size);
+typedef void (*Dart_StreamingCloseCallback)(void* callback_data);
+
+DART_EXPORT Dart_Handle Dart_LoadingUnitLibraryUris(intptr_t loading_unit_id);
+
+// On Darwin systems, 'dlsym' adds an '_' to the beginning of the symbol name.
+// Use the '...CSymbol' definitions for resolving through 'dlsym'. The actual
+// symbol names in the objects are given by the '...AsmSymbol' definitions.
+#if defined(__APPLE__)
+#define kSnapshotBuildIdCSymbol "kDartSnapshotBuildId"
+#define kVmSnapshotDataCSymbol "kDartVmSnapshotData"
+#define kVmSnapshotInstructionsCSymbol "kDartVmSnapshotInstructions"
+#define kVmSnapshotBssCSymbol "kDartVmSnapshotBss"
+#define kIsolateSnapshotDataCSymbol "kDartIsolateSnapshotData"
+#define kIsolateSnapshotInstructionsCSymbol "kDartIsolateSnapshotInstructions"
+#define kIsolateSnapshotBssCSymbol "kDartIsolateSnapshotBss"
+#else
+#define kSnapshotBuildIdCSymbol "_kDartSnapshotBuildId"
+#define kVmSnapshotDataCSymbol "_kDartVmSnapshotData"
+#define kVmSnapshotInstructionsCSymbol "_kDartVmSnapshotInstructions"
+#define kVmSnapshotBssCSymbol "_kDartVmSnapshotBss"
+#define kIsolateSnapshotDataCSymbol "_kDartIsolateSnapshotData"
+#define kIsolateSnapshotInstructionsCSymbol "_kDartIsolateSnapshotInstructions"
+#define kIsolateSnapshotBssCSymbol "_kDartIsolateSnapshotBss"
+#endif
+
+#define kSnapshotBuildIdAsmSymbol "_kDartSnapshotBuildId"
+#define kVmSnapshotDataAsmSymbol "_kDartVmSnapshotData"
+#define kVmSnapshotInstructionsAsmSymbol "_kDartVmSnapshotInstructions"
+#define kVmSnapshotBssAsmSymbol "_kDartVmSnapshotBss"
+#define kIsolateSnapshotDataAsmSymbol "_kDartIsolateSnapshotData"
+#define kIsolateSnapshotInstructionsAsmSymbol \
+ "_kDartIsolateSnapshotInstructions"
+#define kIsolateSnapshotBssAsmSymbol "_kDartIsolateSnapshotBss"
+
+/**
+ * Creates a precompiled snapshot.
+ * - A root library must have been loaded.
+ * - Dart_Precompile must have been called.
+ *
+ * Outputs an assembly file defining the symbols listed in the definitions
+ * above.
+ *
+ * The assembly should be compiled as a static or shared library and linked or
+ * loaded by the embedder. Running this snapshot requires a VM compiled with
+ * DART_PRECOMPILED_SNAPSHOT. The kDartVmSnapshotData and
+ * kDartVmSnapshotInstructions should be passed to Dart_Initialize. The
+ * kDartIsolateSnapshotData and kDartIsolateSnapshotInstructions should be
+ * passed to Dart_CreateIsolateGroup.
+ *
+ * The callback will be invoked one or more times to provide the assembly code.
+ *
+ * If stripped is true, then the assembly code will not include DWARF
+ * debugging sections.
+ *
+ * If debug_callback_data is provided, debug_callback_data will be used with
+ * the callback to provide separate debugging information.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback,
+ void* callback_data,
+ bool stripped,
+ void* debug_callback_data);
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateAppAOTSnapshotAsAssemblies(
+ Dart_CreateLoadingUnitCallback next_callback,
+ void* next_callback_data,
+ bool stripped,
+ Dart_StreamingWriteCallback write_callback,
+ Dart_StreamingCloseCallback close_callback);
+
+/**
+ * Creates a precompiled snapshot.
+ * - A root library must have been loaded.
+ * - Dart_Precompile must have been called.
+ *
+ * Outputs an ELF shared library defining the symbols
+ * - _kDartVmSnapshotData
+ * - _kDartVmSnapshotInstructions
+ * - _kDartIsolateSnapshotData
+ * - _kDartIsolateSnapshotInstructions
+ *
+ * The shared library should be dynamically loaded by the embedder.
+ * Running this snapshot requires a VM compiled with DART_PRECOMPILED_SNAPSHOT.
+ * The kDartVmSnapshotData and kDartVmSnapshotInstructions should be passed to
+ * Dart_Initialize. The kDartIsolateSnapshotData and
+ * kDartIsolateSnapshotInstructions should be passed to Dart_CreateIsolate.
+ *
+ * The callback will be invoked one or more times to provide the binary output.
+ *
+ * If stripped is true, then the binary output will not include DWARF
+ * debugging sections.
+ *
+ * If debug_callback_data is provided, debug_callback_data will be used with
+ * the callback to provide separate debugging information.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateAppAOTSnapshotAsElf(Dart_StreamingWriteCallback callback,
+ void* callback_data,
+ bool stripped,
+ void* debug_callback_data);
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateAppAOTSnapshotAsElfs(Dart_CreateLoadingUnitCallback next_callback,
+ void* next_callback_data,
+ bool stripped,
+ Dart_StreamingWriteCallback write_callback,
+ Dart_StreamingCloseCallback close_callback);
+
+/**
+ * Like Dart_CreateAppAOTSnapshotAsAssembly, but only includes
+ * kDartVmSnapshotData and kDartVmSnapshotInstructions. It also does
+ * not strip DWARF information from the generated assembly or allow for
+ * separate debug information.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateVMAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback,
+ void* callback_data);
+
+/**
+ * Sorts the class-ids in depth first traversal order of the inheritance
+ * tree. This is a costly operation, but it can make method dispatch
+ * more efficient and is done before writing snapshots.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_SortClasses();
+
+/**
+ * Creates a snapshot that caches compiled code and type feedback for faster
+ * startup and quicker warmup in a subsequent process.
+ *
+ * Outputs a snapshot in two pieces. The pieces should be passed to
+ * Dart_CreateIsolateGroup in a VM using the same VM snapshot pieces used in the
+ * current VM. The instructions piece must be loaded with read and execute
+ * permissions; the data piece may be loaded as read-only.
+ *
+ * - Requires the VM to have not been started with --precompilation.
+ * - Not supported when targeting IA32.
+ * - The VM writing the snapshot and the VM reading the snapshot must be the
+ * same version, must be built in the same DEBUG/RELEASE/PRODUCT mode, must
+ * be targeting the same architecture, and must both be in checked mode or
+ * both in unchecked mode.
+ *
+ * The buffers are scope allocated and are only valid until the next call to
+ * Dart_ExitScope.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateAppJITSnapshotAsBlobs(uint8_t** isolate_snapshot_data_buffer,
+ intptr_t* isolate_snapshot_data_size,
+ uint8_t** isolate_snapshot_instructions_buffer,
+ intptr_t* isolate_snapshot_instructions_size);
+
+/**
+ * Like Dart_CreateAppJITSnapshotAsBlobs, but also creates a new VM snapshot.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_CreateCoreJITSnapshotAsBlobs(
+ uint8_t** vm_snapshot_data_buffer,
+ intptr_t* vm_snapshot_data_size,
+ uint8_t** vm_snapshot_instructions_buffer,
+ intptr_t* vm_snapshot_instructions_size,
+ uint8_t** isolate_snapshot_data_buffer,
+ intptr_t* isolate_snapshot_data_size,
+ uint8_t** isolate_snapshot_instructions_buffer,
+ intptr_t* isolate_snapshot_instructions_size);
+
+/**
+ * Get obfuscation map for precompiled code.
+ *
+ * Obfuscation map is encoded as a JSON array of pairs (original name,
+ * obfuscated name).
+ *
+ * \return Returns an error handler if the VM was built in a mode that does not
+ * support obfuscation.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_GetObfuscationMap(uint8_t** buffer, intptr_t* buffer_length);
+
+/**
+ * Returns whether the VM only supports running from precompiled snapshots and
+ * not from any other kind of snapshot or from source (that is, the VM was
+ * compiled with DART_PRECOMPILED_RUNTIME).
+ */
+DART_EXPORT bool Dart_IsPrecompiledRuntime();
+
+/**
+ * Print a native stack trace. Used for crash handling.
+ *
+ * If context is NULL, prints the current stack trace. Otherwise, context
+ * should be a CONTEXT* (Windows) or ucontext_t* (POSIX) from a signal handler
+ * running on the current thread.
+ */
+DART_EXPORT void Dart_DumpNativeStackTrace(void* context);
+
+/**
+ * Indicate that the process is about to abort, and the Dart VM should not
+ * attempt to cleanup resources.
+ */
+DART_EXPORT void Dart_PrepareToAbort();
+
+#endif /* INCLUDE_DART_API_H_ */ /* NOLINT */
diff --git a/src/bindings/ejdb2_dart/lib/dart_native_api.h b/src/bindings/ejdb2_dart/lib/dart_native_api.h
new file mode 100644
index 0000000..a40c522
--- /dev/null
+++ b/src/bindings/ejdb2_dart/lib/dart_native_api.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+ * for details. All rights reserved. Use of this source code is governed by a
+ * BSD-style license that can be found in the LICENSE file.
+ */
+
+#ifndef RUNTIME_INCLUDE_DART_NATIVE_API_H_
+#define RUNTIME_INCLUDE_DART_NATIVE_API_H_
+
+#include "dart_api.h" /* NOLINT */
+
+/*
+ * ==========================================
+ * Message sending/receiving from native code
+ * ==========================================
+ */
+
+/**
+ * A Dart_CObject is used for representing Dart objects as native C
+ * data outside the Dart heap. These objects are totally detached from
+ * the Dart heap. Only a subset of the Dart objects have a
+ * representation as a Dart_CObject.
+ *
+ * The string encoding in the 'value.as_string' is UTF-8.
+ *
+ * All the different types from dart:typed_data are exposed as type
+ * kTypedData. The specific type from dart:typed_data is in the type
+ * field of the as_typed_data structure. The length in the
+ * as_typed_data structure is always in bytes.
+ *
+ * The data for kTypedData is copied on message send and ownership remains with
+ * the caller. The ownership of data for kExternalTyped is passed to the VM on
+ * message send and returned when the VM invokes the
+ * Dart_HandleFinalizer callback; a non-NULL callback must be provided.
+ */
+typedef enum {
+ Dart_CObject_kNull = 0,
+ Dart_CObject_kBool,
+ Dart_CObject_kInt32,
+ Dart_CObject_kInt64,
+ Dart_CObject_kDouble,
+ Dart_CObject_kString,
+ Dart_CObject_kArray,
+ Dart_CObject_kTypedData,
+ Dart_CObject_kExternalTypedData,
+ Dart_CObject_kSendPort,
+ Dart_CObject_kCapability,
+ Dart_CObject_kUnsupported,
+ Dart_CObject_kNumberOfTypes
+} Dart_CObject_Type;
+
+typedef struct _Dart_CObject {
+ Dart_CObject_Type type;
+ union {
+ bool as_bool;
+ int32_t as_int32;
+ int64_t as_int64;
+ double as_double;
+ char* as_string;
+ struct {
+ Dart_Port id;
+ Dart_Port origin_id;
+ } as_send_port;
+ struct {
+ int64_t id;
+ } as_capability;
+ struct {
+ intptr_t length;
+ struct _Dart_CObject** values;
+ } as_array;
+ struct {
+ Dart_TypedData_Type type;
+ intptr_t length;
+ uint8_t* values;
+ } as_typed_data;
+ struct {
+ Dart_TypedData_Type type;
+ intptr_t length;
+ uint8_t* data;
+ void* peer;
+ Dart_HandleFinalizer callback;
+ } as_external_typed_data;
+ } value;
+} Dart_CObject;
+// This struct is versioned by DART_API_DL_MAJOR_VERSION, bump the version when
+// changing this struct.
+
+/**
+ * Posts a message on some port. The message will contain the Dart_CObject
+ * object graph rooted in 'message'.
+ *
+ * While the message is being sent the state of the graph of Dart_CObject
+ * structures rooted in 'message' should not be accessed, as the message
+ * generation will make temporary modifications to the data. When the message
+ * has been sent the graph will be fully restored.
+ *
+ * If true is returned, the message was enqueued, and finalizers for external
+ * typed data will eventually run, even if the receiving isolate shuts down
+ * before processing the message. If false is returned, the message was not
+ * enqueued and ownership of external typed data in the message remains with the
+ * caller.
+ *
+ * This function may be called on any thread when the VM is running (that is,
+ * after Dart_Initialize has returned and before Dart_Cleanup has been called).
+ *
+ * \param port_id The destination port.
+ * \param message The message to send.
+ *
+ * \return True if the message was posted.
+ */
+DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message);
+
+/**
+ * Posts a message on some port. The message will contain the integer 'message'.
+ *
+ * \param port_id The destination port.
+ * \param message The message to send.
+ *
+ * \return True if the message was posted.
+ */
+DART_EXPORT bool Dart_PostInteger(Dart_Port port_id, int64_t message);
+
+/**
+ * A native message handler.
+ *
+ * This handler is associated with a native port by calling
+ * Dart_NewNativePort.
+ *
+ * The message received is decoded into the message structure. The
+ * lifetime of the message data is controlled by the caller. All the
+ * data references from the message are allocated by the caller and
+ * will be reclaimed when returning to it.
+ */
+typedef void (*Dart_NativeMessageHandler)(Dart_Port dest_port_id,
+ Dart_CObject* message);
+
+/**
+ * Creates a new native port. When messages are received on this
+ * native port, then they will be dispatched to the provided native
+ * message handler.
+ *
+ * \param name The name of this port in debugging messages.
+ * \param handler The C handler to run when messages arrive on the port.
+ * \param handle_concurrently Is it okay to process requests on this
+ * native port concurrently?
+ *
+ * \return If successful, returns the port id for the native port. In
+ * case of error, returns ILLEGAL_PORT.
+ */
+DART_EXPORT Dart_Port Dart_NewNativePort(const char* name,
+ Dart_NativeMessageHandler handler,
+ bool handle_concurrently);
+/* TODO(turnidge): Currently handle_concurrently is ignored. */
+
+/**
+ * Closes the native port with the given id.
+ *
+ * The port must have been allocated by a call to Dart_NewNativePort.
+ *
+ * \param native_port_id The id of the native port to close.
+ *
+ * \return Returns true if the port was closed successfully.
+ */
+DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id);
+
+/*
+ * ==================
+ * Verification Tools
+ * ==================
+ */
+
+/**
+ * Forces all loaded classes and functions to be compiled eagerly in
+ * the current isolate..
+ *
+ * TODO(turnidge): Document.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_CompileAll();
+
+/**
+ * Finalizes all classes.
+ */
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_FinalizeAllClasses();
+
+/* This function is intentionally undocumented.
+ *
+ * It should not be used outside internal tests.
+ */
+DART_EXPORT void* Dart_ExecuteInternalCommand(const char* command, void* arg);
+
+#endif /* INCLUDE_DART_NATIVE_API_H_ */ /* NOLINT */
diff --git a/src/bindings/ejdb2_dart/lib/ejdb2_dart.c b/src/bindings/ejdb2_dart/lib/ejdb2_dart.c
new file mode 100644
index 0000000..8834abb
--- /dev/null
+++ b/src/bindings/ejdb2_dart/lib/ejdb2_dart.c
@@ -0,0 +1,1506 @@
+#define DART_SHARED_LIB
+#include "dart_api.h"
+#include "dart_native_api.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+typedef void (*WrapperFunction)(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port);
+
+typedef enum {
+ _EJD_ERROR_START = (IW_ERROR_START + 15000UL + 4000),
+ EJD_ERROR_CREATE_PORT, /**< Failed to create a Dart port (EJD_ERROR_CREATE_PORT) */
+ EJD_ERROR_POST_PORT, /**< Failed to post message to Dart port (EJD_ERROR_POST_PORT) */
+ EJD_ERROR_INVALID_NATIVE_CALL_ARGS, /**< Invalid native function call args (EJD_ERROR_INVALID_NATIVE_CALL_ARGS) */
+ EJD_ERROR_INVALID_STATE, /**< Invalid native extension state (EJD_ERROR_INVALID_STATE) */
+ _EJD_ERROR_END,
+} jbr_ecode_t;
+
+struct NativeFunctionLookup {
+ const char *name;
+ Dart_NativeFunction fn;
+};
+
+struct WrapperFunctionLookup {
+ const char *name;
+ WrapperFunction fn;
+};
+
+typedef struct EJDB2Handle {
+ EJDB db;
+ char *path;
+ int64_t refs;
+ struct EJDB2Handle *next;
+ struct EJDB2Handle *prev;
+} EJDB2Handle;
+
+typedef struct EJDB2Context {
+ Dart_Port port;
+ EJDB2Handle *dbh;
+ Dart_WeakPersistentHandle wph;
+} EJDB2Context;
+
+typedef struct EJDB2JQLContext {
+ JQL q;
+ Dart_WeakPersistentHandle wph;
+} EJDB2JQLContext;
+
+static pthread_mutex_t k_shared_scope_mtx = PTHREAD_MUTEX_INITIALIZER;
+static EJDB2Handle *k_head_handle;
+
+static Dart_NativeFunction ejd_resolve_name(Dart_Handle name, int argc, bool *auto_setup_scope);
+
+IW_INLINE Dart_Handle ejd_error_check_propagate(Dart_Handle handle);
+IW_INLINE Dart_Handle ejd_error_rc_create(iwrc rc);
+IW_INLINE void ejd_error_rc_throw(iwrc rc);
+
+static void ejd_explain_rc(Dart_NativeArguments args);
+static void ejd_exec(Dart_NativeArguments args);
+static void ejd_exec_check(Dart_NativeArguments args);
+static void ejd_jql_set(Dart_NativeArguments args);
+static void ejd_jql_get_limit(Dart_NativeArguments args);
+
+static void ejd_port_handler(Dart_Port receive_port, Dart_CObject *msg);
+static void ejd_ctx_finalizer(void *isolate_callback_data, void *peer);
+
+static void ejd_port(Dart_NativeArguments arguments);
+static void ejd_set_handle(Dart_NativeArguments args);
+static void ejd_get_handle(Dart_NativeArguments args);
+static void ejd_create_query(Dart_NativeArguments args);
+
+static void ejd_open_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port);
+static void ejd_close_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port);
+static void ejd_get_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port);
+static void ejd_put_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port);
+static void ejd_del_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port);
+static void ejd_patch_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port);
+static void ejd_idx_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port);
+static void ejd_rmi_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port);
+static void ejd_rmc_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port);
+static void ejd_info_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port);
+static void ejd_rename_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port);
+static void ejd_bkp_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port);
+
+static struct NativeFunctionLookup k_scoped_functions[] = {
+ { "port", ejd_port },
+ { "exec", ejd_exec },
+ { "check_exec", ejd_exec_check },
+ { "jql_set", ejd_jql_set },
+ { "jql_get_limit", ejd_jql_get_limit },
+ { "create_query", ejd_create_query },
+ { "set_handle", ejd_set_handle },
+ { "get_handle", ejd_get_handle },
+ { "explain_rc", ejd_explain_rc },
+ { 0, 0 }
+};
+
+static struct WrapperFunctionLookup k_wrapped_functions[] = {
+ { "get", ejd_get_wrapped },
+ { "put", ejd_put_wrapped },
+ { "del", ejd_del_wrapped },
+ { "rename", ejd_rename_wrapped },
+ { "patch", ejd_patch_wrapped },
+ { "idx", ejd_idx_wrapped },
+ { "rmi", ejd_rmi_wrapped },
+ { "rmc", ejd_rmc_wrapped },
+ { "info", ejd_info_wrapped },
+ { "open", ejd_open_wrapped },
+ { "close", ejd_close_wrapped },
+ { "bkp", ejd_bkp_wrapped },
+ { 0, 0 }
+};
+
+#define EJTH(h_) ejd_error_check_propagate(h_)
+
+#define EJGO(h_, rh_, label_) \
+ if (Dart_IsError(h_)) { \
+ rh_ = (h_); \
+ goto label_; \
+ }
+
+#define EJLIB() EJTH(Dart_LookupLibrary(Dart_NewStringFromCString("package:ejdb2_dart/ejdb2_dart.dart")))
+
+#define EJPORT_RC(co_, rc_) \
+ if (rc_) { \
+ (co_)->type = Dart_CObject_kInt64; \
+ (co_)->value.as_int64 = (rc_); \
+ }
+
+IW_INLINE char *cobject_str(Dart_CObject *co, bool nulls, iwrc *rcp) {
+ *rcp = 0;
+ if (co) {
+ if (co->type == Dart_CObject_kString) {
+ return co->value.as_string;
+ } else if (nulls && (co->type == Dart_CObject_kNull)) {
+ return 0;
+ }
+ }
+ *rcp = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ return 0;
+}
+
+IW_INLINE int64_t cobject_int(Dart_CObject *co, bool nulls, iwrc *rcp) {
+ *rcp = 0;
+ if (co) {
+ if (co->type == Dart_CObject_kInt32) {
+ return co->value.as_int32;
+ } else if (co->type == Dart_CObject_kInt64) {
+ return co->value.as_int64;
+ } else if (nulls && (co->type == Dart_CObject_kNull)) {
+ return 0;
+ }
+ }
+ *rcp = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ return 0;
+}
+
+IW_INLINE bool cobject_bool(Dart_CObject *co, bool nulls, iwrc *rcp) {
+ *rcp = 0;
+ if (co) {
+ if (co->type == Dart_CObject_kBool) {
+ return co->value.as_bool;
+ } else if (nulls && (co->type == Dart_CObject_kNull)) {
+ return false;
+ }
+ }
+ *rcp = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ return false;
+}
+
+IW_INLINE double cobject_double(Dart_CObject *co, bool nulls, iwrc *rcp) {
+ *rcp = 0;
+ if (co) {
+ if (co->type == Dart_CObject_kDouble) {
+ return co->value.as_double;
+ } else if (nulls && (co->type == Dart_CObject_kNull)) {
+ return 0;
+ }
+ }
+ *rcp = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ return 0;
+}
+
+IW_INLINE Dart_Handle ejd_error_check_propagate(Dart_Handle handle) {
+ if (Dart_IsError(handle)) {
+ Dart_PropagateError(handle);
+ }
+ return handle;
+}
+
+static Dart_Handle ejd_error_object_handle(iwrc rc, const char *msg) {
+ Dart_Handle hmsg = Dart_Null();
+ if (msg) {
+ hmsg = EJTH(Dart_NewStringFromCString(msg));
+ } else if (rc) {
+ const char *explained = iwlog_ecode_explained(rc);
+ if (explained) {
+ hmsg = EJTH(Dart_NewStringFromCString(explained));
+ }
+ }
+ Dart_Handle hrc = EJTH(Dart_NewIntegerFromUint64(rc));
+ Dart_Handle hclass = EJTH(Dart_GetClass(EJLIB(), Dart_NewStringFromCString("EJDB2Error")));
+ Dart_Handle args[] = { hrc, hmsg };
+ return Dart_New(hclass, Dart_Null(), 2, args);
+}
+
+IW_INLINE Dart_Handle ejd_error_rc_create(iwrc rc) {
+ const char *msg = iwlog_ecode_explained(rc);
+ return Dart_NewUnhandledExceptionError(ejd_error_object_handle(rc, msg));
+}
+
+IW_INLINE Dart_Handle ejd_error_rc_create2(iwrc rc, const char *msg) {
+ return Dart_NewUnhandledExceptionError(ejd_error_object_handle(rc, msg));
+}
+
+IW_INLINE void ejd_error_rc_throw(iwrc rc) {
+ Dart_PropagateError(ejd_error_rc_create(rc));
+}
+
+static void ejd_port(Dart_NativeArguments args) {
+ EJDB2Context *ctx;
+ intptr_t ptr = 0;
+
+ Dart_EnterScope();
+ Dart_Handle self = EJTH(Dart_GetNativeArgument(args, 0));
+ EJTH(Dart_GetNativeInstanceField(self, 0, &ptr));
+
+ if (!ptr) {
+ ctx = malloc(sizeof(*ctx));
+ if (!ctx) {
+ Dart_SetReturnValue(args, ejd_error_rc_create(IW_ERROR_ALLOC));
+ goto finish;
+ }
+ ctx->dbh = 0;
+ ctx->port = Dart_NewNativePort("ejd_port_handler", ejd_port_handler, true);
+ if (ctx->port == ILLEGAL_PORT) {
+ Dart_SetReturnValue(args, ejd_error_rc_create(EJD_ERROR_CREATE_PORT));
+ goto finish;
+ }
+ ctx->wph = Dart_NewWeakPersistentHandle(self, ctx, sizeof(*ctx), ejd_ctx_finalizer);
+ if (!ctx->wph) {
+ Dart_SetReturnValue(args, ejd_error_rc_create(EJD_ERROR_INVALID_STATE));
+ goto finish;
+ }
+ Dart_SetNativeInstanceField(self, 0, (intptr_t) ctx);
+ } else {
+ ctx = (void*) ptr;
+ }
+ Dart_SetReturnValue(args, EJTH(Dart_NewSendPort(ctx->port)));
+
+finish:
+ Dart_ExitScope();
+}
+
+static void ejd_get_handle(Dart_NativeArguments args) {
+ intptr_t ptr = 0;
+ Dart_EnterScope();
+ Dart_Handle self = EJTH(Dart_GetNativeArgument(args, 0));
+ EJTH(Dart_GetNativeInstanceField(self, 0, &ptr));
+ EJDB2Context *ctx = (void*) ptr;
+ if (ctx && ctx->dbh) {
+ Dart_SetReturnValue(args, Dart_NewInteger((intptr_t) ctx->dbh));
+ } else {
+ Dart_SetReturnValue(args, Dart_Null());
+ }
+ Dart_ExitScope();
+}
+
+static void ejd_set_handle(Dart_NativeArguments args) {
+ intptr_t ptr;
+ Dart_EnterScope();
+ Dart_SetReturnValue(args, Dart_Null());
+ Dart_Handle self = EJTH(Dart_GetNativeArgument(args, 0));
+ EJTH(Dart_GetNativeInstanceField(self, 0, &ptr));
+ EJDB2Context *ctx = (void*) ptr;
+ if (!ctx) {
+ Dart_SetReturnValue(args, ejd_error_rc_create(EJD_ERROR_INVALID_STATE));
+ goto finish;
+ }
+ Dart_Handle dh = Dart_GetNativeArgument(args, 1);
+ if (Dart_IsInteger(dh)) {
+ int64_t llv;
+ EJTH(Dart_GetNativeIntegerArgument(args, 1, &llv));
+ ctx->dbh = (void*) llv;
+ } else if (Dart_IsNull(dh)) {
+ ctx->dbh = 0;
+ }
+
+finish:
+ Dart_ExitScope();
+}
+
+static void ejd_jql_finalizer(void *isolate_callback_data, void *peer) {
+ EJDB2JQLContext *ctx = peer;
+ if (ctx) {
+ if (ctx->q) {
+ jql_destroy(&ctx->q);
+ }
+ if (ctx->wph && Dart_CurrentIsolateGroup()) {
+ Dart_DeleteWeakPersistentHandle(ctx->wph);
+ }
+ free(ctx);
+ }
+}
+
+static void ejd_create_query(Dart_NativeArguments args) {
+ Dart_EnterScope();
+
+ iwrc rc = 0;
+ JQL q = 0;
+ intptr_t ptr = 0;
+ const char *query = 0;
+ const char *collection = 0;
+ EJDB2JQLContext *qctx = 0;
+
+ Dart_Handle ret = Dart_Null();
+ Dart_Handle hlib = EJLIB();
+ Dart_Handle hself = EJTH(Dart_GetNativeArgument(args, 0));
+ Dart_Handle hquery = EJTH(Dart_GetNativeArgument(args, 1));
+ Dart_Handle hcoll = EJTH(Dart_GetNativeArgument(args, 2));
+
+ EJTH(Dart_StringToCString(hquery, &query));
+ if (Dart_IsString(hcoll)) {
+ EJTH(Dart_StringToCString(hcoll, &collection));
+ }
+ EJTH(Dart_GetNativeInstanceField(hself, 0, &ptr));
+
+ EJDB2Context *ctx = (void*) ptr;
+ if (!ctx || !ctx->dbh || !ctx->dbh->db) {
+ rc = EJD_ERROR_INVALID_STATE;
+ goto finish;
+ }
+ rc = jql_create2(&q, collection, query, JQL_KEEP_QUERY_ON_PARSE_ERROR | JQL_SILENT_ON_PARSE_ERROR);
+ RCGO(rc, finish);
+
+ if (!collection) {
+ collection = jql_collection(q);
+ }
+ hcoll = Dart_NewStringFromCString(collection);
+ EJGO(hcoll, ret, finish);
+
+ Dart_Handle hclass = Dart_GetClass(hlib, Dart_NewStringFromCString("JQL"));
+ EJGO(hclass, ret, finish);
+
+ Dart_Handle jqargs[] = { hself, hquery, hcoll };
+ Dart_Handle jqinst = Dart_New(hclass, Dart_NewStringFromCString("_"), 3, jqargs);
+ EJGO(jqinst, ret, finish);
+
+ ret = Dart_SetNativeInstanceField(jqinst, 0, (intptr_t) q);
+ EJGO(ret, ret, finish);
+
+ qctx = malloc(sizeof(*qctx));
+ if (!qctx) {
+ Dart_SetReturnValue(args, ejd_error_rc_create(IW_ERROR_ALLOC));
+ goto finish;
+ }
+
+ qctx->q = q;
+ qctx->wph = Dart_NewWeakPersistentHandle(jqinst, qctx, jql_estimate_allocated_size(q) + sizeof(*qctx),
+ ejd_jql_finalizer);
+ if (!qctx->wph) {
+ rc = EJD_ERROR_INVALID_STATE;
+ goto finish;
+ }
+
+ ret = jqinst;
+
+finish:
+ if (rc || Dart_IsError(ret)) {
+ if (rc) {
+ if (q && (rc == JQL_ERROR_QUERY_PARSE)) {
+ ret = ejd_error_rc_create2(rc, jql_error(q));
+ } else {
+ ret = ejd_error_rc_create(rc);
+ }
+ }
+ if (q) {
+ jql_destroy(&q);
+ }
+ free(qctx);
+ }
+ Dart_SetReturnValue(args, ret);
+ Dart_ExitScope();
+}
+
+// Query execution context
+// Contains a state to manage resultset backpressure
+typedef struct QCTX {
+ bool aggregate_count;
+ bool explain;
+ bool paused;
+ int pending_count;
+ Dart_Port reply_port;
+ JQL q;
+ EJDB2Context *dctx;
+ int64_t limit;
+ pthread_mutex_t mtx;
+ pthread_cond_t cond;
+} *QCTX;
+
+static iwrc ejd_exec_pause_guard(QCTX qctx) {
+ iwrc rc = 0;
+ int rci = pthread_mutex_lock(&qctx->mtx);
+ if (rci) {
+ return iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rci);
+ }
+ while (qctx->paused) {
+ rci = pthread_cond_wait(&qctx->cond, &qctx->mtx);
+ if (rci) {
+ rc = iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rci);
+ break;
+ }
+ }
+ qctx->pending_count++;
+ pthread_mutex_unlock(&qctx->mtx);
+ return rc;
+}
+
+static iwrc ejd_exec_visitor(struct _EJDB_EXEC *ux, EJDB_DOC doc, int64_t *step) {
+ iwrc rc = 0;
+ QCTX qctx = ux->opaque;
+
+ rc = ejd_exec_pause_guard(qctx);
+ RCRET(rc);
+
+ IWXSTR *xstr = iwxstr_new();
+ if (!xstr) {
+ return iwrc_set_errno(IW_ERROR_ALLOC, errno);
+ }
+ if (doc->node) {
+ rc = jbn_as_json(doc->node, jbl_xstr_json_printer, xstr, 0);
+ } else {
+ rc = jbl_as_json(doc->raw, jbl_xstr_json_printer, xstr, 0);
+ }
+ RCGO(rc, finish);
+
+ Dart_CObject result, rv1, rv2, rv3;
+ Dart_CObject *rv[] = { &rv1, &rv2, &rv3 };
+ result.type = Dart_CObject_kArray;
+ result.value.as_array.length = sizeof(rv) / sizeof(rv[0]);
+ result.value.as_array.values = rv;
+ rv1.type = Dart_CObject_kInt64;
+ rv1.value.as_int64 = doc->id;
+ rv2.type = Dart_CObject_kString;
+ rv2.value.as_string = iwxstr_ptr(xstr);
+ if (ux->log) { // Add explain log to the first record
+ rv3.type = Dart_CObject_kString;
+ rv3.value.as_string = iwxstr_ptr(ux->log);
+ ux->log = 0;
+ } else {
+ rv3.type = Dart_CObject_kNull;
+ }
+ if (!Dart_PostCObject(qctx->reply_port, &result)) {
+ *step = 0; // End of cursor loop
+ }
+
+finish:
+ iwxstr_destroy(xstr);
+ return rc;
+}
+
+static void ejd_exec_port_handler(Dart_Port receive_port, Dart_CObject *msg) {
+ iwrc rc = 0;
+ Dart_CObject result = { .type = Dart_CObject_kNull };
+ if ((msg->type != Dart_CObject_kInt64) || !msg->value.as_int64) {
+ iwlog_error2("Invalid message recieved");
+ return;
+ }
+ QCTX qctx = (void*) msg->value.as_int64;
+ IWXSTR *exlog = 0;
+ EJDB_EXEC ux = { 0 };
+ EJDB2Context *dctx = qctx->dctx;
+
+ if (!qctx->q || !dctx || !dctx->dbh || !dctx->dbh->db) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ if (qctx->explain) {
+ exlog = iwxstr_new();
+ if (!exlog) {
+ rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
+ goto finish;
+ }
+ }
+
+ qctx->aggregate_count = jql_has_aggregate_count(qctx->q);
+
+ ux.q = qctx->q;
+ ux.db = dctx->dbh->db;
+ ux.visitor = qctx->aggregate_count ? 0 : ejd_exec_visitor;
+ ux.opaque = qctx;
+ ux.log = exlog;
+ ux.limit = qctx->limit;
+
+ rc = ejdb_exec(&ux);
+ RCGO(rc, finish);
+
+ if (qctx->aggregate_count) {
+ Dart_CObject result, rv1, rv2, rv3;
+ Dart_CObject *rv[] = { &rv1, &rv2, &rv3 };
+ result.type = Dart_CObject_kArray;
+ result.value.as_array.length = (sizeof(rv) / sizeof(rv[0]));
+ result.value.as_array.values = rv;
+ rv1.type = Dart_CObject_kInt64;
+ rv1.value.as_int64 = ux.cnt;
+ rv2.type = Dart_CObject_kNull;
+ if (exlog) {
+ rv3.type = Dart_CObject_kString;
+ rv3.value.as_string = iwxstr_ptr(exlog);
+ } else {
+ rv3.type = Dart_CObject_kNull;
+ }
+ Dart_PostCObject(qctx->reply_port, &result);
+ } else if (exlog && (ux.cnt == 0)) {
+ result.type = Dart_CObject_kString;
+ result.value.as_string = iwxstr_ptr(exlog);
+ }
+
+finish:
+ if (rc) {
+ iwlog_ecode_error3(rc);
+ EJPORT_RC(&result, rc);
+ }
+ if (qctx->reply_port != ILLEGAL_PORT) {
+ Dart_PostCObject(qctx->reply_port, &result); // Last NULL or error(int)
+ }
+ if (exlog) {
+ iwxstr_destroy(exlog);
+ }
+ Dart_CloseNativePort(receive_port);
+}
+
+static void ejd_exec(Dart_NativeArguments args) {
+ Dart_EnterScope();
+
+ iwrc rc = 0;
+ intptr_t qptr, ptr = 0;
+ bool explain = false;
+ int64_t limit = 0;
+ QCTX qctx = 0;
+
+ Dart_Port reply_port = ILLEGAL_PORT;
+ Dart_Port exec_port = ILLEGAL_PORT;
+ Dart_Handle ret = Dart_Null();
+
+ Dart_Handle hself = EJTH(Dart_GetNativeArgument(args, 0));
+ Dart_Handle hdb = EJTH(Dart_GetField(hself, Dart_NewStringFromCString("db")));
+ Dart_Handle hport = EJTH(Dart_GetNativeArgument(args, 1));
+
+ EJTH(Dart_GetNativeBooleanArgument(args, 2, &explain));
+ EJTH(Dart_GetNativeIntegerArgument(args, 3, &limit));
+ EJTH(Dart_SendPortGetId(hport, &reply_port));
+
+ EJTH(Dart_GetNativeInstanceField(hdb, 0, &ptr));
+ EJDB2Context *dctx = (void*) ptr;
+ if (!dctx || !dctx->dbh || !dctx->dbh->db) {
+ rc = EJD_ERROR_INVALID_STATE;
+ goto finish;
+ }
+
+ // JQL pointer
+ EJTH(Dart_GetNativeInstanceField(hself, 0, &qptr));
+ if (!qptr) {
+ rc = EJD_ERROR_INVALID_STATE;
+ goto finish;
+ }
+
+ // JQL exec port
+ exec_port = Dart_NewNativePort("ejd_exec_port_handler", ejd_exec_port_handler, false);
+ if (exec_port == ILLEGAL_PORT) {
+ rc = EJD_ERROR_CREATE_PORT;
+ goto finish;
+ }
+
+ qctx = calloc(1, sizeof(*qctx));
+ if (!qctx) {
+ rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
+ goto finish;
+ }
+
+ pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
+ pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+ memcpy(&qctx->mtx, &mtx, sizeof(mtx));
+ memcpy(&qctx->cond, &cond, sizeof(cond));
+
+ qctx->reply_port = reply_port;
+ qctx->q = (void*) qptr;
+ qctx->dctx = dctx;
+ qctx->explain = explain;
+ qctx->limit = limit;
+
+ // Now post a message to the query executor
+ Dart_CObject msg;
+ msg.type = Dart_CObject_kInt64;
+ msg.value.as_int64 = (int64_t) qctx;
+
+ if (!Dart_PostCObject(exec_port, &msg)) {
+ rc = EJD_ERROR_POST_PORT;
+ goto finish;
+ }
+
+finish:
+ if (rc || Dart_IsError(ret)) {
+ if (qctx) {
+ free(qctx);
+ qctx = 0;
+ }
+ if (exec_port != ILLEGAL_PORT) {
+ Dart_CloseNativePort(exec_port);
+ }
+ if (rc) {
+ ret = ejd_error_rc_create(rc);
+ }
+ }
+ if (qctx) {
+ ret = Dart_NewInteger((int64_t) (void*) qctx);
+ }
+ Dart_SetReturnValue(args, ret);
+ Dart_ExitScope();
+}
+
+static void ejd_exec_check(Dart_NativeArguments args) {
+ iwrc rc = 0;
+ Dart_EnterScope();
+ Dart_Handle ret = Dart_Null();
+
+ if (Dart_GetNativeArgumentCount(args) < 3) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ bool terminate = false;
+ int64_t hptr = 0;
+
+ EJTH(Dart_GetNativeIntegerArgument(args, 1, &hptr));
+ EJTH(Dart_GetNativeBooleanArgument(args, 2, &terminate));
+
+ if (hptr < 1) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ QCTX qctx = (void*) hptr;
+
+ if (terminate) {
+ free(qctx);
+ goto finish;
+ }
+
+ int rci = pthread_mutex_lock(&qctx->mtx);
+ if (rci) {
+ rc = iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rci);
+ goto finish;
+ }
+ qctx->pending_count--;
+ if (qctx->paused) {
+ if (qctx->pending_count < 32) {
+ qctx->paused = false;
+ pthread_cond_broadcast(&qctx->cond);
+ }
+ } else if (qctx->pending_count > 64) {
+ qctx->paused = true;
+ pthread_cond_broadcast(&qctx->cond);
+ }
+ pthread_mutex_unlock(&qctx->mtx);
+
+finish:
+ if (rc) {
+ ret = ejd_error_rc_create(rc);
+ }
+ Dart_SetReturnValue(args, ret);
+ Dart_ExitScope();
+}
+
+static void ejd_free_str(void *ptr, void *op) {
+ free(ptr);
+}
+
+static void ejd_free_json_node(void *ptr, void *op) {
+ IWPOOL *pool = op;
+ if (pool) {
+ iwpool_destroy(pool);
+ }
+}
+
+static void ejd_jql_get_limit(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_Handle ret = Dart_Null();
+ iwrc rc;
+ int64_t limit;
+ intptr_t ptr = 0;
+ Dart_Handle hself = EJTH(Dart_GetNativeArgument(args, 0));
+ EJTH(Dart_GetNativeInstanceField(hself, 0, &ptr));
+ JQL q = (void*) ptr;
+ if (!q) {
+ rc = EJD_ERROR_INVALID_STATE;
+ goto finish;
+ }
+ rc = jql_get_limit(q, &limit);
+ RCGO(rc, finish);
+ ret = Dart_NewInteger(limit);
+
+finish:
+ if (rc || Dart_IsError(ret)) {
+ if (rc) {
+ ret = ejd_error_rc_create(rc);
+ }
+ }
+ Dart_SetReturnValue(args, ret);
+ Dart_ExitScope();
+}
+
+static void ejd_jql_set(Dart_NativeArguments args) {
+ // void set(dynamic place, dynamic value) native 'ejd_jql_set';
+ Dart_EnterScope();
+ Dart_Handle ret = Dart_Null();
+
+ iwrc rc = 0;
+ intptr_t ptr = 0;
+ Dart_Handle hself = EJTH(Dart_GetNativeArgument(args, 0));
+ EJTH(Dart_GetNativeInstanceField(hself, 0, &ptr));
+ JQL q = (void*) ptr;
+ if (!q) {
+ rc = EJD_ERROR_INVALID_STATE;
+ goto finish;
+ }
+ int64_t npl = 0, type = 0;
+ const char *svalue, *spl = 0;
+ Dart_Handle hpl = EJTH(Dart_GetNativeArgument(args, 1));
+ Dart_Handle hvalue = EJTH(Dart_GetNativeArgument(args, 2));
+ Dart_Handle htype = EJTH(Dart_GetNativeArgument(args, 3));
+
+ if (Dart_IsString(hpl)) {
+ EJTH(Dart_StringToCString(hpl, &spl));
+ } else {
+ EJTH(Dart_IntegerToInt64(hpl, &npl));
+ }
+ if (Dart_IsInteger(htype)) {
+ EJTH(Dart_IntegerToInt64(htype, &type));
+ }
+ if (type == 1) { // JSON
+ EJTH(Dart_StringToCString(hvalue, &svalue));
+ JBL_NODE node;
+ IWPOOL *pool = iwpool_create(64);
+ if (!pool) {
+ rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
+ goto finish;
+ }
+ rc = jbn_from_json(svalue, &node, pool);
+ if (rc) {
+ iwpool_destroy(pool);
+ goto finish;
+ }
+ rc = jql_set_json2(q, spl, npl, node, ejd_free_json_node, pool);
+ if (rc) {
+ iwpool_destroy(pool);
+ goto finish;
+ }
+ } else if (type == 2) { // Regexp
+ EJTH(Dart_StringToCString(hvalue, &svalue));
+ char *str = strdup(svalue);
+ if (!str) {
+ rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
+ goto finish;
+ }
+ rc = jql_set_regexp2(q, spl, npl, str, ejd_free_str, 0);
+ if (rc) {
+ free(str);
+ goto finish;
+ }
+ } else { // All other cases
+ if (Dart_IsString(hvalue)) {
+ EJTH(Dart_StringToCString(hvalue, &svalue));
+ char *str = strdup(svalue);
+ if (!str) {
+ rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
+ goto finish;
+ }
+ rc = jql_set_str2(q, spl, npl, str, ejd_free_str, 0);
+ if (rc) {
+ free(str);
+ goto finish;
+ }
+ } else if (Dart_IsInteger(hvalue)) {
+ int64_t val;
+ EJTH(Dart_IntegerToInt64(hvalue, &val));
+ rc = jql_set_i64(q, spl, npl, val);
+ } else if (Dart_IsDouble(hvalue)) {
+ double val;
+ EJTH(Dart_DoubleValue(hvalue, &val));
+ rc = jql_set_f64(q, spl, npl, val);
+ } else if (Dart_IsBoolean(hvalue)) {
+ bool val;
+ EJTH(Dart_BooleanValue(hvalue, &val));
+ rc = jql_set_bool(q, spl, npl, val);
+ } else if (Dart_IsNull(hvalue)) {
+ rc = jql_set_null(q, spl, npl);
+ }
+ }
+
+finish:
+ if (rc || Dart_IsError(ret)) {
+ if (rc) {
+ ret = ejd_error_rc_create(rc);
+ }
+ }
+ Dart_SetReturnValue(args, ret);
+ Dart_ExitScope();
+}
+
+static void ejd_explain_rc(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ int64_t llv = 0;
+ EJTH(Dart_GetNativeIntegerArgument(args, 0, &llv));
+ const char *msg = iwlog_ecode_explained((iwrc) llv);
+ if (msg) {
+ Dart_SetReturnValue(args, EJTH(Dart_NewStringFromCString(msg)));
+ } else {
+ Dart_SetReturnValue(args, Dart_Null());
+ }
+ Dart_ExitScope();
+}
+
+static Dart_NativeFunction ejd_resolve_name(
+ Dart_Handle name,
+ int argc,
+ bool *auto_setup_scope) {
+ if (!Dart_IsString(name) || !auto_setup_scope) {
+ return 0;
+ }
+ Dart_EnterScope();
+ const char *cname;
+ EJTH(Dart_StringToCString(name, &cname));
+ for (int i = 0; k_scoped_functions[i].name; ++i) {
+ if (strcmp(cname, k_scoped_functions[i].name) == 0) {
+ *auto_setup_scope = true;
+ Dart_ExitScope();
+ return k_scoped_functions[i].fn;
+ }
+ }
+ Dart_ExitScope();
+ return 0;
+}
+
+static void ejd_port_handler(Dart_Port receive_port, Dart_CObject *msg) {
+ if ( (msg->type != Dart_CObject_kArray)
+ || (msg->value.as_array.length < 2)
+ || (msg->value.as_array.values[0]->type != Dart_CObject_kSendPort)
+ || (msg->value.as_array.values[1]->type != Dart_CObject_kString)) {
+ iwlog_error2("Invalid message recieved");
+ return;
+ }
+ Dart_Port reply_port = msg->value.as_array.values[0]->value.as_send_port.id;
+ const char *fname = msg->value.as_array.values[1]->value.as_string;
+ for (int i = 0; k_wrapped_functions[i].name; ++i) {
+ if (strcmp(k_wrapped_functions[i].name, fname) == 0) {
+ k_wrapped_functions[i].fn(receive_port, msg, reply_port);
+ break;
+ }
+ }
+}
+
+static iwrc ejdb2_isolate_shared_open(const EJDB_OPTS *opts, EJDB2Handle **hptr) {
+ iwrc rc = 0;
+ EJDB db = 0;
+ int rci = pthread_mutex_lock(&k_shared_scope_mtx);
+ if (rci) {
+ return iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rci);
+ }
+ const char *path = opts->kv.path;
+ EJDB2Handle *h = k_head_handle;
+ while (h) {
+ if (!strcmp(h->path, path)) {
+ break;
+ }
+ h = h->next;
+ }
+ if (h) {
+ h->refs++;
+ *hptr = h;
+ goto finish;
+ }
+ rc = ejdb_open(opts, &db);
+ RCGO(rc, finish);
+
+ h = calloc(1, sizeof(*h));
+ if (!h) {
+ rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
+ goto finish;
+ }
+ h->path = strdup(path);
+ if (!h->path) {
+ free(h);
+ rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
+ goto finish;
+ }
+ h->refs = 1;
+ h->db = db;
+ if (k_head_handle) {
+ k_head_handle->prev = h;
+ h->next = k_head_handle;
+ }
+ k_head_handle = h;
+ *hptr = h;
+
+finish:
+ pthread_mutex_unlock(&k_shared_scope_mtx);
+ if (rc) {
+ iwlog_ecode_error3(rc);
+ if (db) {
+ ejdb_close(&db);
+ }
+ }
+ return rc;
+}
+
+static iwrc ejdb2_isolate_shared_release(EJDB2Handle **hp) {
+ iwrc rc = 0;
+ int rci = pthread_mutex_lock(&k_shared_scope_mtx);
+ if (rci) {
+ return iwrc_set_errno(IW_ERROR_THREADING_ERRNO, rci);
+ }
+ EJDB2Handle *h = *hp;
+ *hp = 0;
+ if (--h->refs <= 0) {
+ if (h->db) {
+ rc = ejdb_close(&h->db);
+ }
+ if (h->prev) {
+ h->prev->next = h->next;
+ } else {
+ k_head_handle = h->next;
+ }
+ if (h->next) {
+ h->next->prev = h->prev;
+ }
+ free(h->path);
+ free(h);
+ }
+ pthread_mutex_unlock(&k_shared_scope_mtx);
+ return rc;
+}
+
+static void ejd_open_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port) {
+ iwrc rc = 0;
+ Dart_CObject result, rv1;
+ Dart_CObject *rv[1] = { &rv1 };
+
+ int c = 2;
+ EJDB_OPTS opts = { 0 };
+ EJDB2Handle *dbh = 0;
+
+ if ((msg->type != Dart_CObject_kArray) || (msg->value.as_array.length != 16 + c)) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ Dart_CObject **varr = msg->value.as_array.values;
+
+ // opts.kv.path // non null
+ // opts.kv.oflags // non null
+ // opts.kv.wal.enabled // non null
+ // opts.kv.wal.check_crc_on_checkpoint
+ // opts.kv.wal.checkpoint_buffer_sz
+ // opts.kv.wal.checkpoint_timeout_sec
+ // opts.kv.wal.savepoint_timeout_sec
+ // opts.kv.wal.wal_buffer_sz
+ // opts.document_buffer_sz
+ // opts.sort_buffer_sz
+ // opts.http.enabled
+ // opts.http.access_token
+ // opts.http.bind
+ // opts.http.max_body_size
+ // opts.http.port
+ // opts.http.read_anon
+
+ opts.kv.path = cobject_str(varr[c++], false, &rc);
+ RCGO(rc, finish);
+ opts.kv.oflags = cobject_int(varr[c++], false, &rc);
+ RCGO(rc, finish);
+ opts.kv.wal.enabled = cobject_bool(varr[c++], false, &rc);
+ RCGO(rc, finish);
+ opts.kv.wal.check_crc_on_checkpoint = cobject_bool(varr[c++], true, &rc);
+ RCGO(rc, finish);
+ opts.kv.wal.checkpoint_buffer_sz = cobject_int(varr[c++], true, &rc);
+ RCGO(rc, finish);
+ opts.kv.wal.checkpoint_timeout_sec = cobject_int(varr[c++], true, &rc);
+ RCGO(rc, finish);
+ opts.kv.wal.savepoint_timeout_sec = cobject_int(varr[c++], true, &rc);
+ RCGO(rc, finish);
+ opts.kv.wal.wal_buffer_sz = cobject_int(varr[c++], true, &rc);
+ RCGO(rc, finish);
+ opts.document_buffer_sz = cobject_int(varr[c++], true, &rc);
+ RCGO(rc, finish);
+ opts.sort_buffer_sz = cobject_int(varr[c++], true, &rc);
+ RCGO(rc, finish);
+ opts.http.enabled = cobject_bool(varr[c++], true, &rc);
+ RCGO(rc, finish);
+ opts.http.access_token = cobject_str(varr[c++], true, &rc);
+ RCGO(rc, finish);
+ opts.http.bind = cobject_str(varr[c++], true, &rc);
+ RCGO(rc, finish);
+ opts.http.max_body_size = cobject_int(varr[c++], true, &rc);
+ RCGO(rc, finish);
+ opts.http.port = cobject_int(varr[c++], true, &rc);
+ RCGO(rc, finish);
+ opts.http.read_anon = cobject_bool(varr[c++], true, &rc);
+ RCGO(rc, finish);
+
+ opts.kv.file_lock_fail_fast = true;
+ opts.no_wal = !opts.kv.wal.enabled;
+ opts.http.blocking = false;
+ opts.http.access_token_len = opts.http.access_token ? strlen(opts.http.access_token) : 0;
+
+ rc = ejdb2_isolate_shared_open(&opts, &dbh);
+ RCGO(rc, finish);
+
+ rv1.type = Dart_CObject_kInt64;
+ rv1.value.as_int64 = (intptr_t) dbh;
+ result.type = Dart_CObject_kArray;
+ result.value.as_array.length = sizeof(rv) / sizeof(rv[0]);
+ result.value.as_array.values = rv;
+
+finish:
+ EJPORT_RC(&result, rc);
+ Dart_PostCObject(reply_port, &result);
+}
+
+static void ejd_close_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port) {
+ iwrc rc = 0;
+ Dart_CObject result = { .type = Dart_CObject_kArray };
+
+ if (msg->value.as_array.length != 3) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ intptr_t ptr = cobject_int(msg->value.as_array.values[2], false, &rc);
+ RCGO(rc, finish);
+ EJDB2Handle *dbh = (EJDB2Handle*) ptr;
+ if (!dbh) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ rc = ejdb2_isolate_shared_release(&dbh);
+ RCGO(rc, finish);
+
+ if (receive_port != ILLEGAL_PORT) {
+ Dart_CloseNativePort(receive_port);
+ }
+
+finish:
+ EJPORT_RC(&result, rc);
+ Dart_PostCObject(reply_port, &result);
+ return;
+}
+
+static void ejd_patch_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port) {
+ iwrc rc = 0;
+ Dart_CObject result = { .type = Dart_CObject_kArray };
+
+ int c = 2;
+ if ((msg->type != Dart_CObject_kArray) || (msg->value.as_array.length != 5 + c)) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+
+ intptr_t ptr = cobject_int(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+ EJDB2Handle *dbh = (EJDB2Handle*) ptr;
+ if (!dbh || !dbh->db) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ EJDB db = dbh->db;
+ const char *coll = cobject_str(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ const char *patch = cobject_str(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ int64_t id = cobject_int(msg->value.as_array.values[c++], true, &rc);
+ RCGO(rc, finish);
+
+ bool upsert = cobject_bool(msg->value.as_array.values[c++], true, &rc);
+ RCGO(rc, finish);
+
+ if (upsert) {
+ rc = ejdb_merge_or_put(db, coll, patch, id);
+ } else {
+ rc = ejdb_patch(db, coll, patch, id);
+ }
+
+finish:
+ EJPORT_RC(&result, rc);
+ Dart_PostCObject(reply_port, &result);
+}
+
+static void ejd_put_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port) {
+ iwrc rc = 0;
+ Dart_CObject result, rv1;
+ Dart_CObject *rv[1] = { &rv1 };
+
+ JBL jbl = 0;
+ int c = 2;
+ if ((msg->type != Dart_CObject_kArray) || (msg->value.as_array.length != 4 + c)) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+
+ intptr_t ptr = cobject_int(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+ EJDB2Handle *dbh = (EJDB2Handle*) ptr;
+ if (!dbh || !dbh->db) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ EJDB db = dbh->db;
+ const char *coll = cobject_str(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ const char *json = cobject_str(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ int64_t id = cobject_int(msg->value.as_array.values[c++], true, &rc);
+ RCGO(rc, finish);
+
+ rc = jbl_from_json(&jbl, json);
+ RCGO(rc, finish);
+
+ if (id > 0) {
+ rc = ejdb_put(db, coll, jbl, id);
+ } else {
+ rc = ejdb_put_new(db, coll, jbl, &id);
+ }
+ RCGO(rc, finish);
+
+ rv1.type = Dart_CObject_kInt64;
+ rv1.value.as_int64 = id;
+ result.type = Dart_CObject_kArray;
+ result.value.as_array.length = sizeof(rv) / sizeof(rv[0]);
+ result.value.as_array.values = rv;
+
+finish:
+ if (jbl) {
+ jbl_destroy(&jbl);
+ }
+ EJPORT_RC(&result, rc);
+ Dart_PostCObject(reply_port, &result);
+}
+
+static void ejd_del_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port) {
+ iwrc rc = 0;
+ Dart_CObject result = { .type = Dart_CObject_kArray };
+
+ int c = 2;
+ if ((msg->type != Dart_CObject_kArray) || (msg->value.as_array.length != 3 + c)) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+
+ intptr_t ptr = cobject_int(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+ EJDB2Handle *dbh = (EJDB2Handle*) ptr;
+ if (!dbh || !dbh->db) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ EJDB db = dbh->db;
+ const char *coll = cobject_str(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ int64_t id = cobject_int(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ rc = ejdb_del(db, coll, id);
+
+finish:
+ EJPORT_RC(&result, rc);
+ Dart_PostCObject(reply_port, &result);
+}
+
+static void ejd_rename_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port) {
+ iwrc rc = 0;
+ Dart_CObject result = { .type = Dart_CObject_kArray };
+
+ int c = 2;
+ if ((msg->type != Dart_CObject_kArray) || (msg->value.as_array.length != 3 + c)) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ intptr_t ptr = cobject_int(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+ EJDB2Handle *dbh = (EJDB2Handle*) ptr;
+ if (!dbh || !dbh->db) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ EJDB db = dbh->db;
+
+ const char *oname = cobject_str(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ const char *nname = cobject_str(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ rc = ejdb_rename_collection(db, oname, nname);
+
+finish:
+ EJPORT_RC(&result, rc);
+ Dart_PostCObject(reply_port, &result);
+}
+
+static void ejd_idx_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port) {
+ iwrc rc = 0;
+ Dart_CObject result = { .type = Dart_CObject_kArray };
+
+ int c = 2;
+ if ((msg->type != Dart_CObject_kArray) || (msg->value.as_array.length != 4 + c)) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+
+ intptr_t ptr = cobject_int(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+ EJDB2Handle *dbh = (EJDB2Handle*) ptr;
+ if (!dbh || !dbh->db) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ EJDB db = dbh->db;
+ const char *coll = cobject_str(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ const char *path = cobject_str(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ int64_t mode = cobject_int(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ rc = ejdb_ensure_index(db, coll, path, mode);
+
+finish:
+ EJPORT_RC(&result, rc);
+ Dart_PostCObject(reply_port, &result);
+}
+
+static void ejd_rmi_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port) {
+ iwrc rc = 0;
+ Dart_CObject result = { .type = Dart_CObject_kArray };
+
+ int c = 2;
+ if ((msg->type != Dart_CObject_kArray) || (msg->value.as_array.length != 4 + c)) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+
+ intptr_t ptr = cobject_int(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+ EJDB2Handle *dbh = (EJDB2Handle*) ptr;
+ if (!dbh || !dbh->db) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ EJDB db = dbh->db;
+ const char *coll = cobject_str(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ const char *path = cobject_str(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ int64_t mode = cobject_int(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ rc = ejdb_remove_index(db, coll, path, mode);
+
+finish:
+ EJPORT_RC(&result, rc);
+ Dart_PostCObject(reply_port, &result);
+}
+
+static void ejd_rmc_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port) {
+ iwrc rc = 0;
+ Dart_CObject result = { .type = Dart_CObject_kArray };
+
+ int c = 2;
+ if ((msg->type != Dart_CObject_kArray) || (msg->value.as_array.length != 2 + c)) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+
+ intptr_t ptr = cobject_int(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+ EJDB2Handle *dbh = (EJDB2Handle*) ptr;
+ if (!dbh || !dbh->db) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ EJDB db = dbh->db;
+ const char *coll = cobject_str(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ rc = ejdb_remove_collection(db, coll);
+
+finish:
+ EJPORT_RC(&result, rc);
+ Dart_PostCObject(reply_port, &result);
+}
+
+static void ejd_bkp_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port) {
+ iwrc rc = 0;
+ Dart_CObject result, rv1;
+ Dart_CObject *rv[1] = { &rv1 };
+ uint64_t ts = 0;
+
+ int c = 2;
+ if ((msg->type != Dart_CObject_kArray) || (msg->value.as_array.length != 2 + c)) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+
+ intptr_t ptr = cobject_int(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+ EJDB2Handle *dbh = (EJDB2Handle*) ptr;
+ if (!dbh || !dbh->db) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+
+ EJDB db = dbh->db;
+ const char *fileName = cobject_str(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ rc = ejdb_online_backup(db, &ts, fileName);
+
+ rv1.type = Dart_CObject_kInt64;
+ rv1.value.as_int64 = ts;
+ result.type = Dart_CObject_kArray;
+ result.value.as_array.length = sizeof(rv) / sizeof(rv[0]);
+ result.value.as_array.values = rv;
+
+finish:
+ EJPORT_RC(&result, rc);
+ Dart_PostCObject(reply_port, &result);
+}
+
+static void ejd_info_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port) {
+ iwrc rc = 0;
+ Dart_CObject result, rv1;
+ Dart_CObject *rv[1] = { &rv1 };
+
+ JBL jbl = 0;
+ IWXSTR *xstr = 0;
+ int c = 2;
+
+ if ((msg->type != Dart_CObject_kArray) || (msg->value.as_array.length != 1 + c)) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+
+ intptr_t ptr = cobject_int(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+ EJDB2Handle *dbh = (EJDB2Handle*) ptr;
+ if (!dbh || !dbh->db) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ EJDB db = dbh->db;
+ rc = ejdb_get_meta(db, &jbl);
+ RCGO(rc, finish);
+
+ xstr = iwxstr_new2(jbl_size(jbl) * 2);
+ if (!xstr) {
+ rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
+ goto finish;
+ }
+ rc = jbl_as_json(jbl, jbl_xstr_json_printer, xstr, 0);
+ RCGO(rc, finish);
+
+ rv1.type = Dart_CObject_kString;
+ rv1.value.as_string = iwxstr_ptr(xstr);
+ result.type = Dart_CObject_kArray;
+ result.value.as_array.length = sizeof(rv) / sizeof(rv[0]);
+ result.value.as_array.values = rv;
+
+finish:
+ if (jbl) {
+ jbl_destroy(&jbl);
+ }
+ EJPORT_RC(&result, rc);
+ Dart_PostCObject(reply_port, &result);
+ if (xstr) {
+ iwxstr_destroy(xstr);
+ }
+}
+
+static void ejd_get_wrapped(Dart_Port receive_port, Dart_CObject *msg, Dart_Port reply_port) {
+ iwrc rc = 0;
+ Dart_CObject result, rv1;
+ Dart_CObject *rv[1] = { &rv1 };
+
+ JBL jbl = 0;
+ IWXSTR *xstr = 0;
+ int c = 2;
+
+ if ((msg->type != Dart_CObject_kArray) || (msg->value.as_array.length != 3 + c)) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+
+ intptr_t ptr = cobject_int(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+ EJDB2Handle *dbh = (EJDB2Handle*) ptr;
+ if (!dbh || !dbh->db) {
+ rc = EJD_ERROR_INVALID_NATIVE_CALL_ARGS;
+ goto finish;
+ }
+ EJDB db = dbh->db;
+ const char *coll = cobject_str(msg->value.as_array.values[c++], false, &rc);
+ RCGO(rc, finish);
+
+ int64_t id = cobject_int(msg->value.as_array.values[c++], true, &rc);
+ RCGO(rc, finish);
+
+ rc = ejdb_get(db, coll, id, &jbl);
+ RCGO(rc, finish);
+
+ xstr = iwxstr_new2(jbl_size(jbl) * 2);
+ if (!xstr) {
+ rc = iwrc_set_errno(IW_ERROR_ALLOC, errno);
+ goto finish;
+ }
+ rc = jbl_as_json(jbl, jbl_xstr_json_printer, xstr, 0);
+ RCGO(rc, finish);
+
+ rv1.type = Dart_CObject_kString;
+ rv1.value.as_string = iwxstr_ptr(xstr);
+ result.type = Dart_CObject_kArray;
+ result.value.as_array.length = sizeof(rv) / sizeof(rv[0]);
+ result.value.as_array.values = rv;
+
+finish:
+ if (jbl) {
+ jbl_destroy(&jbl);
+ }
+ EJPORT_RC(&result, rc);
+ Dart_PostCObject(reply_port, &result);
+ if (xstr) {
+ iwxstr_destroy(xstr);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+//
+///////////////////////////////////////////////////////////////////////////
+
+static const char *ejd_ecodefn(locale_t locale, uint32_t ecode) {
+ if (!((ecode > _EJD_ERROR_START) && (ecode < _EJD_ERROR_END))) {
+ return 0;
+ }
+ switch (ecode) {
+ case EJD_ERROR_CREATE_PORT:
+ return "Failed to create a Dart port (EJD_ERROR_CREATE_PORT)";
+ case EJD_ERROR_INVALID_NATIVE_CALL_ARGS:
+ return "Invalid native function call args (EJD_ERROR_INVALID_NATIVE_CALL_ARGS)";
+ case EJD_ERROR_INVALID_STATE:
+ return "Invalid native extension state (EJD_ERROR_INVALID_STATE)";
+ case EJD_ERROR_POST_PORT:
+ return "Failed to post message to Dart port (EJD_ERROR_POST_PORT)";
+ }
+ return 0;
+}
+
+DART_EXPORT Dart_Handle ejdb2dart_Init(Dart_Handle parent_library) {
+ static volatile int ejd_ecodefn_initialized = 0;
+ if (__sync_bool_compare_and_swap(&ejd_ecodefn_initialized, 0, 1)) {
+ iwrc rc = ejdb_init();
+ if (rc) {
+ return ejd_error_rc_create(rc);
+ }
+ iwlog_register_ecodefn(ejd_ecodefn);
+ }
+ if (Dart_IsError(parent_library)) {
+ return parent_library;
+ }
+ Dart_Handle dh = Dart_SetNativeResolver(parent_library, ejd_resolve_name, 0);
+ if (Dart_IsError(dh)) {
+ return dh;
+ }
+ return Dart_Null();
+}
+
+static void ejd_ctx_finalizer(void *isolate_callback_data, void *peer) {
+ EJDB2Context *ctx = peer;
+ if (ctx) {
+ if (ctx->dbh) {
+ iwrc rc = ejdb2_isolate_shared_release(&ctx->dbh);
+ if (rc) {
+ iwlog_ecode_error3(rc);
+ }
+ }
+ if (ctx->wph && Dart_CurrentIsolateGroup()) {
+ Dart_DeleteWeakPersistentHandle(ctx->wph);
+ }
+ }
+
+ free(ctx);
+}
diff --git a/src/bindings/ejdb2_dart/lib/ejdb2_dart.dart b/src/bindings/ejdb2_dart/lib/ejdb2_dart.dart
new file mode 100644
index 0000000..48988d8
--- /dev/null
+++ b/src/bindings/ejdb2_dart/lib/ejdb2_dart.dart
@@ -0,0 +1,632 @@
+///
+/// EJDB2 Dart VM native API binding.
+///
+/// See https://github.com/Softmotions/ejdb/blob/master/README.md
+///
+/// For API usage examples look into `/example` and `/test` folders.
+///
+
+library ejdb2_dart;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:convert' as convert_lib;
+import 'dart:io';
+import 'dart:isolate';
+import 'dart:nativewrappers' show NativeFieldWrapperClass2;
+
+import 'package:path/path.dart' as path_lib;
+import 'package:quiver/core.dart';
+import 'package:json_at/json_at.dart';
+
+import 'dart-ext:ejdb2dart';
+
+String ejdb2ExplainRC(int rc) native 'explain_rc';
+
+/// EJDB specific exception
+class EJDB2Error implements Exception {
+ EJDB2Error(this.code, this.message);
+
+ EJDB2Error.fromCode(int code) : this(code, ejdb2ExplainRC(code));
+
+ EJDB2Error.invalidState() : this.fromCode(EJD_ERROR_INVALID_STATE);
+
+ EJDB2Error.notFound() : this.fromCode(IWKV_ERROR_NOTFOUND);
+
+ static int EJD_ERROR_CREATE_PORT = 89001;
+ static int EJD_ERROR_POST_PORT = 89002;
+ static int EJD_ERROR_INVALID_NATIVE_CALL_ARGS = 89003;
+ static int EJD_ERROR_INVALID_STATE = 89004;
+ static int IWKV_ERROR_NOTFOUND = 75001;
+
+ final int code;
+
+ final String message;
+
+ bool get notFound => code == IWKV_ERROR_NOTFOUND;
+
+ bool get invalidQuery => code == 87001;
+
+ @override
+ String toString() => '$runtimeType: $code $message';
+}
+
+/// EJDB document item
+class JBDOC {
+ JBDOC(this.id, this._json);
+ JBDOC._fromList(List list) : this(list[0] as int, list[1] as String?);
+
+ /// Document identifier
+ final int id;
+
+ /// Document body as JSON string
+ String get json => _json ?? convert_lib.jsonEncode(_object);
+
+ /// Document body as parsed JSON object.
+ dynamic get object {
+ if (_json == null) {
+ return _object;
+ } else {
+ _object = convert_lib.jsonDecode(_json!);
+ _json = null; // Release memory used to store JSON string data
+ return _object;
+ }
+ }
+
+ /// Gets subset of document using RFC 6901 JSON [pointer].
+ Optional at(String pointer) => jsonAt(object, pointer);
+
+ /// Gets subset of document using RFC 6901 JSON [pointer].
+ Optional operator [](String pointer) => at(pointer);
+
+ String? _json;
+
+ dynamic _object;
+
+ @override
+ String toString() => '$runtimeType: $id $json';
+}
+
+/// Represents query on ejdb collection.
+/// Instance can be reused for multiple queries reusing
+/// placeholder parameters.
+class JQL extends NativeFieldWrapperClass2 {
+ JQL._(this.db, this.query, this.collection);
+
+ final String query;
+ final String collection;
+ final EJDB2 db;
+
+ StreamController? _controller;
+ RawReceivePort? _replyPort;
+
+ /// Execute query and returns a stream of matched documents.
+ ///
+ /// [explainCallback] Used to get query execution log.
+ /// [limit] Overrides `limit` set by query text for this execution session.
+ ///
+ Stream execute({void explainCallback(String log)?, int limit = 0}) {
+ abort();
+ var execHandle = 0;
+ _controller = StreamController();
+ _replyPort = RawReceivePort();
+ _replyPort!.handler = (dynamic reply) {
+ if (reply is int) {
+ _exec_check(execHandle, true);
+ _replyPort!.close();
+ _controller!.addError(EJDB2Error.fromCode(reply));
+ return;
+ } else if (reply is List) {
+ _exec_check(execHandle, false);
+ if (reply[2] != null && explainCallback != null) {
+ explainCallback(reply[2] as String);
+ }
+ _controller!.add(JBDOC._fromList(reply));
+ } else {
+ _exec_check(execHandle, true);
+ if (reply != null && explainCallback != null) {
+ explainCallback(reply as String);
+ }
+ abort();
+ }
+ };
+ execHandle = _exec(_replyPort!.sendPort, explainCallback != null, limit);
+ return _controller!.stream;
+ }
+
+ /// Returns optional element for first record in result set.
+ Future> first({void explainCallback(String log)?}) async {
+ await for (final doc in execute(explainCallback: explainCallback, limit: 1)) {
+ return Optional.of(doc);
+ }
+ return const Optional.absent();
+ }
+
+ /// Return first record in result set or throw not found [EJDB2Error] error.
+ Future firstRequired({void explainCallback(String log)?}) async {
+ await for (final doc in execute(explainCallback: explainCallback, limit: 1)) {
+ return doc;
+ }
+ throw EJDB2Error.notFound();
+ }
+
+ /// Collects up to [n] elements from result set into array.
+ Future> firstN(int n, {void explainCallback(String log)?}) async {
+ final ret = [];
+ await for (final doc in execute(explainCallback: explainCallback, limit: n)) {
+ if (n-- <= 0) break;
+ ret.add(doc);
+ }
+ return ret;
+ }
+
+ /// Abort query execution.
+ void abort() {
+ _replyPort?.close();
+ _replyPort = null;
+ _controller?.close();
+ _controller = null;
+ }
+
+ /// Return scalar integer value as result of query execution.
+ /// For example execution of count query: `/... | count`
+ Future scalarInt({void explainCallback(String log)?}) {
+ return execute(explainCallback: explainCallback).map((d) => d.id).first;
+ }
+
+ /// Set [json] at the specified [placeholder].
+ /// [placeholder] can be either `string` or `int`
+ JQL setJson(dynamic placeholder, dynamic json) {
+ _checkPlaceholder(placeholder);
+ ArgumentError.checkNotNull(json);
+ _set(placeholder, _asJsonString(json), 1);
+ return this;
+ }
+
+ /// Set [regexp] at the specified [placeholder].
+ /// [placeholder] can be either `string` or `int`
+ JQL setRegExp(dynamic placeholder, RegExp regexp) {
+ _checkPlaceholder(placeholder);
+ ArgumentError.checkNotNull(regexp);
+ _set(placeholder, regexp.pattern, 2);
+ return this;
+ }
+
+ /// Set integer [val] at the specified [placeholder].
+ /// [placeholder] can be either `string` or `int`
+ JQL setInt(dynamic placeholder, int val) {
+ _checkPlaceholder(placeholder);
+ ArgumentError.checkNotNull(val);
+ _set(placeholder, val);
+ return this;
+ }
+
+ /// Set double [val] at the specified [placeholder].
+ /// [placeholder] can be either `string` or `int`
+ JQL setDouble(dynamic placeholder, double val) {
+ _checkPlaceholder(placeholder);
+ ArgumentError.checkNotNull(val);
+ _set(placeholder, val);
+ return this;
+ }
+
+ /// Set boolean [val] at the specified [placeholder].
+ /// [placeholder] can be either `string` or `int`
+ JQL setBoolean(dynamic placeholder, bool val) {
+ _checkPlaceholder(placeholder);
+ ArgumentError.checkNotNull(val);
+ _set(placeholder, val);
+ return this;
+ }
+
+ /// Set string [val] at the specified [placeholder].
+ /// [placeholder] can be either `string` or `int`
+ JQL setString(dynamic placeholder, String val) {
+ _checkPlaceholder(placeholder);
+ ArgumentError.checkNotNull(val);
+ _set(placeholder, val);
+ return this;
+ }
+
+ /// Set `null` at the specified [placeholder].
+ /// [placeholder] can be either `string` or `int`
+ JQL setNull(dynamic placeholder) {
+ _checkPlaceholder(placeholder);
+ _set(placeholder, null);
+ return this;
+ }
+
+ /// Get current `limit` encoded in query.
+ int get limit native 'jql_get_limit';
+
+ void _checkPlaceholder(dynamic placeholder) {
+ if (!(placeholder is String) && !(placeholder is int)) {
+ ArgumentError.value(placeholder, 'placeholder');
+ }
+ }
+
+ void _set(dynamic placeholder, dynamic value, [int type]) native 'jql_set';
+
+ int _exec(SendPort sendPort, bool explain, int limit) native 'exec';
+
+ void _exec_check(int execHandle, bool terminate) native 'check_exec';
+}
+
+/// Database wrapper
+class EJDB2 extends NativeFieldWrapperClass2 {
+ EJDB2._();
+
+ static bool _checkCompleterPortError(Completer completer, dynamic reply) {
+ if (reply is int) {
+ completer.completeError(EJDB2Error(reply, ejdb2ExplainRC(reply)));
+ return true;
+ } else if (reply is! List) {
+ completer.completeError(EJDB2Error(0, 'Invalid port response'));
+ return true;
+ }
+ return false;
+ }
+
+ /// Open EJDB2 database
+ /// See https://github.com/Softmotions/ejdb/blob/master/src/ejdb2.h#L104
+ /// for description of options.
+ static Future open(String path,
+ {bool truncate = false,
+ bool readonly = false,
+ bool http_enabled = false,
+ bool http_read_anon = false,
+ bool wal_enabled = true,
+ bool wal_check_crc_on_checkpoint = false,
+ int? wal_checkpoint_buffer_sz,
+ int? wal_checkpoint_timeout_sec,
+ int? wal_savepoint_timeout_sec,
+ int? wal_wal_buffer_sz,
+ int? document_buffer_sz,
+ int? sort_buffer_sz,
+ String? http_access_token,
+ String? http_bind,
+ int? http_max_body_size,
+ int? http_port}) {
+ final completer = Completer();
+ final replyPort = RawReceivePort();
+ final jb = EJDB2._();
+
+ path = path_lib.canonicalize(File(path).absolute.path);
+
+ replyPort.handler = (dynamic reply) {
+ replyPort.close();
+ if (_checkCompleterPortError(completer, reply)) {
+ return;
+ }
+ try {
+ jb._set_handle((reply as List).first as int);
+ } catch (e) {
+ completer.completeError(e);
+ return;
+ }
+ completer.complete(jb);
+ };
+
+ // Open
+ var oflags = 0;
+ if (readonly) {
+ oflags |= 0x02;
+ } else if (truncate) {
+ oflags |= 0x04;
+ }
+
+ jb._port().send([
+ replyPort.sendPort,
+ 'open',
+ path,
+ oflags,
+ wal_enabled,
+ wal_check_crc_on_checkpoint,
+ wal_checkpoint_buffer_sz as dynamic,
+ wal_checkpoint_timeout_sec as dynamic,
+ wal_savepoint_timeout_sec as dynamic,
+ wal_wal_buffer_sz as dynamic,
+ document_buffer_sz as dynamic,
+ sort_buffer_sz as dynamic,
+ http_enabled,
+ http_access_token as dynamic,
+ http_bind as dynamic,
+ http_max_body_size as dynamic,
+ http_port as dynamic,
+ http_read_anon
+ ]);
+ return completer.future;
+ }
+
+ /// Closes database instance.
+ Future close() {
+ final hdb = _get_handle();
+ if (hdb == null) {
+ return Future.value();
+ }
+ final completer = Completer();
+ final replyPort = RawReceivePort();
+ replyPort.handler = (dynamic reply) {
+ replyPort.close();
+ if (_checkCompleterPortError(completer, reply)) {
+ return;
+ }
+ completer.complete();
+ };
+ _set_handle(null);
+ _port().send([replyPort.sendPort, 'close', hdb as dynamic]);
+ return completer.future;
+ }
+
+ /// Save [json] document under specified [id] or create a document
+ /// with new generated `id`. Returns future holding actual document `id`.
+ Future put(String collection, dynamic json, [int? id]) {
+ final hdb = _get_handle();
+ if (hdb == null) {
+ return Future.error(EJDB2Error.invalidState());
+ }
+ final completer = Completer();
+ final replyPort = RawReceivePort();
+ replyPort.handler = (dynamic reply) {
+ replyPort.close();
+ if (_checkCompleterPortError(completer, reply)) {
+ return;
+ }
+ completer.complete((reply as List).first as int);
+ };
+ _port().send([
+ replyPort.sendPort,
+ 'put',
+ hdb as dynamic,
+ collection,
+ _asJsonString(json),
+ id as dynamic
+ ]);
+ return completer.future;
+ }
+
+ /// Apply rfc6902/rfc7386 JSON [patch] to the document identified by [id].
+ Future patch(String collection, dynamic patchObj, int id, [bool upsert = false]) {
+ final hdb = _get_handle();
+ if (hdb == null) {
+ return Future.error(EJDB2Error.invalidState());
+ }
+ final completer = Completer();
+ final replyPort = RawReceivePort();
+ replyPort.handler = (dynamic reply) {
+ replyPort.close();
+ if (_checkCompleterPortError(completer, reply)) {
+ return;
+ }
+ completer.complete();
+ };
+ _port().send([
+ replyPort.sendPort,
+ 'patch',
+ hdb as dynamic,
+ collection,
+ _asJsonString(patchObj),
+ id as dynamic,
+ upsert
+ ]);
+ return completer.future;
+ }
+
+ /// Apply JSON merge patch (rfc7396) to the document identified by `id` or
+ /// insert new document under specified `id`.
+ Future patchOrPut(String collection, dynamic patchObj, int id) =>
+ patch(collection, patch, id, true);
+
+ /// Get json body of document identified by [id] and stored in [collection].
+ /// Throws [EJDB2Error] not found exception if document is not found.
+ Future get(String collection, int id) {
+ final hdb = _get_handle();
+ if (hdb == null) {
+ return Future.error(EJDB2Error.invalidState());
+ }
+ final completer = Completer();
+ final replyPort = RawReceivePort();
+ replyPort.handler = (dynamic reply) {
+ replyPort.close();
+ if (_checkCompleterPortError(completer, reply)) {
+ return;
+ }
+ completer.complete((reply as List).first as String);
+ };
+ _port().send([replyPort.sendPort, 'get', hdb as dynamic, collection, id]);
+ return completer.future;
+ }
+
+ /// Get json body of database metadata.
+ Future info() {
+ final hdb = _get_handle();
+ if (hdb == null) {
+ return Future.error(EJDB2Error.invalidState());
+ }
+ final completer = Completer();
+ final replyPort = RawReceivePort();
+ replyPort.handler = (dynamic reply) {
+ replyPort.close();
+ if (_checkCompleterPortError(completer, reply)) {
+ return;
+ }
+ completer.complete((reply as List).first as String);
+ };
+ _port().send([replyPort.sendPort, 'info', hdb as dynamic]);
+ return completer.future;
+ }
+
+ /// Remove document idenfied by [id] from [collection].
+ Future del(String collection, int id) {
+ final hdb = _get_handle();
+ if (hdb == null) {
+ return Future.error(EJDB2Error.invalidState());
+ }
+ final completer = Completer();
+ final replyPort = RawReceivePort();
+ replyPort.handler = (dynamic reply) {
+ replyPort.close();
+ if (_checkCompleterPortError(completer, reply)) {
+ return;
+ }
+ completer.complete();
+ };
+ _port().send([replyPort.sendPort, 'del', hdb as dynamic, collection, id]);
+ return completer.future;
+ }
+
+ /// Remove document idenfied by [id] from [collection].
+ /// Doesn't raise error if document is not found.
+ Future delIgnoreNotFound(String collection, int id) =>
+ del(collection, id).catchError((err) {
+ if (err is EJDB2Error && err.notFound) {
+ return Future.value();
+ } else {
+ return Future.error(err as Object);
+ }
+ });
+
+ Future renameCollection(String oldCollection, String newCollectionName) {
+ final hdb = _get_handle();
+ if (hdb == null) {
+ return Future.error(EJDB2Error.invalidState());
+ }
+ final completer = Completer();
+ final replyPort = RawReceivePort();
+ replyPort.handler = (dynamic reply) {
+ replyPort.close();
+ if (_checkCompleterPortError(completer, reply)) {
+ return;
+ }
+ completer.complete();
+ };
+ _port().send([replyPort.sendPort, 'rename', hdb as dynamic, oldCollection, newCollectionName]);
+ return completer.future;
+ }
+
+ /// Ensures json document database index specified by [path] json pointer to string data type.
+ Future ensureStringIndex(String collection, String path, {bool unique = false}) {
+ return _idx(collection, path, 0x04 | (unique ? 0x01 : 0));
+ }
+
+ /// Removes specified database index.
+ Future removeStringIndex(String collection, String path, {bool unique = false}) {
+ return _rmi(collection, path, 0x04 | (unique ? 0x01 : 0));
+ }
+
+ /// Ensures json document database index specified by [path] json pointer to integer data type.
+ Future ensureIntIndex(String collection, String path, {bool unique = false}) {
+ return _idx(collection, path, 0x08 | (unique ? 0x01 : 0));
+ }
+
+ /// Removes specified database index.
+ Future removeIntIndex(String collection, String path, {bool unique = false}) {
+ return _rmi(collection, path, 0x08 | (unique ? 0x01 : 0));
+ }
+
+ /// Ensures json document database index specified by [path] json pointer to floating point data type.
+ Future ensureFloatIndex(String collection, String path, {bool unique = false}) {
+ return _idx(collection, path, 0x10 | (unique ? 0x01 : 0));
+ }
+
+ /// Removes specified database index.
+ Future removeFloatIndex(String collection, String path, {bool unique = false}) {
+ return _rmi(collection, path, 0x10 | (unique ? 0x01 : 0));
+ }
+
+ /// Removes database [collection].
+ Future removeCollection(String collection) {
+ final hdb = _get_handle();
+ if (hdb == null) {
+ return Future.error(EJDB2Error.invalidState());
+ }
+ final completer = Completer();
+ final replyPort = RawReceivePort();
+ replyPort.handler = (dynamic reply) {
+ replyPort.close();
+ if (_checkCompleterPortError(completer, reply)) {
+ return;
+ }
+ completer.complete();
+ };
+ _port().send([replyPort.sendPort, 'rmc', hdb as dynamic, collection]);
+ return completer.future;
+ }
+
+ /// Creates an online database backup image and copies it into the specified [fileName].
+ /// During online backup phase read/write database operations are allowed and not
+ /// blocked for significant amount of time. Returns future with backup
+ /// finish time as number of milliseconds since epoch.
+ Future onlineBackup(String fileName) {
+ final hdb = _get_handle();
+ if (hdb == null) {
+ return Future.error(EJDB2Error.invalidState());
+ }
+ final completer = Completer();
+ final replyPort = RawReceivePort();
+ replyPort.handler = (dynamic reply) {
+ replyPort.close();
+ if (_checkCompleterPortError(completer, reply)) {
+ return;
+ }
+ completer.complete((reply as List).first as int);
+ };
+ _port().send([replyPort.sendPort, 'bkp', hdb as dynamic, fileName]);
+ return completer.future;
+ }
+
+ /// Create instance of [query] specified for [collection].
+ /// If [collection] is not specified a [query] spec must contain collection name,
+ /// eg: `@mycollection/[foo=bar]`
+ JQL createQuery(String query, [String collection]) native 'create_query';
+
+ Future _idx(String collection, String path, int mode) {
+ final hdb = _get_handle();
+ if (hdb == null) {
+ return Future.error(EJDB2Error.invalidState());
+ }
+ final completer = Completer();
+ final replyPort = RawReceivePort();
+ replyPort.handler = (dynamic reply) {
+ replyPort.close();
+ if (_checkCompleterPortError(completer, reply)) {
+ return;
+ }
+ completer.complete();
+ };
+ _port().send([replyPort.sendPort, 'idx', hdb as dynamic, collection, path, mode]);
+ return completer.future;
+ }
+
+ Future _rmi(String collection, String path, int mode) {
+ final hdb = _get_handle();
+ if (hdb == null) {
+ return Future.error(EJDB2Error.invalidState());
+ }
+ final completer = Completer();
+ final replyPort = RawReceivePort();
+ replyPort.handler = (dynamic reply) {
+ replyPort.close();
+ if (_checkCompleterPortError(completer, reply)) {
+ return;
+ }
+ completer.complete();
+ };
+ _port().send([replyPort.sendPort, 'rmi', hdb as dynamic, collection, path, mode]);
+ return completer.future;
+ }
+
+ SendPort _port() native 'port';
+
+ void _set_handle(int? handle) native 'set_handle';
+
+ int? _get_handle() native 'get_handle';
+}
+
+String _asJsonString(dynamic val) {
+ if (val is String) {
+ return val;
+ } else {
+ return jsonEncode(val);
+ }
+}
diff --git a/src/bindings/ejdb2_dart/pubspec.yaml b/src/bindings/ejdb2_dart/pubspec.yaml
new file mode 100644
index 0000000..c2d9bc4
--- /dev/null
+++ b/src/bindings/ejdb2_dart/pubspec.yaml
@@ -0,0 +1,15 @@
+name: ejdb2_dart
+description: Embeddable JSON Database engine EJDB http://ejdb.org Dart binding.
+version: 1.0.63
+homepage: https://github.com/Softmotions/ejdb
+issue_tracker: https://github.com/Softmotions/ejdb/issues?q=is%3Aissue+label%3ADart+
+license: MIT
+
+environment:
+ sdk: ">=2.12.0-0 <3.0.0"
+
+dependencies:
+ json_at: ^2.0.0-nullsafety.1
+ path: ^1.8.0-nullsafety.3
+ quiver: ^3.0.0-nullsafety.2
+ test: ^1.16.0-nullsafety.13
diff --git a/src/bindings/ejdb2_dart/pubspec.yaml.in b/src/bindings/ejdb2_dart/pubspec.yaml.in
new file mode 100644
index 0000000..c6a9ffa
--- /dev/null
+++ b/src/bindings/ejdb2_dart/pubspec.yaml.in
@@ -0,0 +1,15 @@
+name: ejdb2_dart
+description: Embeddable JSON Database engine EJDB http://ejdb.org Dart binding.
+version: @EJDB2_DART_VERSION@
+homepage: https://github.com/Softmotions/ejdb
+issue_tracker: https://github.com/Softmotions/ejdb/issues?q=is%3Aissue+label%3ADart+
+license: MIT
+
+environment:
+ sdk: ">=2.12.0-0 <3.0.0"
+
+dependencies:
+ json_at: ^2.0.0-nullsafety.1
+ path: ^1.8.0-nullsafety.3
+ quiver: ^3.0.0-nullsafety.2
+ test: ^1.16.0-nullsafety.13
diff --git a/src/bindings/ejdb2_dart/test/ejdb2_dart_test.dart b/src/bindings/ejdb2_dart/test/ejdb2_dart_test.dart
new file mode 100644
index 0000000..980d8f5
--- /dev/null
+++ b/src/bindings/ejdb2_dart/test/ejdb2_dart_test.dart
@@ -0,0 +1,192 @@
+import 'package:ejdb2_dart/ejdb2_dart.dart';
+
+void main() async {
+ final db = await EJDB2.open('hello.db', truncate: true);
+
+ var q = db.createQuery('@mycoll/*');
+ assert(q.collection == 'mycoll');
+
+ var id = await db.put('mycoll', {'foo': 'bar'});
+ assert(id == 1);
+
+ dynamic error;
+ try {
+ await db.put('mycoll', '{"');
+ } on EJDB2Error catch (e) {
+ error = e;
+ assert(e.code == 86005);
+ assert(e.message == 'Unquoted JSON string (JBL_ERROR_PARSE_UNQUOTED_STRING)');
+ }
+ assert(error != null);
+
+ var json = await db.get('mycoll', id);
+ assert(json == '{"foo":"bar"}');
+
+ await db.put('mycoll', {'foo': 'baz'});
+
+ final list = await db.createQuery('@mycoll/*').execute(limit: 1).toList();
+ assert(list.length == 1);
+
+ var first = await db.createQuery('@mycoll/*').first();
+ assert(first.isPresent);
+ assert(first.value.json == '{"foo":"baz"}');
+
+ first = await db.createQuery('@mycoll/[zzz=bbb]').first();
+ assert(first.isEmpty);
+
+ var firstN = await db.createQuery('@mycoll/*').firstN(5);
+ assert(firstN.length == 2);
+ assert(firstN[0].json == '{"foo":"baz"}');
+ assert(firstN[1].json == '{"foo":"bar"}');
+
+ firstN = await db.createQuery('@mycoll/*').firstN(1);
+ assert(firstN.length == 1);
+
+ // Query 1
+ final rbuf = [];
+ await for (final doc in q.execute()) {
+ rbuf..add(doc.id.toString())..add(doc.json);
+ }
+ assert(rbuf.toString() == '[2, {"foo":"baz"}, 1, {"foo":"bar"}]');
+ rbuf.clear();
+
+ // Query 2
+ await for (final doc in db.createQuery('@mycoll/[foo=zaz]').execute()) {
+ rbuf..add(doc.id.toString())..add(doc.json);
+ }
+ assert(rbuf.isEmpty);
+
+ // Query 3
+ await for (final doc in db.createQuery('/[foo=bar]', 'mycoll').execute()) {
+ rbuf..add(doc.id.toString())..add(doc.json);
+ }
+ assert(rbuf.toString() == '[1, {"foo":"bar"}]');
+
+ error = null;
+ try {
+ await db.createQuery('@mycoll/[').execute();
+ } on EJDB2Error catch (e) {
+ error = e;
+ assert(e.invalidQuery);
+ assert(e.message.contains('@mycoll/[ <---'));
+ }
+ assert(error != null);
+
+ var count = await db.createQuery('@mycoll/* | count').scalarInt();
+ assert(count == 2);
+
+ count = await db.createQuery('@mycoll/* | count').scalarInt(explainCallback: (log) {
+ log.contains('[INDEX] NO [COLLECTOR] PLAIN');
+ });
+ assert(count == 2);
+
+ // Del
+ await db.del('mycoll', 1);
+ error = null;
+ try {
+ await db.get('mycoll', 1);
+ } on EJDB2Error catch (e) {
+ error = e;
+ assert(e.notFound);
+ assert(e.message.contains('IWKV_ERROR_NOTFOUND'));
+ }
+ assert(error != null);
+
+ count = await db.createQuery('@mycoll/* | count').scalarInt();
+ assert(count == 1);
+
+ // Patch
+ await db.patch('mycoll', '[{"op":"add", "path":"/baz", "value":"qux"}]', 2);
+ json = await db.get('mycoll', 2);
+ assert(json == '{"foo":"baz","baz":"qux"}');
+
+ // DB Info
+ json = await db.info();
+ assert(json.contains('"collections":[{"name":"mycoll","dbid":3,"rnum":1,"indexes":[]}]'));
+
+ // Indexes
+ await db.ensureStringIndex('mycoll', '/foo', unique: true);
+ json = await db.info();
+ assert(json.contains('"indexes":[{"ptr":"/foo","mode":5,"idbf":0,"dbid":4,"rnum":1}]'));
+
+ // Test JQL set
+ JBDOC? doc = await db.createQuery('@mycoll/[foo=:?]').setString(0, 'baz').execute().first;
+ assert(doc.json == '{"foo":"baz","baz":"qux"}');
+
+ // Test explain log
+ await db.createQuery('@mycoll/[foo=:?]').setString(0, 'baz').execute(explainCallback: (log) {
+ assert(
+ log.contains("[INDEX] SELECTED UNIQUE|STR|1 /foo EXPR1: 'foo = :?' INIT: IWKV_CURSOR_EQ"));
+ });
+
+ doc = await db
+ .createQuery('@mycoll/[foo=:?] and /[baz=:?]')
+ .setString(0, 'baz')
+ .setString(1, 'qux')
+ .execute()
+ .first;
+ assert(doc.json == '{"foo":"baz","baz":"qux"}');
+
+ doc = await db
+ .createQuery('@mycoll/[foo=:foo] and /[baz=:baz]')
+ .setString('foo', 'baz')
+ .setString('baz', 'qux')
+ .execute()
+ .first;
+
+ doc = await db.createQuery('@mycoll/[foo re :?]').setRegExp(0, RegExp('.*')).execute().first;
+ assert(doc.json == '{"foo":"baz","baz":"qux"}');
+
+ doc = await db.createQuery('@mycoll/* | /foo').execute().first;
+ assert(doc.json == '{"foo":"baz"}');
+
+ await db.removeStringIndex('mycoll', '/foo', unique: true);
+ json = await db.info();
+ assert(json.contains('"collections":[{"name":"mycoll","dbid":3,"rnum":1,"indexes":[]}]'));
+
+ // Remove collection
+ await db.removeCollection('mycoll');
+ json = await db.info();
+ assert(json.contains('"collections":[]'));
+
+ // Check apply
+ await db.put(
+ 'apply1', {'tx_hash': 'ed36cfd14a4fe29b16c511d68a8be89e42dcc6e4ced69d04f318448a2b8fafa0'});
+ doc = await db
+ .createQuery('/[tx_hash = :?] | apply :?', 'apply1')
+ .setString(0, 'ed36cfd14a4fe29b16c511d68a8be89e42dcc6e4ced69d04f318448a2b8fafa0')
+ .setJson(1, {'status': 'completed'}).firstRequired();
+ assert(doc.object['status'] == 'completed');
+
+ /// Test get limit
+ q = db.createQuery('@c1/* | limit 1');
+ assert(q.limit == 1);
+
+ q = db.createQuery('@c1/*');
+ assert(q.limit == 0);
+
+ id = await db.put('cc1', {'foo': 1});
+ await db.renameCollection('cc1', 'cc2');
+ json = await db.get('cc2', id);
+ assert(json == '{"foo":1}');
+
+ for (var i = 0; i < 10000; ++i) {
+ await db.put('cc1', {'name': 'v${i}'});
+ }
+ var cnt = 0;
+ await for (final _ in db.createQuery('@cc1/*').execute()) {
+ cnt++;
+ }
+ assert(cnt == 10000);
+
+ final ts0 = DateTime.now().millisecondsSinceEpoch;
+ final ts = await db.onlineBackup('hello-bkp.db');
+ assert(ts > ts0);
+ await db.close();
+
+ // Reopen backup image
+ final db2 = await EJDB2.open('hello-bkp.db', truncate: false);
+ doc = (await db2.createQuery('@cc1/*').first()).orNull;
+ assert(doc != null);
+ await db2.close();
+}
diff --git a/src/bindings/ejdb2_dart/version.txt b/src/bindings/ejdb2_dart/version.txt
new file mode 100644
index 0000000..b0d4e4c
--- /dev/null
+++ b/src/bindings/ejdb2_dart/version.txt
@@ -0,0 +1 @@
+1-nullsafety.1
\ No newline at end of file
diff --git a/src/bindings/ejdb2_flutter/.gitignore b/src/bindings/ejdb2_flutter/.gitignore
new file mode 100644
index 0000000..5d88f49
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/.gitignore
@@ -0,0 +1,12 @@
+local.properties
+!*.iml
+.classpath
+!.project
+.DS_Store
+.dart_tool/
+.packages
+.pub/
+build/
+.flutter-plugins-dependencies
+Podfile.lock
+
diff --git a/src/bindings/ejdb2_flutter/.metadata b/src/bindings/ejdb2_flutter/.metadata
new file mode 100644
index 0000000..8536f75
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/.metadata
@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: 68587a0916366e9512a78df22c44163d041dd5f3
+ channel: stable
+
+project_type: plugin
diff --git a/src/bindings/ejdb2_flutter/CHANGELOG.md b/src/bindings/ejdb2_flutter/CHANGELOG.md
new file mode 100644
index 0000000..1605127
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/CHANGELOG.md
@@ -0,0 +1,5 @@
+## @EJDB2_FLUTTER_VERSION@
+
+ - Used new versioning scheme: {EJDB_VERSION}{BINDING_VERSION_NUMBER}
+ - Opted out null safety mode
+
diff --git a/src/bindings/ejdb2_flutter/CMakeLists.txt b/src/bindings/ejdb2_flutter/CMakeLists.txt
new file mode 100644
index 0000000..ee29ace
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/CMakeLists.txt
@@ -0,0 +1,62 @@
+file(READ ${CMAKE_CURRENT_SOURCE_DIR}/version.txt _VERSION)
+set_property(GLOBAL PROPERTY EJDB2_FLUTTER_VERSION_PROPERTY
+ "${PROJECT_VERSION}${_VERSION}")
+set(EJDB2_FLUTTER_VERSION "${PROJECT_VERSION}${_VERSION}")
+
+
+file(
+ COPY .
+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
+ REGEX "(/\\.gradle)|(/node_modules)|(/build$)|(/libs)|(/jniLibs)" EXCLUDE
+)
+
+set(ANDROID_LIBS_DIR "${CMAKE_CURRENT_BINARY_DIR}/android/src/main/jniLibs")
+set(PUB_PUBLISH_DIR "${CMAKE_CURRENT_BINARY_DIR}/pub_publish")
+
+foreach (AABI IN ITEMS ${ANDROID_ABIS})
+ list(APPEND ANDROID_ABIS_LIBS "android_${AABI}")
+endforeach()
+
+add_custom_target(
+ ejdb2_flutter ALL
+ DEPENDS ${ANDROID_ABIS_LIBS}
+ COMMAND ${CMAKE_COMMAND} -E remove_directory ${ANDROID_LIBS_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/../ejdb2_android/libs ${ANDROID_LIBS_DIR}
+
+ # Prepare pub publish dir:
+
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${PUB_PUBLISH_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/LICENSE ${PUB_PUBLISH_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/README.md ${PUB_PUBLISH_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/analysis_options.yaml ${PUB_PUBLISH_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/lib ${PUB_PUBLISH_DIR}/lib
+
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/ios ${PUB_PUBLISH_DIR}/ios
+
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${PUB_PUBLISH_DIR}/android
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${PUB_PUBLISH_DIR}/android/src
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/android/gradlew* ${PUB_PUBLISH_DIR}/android
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/android/*.gradle ${PUB_PUBLISH_DIR}/android
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/android/gradle.properties ${PUB_PUBLISH_DIR}/android
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/android/src ${PUB_PUBLISH_DIR}/android/src
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/android/gradle ${PUB_PUBLISH_DIR}/android/gradle
+
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${PUB_PUBLISH_DIR}/example
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/example/ios ${PUB_PUBLISH_DIR}/example/ios
+
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${PUB_PUBLISH_DIR}/example/android
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${PUB_PUBLISH_DIR}/example/android/app
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/example/*.md ${PUB_PUBLISH_DIR}/example
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/example/*.yaml ${PUB_PUBLISH_DIR}/example
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/example/lib ${PUB_PUBLISH_DIR}/example/lib
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/example/test_driver ${PUB_PUBLISH_DIR}/example/test_driver
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/example/android/*.gradle ${PUB_PUBLISH_DIR}/example/android
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/example/android/gradlew* ${PUB_PUBLISH_DIR}/example/android
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/example/android/gradle.properties ${PUB_PUBLISH_DIR}/example/android
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/example/android/app/*.gradle ${PUB_PUBLISH_DIR}/example/android/app
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/example/android/app/src ${PUB_PUBLISH_DIR}/example/android/app/src
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/example/android/gradle ${PUB_PUBLISH_DIR}/example/android/gradle
+)
+
+configure_file(pubspec.yaml.in ${PUB_PUBLISH_DIR}/pubspec.yaml @ONLY)
+configure_file(CHANGELOG.md ${PUB_PUBLISH_DIR}/CHANGELOG.md @ONLY)
\ No newline at end of file
diff --git a/src/bindings/ejdb2_flutter/LICENSE b/src/bindings/ejdb2_flutter/LICENSE
new file mode 100644
index 0000000..90d6fd3
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2012-2021 Softmotions Ltd
+
+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.
diff --git a/src/bindings/ejdb2_flutter/README.md b/src/bindings/ejdb2_flutter/README.md
new file mode 100644
index 0000000..d348604
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/README.md
@@ -0,0 +1,101 @@
+# EJDB2 Flutter integration
+
+Embeddable JSON Database engine http://ejdb.org Dart binding.
+
+See https://github.com/Softmotions/ejdb/blob/master/README.md
+
+For API usage examples take a look into [/example](https://github.com/Softmotions/ejdb/tree/master/src/bindings/ejdb2_flutter/example)
+application.
+
+## Example
+
+pubspec.yaml
+
+```yaml
+dependencies:
+ ejdb2_flutter:
+```
+
+```dart
+import 'package:ejdb2_flutter/ejdb2_flutter.dart';
+
+var db = await EJDB2Builder('test.db').open();
+
+var id = await db.put('parrots', {'name': 'Bianca', 'age': 4});
+ print('Bianca record: ${id}');
+
+id = await db.put('parrots', {'name': 'Darko', 'age': 8});
+print('Darko record: ${id}');
+
+final q = db.createQuery('/[age > :age]', 'parrots');
+await for (final doc in q.setInt('age', 3).execute()) {
+ print('Found ${doc}');
+}
+
+await db.close();
+```
+
+## Supported platforms
+
+- iOS
+- Android
+
+## iOS notes
+
+In order to build app with this binding you have
+to add the following code into application `Podfile`:
+
+```ruby
+pre_install do |installer|
+ # workaround for https://github.com/CocoaPods/CocoaPods/issues/3289
+ Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
+end
+```
+
+## Android notes
+
+For release builds you have to setup proguard rules as follows:
+
+`build.gradle`
+```
+ buildTypes {
+ ...
+ release {
+ ...
+ minifyEnabled true
+ useProguard true
+ proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
+ }
+ }
+```
+
+`proguard-rules.pro`
+```
+...
+
+# Keep EJDB
+-keep class com.softmotions.ejdb2.** { *; }
+
+```
+
+## How build it manually
+
+```sh
+git clone https://github.com/Softmotions/ejdb.git
+
+cd ./ejdb
+mkdir ./build && cd build
+
+cmake .. -DCMAKE_BUILD_TYPE=Release \
+ -DANDROID_NDK_HOME= \
+ -DBUILD_FLUTTER_BINDING=ON
+make
+
+# Move generate to ejdb2 flutter pub package with example app
+cd src/bindings/ejdb2_flutter/pub_publish
+flutter pub get
+cd ./example
+
+# Start Android emulator
+flutter run
+```
diff --git a/src/bindings/ejdb2_flutter/analysis_options.yaml b/src/bindings/ejdb2_flutter/analysis_options.yaml
new file mode 100644
index 0000000..0a871c1
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/analysis_options.yaml
@@ -0,0 +1,157 @@
+analyzer:
+ errors:
+ native_function_body_in_non_sdk_code: ignore
+ strong-mode:
+ implicit-casts: false
+ implicit-dynamic: true
+linter:
+ rules:
+ - always_declare_return_types
+ - always_put_required_named_parameters_first
+ - always_require_non_null_named_parameters
+ - annotate_overrides
+ - avoid_bool_literals_in_conditional_expressions
+ - avoid_catching_errors
+ - avoid_classes_with_only_static_members
+ - avoid_double_and_int_checks
+ - avoid_empty_else
+ - avoid_field_initializers_in_const_classes
+ - avoid_implementing_value_types
+ - avoid_init_to_null
+ - avoid_js_rounded_ints
+ - avoid_null_checks_in_equality_operators
+ - avoid_private_typedef_functions
+ - avoid_relative_lib_imports
+ - avoid_renaming_method_parameters
+ - avoid_return_types_on_setters
+ - avoid_returning_null
+ - avoid_returning_null_for_future
+ - avoid_returning_null_for_void
+ #- avoid_returning_this
+ - avoid_setters_without_getters
+ - avoid_shadowing_type_parameters
+ - avoid_single_cascade_in_expression_statements
+ - avoid_slow_async_io
+ - avoid_types_as_parameter_names
+ - avoid_unused_constructor_parameters
+ - camel_case_extensions
+ - camel_case_types
+ - cancel_subscriptions
+ - comment_references
+ - control_flow_in_finally
+ - curly_braces_in_flow_control_structures
+ - diagnostic_describe_all_properties
+ - directives_ordering
+ - empty_catches
+ - empty_constructor_bodies
+ - empty_statements
+ - file_names
+ - flutter_style_todos
+ - hash_and_equals
+ - implementation_imports
+ - invariant_booleans
+ - iterable_contains_unrelated_type
+ - join_return_with_assignment
+ - library_names
+ - list_remove_unrelated_type
+ - literal_only_boolean_expressions
+ - no_adjacent_strings_in_list
+ - no_duplicate_case_values
+ - null_closures
+ - one_member_abstracts
+ - only_throw_errors
+ - overridden_fields
+ - package_api_docs
+ - package_names
+ - package_prefixed_library_names
+ - prefer_adjacent_string_concatenation
+ - prefer_asserts_in_initializer_lists
+ - prefer_asserts_with_message
+ - prefer_collection_literals
+ - prefer_conditional_assignment
+ - prefer_const_constructors
+ - prefer_const_declarations
+ - prefer_const_literals_to_create_immutables
+ - prefer_constructors_over_static_methods
+ - prefer_contains
+ - prefer_equal_for_default_values
+ - prefer_expression_function_bodies
+ - prefer_final_fields
+ - prefer_final_in_for_each
+ - prefer_final_locals
+ - prefer_for_elements_to_map_fromIterable
+ - prefer_foreach
+ - prefer_function_declarations_over_variables
+ - prefer_generic_function_type_aliases
+ - prefer_if_null_operators
+ - prefer_initializing_formals
+ - prefer_inlined_adds
+ - prefer_interpolation_to_compose_strings
+ - prefer_is_empty
+ - prefer_is_not_empty
+ - prefer_iterable_whereType
+ - prefer_mixin
+ - prefer_null_aware_operators
+ - prefer_single_quotes
+ - prefer_spread_collections
+ - prefer_typing_uninitialized_variables
+ - prefer_void_to_null
+ - provide_deprecation_message
+ - recursive_getters
+ - slash_for_doc_comments
+ - sort_child_properties_last
+ - sort_constructors_first
+ - sort_pub_dependencies
+ - sort_unnamed_constructors_first
+ - test_types_in_equals
+ - throw_in_finally
+ - type_init_formals
+ - unawaited_futures
+ - unnecessary_await_in_return
+ - unnecessary_const
+ - unnecessary_getters_setters
+ - unnecessary_lambdas
+ - unnecessary_new
+ - unnecessary_null_aware_assignments
+ - unnecessary_null_in_if_null_operators
+ - unnecessary_overrides
+ - unnecessary_parenthesis
+ - unnecessary_statements
+ - unnecessary_this
+ - unrelated_type_equality_checks
+ - unsafe_html
+ - use_full_hex_values_for_flutter_colors
+ - use_rethrow_when_possible
+ - use_setters_to_change_properties
+ - use_string_buffers
+ - use_to_and_as_if_applicable
+ - valid_regexps
+ - void_checks
+ # - always_put_control_body_on_new_line
+ # - always_specify_types
+ # - avoid_annotating_with_dynamic
+ # - avoid_as
+ # - avoid_catches_without_on_clauses
+ # - avoid_equals_and_hash_code_on_mutable_classes
+ # - avoid_function_literals_in_foreach_calls
+ # - avoid_positional_boolean_parameters
+ # - avoid_print
+ # - avoid_types_on_closure_parameters
+ # - avoid_void_async
+ # - await_only_futures
+ # - cascade_invocations
+ # - close_sinks
+ # - constant_identifier_names
+ # - library_prefixes
+ # - lines_longer_than_80_chars
+ # - non_constant_identifier_names
+ # - omit_local_variable_types
+ # - parameter_assignments
+ # - prefer_const_constructors_in_immutables
+ # - prefer_double_quotes
+ # - prefer_if_elements_to_conditional_expressions
+ # - prefer_int_literals
+ # - public_member_api_docs
+ # - type_annotate_public_apis
+ # - unnecessary_brace_in_string_interps
+ # - use_function_type_syntax_for_parameters
diff --git a/src/bindings/ejdb2_flutter/android/.gitignore b/src/bindings/ejdb2_flutter/android/.gitignore
new file mode 100644
index 0000000..4707429
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/android/.gitignore
@@ -0,0 +1,9 @@
+!*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+/libs
diff --git a/src/bindings/ejdb2_flutter/android/.project b/src/bindings/ejdb2_flutter/android/.project
new file mode 100644
index 0000000..90e475a
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/android/.project
@@ -0,0 +1,34 @@
+
+
+ ejdb2_flutter
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectbuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.buildship.core.gradleprojectnature
+
+
+
+ 1607244372293
+
+ 30
+
+ org.eclipse.core.resources.regexFilterMatcher
+ node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
+
+
+
+
diff --git a/src/bindings/ejdb2_flutter/android/build.gradle b/src/bindings/ejdb2_flutter/android/build.gradle
new file mode 100644
index 0000000..830e904
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/android/build.gradle
@@ -0,0 +1,97 @@
+import org.gradle.plugins.ide.eclipse.model.Library
+
+group 'com.softmotions.ejdb2'
+version '1.0'
+
+apply plugin: 'com.android.library'
+//apply plugin: "com.greensopinion.gradle-android-eclipse"
+//apply plugin: 'eclipse'
+
+sourceCompatibility = 1.8
+
+ext {
+
+ flutterRoot = {
+ def flutterProperties = new Properties()
+ def flutterPropertiesFile = rootProject.file('local.properties')
+ if (!flutterPropertiesFile.exists()) {
+ throw new GradleException("Flutter properties file not found. Define a flutter.properties file in your project root.")
+ }
+ flutterPropertiesFile.withInputStream { stream ->
+ flutterProperties.load(stream)
+ }
+ def flutterRoot = flutterProperties.getProperty('flutter.sdk')
+ if (flutterRoot == null) {
+ throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the flutter.properties file.")
+ }
+ return flutterRoot
+ }()
+
+ androidHome = {
+ if (System.env.ANDROID_HOME == null) {
+ throw new GradleException("Missing required ANDROID_HOME env variable");
+ }
+ return System.env.ANDROID_HOME;
+ }()
+}
+
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ maven {
+ url "https://plugins.gradle.org/m2/"
+ }
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.2.1'
+ //classpath "gradle.plugin.com.greensopinion.gradle-android-eclipse:gradle-android-eclipse:1.1"
+ }
+}
+
+rootProject.allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+android {
+ compileSdkVersion 28
+ defaultConfig {
+ minSdkVersion 16
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ lintOptions {
+ disable 'InvalidPackage'
+ }
+}
+
+dependencies {
+ compile fileTree(dir: 'src/main/jniLibs', include: ['*.jar'])
+}
+
+// eclipse {
+// classpath {
+// plusConfigurations += [ configurations.compile, configurations.testCompile ]
+// downloadSources = true
+// file {
+// whenMerged {
+// def androidHome = project.ext.get('androidHome')
+// def libAndroid = new Library(fileReference(file("$System.env.ANDROID_HOME/platforms/$project.android.compileSdkVersion/android.jar")));
+// libAndroid.setSourcePath(fileReference(file("$System.env.ANDROID_HOME/sources/$project.android.compileSdkVersion")));
+// // def flutterRoot = project.ext.get('flutterRoot')
+// // def flutterLib = new Library(fileReference(file("$flutterRoot/bin/cache/artifacts/engine/android-x86/flutter.jar")))
+// // flutterLib.setSourcePath(fileReference(file('/home/adam/Projects/tmp/engine/shell/platform/android')))
+// // entries += [ libAndroid, flutterLib ]
+// entries += [ libAndroid ]
+// }
+// }
+// }
+// }
diff --git a/src/bindings/ejdb2_flutter/android/gradle.properties b/src/bindings/ejdb2_flutter/android/gradle.properties
new file mode 100644
index 0000000..e30ec9d
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx1024M
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/src/bindings/ejdb2_flutter/android/gradle/wrapper/gradle-wrapper.jar b/src/bindings/ejdb2_flutter/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..5c2d1cf
Binary files /dev/null and b/src/bindings/ejdb2_flutter/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/src/bindings/ejdb2_flutter/android/gradle/wrapper/gradle-wrapper.properties b/src/bindings/ejdb2_flutter/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..f4d7b2b
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/src/bindings/ejdb2_flutter/android/gradlew b/src/bindings/ejdb2_flutter/android/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/android/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/src/bindings/ejdb2_flutter/android/gradlew.bat b/src/bindings/ejdb2_flutter/android/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/android/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/src/bindings/ejdb2_flutter/android/settings.gradle b/src/bindings/ejdb2_flutter/android/settings.gradle
new file mode 100644
index 0000000..f034e9f
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/android/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'ejdb2_flutter'
diff --git a/src/bindings/ejdb2_flutter/android/src/main/AndroidManifest.xml b/src/bindings/ejdb2_flutter/android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..7061af9
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/android/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/src/bindings/ejdb2_flutter/android/src/main/java/com/softmotions/ejdb2/Ejdb2FlutterPlugin.java b/src/bindings/ejdb2_flutter/android/src/main/java/com/softmotions/ejdb2/Ejdb2FlutterPlugin.java
new file mode 100644
index 0000000..efa985e
--- /dev/null
+++ b/src/bindings/ejdb2_flutter/android/src/main/java/com/softmotions/ejdb2/Ejdb2FlutterPlugin.java
@@ -0,0 +1,576 @@
+package com.softmotions.ejdb2;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.Log;
+import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.EventChannel.EventSink;
+import io.flutter.plugin.common.EventChannel.StreamHandler;
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
+import io.flutter.plugin.common.MethodChannel.Result;
+import io.flutter.plugin.common.PluginRegistry.Registrar;
+
+/**
+ * Ejdb2FlutterPlugin
+ */
+public final class Ejdb2FlutterPlugin implements MethodCallHandler, StreamHandler {
+
+ public static final String TAG = "Ejdb2FlutterPlugin";
+
+ @SuppressWarnings("StaticCollection")
+ static final Map dbmap = new ConcurrentHashMap<>();
+
+ static final AtomicInteger dbkeys = new AtomicInteger();
+
+ static final Map methods = new ConcurrentHashMap<>();
+
+ static final Executor executor = new ThreadPoolExecutor(0, 5, 60L, TimeUnit.SECONDS,
+ new SynchronousQueue());
+
+ static {
+ methods.put("executeFirst", thread(Ejdb2FlutterPlugin::executeFirst));
+ methods.put("executeList", thread(Ejdb2FlutterPlugin::executeList));
+ methods.put("executeScalarInt", thread(Ejdb2FlutterPlugin::executeScalarInt));
+ methods.put("executeQuery", thread(Ejdb2FlutterPlugin::executeQuery));
+ methods.put("onlineBackup", thread(Ejdb2FlutterPlugin::onlineBackup));
+ methods.put("removeFloatIndex", thread(Ejdb2FlutterPlugin::removeFloatIndex));
+ methods.put("ensureFloatIndex", thread(Ejdb2FlutterPlugin::ensureFloatIndex));
+ methods.put("removeIntIndex", thread(Ejdb2FlutterPlugin::removeIntIndex));
+ methods.put("ensureIntIndex", thread(Ejdb2FlutterPlugin::ensureIntIndex));
+ methods.put("removeStringIndex", thread(Ejdb2FlutterPlugin::removeStringIndex));
+ methods.put("ensureStringIndex", thread(Ejdb2FlutterPlugin::ensureStringIndex));
+ methods.put("removeCollection", thread(Ejdb2FlutterPlugin::removeCollection));
+ methods.put("renameCollection", thread(Ejdb2FlutterPlugin::renameCollection));
+ methods.put("del", thread(Ejdb2FlutterPlugin::del));
+ methods.put("get", thread(Ejdb2FlutterPlugin::get));
+ methods.put("patch", thread(Ejdb2FlutterPlugin::patch));
+ methods.put("put", thread(Ejdb2FlutterPlugin::put));
+ methods.put("info", thread(Ejdb2FlutterPlugin::info));
+ methods.put("open", thread(Ejdb2FlutterPlugin::open));
+ methods.put("close", thread(Ejdb2FlutterPlugin::close));
+ }
+
+ Ejdb2FlutterPlugin(Registrar registrar) {
+ this.registrar = registrar;
+ this.methodChannel = new MethodChannel(registrar.messenger(), "ejdb2");
+ this.methodChannel.setMethodCallHandler(this);
+ this.eventChannel = new EventChannel(registrar.messenger(), "ejdb2/query");
+ this.eventChannel.setStreamHandler(this);
+ }
+
+ final Registrar registrar;
+
+ final MethodChannel methodChannel;
+
+ final EventChannel eventChannel;
+
+ EventSink events;
+
+ static Ejdb2FlutterPlugin plugin;
+
+ /**
+ * Plugin registration.
+ */
+ public static void registerWith(Registrar registrar) {
+ plugin = new Ejdb2FlutterPlugin(registrar);
+ }
+
+ @Override
+ public void onMethodCall(MethodCall call, Result result) {
+ DbMethod method = methods.get(call.method);
+ if (method == null) {
+ result.notImplemented();
+ return;
+ }
+ @SuppressWarnings("unchecked")
+ Object[] args = ((List) call.arguments).toArray();
+ DbEntry dbe = null;
+ if (args[0] != null) {
+ dbe = dbmap.get(((Number) args[0]).intValue());
+ if (dbe == null) {
+ result.error("@ejdb", "Database handle already disposed", null);
+ return;
+ }
+ }
+ try {
+ method.handle(new DbMethodCall(this, dbe, args, result));
+ } catch (EJDB2Exception e) {
+ result.error("@ejdb IWRC:" + e.getCode(), e.getMessage(), null);
+ } catch (Exception e) {
+ Log.e(TAG, e.getMessage(), e);
+ result.error("@ejdb", e.toString(), null);
+ }
+ }
+
+ @Override
+ public void onListen(Object arguments, EventSink events) {
+ this.events = events;
+ }
+
+ @Override
+ public void onCancel(Object arguments) {
+ this.events = null;
+ }
+
+ private static void executeFirst(DbMethodCall mc) throws Exception {
+ executeListImpl(mc, 1L);
+ }
+
+ private static void executeList(DbMethodCall mc) throws Exception {
+ executeListImpl(mc, null);
+ }
+
+ private static void executeListImpl(DbMethodCall mc, Long limit) throws Exception {
+ prepareQuery(mc, (q, hook) -> {
+ if (limit != null) {
+ q.setLimit(limit);
+ }
+ final List