libcouchbase 1.0.4 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +11 -8
- data/ext/libcouchbase/CMakeLists.txt +1 -1
- data/ext/libcouchbase/README.markdown +38 -6
- data/ext/libcouchbase/RELEASE_NOTES.markdown +151 -0
- data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +2 -2
- data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
- data/ext/libcouchbase/cmake/source_files.cmake +1 -0
- data/ext/libcouchbase/contrib/cJSON/cJSON.c +686 -288
- data/ext/libcouchbase/contrib/cJSON/cJSON.h +0 -0
- data/ext/libcouchbase/contrib/cbsasl/src/hash.c +17 -17
- data/ext/libcouchbase/contrib/cliopts/cliopts.c +76 -0
- data/ext/libcouchbase/contrib/cliopts/cliopts.h +66 -15
- data/ext/libcouchbase/contrib/genhash/genhash.c +1 -2
- data/ext/libcouchbase/contrib/lcb-jsoncpp/lcb-jsoncpp.cpp +4 -3
- data/ext/libcouchbase/example/instancepool/main.cc +12 -2
- data/ext/libcouchbase/example/libeventdirect/main.c +99 -25
- data/ext/libcouchbase/example/minimal/minimal.c +7 -5
- data/ext/libcouchbase/example/observe/durability.c +102 -0
- data/ext/libcouchbase/example/observe/observe.c +19 -6
- data/ext/libcouchbase/example/subdoc/subdoc-xattrs.c +1 -2
- data/ext/libcouchbase/include/libcouchbase/cntl-private.h +6 -8
- data/ext/libcouchbase/include/libcouchbase/cntl.h +84 -64
- data/ext/libcouchbase/include/libcouchbase/couchbase.h +295 -78
- data/ext/libcouchbase/include/libcouchbase/deprecated.h +2 -2
- data/ext/libcouchbase/include/libcouchbase/error.h +1 -1
- data/ext/libcouchbase/include/libcouchbase/iops.h +9 -9
- data/ext/libcouchbase/include/libcouchbase/ixmgmt.h +2 -2
- data/ext/libcouchbase/include/libcouchbase/n1ql.h +69 -7
- data/ext/libcouchbase/include/libcouchbase/vbucket.h +17 -0
- data/ext/libcouchbase/include/libcouchbase/views.h +3 -3
- data/ext/libcouchbase/include/memcached/protocol_binary.h +62 -1
- data/ext/libcouchbase/packaging/deb/control +1 -1
- data/ext/libcouchbase/packaging/rpm/libcouchbase.spec.in +37 -36
- data/ext/libcouchbase/src/bootstrap.cc +22 -8
- data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +1 -1
- data/ext/libcouchbase/src/bucketconfig/bc_http.cc +0 -1
- data/ext/libcouchbase/src/bucketconfig/confmon.cc +13 -8
- data/ext/libcouchbase/src/callbacks.c +2 -0
- data/ext/libcouchbase/src/cntl.cc +28 -17
- data/ext/libcouchbase/src/dns-srv.cc +1 -2
- data/ext/libcouchbase/src/dump.cc +4 -0
- data/ext/libcouchbase/src/errmap.h +89 -16
- data/ext/libcouchbase/src/handler.cc +28 -11
- data/ext/libcouchbase/src/http/http-priv.h +4 -1
- data/ext/libcouchbase/src/http/http.cc +3 -0
- data/ext/libcouchbase/src/instance.cc +1 -1
- data/ext/libcouchbase/src/internal.h +1 -0
- data/ext/libcouchbase/src/lcbio/connect.cc +2 -3
- data/ext/libcouchbase/src/lcbio/manager.cc +2 -2
- data/ext/libcouchbase/src/lcbio/ssl.h +10 -0
- data/ext/libcouchbase/src/mc/mcreq.c +8 -0
- data/ext/libcouchbase/src/mcserver/mcserver.cc +14 -1
- data/ext/libcouchbase/src/n1ql/ixmgmt.cc +0 -3
- data/ext/libcouchbase/src/n1ql/n1ql.cc +22 -29
- data/ext/libcouchbase/src/n1ql/params.cc +46 -1
- data/ext/libcouchbase/src/newconfig.cc +4 -4
- data/ext/libcouchbase/src/operations/durability-seqno.cc +4 -0
- data/ext/libcouchbase/src/operations/durability.cc +3 -0
- data/ext/libcouchbase/src/operations/ping.cc +315 -0
- data/ext/libcouchbase/src/operations/stats.cc +10 -0
- data/ext/libcouchbase/src/operations/subdoc.cc +13 -1
- data/ext/libcouchbase/src/retrychk.cc +1 -0
- data/ext/libcouchbase/src/settings.c +2 -0
- data/ext/libcouchbase/src/settings.h +13 -7
- data/ext/libcouchbase/src/ssl/ssl_c.c +28 -2
- data/ext/libcouchbase/src/ssl/ssl_common.c +3 -0
- data/ext/libcouchbase/src/ssl/ssl_e.c +15 -1
- data/ext/libcouchbase/src/ssl/ssl_iot_common.h +3 -1
- data/ext/libcouchbase/src/timings.c +0 -1
- data/ext/libcouchbase/src/vbucket/vbucket.c +49 -1
- data/ext/libcouchbase/tests/iotests/mock-environment.cc +58 -40
- data/ext/libcouchbase/tests/iotests/mock-environment.h +23 -4
- data/ext/libcouchbase/tests/iotests/mock-unit-test.h +8 -8
- data/ext/libcouchbase/tests/iotests/t_behavior.cc +5 -5
- data/ext/libcouchbase/tests/iotests/t_durability.cc +50 -0
- data/ext/libcouchbase/tests/iotests/t_eerrs.cc +4 -2
- data/ext/libcouchbase/tests/iotests/t_errmap.cc +6 -3
- data/ext/libcouchbase/tests/iotests/t_lock.cc +5 -6
- data/ext/libcouchbase/tests/iotests/t_misc.cc +44 -0
- data/ext/libcouchbase/tests/iotests/t_serverops.cc +1 -0
- data/ext/libcouchbase/tests/iotests/t_subdoc.cc +28 -0
- data/ext/libcouchbase/tests/iotests/t_views.cc +22 -10
- data/ext/libcouchbase/tools/CMakeLists.txt +21 -1
- data/ext/libcouchbase/tools/cbc-handlers.h +23 -3
- data/ext/libcouchbase/tools/cbc-n1qlback.cc +1 -1
- data/ext/libcouchbase/tools/cbc-pillowfight.cc +126 -26
- data/ext/libcouchbase/tools/cbc-proxy.cc +403 -0
- data/ext/libcouchbase/tools/cbc-subdoc.cc +826 -0
- data/ext/libcouchbase/tools/cbc.cc +149 -37
- data/ext/libcouchbase/tools/common/options.h +5 -2
- data/ext/libcouchbase/tools/linenoise/linenoise.c +15 -15
- data/lib/libcouchbase.rb +4 -0
- data/lib/libcouchbase/bucket.rb +51 -0
- data/lib/libcouchbase/connection.rb +100 -13
- data/lib/libcouchbase/ext/libcouchbase.rb +40 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdsubdoc.rb +13 -1
- data/lib/libcouchbase/ext/libcouchbase/enums.rb +2 -1
- data/lib/libcouchbase/ext/libcouchbase/sdspec.rb +5 -0
- data/lib/libcouchbase/subdoc_request.rb +129 -0
- data/lib/libcouchbase/version.rb +1 -1
- data/spec/bucket_spec.rb +15 -1
- data/spec/connection_spec.rb +1 -1
- data/spec/subdoc_spec.rb +192 -0
- metadata +13 -4
- data/ext/libcouchbase/.travis.yml +0 -19
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: be988dba6fcc3cad2ae5e6b5ee57be6382fab952
|
|
4
|
+
data.tar.gz: 7eba0fd2d3ec665e9373e308bd78405766670769
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 386f1456c6853cae5766041ee2ee988703cf1f71d4d4d5974ebbc00ee887f44f6b0a8689144b83bc2b9c13df573b262ecd281cc1fa57e817904544ef96576889
|
|
7
|
+
data.tar.gz: 7a37eecb3b1bbb3c761fc21f68a4eb6c5a7974e32624642f49de9a89b3e84581444cb40e13f970f66774c57fee977f3d4215a9bbefd4577ade7f4e867d8d1784
|
data/.travis.yml
CHANGED
|
@@ -1,28 +1,30 @@
|
|
|
1
1
|
language: ruby
|
|
2
2
|
rvm:
|
|
3
|
-
- ruby-2.4.
|
|
4
|
-
- ruby-2.3.
|
|
3
|
+
- ruby-2.4.2
|
|
4
|
+
- ruby-2.3.5
|
|
5
5
|
- ruby-head
|
|
6
|
-
- jruby-9.1.
|
|
6
|
+
- jruby-9.1.13.0
|
|
7
7
|
- jruby-head
|
|
8
8
|
- rubinius
|
|
9
|
-
- rubinius-3.
|
|
9
|
+
- rubinius-3.86
|
|
10
10
|
branches:
|
|
11
11
|
only:
|
|
12
12
|
- master
|
|
13
13
|
before_install:
|
|
14
14
|
- git submodule update --init --recursive
|
|
15
15
|
- gem install ffi
|
|
16
|
-
- sudo apt-get install libev-dev
|
|
17
|
-
- sudo wget https://packages.couchbase.com/releases/
|
|
18
|
-
- sudo dpkg -i couchbase-server-
|
|
16
|
+
- sudo apt-get install libev-dev python-httplib2
|
|
17
|
+
- sudo wget https://packages.couchbase.com/releases/5.0.0/couchbase-server-enterprise_5.0.0-ubuntu14.04_amd64.deb
|
|
18
|
+
- sudo dpkg -i couchbase-server-enterprise_5.0.0-ubuntu14.04_amd64.deb
|
|
19
19
|
- sleep 4
|
|
20
20
|
- sudo service couchbase-server status
|
|
21
21
|
- /opt/couchbase/bin/couchbase-cli cluster-init -c 127.0.0.1:8091 --cluster-username=admin --cluster-password=password --cluster-ramsize=320 --cluster-index-ramsize=256 --cluster-fts-ramsize=256 --services=data,index,query,fts
|
|
22
22
|
- sleep 4
|
|
23
23
|
- /opt/couchbase/bin/couchbase-cli server-info -c 127.0.0.1:8091 -u admin -p password
|
|
24
24
|
- /opt/couchbase/bin/couchbase-cli bucket-create -c 127.0.0.1:8091 -u admin -p password --bucket=default --bucket-type=couchbase --bucket-ramsize=160 --bucket-replica=0 --wait
|
|
25
|
-
- /opt/couchbase/bin/couchbase-cli bucket-create -c 127.0.0.1:8091 -u admin -p password --bucket=test --bucket-type=couchbase --bucket-ramsize=160 --bucket-replica=0 --
|
|
25
|
+
- /opt/couchbase/bin/couchbase-cli bucket-create -c 127.0.0.1:8091 -u admin -p password --bucket=test --bucket-type=couchbase --bucket-ramsize=160 --bucket-replica=0 --enable-flush=1 --wait
|
|
26
|
+
- sleep 1
|
|
27
|
+
- /opt/couchbase/bin/couchbase-cli user-manage -c 127.0.0.1:8091 -u admin -p password --set --rbac-username tester --rbac-password password123 --rbac-name "Auto Tester" --roles admin --auth-domain local
|
|
26
28
|
- /opt/couchbase/bin/cbrestore -x rehash=1 -b default -B default -u admin -p password ./spec/seed http://127.0.0.1:8091
|
|
27
29
|
before_script:
|
|
28
30
|
- rake compile
|
|
@@ -31,5 +33,6 @@ matrix:
|
|
|
31
33
|
- rvm: jruby-head
|
|
32
34
|
- rvm: ruby-head
|
|
33
35
|
- rvm: rubinius
|
|
36
|
+
- rvm: rubinius-3.86
|
|
34
37
|
sudo: required
|
|
35
38
|
dist: trusty
|
|
@@ -21,7 +21,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8.9)
|
|
|
21
21
|
# These variables can be modified as needed
|
|
22
22
|
|
|
23
23
|
# Couchbase mock path to download
|
|
24
|
-
SET(COUCHBASE_MOCK_VERSION CouchbaseMock-
|
|
24
|
+
SET(COUCHBASE_MOCK_VERSION CouchbaseMock-1.5.12.jar)
|
|
25
25
|
# Maven repository where ${COUCHBASE_MOCK_VERSION} is to be found
|
|
26
26
|
SET(COUCHBASE_MOCK_DLSERVER http://packages.couchbase.com/clients/c/mock)
|
|
27
27
|
project(libcouchbase)
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# Couchbase C Client
|
|
2
2
|
|
|
3
|
-
[](https://travis-ci.org/couchbase/libcouchbase)
|
|
4
|
-
|
|
5
3
|
This is the C client library for [Couchbase](http://www.couchbase.com)
|
|
6
4
|
It communicates with the cluster and speaks the relevant protocols
|
|
7
5
|
necessary to connect to the cluster and execute data operations.
|
|
@@ -23,7 +21,7 @@ necessary to connect to the cluster and execute data operations.
|
|
|
23
21
|
## Building
|
|
24
22
|
|
|
25
23
|
Before you build from this repository, please check the
|
|
26
|
-
[installation page](
|
|
24
|
+
[installation page](https://developer.couchbase.com/server/other-products/release-notes-archives/c-sdk)
|
|
27
25
|
to see if there is a binary or release tarball available for your needs. Since the code here is
|
|
28
26
|
not part of an official release it has therefore not gone through our
|
|
29
27
|
release testing process.
|
|
@@ -76,6 +74,40 @@ If you wish to link against OpenSSL, you should set the value of
|
|
|
76
74
|
`OPENSSL_ROOT_DIR` to the location of the installation path, as described
|
|
77
75
|
[here](https://github.com/Kitware/CMake/blob/master/Modules/FindOpenSSL.cmake)
|
|
78
76
|
|
|
77
|
+
## Running tests
|
|
78
|
+
|
|
79
|
+
To run tests, you can use either ctest directly or generated build targets.
|
|
80
|
+
For Unix-like:
|
|
81
|
+
|
|
82
|
+
```shell
|
|
83
|
+
make test
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
For windows:
|
|
87
|
+
|
|
88
|
+
```batchfile
|
|
89
|
+
cmake --build . --target alltests
|
|
90
|
+
ctest -C debug
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
By default tests will use [CouchbaseMock](https://github.com/couchbase/CouchbaseMock) project to simulate the Couchbase
|
|
94
|
+
Cluster. It allows to cover more different failure scenarios, although does not implement all kinds of APIs provided
|
|
95
|
+
by real server.
|
|
96
|
+
|
|
97
|
+
If you need to test against real server, you have to provide comma-separated configuration in `LCB_TEST_CLUSTER_CONF`
|
|
98
|
+
environment variable. For example, the following command will run tests against local cluster and bucket `default` using
|
|
99
|
+
administrator credentials:
|
|
100
|
+
|
|
101
|
+
```shell
|
|
102
|
+
export LCB_TEST_CLUSTER_CONF=couchbase://localhost,default,Administrator,password
|
|
103
|
+
make test
|
|
104
|
+
```
|
|
105
|
+
Note that specifying username will automatically switch to RBAC mode, which supported by Couchbase Server 5.0+. For old
|
|
106
|
+
servers the spec will look like `couchbase://localhost,default` or `couchbase://localhost,protected,,secret`.
|
|
107
|
+
|
|
108
|
+
Also tests expecting `beer-sample` bucket loaded. It comes with the server. Look at "Sample buckets" section of Admin
|
|
109
|
+
Console.
|
|
110
|
+
|
|
79
111
|
## Bugs, Support, Issues
|
|
80
112
|
You may report issues in the library in our issue tracked at
|
|
81
113
|
<https://issues.couchbase.com>. Sign up for an account and file an issue
|
|
@@ -91,18 +123,18 @@ irc.freenode.net.
|
|
|
91
123
|
* Official client libraries using libcouchbase
|
|
92
124
|
* [node.js](http://github.com/couchbase/couchnode)
|
|
93
125
|
* [Python](http://github.com/couchbase/couchbase-python-client)
|
|
94
|
-
* [
|
|
95
|
-
* [PHP](http://github.com/couchbase/php-couchbase) (uses the old < 2.6 API)
|
|
126
|
+
* [PHP](http://github.com/couchbase/php-couchbase)
|
|
96
127
|
* Community projects using libcouchbase
|
|
97
128
|
* [C++11 wrapper](https://github.com/couchbaselabs/libcouchbase-cxx)
|
|
98
129
|
* [cberl - Couchbase NIF](https://github.com/wcummings/cberl)
|
|
99
130
|
* [Perl client](https://github.com/mnunberg/perl-Couchbase-Client)
|
|
131
|
+
* [Ruby](http://github.com/couchbase/couchbase-ruby-client) (uses the old < 2.6 API)
|
|
100
132
|
|
|
101
133
|
## Documentation
|
|
102
134
|
|
|
103
135
|
Documentation is available in guide format (introducing the basic concepts of
|
|
104
136
|
Couchbase and the library). It is recommended for first-time users, and can
|
|
105
|
-
be accessed at our [Documentation Site](
|
|
137
|
+
be accessed at our [Documentation Site](https://developer.couchbase.com/documentation/server/current/sdk/c/start-using-sdk.html).
|
|
106
138
|
|
|
107
139
|
API documentation is also available and is generated from the library's headers.
|
|
108
140
|
It may contain references to more advanced features not found in the guide.
|
|
@@ -1,5 +1,156 @@
|
|
|
1
1
|
# Release Notes
|
|
2
2
|
|
|
3
|
+
## 2.8.2 (October 17 2017)
|
|
4
|
+
|
|
5
|
+
* [CCBC-833](https://issues.couchbase.com/browse/CCBC-833), [CCBC-834](https://issues.couchbase.com/browse/CCBC-834):
|
|
6
|
+
Update real cluster integration in the test suite.
|
|
7
|
+
|
|
8
|
+
* [CCBC-860](https://issues.couchbase.com/browse/CCBC-860): cbc-connstr: Do not zero out C++ instances.
|
|
9
|
+
|
|
10
|
+
* [CCBC-859](https://issues.couchbase.com/browse/CCBC-859): Fix libm shared object detection on Debian 9.
|
|
11
|
+
|
|
12
|
+
* Bugs reported by [clang analyzer](http://clang-analyzer.llvm.org/):
|
|
13
|
+
|
|
14
|
+
* [CCBC-858](https://issues.couchbase.com/browse/CCBC-858): Fix memory leak for compressed packet.
|
|
15
|
+
* [CCBC-857](https://issues.couchbase.com/browse/CCBC-857): Fix possible NULL pointer dereference in `mcreq_reserve_key`.
|
|
16
|
+
* [CCBC-856](https://issues.couchbase.com/browse/CCBC-856): Initialize response struct in `H_config`.
|
|
17
|
+
* [CCBC-855](https://issues.couchbase.com/browse/CCBC-855): Fix dead assignments in `contrib/genhash`.
|
|
18
|
+
* [CCBC-854](https://issues.couchbase.com/browse/CCBC-854): Init vbguess array before entry lookup.
|
|
19
|
+
* [CCBC-853](https://issues.couchbase.com/browse/CCBC-853): cbc-proxy: do not use client object after free.
|
|
20
|
+
* [CCBC-852](https://issues.couchbase.com/browse/CCBC-852): Do not free memory twice in N1QL index manager.
|
|
21
|
+
|
|
22
|
+
## 2.8.1 (September 20 2017)
|
|
23
|
+
|
|
24
|
+
* Check nodes number for durability checks. The store with durability
|
|
25
|
+
requirements will report more specific error when the library cannot
|
|
26
|
+
fulfill the condition during failover.
|
|
27
|
+
* Issues: [CCBC-817](https://issues.couchbase.com/browse/CCBC-817)
|
|
28
|
+
|
|
29
|
+
* Handle enhanced error messages for subdoc operations. The subdoc
|
|
30
|
+
responses will now expose context and reference ID if present.
|
|
31
|
+
* Issues: [CCBC-846](https://issues.couchbase.com/browse/CCBC-846)
|
|
32
|
+
|
|
33
|
+
* Discover and bootstrap analytics service from cluster configuration.
|
|
34
|
+
* Issues: [CCBC-840](https://issues.couchbase.com/browse/CCBC-840)
|
|
35
|
+
|
|
36
|
+
* Improve documentation of configuration parameters.
|
|
37
|
+
* Issues: [CCBC-835](https://issues.couchbase.com/browse/CCBC-835)
|
|
38
|
+
|
|
39
|
+
* Enable Error Map feature by default.
|
|
40
|
+
* Issues: [CCBC-838](https://issues.couchbase.com/browse/CCBC-838)
|
|
41
|
+
|
|
42
|
+
* Cleanup and extend `minimal`, `libeventdirect`, `instancepool` examples
|
|
43
|
+
|
|
44
|
+
* Tools:
|
|
45
|
+
* improve error reporting
|
|
46
|
+
* experimental subcommand `cbc-proxy`
|
|
47
|
+
* fix memory leaks
|
|
48
|
+
* retry store operations during population phase in `cbc-pillowfight`
|
|
49
|
+
|
|
50
|
+
## 2.8.0 (August 31 2017)
|
|
51
|
+
|
|
52
|
+
* Add support for OpenSSL-1.1.
|
|
53
|
+
* Issues: [CCBC-814](https://issues.couchbase.com/browse/CCBC-814)
|
|
54
|
+
|
|
55
|
+
* Mask `LOCKED` status code for backward compatibility. This code
|
|
56
|
+
(as well as others possible codes with 'item-locked' attribute)
|
|
57
|
+
replaced with `LCB_KEY_EEXISTS` for `SET`, `REPLACE` and `DELETE`
|
|
58
|
+
operations, and with `LCB_ETMPFAIL` for the rest.
|
|
59
|
+
* Issues: [CCBC-832](https://issues.couchbase.com/browse/CCBC-832)
|
|
60
|
+
|
|
61
|
+
* Stop enumerating bootstrap nodes and mechanisms when the server
|
|
62
|
+
returns authentication error.
|
|
63
|
+
* Issues: [CCBC-825](https://issues.couchbase.com/browse/CCBC-825)
|
|
64
|
+
|
|
65
|
+
* Fixed double free error with `lcb_ping3`.
|
|
66
|
+
* Issues: [CCBC-826](https://issues.couchbase.com/browse/CCBC-826)
|
|
67
|
+
|
|
68
|
+
* Exposed additional N1QL query parameters: `lcb_n1p_readonly`,
|
|
69
|
+
`lcb_n1p_scancap`, `lcb_n1p_pipelinecap`.
|
|
70
|
+
* Issues: [CCBC-823](https://issues.couchbase.com/browse/CCBC-823)
|
|
71
|
+
|
|
72
|
+
* Fixed `cbc-subdoc/upsert` without XATTR.
|
|
73
|
+
* Issues: [CCBC-823](https://issues.couchbase.com/browse/CCBC-823)
|
|
74
|
+
|
|
75
|
+
* XERROR attributes synchronized with recent list on server.
|
|
76
|
+
* Issues: [CCBC-828](https://issues.couchbase.com/browse/CCBC-828)
|
|
77
|
+
|
|
78
|
+
* Add missing documentation, and update stability of the API.
|
|
79
|
+
* Issues:
|
|
80
|
+
[CCBC-830](https://issues.couchbase.com/browse/CCBC-830),
|
|
81
|
+
[CCBC-831](https://issues.couchbase.com/browse/CCBC-831),
|
|
82
|
+
[CCBC-827](https://issues.couchbase.com/browse/CCBC-827)
|
|
83
|
+
|
|
84
|
+
* Do not throttle background configuration polling by throttle interval
|
|
85
|
+
of configuration error handler.
|
|
86
|
+
* Issues: [CCBC-829](https://issues.couchbase.com/browse/CCBC-829)
|
|
87
|
+
|
|
88
|
+
* Turn on background polling by default. The library will try
|
|
89
|
+
to schedule configuration update every 2.5 seconds. To disable it
|
|
90
|
+
use `config_poll_interval=0`.
|
|
91
|
+
* Issues: [CCBC-836](https://issues.couchbase.com/browse/CCBC-836)
|
|
92
|
+
|
|
93
|
+
## 2.7.7 (August 17 2017)
|
|
94
|
+
|
|
95
|
+
* Implement new function `lcb_ping3`, which sends NOOP-like message to
|
|
96
|
+
each service in the cluster and allows to measure latency along with
|
|
97
|
+
health status of the connection. Might be useful for application-side
|
|
98
|
+
keep-alive mechanisms.
|
|
99
|
+
* Issues: [CCBC-801](https://issues.couchbase.com/browse/CCBC-801)
|
|
100
|
+
|
|
101
|
+
* Detect and expose bucket type through `LCB_CNTL_BUCKETTYPE`:
|
|
102
|
+
|
|
103
|
+
lcb_BTYPE type;
|
|
104
|
+
lcb_cntl(instance, LCB_CNTL_GET, LCB_CNTL_BUCKETTYPE, &type);
|
|
105
|
+
|
|
106
|
+
* Issues: [CCBC-790](https://issues.couchbase.com/browse/CCBC-790)
|
|
107
|
+
|
|
108
|
+
* Fixed setting expiration in subdoc mutations.
|
|
109
|
+
* Issues: [CCBC-799](https://issues.couchbase.com/browse/CCBC-816)
|
|
110
|
+
|
|
111
|
+
* Fixed DNS SRV support of Fedora 26 and FreeBSD.
|
|
112
|
+
* Issues: [CCBC-816](https://issues.couchbase.com/browse/CCBC-816)
|
|
113
|
+
|
|
114
|
+
* Fixed DNS SRV with SSL connections.
|
|
115
|
+
* Issues: [CCBC-794](https://issues.couchbase.com/browse/CCBC-794)
|
|
116
|
+
|
|
117
|
+
* Define EREMOTEIO in libuv
|
|
118
|
+
* Issues: [CCBC-812](https://issues.couchbase.com/browse/CCBC-812)
|
|
119
|
+
|
|
120
|
+
* New subdocument command to remove whole document
|
|
121
|
+
* Issues: [CCBC-811](https://issues.couchbase.com/browse/CCBC-811)
|
|
122
|
+
|
|
123
|
+
* New cbc command: `cbc-subdoc`. It provides interactive shell, where
|
|
124
|
+
all subdocument commands accessible to inspect and modify documents
|
|
125
|
+
in the cluster.
|
|
126
|
+
|
|
127
|
+
* New cbc command: `cbc-ping`. It sends NOOP-like messages to all accessible
|
|
128
|
+
services in the cluster, and displays the status along with latency.
|
|
129
|
+
* Issues: [CCBC-801](https://issues.couchbase.com/browse/CCBC-801)
|
|
130
|
+
|
|
131
|
+
* Fix `cbc-cat --replica`, which now allows reading documents from replicas.
|
|
132
|
+
* Issues: [CCBC-820](https://issues.couchbase.com/browse/CCBC-820)
|
|
133
|
+
|
|
134
|
+
* Implement NOOP command and `cbc-pillowfight --noop`, which sends NOOP
|
|
135
|
+
instead of data manipulation commands.
|
|
136
|
+
* Issues: [CCBC-801](https://issues.couchbase.com/browse/CCBC-801)
|
|
137
|
+
|
|
138
|
+
* Clarify errors found in `.cbcrc`. Now it will display configuration path
|
|
139
|
+
along with error message.
|
|
140
|
+
* Issues: [CCBC-759](https://issues.couchbase.com/browse/CCBC-759]
|
|
141
|
+
|
|
142
|
+
* Update examples:
|
|
143
|
+
* Support username/password in subdoc and libeventdirect examples
|
|
144
|
+
* Added example for subdoc XATTRs
|
|
145
|
+
|
|
146
|
+
* Integrate fix for parallel build with dtrace on FreeBSD
|
|
147
|
+
https://github.com/freebsd/freebsd-ports/commit/a71e1a86b851d42cd08319d9b28a4424e508e216
|
|
148
|
+
|
|
149
|
+
* Make enhanced errors API public
|
|
150
|
+
* Issues: [CCBC-803](https://issues.couchbase.com/browse/CCBC-803)
|
|
151
|
+
|
|
152
|
+
* Fixed various compiler and cppcheck warnings and documentation update.
|
|
153
|
+
|
|
3
154
|
## 2.7.6 (July 11 2017)
|
|
4
155
|
|
|
5
156
|
* Expose enhanced errors for data commands. Couchbase Server 5 might return
|
|
@@ -9,7 +9,7 @@ IF(UNIX)
|
|
|
9
9
|
CHECK_FUNCTION_EXISTS(clock_gettime HAVE_CLOCK_GETTIME)
|
|
10
10
|
CHECK_FUNCTION_EXISTS(setitimer HAVE_SETITIMER)
|
|
11
11
|
CHECK_SYMBOL_EXISTS(htonll arpa/inet.h HAVE_HTONLL)
|
|
12
|
-
CHECK_SYMBOL_EXISTS(res_search resolv.h HAVE_RES_SEARCH)
|
|
12
|
+
CHECK_SYMBOL_EXISTS(res_search "netinet/in.h;resolv.h" HAVE_RES_SEARCH)
|
|
13
13
|
CHECK_INCLUDE_FILES(dlfcn.h HAVE_DLFCN_H)
|
|
14
14
|
CHECK_INCLUDE_FILES(netdb.h HAVE_NETDB_H)
|
|
15
15
|
CHECK_INCLUDE_FILES(stdint.h HAVE_STDINT_H)
|
|
@@ -36,7 +36,7 @@ ELSEIF (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
|
|
36
36
|
OUTPUT_VARIABLE LIBM_SO_TRACE
|
|
37
37
|
ERROR_QUIET
|
|
38
38
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
39
|
-
STRING(REGEX MATCH [
|
|
39
|
+
STRING(REGEX MATCH [-_a-z0-9/]+libm.so[.0-9]* LIBM_SO_PATH ${LIBM_SO_TRACE})
|
|
40
40
|
IF (EXISTS "${LIBM_SO_PATH}")
|
|
41
41
|
GET_FILENAME_COMPONENT(CMAKE_TEST_SHARED_OBJECT ${LIBM_SO_PATH} NAME)
|
|
42
42
|
ENDIF()
|
|
@@ -42,13 +42,13 @@ ENDIF()
|
|
|
42
42
|
|
|
43
43
|
IF (NOT LCB_VERSION)
|
|
44
44
|
SET(LCB_NOGITVERSION ON)
|
|
45
|
-
SET(LCB_VERSION "2.
|
|
45
|
+
SET(LCB_VERSION "2.8.2")
|
|
46
46
|
ENDIF()
|
|
47
47
|
IF (NOT LCB_VERSION_CHANGESET)
|
|
48
48
|
SET(LCB_VERSION_CHANGESET "0xdeadbeef")
|
|
49
49
|
ENDIF()
|
|
50
50
|
IF (NOT LCB_VERSION_HEX)
|
|
51
|
-
SET(LCB_VERSION_HEX
|
|
51
|
+
SET(LCB_VERSION_HEX 0x020802)
|
|
52
52
|
ENDIF()
|
|
53
53
|
|
|
54
54
|
# Now parse the version string
|
|
@@ -63,7 +63,7 @@ IF(APPLE)
|
|
|
63
63
|
ELSE()
|
|
64
64
|
SET(LCB_SONAME_MAJOR "2")
|
|
65
65
|
ENDIF()
|
|
66
|
-
SET(LCB_SONAME_FULL "${LCB_SONAME_MAJOR}.0.
|
|
66
|
+
SET(LCB_SONAME_FULL "${LCB_SONAME_MAJOR}.0.50")
|
|
67
67
|
|
|
68
68
|
MESSAGE(STATUS
|
|
69
69
|
"libcouchbase ${LCB_VERSION_MAJOR},${LCB_VERSION_MINOR},${LCB_VERSION_PATCH}")
|
|
@@ -33,28 +33,34 @@
|
|
|
33
33
|
#include <assert.h>
|
|
34
34
|
#include "cJSON.h"
|
|
35
35
|
|
|
36
|
-
static int cJSON_strcasecmp(const char *s1,const char *s2)
|
|
36
|
+
static int cJSON_strcasecmp(const char *s1, const char *s2)
|
|
37
37
|
{
|
|
38
|
-
if (!s1)
|
|
39
|
-
|
|
38
|
+
if (!s1)
|
|
39
|
+
return (s1 == s2) ? 0 : 1;
|
|
40
|
+
if (!s2)
|
|
41
|
+
return 1;
|
|
42
|
+
for (; tolower(*s1) == tolower(*s2); ++s1, ++s2)
|
|
43
|
+
if (*s1 == 0)
|
|
44
|
+
return 0;
|
|
40
45
|
return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
|
|
41
46
|
}
|
|
42
47
|
|
|
43
48
|
static void *(*cJSON_malloc)(size_t sz) = malloc;
|
|
44
49
|
static void (*cJSON_free)(void *ptr) = free;
|
|
45
50
|
|
|
46
|
-
static char*
|
|
51
|
+
static char *cJSON_strdup(const char *str)
|
|
47
52
|
{
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
size_t len;
|
|
54
|
+
char *copy;
|
|
50
55
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
len = strlen(str) + 1;
|
|
57
|
+
if (!(copy = (char *)cJSON_malloc(len)))
|
|
58
|
+
return 0;
|
|
59
|
+
memcpy(copy, str, len);
|
|
60
|
+
return copy;
|
|
55
61
|
}
|
|
56
62
|
|
|
57
|
-
void cJSON_InitHooks(cJSON_Hooks*
|
|
63
|
+
void cJSON_InitHooks(cJSON_Hooks *hooks)
|
|
58
64
|
{
|
|
59
65
|
if (!hooks) { /* Reset hooks */
|
|
60
66
|
cJSON_malloc = malloc;
|
|
@@ -62,8 +68,8 @@ void cJSON_InitHooks(cJSON_Hooks* hooks)
|
|
|
62
68
|
return;
|
|
63
69
|
}
|
|
64
70
|
|
|
65
|
-
cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
|
|
66
|
-
cJSON_free
|
|
71
|
+
cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc;
|
|
72
|
+
cJSON_free = (hooks->free_fn) ? hooks->free_fn : free;
|
|
67
73
|
}
|
|
68
74
|
|
|
69
75
|
/* The size of pool allocation groups. Note that the allocation
|
|
@@ -72,7 +78,7 @@ void cJSON_InitHooks(cJSON_Hooks* hooks)
|
|
|
72
78
|
evidence of best performance with Couchbase configuration
|
|
73
79
|
data */
|
|
74
80
|
#ifndef CJSON_POOL_ALLOC_SIZE
|
|
75
|
-
|
|
81
|
+
#define CJSON_POOL_ALLOC_SIZE 1024
|
|
76
82
|
#endif
|
|
77
83
|
|
|
78
84
|
/* Creates a new allocation pool. */
|
|
@@ -86,21 +92,19 @@ static cJSON_PoolBlock *cJSON_New_PoolBlock(cJSON_Pool *pool)
|
|
|
86
92
|
return 0;
|
|
87
93
|
}
|
|
88
94
|
|
|
89
|
-
new_block = (cJSON_PoolBlock*)cJSON_malloc(
|
|
90
|
-
sizeof(cJSON_PoolBlock) + sizeof(cJSON)*CJSON_POOL_ALLOC_SIZE);
|
|
95
|
+
new_block = (cJSON_PoolBlock *)cJSON_malloc(sizeof(cJSON_PoolBlock) + sizeof(cJSON) * CJSON_POOL_ALLOC_SIZE);
|
|
91
96
|
if (!new_block) {
|
|
92
97
|
return 0;
|
|
93
98
|
}
|
|
94
99
|
|
|
95
|
-
new_alloc = (cJSON*)(new_block+1);
|
|
100
|
+
new_alloc = (cJSON *)(new_block + 1);
|
|
96
101
|
|
|
97
|
-
memset(new_block, 0,
|
|
98
|
-
sizeof(cJSON_PoolBlock) + sizeof(cJSON)*CJSON_POOL_ALLOC_SIZE);
|
|
102
|
+
memset(new_block, 0, sizeof(cJSON_PoolBlock) + sizeof(cJSON) * CJSON_POOL_ALLOC_SIZE);
|
|
99
103
|
|
|
100
104
|
new_block->next = pool->blocks;
|
|
101
105
|
pool->blocks = new_block;
|
|
102
106
|
|
|
103
|
-
for (i=0, item=new_alloc; i<CJSON_POOL_ALLOC_SIZE; ++i, ++item) {
|
|
107
|
+
for (i = 0, item = new_alloc; i < CJSON_POOL_ALLOC_SIZE; ++i, ++item) {
|
|
104
108
|
item->next = pool->free_items;
|
|
105
109
|
pool->free_items = item;
|
|
106
110
|
}
|
|
@@ -109,12 +113,12 @@ static cJSON_PoolBlock *cJSON_New_PoolBlock(cJSON_Pool *pool)
|
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
/* This will create an allocation pool */
|
|
112
|
-
static cJSON_Pool *
|
|
116
|
+
static cJSON_Pool *cJSON_New_Pool(void)
|
|
113
117
|
{
|
|
114
118
|
if (CJSON_POOL_ALLOC_SIZE <= 0) {
|
|
115
119
|
return 0;
|
|
116
120
|
} else {
|
|
117
|
-
cJSON_Pool *
|
|
121
|
+
cJSON_Pool *pool = (cJSON_Pool *)cJSON_malloc(sizeof(cJSON_Pool));
|
|
118
122
|
if (!pool) {
|
|
119
123
|
return 0;
|
|
120
124
|
}
|
|
@@ -175,14 +179,14 @@ static void cJSON_Pool_Free_Item(cJSON_Pool *pool, cJSON *node)
|
|
|
175
179
|
/* Internal constructor. */
|
|
176
180
|
static cJSON *cJSON_New_Item(cJSON *parent)
|
|
177
181
|
{
|
|
178
|
-
cJSON*
|
|
182
|
+
cJSON *node = 0;
|
|
179
183
|
if (parent && parent->alloc_pool) {
|
|
180
184
|
node = cJSON_Pool_New_Item(parent->alloc_pool);
|
|
181
185
|
}
|
|
182
186
|
if (!node) {
|
|
183
|
-
node = (cJSON*)cJSON_malloc(sizeof(cJSON));
|
|
187
|
+
node = (cJSON *)cJSON_malloc(sizeof(cJSON));
|
|
184
188
|
if (node) {
|
|
185
|
-
memset(node,0,sizeof(cJSON));
|
|
189
|
+
memset(node, 0, sizeof(cJSON));
|
|
186
190
|
}
|
|
187
191
|
}
|
|
188
192
|
return node;
|
|
@@ -202,37 +206,56 @@ static void cJSON_Free_Item(cJSON *node)
|
|
|
202
206
|
void cJSON_Delete(cJSON *c)
|
|
203
207
|
{
|
|
204
208
|
cJSON *next;
|
|
205
|
-
while (c)
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
if (!(c->type&cJSON_IsReference) && c->valuestring)
|
|
210
|
-
|
|
209
|
+
while (c) {
|
|
210
|
+
next = c->next;
|
|
211
|
+
if (!(c->type & cJSON_IsReference) && c->child)
|
|
212
|
+
cJSON_Delete(c->child);
|
|
213
|
+
if (!(c->type & cJSON_IsReference) && c->valuestring)
|
|
214
|
+
cJSON_free(c->valuestring);
|
|
215
|
+
if (c->string)
|
|
216
|
+
cJSON_free(c->string);
|
|
211
217
|
cJSON_Free_Item(c);
|
|
212
|
-
c=next;
|
|
218
|
+
c = next;
|
|
213
219
|
}
|
|
214
220
|
}
|
|
215
221
|
|
|
216
222
|
/* Parse the input text to generate a number, and populate the result into item. */
|
|
217
|
-
static const char *parse_number(cJSON *item,const char *num)
|
|
223
|
+
static const char *parse_number(cJSON *item, const char *num)
|
|
218
224
|
{
|
|
219
|
-
double n=0,sign=1,scale=
|
|
225
|
+
double n = 0, sign = 1, scale = 0;
|
|
226
|
+
int subscale = 0, signsubscale = 1;
|
|
220
227
|
|
|
221
228
|
/* Could use sscanf for this? */
|
|
222
|
-
if (*num=='-')
|
|
223
|
-
|
|
224
|
-
if (*num
|
|
225
|
-
|
|
226
|
-
if (*num
|
|
227
|
-
|
|
228
|
-
|
|
229
|
+
if (*num == '-')
|
|
230
|
+
sign = -1, num++; /* Has sign? */
|
|
231
|
+
if (*num == '0')
|
|
232
|
+
num++; /* is zero */
|
|
233
|
+
if (*num >= '1' && *num <= '9')
|
|
234
|
+
do
|
|
235
|
+
n = (n * 10.0) + (*num++ - '0');
|
|
236
|
+
while (*num >= '0' && *num <= '9'); /* Number? */
|
|
237
|
+
if (*num == '.') {
|
|
238
|
+
num++;
|
|
239
|
+
do
|
|
240
|
+
n = (n * 10.0) + (*num++ - '0'), scale--;
|
|
241
|
+
while (*num >= '0' && *num <= '9');
|
|
242
|
+
} /* Fractional part? */
|
|
243
|
+
if (*num == 'e' || *num == 'E') /* Exponent? */
|
|
244
|
+
{
|
|
245
|
+
num++;
|
|
246
|
+
if (*num == '+')
|
|
247
|
+
num++;
|
|
248
|
+
else if (*num == '-')
|
|
249
|
+
signsubscale = -1, num++; /* With sign? */
|
|
250
|
+
while (*num >= '0' && *num <= '9')
|
|
251
|
+
subscale = (subscale * 10) + (*num++ - '0'); /* Number? */
|
|
229
252
|
}
|
|
230
253
|
|
|
231
|
-
n=sign*n*pow(10.0,(scale+subscale*signsubscale));
|
|
254
|
+
n = sign * n * pow(10.0, (scale + subscale * signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
|
|
232
255
|
|
|
233
|
-
item->valuedouble=n;
|
|
234
|
-
item->valueint=(int)n;
|
|
235
|
-
item->type=cJSON_Number;
|
|
256
|
+
item->valuedouble = n;
|
|
257
|
+
item->valueint = (int)n;
|
|
258
|
+
item->type = cJSON_Number;
|
|
236
259
|
return num;
|
|
237
260
|
}
|
|
238
261
|
|
|
@@ -240,117 +263,180 @@ static const char *parse_number(cJSON *item,const char *num)
|
|
|
240
263
|
static char *print_number(cJSON *item)
|
|
241
264
|
{
|
|
242
265
|
char *str;
|
|
243
|
-
double d=item->valuedouble;
|
|
244
|
-
if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
|
|
245
|
-
|
|
246
|
-
str
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
else
|
|
254
|
-
|
|
266
|
+
double d = item->valuedouble;
|
|
267
|
+
if (fabs(((double)item->valueint) - d) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN) {
|
|
268
|
+
str = (char *)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
|
|
269
|
+
sprintf(str, "%d", item->valueint);
|
|
270
|
+
} else {
|
|
271
|
+
str = (char *)cJSON_malloc(64); /* This is a nice tradeoff. */
|
|
272
|
+
if (fabs(floor(d) - d) <= DBL_EPSILON)
|
|
273
|
+
sprintf(str, "%.0f", d);
|
|
274
|
+
else if (fabs(d) < 1.0e-6 || fabs(d) > 1.0e9)
|
|
275
|
+
sprintf(str, "%e", d);
|
|
276
|
+
else
|
|
277
|
+
sprintf(str, "%f", d);
|
|
255
278
|
}
|
|
256
279
|
return str;
|
|
257
280
|
}
|
|
258
281
|
|
|
259
282
|
/* Parse the input text into an unescaped cstring, and populate item. */
|
|
260
|
-
static const unsigned char firstByteMark[7] = {
|
|
261
|
-
static const char *parse_string(cJSON *item,const char *str)
|
|
283
|
+
static const unsigned char firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
|
|
284
|
+
static const char *parse_string(cJSON *item, const char *str)
|
|
262
285
|
{
|
|
263
|
-
const char *ptr=str+1;
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
286
|
+
const char *ptr = str + 1;
|
|
287
|
+
char *ptr2;
|
|
288
|
+
char *out;
|
|
289
|
+
int len = 0;
|
|
290
|
+
unsigned uc;
|
|
291
|
+
if (*str != '\"')
|
|
292
|
+
return 0; /* not a string! */
|
|
293
|
+
|
|
294
|
+
while (*ptr != '\"' && (unsigned char)*ptr > 31 && ++len)
|
|
295
|
+
if (*ptr++ == '\\')
|
|
296
|
+
ptr++; /* Skip escaped quotes. */
|
|
297
|
+
|
|
298
|
+
out = (char *)cJSON_malloc(len + 1); /* This is how long we need for the string, roughly. */
|
|
299
|
+
if (!out)
|
|
300
|
+
return 0;
|
|
270
301
|
|
|
271
|
-
ptr=str+1;
|
|
272
|
-
|
|
273
|
-
{
|
|
274
|
-
if (*ptr!='\\')
|
|
275
|
-
|
|
276
|
-
{
|
|
302
|
+
ptr = str + 1;
|
|
303
|
+
ptr2 = out;
|
|
304
|
+
while (*ptr != '\"' && (unsigned char)*ptr > 31) {
|
|
305
|
+
if (*ptr != '\\')
|
|
306
|
+
*ptr2++ = *ptr++;
|
|
307
|
+
else {
|
|
277
308
|
ptr++;
|
|
278
|
-
switch (*ptr)
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
case '
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
case '
|
|
286
|
-
|
|
287
|
-
|
|
309
|
+
switch (*ptr) {
|
|
310
|
+
case 'b':
|
|
311
|
+
*ptr2++ = '\b';
|
|
312
|
+
break;
|
|
313
|
+
case 'f':
|
|
314
|
+
*ptr2++ = '\f';
|
|
315
|
+
break;
|
|
316
|
+
case 'n':
|
|
317
|
+
*ptr2++ = '\n';
|
|
318
|
+
break;
|
|
319
|
+
case 'r':
|
|
320
|
+
*ptr2++ = '\r';
|
|
321
|
+
break;
|
|
322
|
+
case 't':
|
|
323
|
+
*ptr2++ = '\t';
|
|
324
|
+
break;
|
|
325
|
+
case 'u': /* transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY. */
|
|
326
|
+
sscanf(ptr + 1, "%4x", &uc); /* get the unicode char. */
|
|
327
|
+
len = 3;
|
|
328
|
+
if (uc < 0x80)
|
|
329
|
+
len = 1;
|
|
330
|
+
else if (uc < 0x800)
|
|
331
|
+
len = 2;
|
|
332
|
+
ptr2 += len;
|
|
288
333
|
|
|
289
334
|
switch (len) {
|
|
290
|
-
case 3:
|
|
291
|
-
|
|
292
|
-
|
|
335
|
+
case 3:
|
|
336
|
+
*--ptr2 = ((uc | 0x80) & 0xBF);
|
|
337
|
+
uc >>= 6; /* fall through */
|
|
338
|
+
case 2:
|
|
339
|
+
*--ptr2 = ((uc | 0x80) & 0xBF);
|
|
340
|
+
uc >>= 6; /* fall through */
|
|
341
|
+
case 1:
|
|
342
|
+
*--ptr2 = (uc | firstByteMark[len]); /* fall through */
|
|
293
343
|
}
|
|
294
|
-
ptr2+=len;
|
|
344
|
+
ptr2 += len;
|
|
345
|
+
ptr += 4;
|
|
346
|
+
break;
|
|
347
|
+
default:
|
|
348
|
+
*ptr2++ = *ptr;
|
|
295
349
|
break;
|
|
296
|
-
default: *ptr2++=*ptr; break;
|
|
297
350
|
}
|
|
298
351
|
ptr++;
|
|
299
352
|
}
|
|
300
353
|
}
|
|
301
|
-
*ptr2=0;
|
|
302
|
-
if (*ptr=='\"')
|
|
303
|
-
|
|
304
|
-
item->
|
|
354
|
+
*ptr2 = 0;
|
|
355
|
+
if (*ptr == '\"')
|
|
356
|
+
ptr++;
|
|
357
|
+
item->valuestring = out;
|
|
358
|
+
item->type = cJSON_String;
|
|
305
359
|
return ptr;
|
|
306
360
|
}
|
|
307
361
|
|
|
308
362
|
/* Render the cstring provided to an escaped version that can be printed. */
|
|
309
363
|
static char *print_string_ptr(const char *str)
|
|
310
364
|
{
|
|
311
|
-
const char *ptr;
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
365
|
+
const char *ptr;
|
|
366
|
+
char *ptr2, *out;
|
|
367
|
+
int len = 0;
|
|
368
|
+
|
|
369
|
+
if (!str)
|
|
370
|
+
return cJSON_strdup("");
|
|
371
|
+
ptr = str;
|
|
372
|
+
while (*ptr && ++len) {
|
|
373
|
+
if ((unsigned char)*ptr < 32 || *ptr == '\"' || *ptr == '\\')
|
|
374
|
+
len++;
|
|
375
|
+
ptr++;
|
|
376
|
+
}
|
|
315
377
|
|
|
316
|
-
out=(char*)cJSON_malloc(len+3);
|
|
317
|
-
ptr2=out;
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
{
|
|
321
|
-
if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\')
|
|
322
|
-
|
|
323
|
-
{
|
|
324
|
-
*ptr2
|
|
325
|
-
switch (*ptr++)
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
case '\
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
case '\
|
|
333
|
-
|
|
334
|
-
|
|
378
|
+
out = (char *)cJSON_malloc(len + 3);
|
|
379
|
+
ptr2 = out;
|
|
380
|
+
ptr = str;
|
|
381
|
+
*ptr2++ = '\"';
|
|
382
|
+
while (*ptr) {
|
|
383
|
+
if ((unsigned char)*ptr > 31 && *ptr != '\"' && *ptr != '\\')
|
|
384
|
+
*ptr2++ = *ptr++;
|
|
385
|
+
else {
|
|
386
|
+
*ptr2++ = '\\';
|
|
387
|
+
switch (*ptr++) {
|
|
388
|
+
case '\\':
|
|
389
|
+
*ptr2++ = '\\';
|
|
390
|
+
break;
|
|
391
|
+
case '\"':
|
|
392
|
+
*ptr2++ = '\"';
|
|
393
|
+
break;
|
|
394
|
+
case '\b':
|
|
395
|
+
*ptr2++ = 'b';
|
|
396
|
+
break;
|
|
397
|
+
case '\f':
|
|
398
|
+
*ptr2++ = 'f';
|
|
399
|
+
break;
|
|
400
|
+
case '\n':
|
|
401
|
+
*ptr2++ = 'n';
|
|
402
|
+
break;
|
|
403
|
+
case '\r':
|
|
404
|
+
*ptr2++ = 'r';
|
|
405
|
+
break;
|
|
406
|
+
case '\t':
|
|
407
|
+
*ptr2++ = 't';
|
|
408
|
+
break;
|
|
409
|
+
default:
|
|
410
|
+
ptr2--;
|
|
411
|
+
break; /* eviscerate with prejudice. */
|
|
335
412
|
}
|
|
336
413
|
}
|
|
337
414
|
}
|
|
338
|
-
*ptr2
|
|
415
|
+
*ptr2++ = '\"';
|
|
416
|
+
*ptr2++ = 0;
|
|
339
417
|
return out;
|
|
340
418
|
}
|
|
341
419
|
/* Invote print_string_ptr (which is useful) on an item. */
|
|
342
|
-
static char *print_string(cJSON *item)
|
|
420
|
+
static char *print_string(cJSON *item)
|
|
421
|
+
{
|
|
422
|
+
return print_string_ptr(item->valuestring);
|
|
423
|
+
}
|
|
343
424
|
|
|
344
425
|
/* Predeclare these prototypes. */
|
|
345
|
-
static const char *parse_value(cJSON *item,const char *value);
|
|
346
|
-
static char *print_value(cJSON *item,int depth,int fmt);
|
|
347
|
-
static const char *parse_array(cJSON *item,const char *value);
|
|
348
|
-
static char *print_array(cJSON *item,int depth,int fmt);
|
|
349
|
-
static const char *parse_object(cJSON *item,const char *value);
|
|
350
|
-
static char *print_object(cJSON *item,int depth,int fmt);
|
|
426
|
+
static const char *parse_value(cJSON *item, const char *value);
|
|
427
|
+
static char *print_value(cJSON *item, int depth, int fmt);
|
|
428
|
+
static const char *parse_array(cJSON *item, const char *value);
|
|
429
|
+
static char *print_array(cJSON *item, int depth, int fmt);
|
|
430
|
+
static const char *parse_object(cJSON *item, const char *value);
|
|
431
|
+
static char *print_object(cJSON *item, int depth, int fmt);
|
|
351
432
|
|
|
352
433
|
/* Utility to jump whitespace and cr/lf */
|
|
353
|
-
static const char *skip(const char *in)
|
|
434
|
+
static const char *skip(const char *in)
|
|
435
|
+
{
|
|
436
|
+
while (in && *in && (unsigned char)*in <= 32)
|
|
437
|
+
in++;
|
|
438
|
+
return in;
|
|
439
|
+
}
|
|
354
440
|
|
|
355
441
|
/* Parse an object - create a new root, and populate. */
|
|
356
442
|
cJSON *cJSON_Parse(const char *value)
|
|
@@ -363,262 +449,574 @@ cJSON *cJSON_Parse(const char *value)
|
|
|
363
449
|
if (!c) {
|
|
364
450
|
c = cJSON_New_Item(0);
|
|
365
451
|
}
|
|
366
|
-
if (!c)
|
|
452
|
+
if (!c)
|
|
453
|
+
return 0; /* memory fail */
|
|
367
454
|
|
|
368
455
|
c->alloc_pool = pool;
|
|
369
456
|
|
|
370
|
-
if (!parse_value(c,skip(value))) {
|
|
457
|
+
if (!parse_value(c, skip(value))) {
|
|
458
|
+
cJSON_Delete(c);
|
|
459
|
+
return 0;
|
|
460
|
+
}
|
|
371
461
|
return c;
|
|
372
462
|
}
|
|
373
463
|
|
|
374
464
|
/* Render a cJSON item/entity/structure to text. */
|
|
375
|
-
char *cJSON_Print(cJSON *item)
|
|
376
|
-
|
|
465
|
+
char *cJSON_Print(cJSON *item)
|
|
466
|
+
{
|
|
467
|
+
return print_value(item, 0, 1);
|
|
468
|
+
}
|
|
469
|
+
char *cJSON_PrintUnformatted(cJSON *item)
|
|
470
|
+
{
|
|
471
|
+
return print_value(item, 0, 0);
|
|
472
|
+
}
|
|
377
473
|
|
|
378
474
|
/* Parser core - when encountering text, process appropriately. */
|
|
379
|
-
static const char *parse_value(cJSON *item,const char *value)
|
|
475
|
+
static const char *parse_value(cJSON *item, const char *value)
|
|
380
476
|
{
|
|
381
|
-
if (!value)
|
|
382
|
-
|
|
383
|
-
if (!strncmp(value,"
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
if (
|
|
388
|
-
|
|
477
|
+
if (!value)
|
|
478
|
+
return 0; /* Fail on null. */
|
|
479
|
+
if (!strncmp(value, "null", 4)) {
|
|
480
|
+
item->type = cJSON_NULL;
|
|
481
|
+
return value + 4;
|
|
482
|
+
}
|
|
483
|
+
if (!strncmp(value, "false", 5)) {
|
|
484
|
+
item->type = cJSON_False;
|
|
485
|
+
return value + 5;
|
|
486
|
+
}
|
|
487
|
+
if (!strncmp(value, "true", 4)) {
|
|
488
|
+
item->type = cJSON_True;
|
|
489
|
+
item->valueint = 1;
|
|
490
|
+
return value + 4;
|
|
491
|
+
}
|
|
492
|
+
if (*value == '\"') {
|
|
493
|
+
return parse_string(item, value);
|
|
494
|
+
}
|
|
495
|
+
if (*value == '-' || (*value >= '0' && *value <= '9')) {
|
|
496
|
+
return parse_number(item, value);
|
|
497
|
+
}
|
|
498
|
+
if (*value == '[') {
|
|
499
|
+
return parse_array(item, value);
|
|
500
|
+
}
|
|
501
|
+
if (*value == '{') {
|
|
502
|
+
return parse_object(item, value);
|
|
503
|
+
}
|
|
389
504
|
|
|
390
|
-
return 0;
|
|
505
|
+
return 0; /* failure. */
|
|
391
506
|
}
|
|
392
507
|
|
|
393
508
|
/* Render a value to text. */
|
|
394
|
-
static char *print_value(cJSON *item,int depth,int fmt)
|
|
509
|
+
static char *print_value(cJSON *item, int depth, int fmt)
|
|
395
510
|
{
|
|
396
|
-
char *out=0;
|
|
397
|
-
if (!item)
|
|
398
|
-
|
|
399
|
-
{
|
|
400
|
-
case cJSON_NULL:
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
case
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
case
|
|
511
|
+
char *out = 0;
|
|
512
|
+
if (!item)
|
|
513
|
+
return 0;
|
|
514
|
+
switch ((item->type) & 255) {
|
|
515
|
+
case cJSON_NULL:
|
|
516
|
+
out = cJSON_strdup("null");
|
|
517
|
+
break;
|
|
518
|
+
case cJSON_False:
|
|
519
|
+
out = cJSON_strdup("false");
|
|
520
|
+
break;
|
|
521
|
+
case cJSON_True:
|
|
522
|
+
out = cJSON_strdup("true");
|
|
523
|
+
break;
|
|
524
|
+
case cJSON_Number:
|
|
525
|
+
out = print_number(item);
|
|
526
|
+
break;
|
|
527
|
+
case cJSON_String:
|
|
528
|
+
out = print_string(item);
|
|
529
|
+
break;
|
|
530
|
+
case cJSON_Array:
|
|
531
|
+
out = print_array(item, depth, fmt);
|
|
532
|
+
break;
|
|
533
|
+
case cJSON_Object:
|
|
534
|
+
out = print_object(item, depth, fmt);
|
|
535
|
+
break;
|
|
407
536
|
}
|
|
408
537
|
return out;
|
|
409
538
|
}
|
|
410
539
|
|
|
411
540
|
/* Build an array from input text. */
|
|
412
|
-
static const char *parse_array(cJSON *item,const char *value)
|
|
541
|
+
static const char *parse_array(cJSON *item, const char *value)
|
|
413
542
|
{
|
|
414
543
|
cJSON *child;
|
|
415
|
-
if (*value!='[')
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
if (!
|
|
544
|
+
if (*value != '[')
|
|
545
|
+
return 0; /* not an array! */
|
|
546
|
+
|
|
547
|
+
item->type = cJSON_Array;
|
|
548
|
+
value = skip(value + 1);
|
|
549
|
+
if (*value == ']')
|
|
550
|
+
return value + 1; /* empty array. */
|
|
551
|
+
|
|
552
|
+
item->child = child = cJSON_New_Item(item);
|
|
553
|
+
if (!item->child)
|
|
554
|
+
return 0; /* memory fail */
|
|
555
|
+
value = skip(parse_value(child, skip(value))); /* skip any spacing, get the value. */
|
|
556
|
+
if (!value)
|
|
557
|
+
return 0;
|
|
425
558
|
|
|
426
|
-
while (*value==',')
|
|
427
|
-
{
|
|
559
|
+
while (*value == ',') {
|
|
428
560
|
cJSON *new_item;
|
|
429
|
-
if (!(new_item=cJSON_New_Item(item)))
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
561
|
+
if (!(new_item = cJSON_New_Item(item)))
|
|
562
|
+
return 0; /* memory fail */
|
|
563
|
+
child->next = new_item;
|
|
564
|
+
new_item->prev = child;
|
|
565
|
+
child = new_item;
|
|
566
|
+
value = skip(parse_value(child, skip(value + 1)));
|
|
567
|
+
if (!value)
|
|
568
|
+
return 0; /* memory fail */
|
|
433
569
|
}
|
|
434
570
|
|
|
435
|
-
if (*value==']')
|
|
436
|
-
|
|
571
|
+
if (*value == ']')
|
|
572
|
+
return value + 1; /* end of array */
|
|
573
|
+
return 0; /* malformed. */
|
|
437
574
|
}
|
|
438
575
|
|
|
439
576
|
/* Render an array to text */
|
|
440
|
-
static char *print_array(cJSON *item,int depth,int fmt)
|
|
577
|
+
static char *print_array(cJSON *item, int depth, int fmt)
|
|
441
578
|
{
|
|
442
579
|
char **entries;
|
|
443
|
-
char *out=0
|
|
444
|
-
|
|
445
|
-
|
|
580
|
+
char *out = 0, *ptr, *ret;
|
|
581
|
+
size_t len = 5;
|
|
582
|
+
cJSON *child = item->child;
|
|
583
|
+
int numentries = 0, i = 0, fail = 0;
|
|
446
584
|
|
|
447
585
|
/* How many entries in the array? */
|
|
448
|
-
while (child)
|
|
586
|
+
while (child)
|
|
587
|
+
numentries++, child = child->next;
|
|
449
588
|
/* Allocate an array to hold the values for each */
|
|
450
|
-
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
|
|
451
|
-
if (!entries)
|
|
452
|
-
|
|
589
|
+
entries = (char **)cJSON_malloc(numentries * sizeof(char *));
|
|
590
|
+
if (!entries)
|
|
591
|
+
return 0;
|
|
592
|
+
memset(entries, 0, numentries * sizeof(char *));
|
|
453
593
|
/* Retrieve all the results: */
|
|
454
|
-
child=item->child;
|
|
455
|
-
while (child && !fail)
|
|
456
|
-
|
|
457
|
-
ret
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
594
|
+
child = item->child;
|
|
595
|
+
while (child && !fail) {
|
|
596
|
+
ret = print_value(child, depth + 1, fmt);
|
|
597
|
+
entries[i++] = ret;
|
|
598
|
+
if (ret)
|
|
599
|
+
len += strlen(ret) + 2 + (fmt ? 1 : 0);
|
|
600
|
+
else
|
|
601
|
+
fail = 1;
|
|
602
|
+
child = child->next;
|
|
461
603
|
}
|
|
462
604
|
|
|
463
605
|
/* If we didn't fail, try to malloc the output string */
|
|
464
|
-
if (!fail)
|
|
606
|
+
if (!fail)
|
|
607
|
+
out = cJSON_malloc(len);
|
|
465
608
|
/* If that fails, we fail. */
|
|
466
|
-
if (!out)
|
|
609
|
+
if (!out)
|
|
610
|
+
fail = 1;
|
|
467
611
|
|
|
468
612
|
/* Handle failure. */
|
|
469
|
-
if (fail)
|
|
470
|
-
|
|
471
|
-
|
|
613
|
+
if (fail) {
|
|
614
|
+
for (i = 0; i < numentries; i++)
|
|
615
|
+
if (entries[i])
|
|
616
|
+
cJSON_free(entries[i]);
|
|
472
617
|
cJSON_free(entries);
|
|
473
618
|
return 0;
|
|
474
619
|
}
|
|
475
620
|
|
|
476
621
|
/* Compose the output array. */
|
|
477
|
-
*out='[';
|
|
478
|
-
ptr=out+1
|
|
479
|
-
|
|
480
|
-
{
|
|
481
|
-
strcpy(ptr,entries[i]);
|
|
482
|
-
|
|
622
|
+
*out = '[';
|
|
623
|
+
ptr = out + 1;
|
|
624
|
+
*ptr = 0;
|
|
625
|
+
for (i = 0; i < numentries; i++) {
|
|
626
|
+
strcpy(ptr, entries[i]);
|
|
627
|
+
ptr += strlen(entries[i]);
|
|
628
|
+
if (i != numentries - 1) {
|
|
629
|
+
*ptr++ = ',';
|
|
630
|
+
if (fmt)
|
|
631
|
+
*ptr++ = ' ';
|
|
632
|
+
*ptr = 0;
|
|
633
|
+
}
|
|
483
634
|
cJSON_free(entries[i]);
|
|
484
635
|
}
|
|
485
636
|
cJSON_free(entries);
|
|
486
|
-
*ptr
|
|
637
|
+
*ptr++ = ']';
|
|
638
|
+
*ptr++ = 0;
|
|
487
639
|
return out;
|
|
488
640
|
}
|
|
489
641
|
|
|
490
642
|
/* Build an object from the text. */
|
|
491
|
-
static const char *parse_object(cJSON *item,const char *value)
|
|
643
|
+
static const char *parse_object(cJSON *item, const char *value)
|
|
492
644
|
{
|
|
493
645
|
cJSON *child;
|
|
494
|
-
if (*value!='{')
|
|
646
|
+
if (*value != '{')
|
|
647
|
+
return 0; /* not an object! */
|
|
495
648
|
|
|
496
|
-
item->type=cJSON_Object;
|
|
497
|
-
value=skip(value+1);
|
|
498
|
-
if (*value=='}')
|
|
649
|
+
item->type = cJSON_Object;
|
|
650
|
+
value = skip(value + 1);
|
|
651
|
+
if (*value == '}')
|
|
652
|
+
return value + 1; /* empty array. */
|
|
499
653
|
|
|
500
|
-
item->child=child=cJSON_New_Item(item);
|
|
501
|
-
value=skip(parse_string(child,skip(value)));
|
|
502
|
-
if (!value)
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
if (
|
|
654
|
+
item->child = child = cJSON_New_Item(item);
|
|
655
|
+
value = skip(parse_string(child, skip(value)));
|
|
656
|
+
if (!value)
|
|
657
|
+
return 0;
|
|
658
|
+
child->string = child->valuestring;
|
|
659
|
+
child->valuestring = 0;
|
|
660
|
+
if (*value != ':')
|
|
661
|
+
return 0; /* fail! */
|
|
662
|
+
value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */
|
|
663
|
+
if (!value)
|
|
664
|
+
return 0;
|
|
507
665
|
|
|
508
|
-
while (*value==',')
|
|
509
|
-
{
|
|
666
|
+
while (*value == ',') {
|
|
510
667
|
cJSON *new_item;
|
|
511
|
-
if (!(new_item=cJSON_New_Item(item)))
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
child
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
668
|
+
if (!(new_item = cJSON_New_Item(item)))
|
|
669
|
+
return 0; /* memory fail */
|
|
670
|
+
child->next = new_item;
|
|
671
|
+
new_item->prev = child;
|
|
672
|
+
child = new_item;
|
|
673
|
+
value = skip(parse_string(child, skip(value + 1)));
|
|
674
|
+
if (!value)
|
|
675
|
+
return 0;
|
|
676
|
+
child->string = child->valuestring;
|
|
677
|
+
child->valuestring = 0;
|
|
678
|
+
if (*value != ':')
|
|
679
|
+
return 0; /* fail! */
|
|
680
|
+
value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */
|
|
681
|
+
if (!value)
|
|
682
|
+
return 0;
|
|
519
683
|
}
|
|
520
684
|
|
|
521
|
-
if (*value=='}')
|
|
522
|
-
|
|
685
|
+
if (*value == '}')
|
|
686
|
+
return value + 1; /* end of array */
|
|
687
|
+
return 0; /* malformed. */
|
|
523
688
|
}
|
|
524
689
|
|
|
525
690
|
/* Render an object to text. */
|
|
526
|
-
static char *print_object(cJSON *item,int depth,int fmt)
|
|
691
|
+
static char *print_object(cJSON *item, int depth, int fmt)
|
|
527
692
|
{
|
|
528
|
-
char **entries=0
|
|
529
|
-
char *out=0
|
|
530
|
-
|
|
531
|
-
int
|
|
693
|
+
char **entries = 0, **names = 0;
|
|
694
|
+
char *out = 0, *ptr, *ret, *str;
|
|
695
|
+
size_t len = 7;
|
|
696
|
+
int i = 0, j;
|
|
697
|
+
cJSON *child = item->child;
|
|
698
|
+
int numentries = 0, fail = 0;
|
|
532
699
|
/* Count the number of entries. */
|
|
533
|
-
while (child)
|
|
700
|
+
while (child)
|
|
701
|
+
numentries++, child = child->next;
|
|
534
702
|
/* Allocate space for the names and the objects */
|
|
535
|
-
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
|
|
536
|
-
if (!entries)
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
703
|
+
entries = (char **)cJSON_malloc(numentries * sizeof(char *));
|
|
704
|
+
if (!entries)
|
|
705
|
+
return 0;
|
|
706
|
+
names = (char **)cJSON_malloc(numentries * sizeof(char *));
|
|
707
|
+
if (!names) {
|
|
708
|
+
cJSON_free(entries);
|
|
709
|
+
return 0;
|
|
710
|
+
}
|
|
711
|
+
memset(entries, 0, sizeof(char *) * numentries);
|
|
712
|
+
memset(names, 0, sizeof(char *) * numentries);
|
|
541
713
|
|
|
542
714
|
/* Collect all the results into our arrays: */
|
|
543
|
-
child=item->child;
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
715
|
+
child = item->child;
|
|
716
|
+
depth++;
|
|
717
|
+
if (fmt)
|
|
718
|
+
len += depth;
|
|
719
|
+
while (child) {
|
|
720
|
+
names[i] = str = print_string_ptr(child->string);
|
|
721
|
+
entries[i++] = ret = print_value(child, depth, fmt);
|
|
722
|
+
if (str && ret)
|
|
723
|
+
len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0);
|
|
724
|
+
else
|
|
725
|
+
fail = 1;
|
|
726
|
+
child = child->next;
|
|
550
727
|
}
|
|
551
728
|
|
|
552
729
|
/* Try to allocate the output string */
|
|
553
|
-
if (!fail)
|
|
554
|
-
|
|
730
|
+
if (!fail)
|
|
731
|
+
out = (char *)cJSON_malloc(len);
|
|
732
|
+
if (!out)
|
|
733
|
+
fail = 1;
|
|
555
734
|
|
|
556
735
|
/* Handle failure */
|
|
557
|
-
if (fail)
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
736
|
+
if (fail) {
|
|
737
|
+
for (i = 0; i < numentries; i++) {
|
|
738
|
+
if (names[i])
|
|
739
|
+
free(names[i]);
|
|
740
|
+
if (entries[i])
|
|
741
|
+
free(entries[i]);
|
|
742
|
+
}
|
|
743
|
+
free(names);
|
|
744
|
+
free(entries);
|
|
561
745
|
return 0;
|
|
562
746
|
}
|
|
563
747
|
|
|
564
748
|
/* Compose the output: */
|
|
565
|
-
*out='{';
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
749
|
+
*out = '{';
|
|
750
|
+
ptr = out + 1;
|
|
751
|
+
if (fmt)
|
|
752
|
+
*ptr++ = '\n';
|
|
753
|
+
*ptr = 0;
|
|
754
|
+
for (i = 0; i < numentries; i++) {
|
|
755
|
+
if (fmt)
|
|
756
|
+
for (j = 0; j < depth; j++)
|
|
757
|
+
*ptr++ = '\t';
|
|
758
|
+
strcpy(ptr, names[i]);
|
|
759
|
+
ptr += strlen(names[i]);
|
|
760
|
+
*ptr++ = ':';
|
|
761
|
+
if (fmt)
|
|
762
|
+
*ptr++ = '\t';
|
|
763
|
+
strcpy(ptr, entries[i]);
|
|
764
|
+
ptr += strlen(entries[i]);
|
|
765
|
+
if (i != numentries - 1)
|
|
766
|
+
*ptr++ = ',';
|
|
767
|
+
if (fmt)
|
|
768
|
+
*ptr++ = '\n';
|
|
769
|
+
*ptr = 0;
|
|
770
|
+
cJSON_free(names[i]);
|
|
771
|
+
cJSON_free(entries[i]);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
cJSON_free(names);
|
|
775
|
+
cJSON_free(entries);
|
|
776
|
+
if (fmt)
|
|
777
|
+
for (i = 0; i < depth - 1; i++)
|
|
778
|
+
*ptr++ = '\t';
|
|
779
|
+
*ptr++ = '}';
|
|
780
|
+
*ptr++ = 0;
|
|
580
781
|
return out;
|
|
581
782
|
}
|
|
582
783
|
|
|
583
784
|
/* Get Array size/item / object item. */
|
|
584
|
-
int
|
|
585
|
-
|
|
586
|
-
|
|
785
|
+
int cJSON_GetArraySize(cJSON *array)
|
|
786
|
+
{
|
|
787
|
+
cJSON *c = array->child;
|
|
788
|
+
int i = 0;
|
|
789
|
+
while (c)
|
|
790
|
+
i++, c = c->next;
|
|
791
|
+
return i;
|
|
792
|
+
}
|
|
793
|
+
cJSON *cJSON_GetArrayItem(cJSON *array, int item)
|
|
794
|
+
{
|
|
795
|
+
cJSON *c = array->child;
|
|
796
|
+
while (c && item > 0)
|
|
797
|
+
item--, c = c->next;
|
|
798
|
+
return c;
|
|
799
|
+
}
|
|
800
|
+
cJSON *cJSON_GetObjectItem(cJSON *object, const char *string)
|
|
801
|
+
{
|
|
802
|
+
cJSON *c = object->child;
|
|
803
|
+
while (c && cJSON_strcasecmp(c->string, string))
|
|
804
|
+
c = c->next;
|
|
805
|
+
return c;
|
|
806
|
+
}
|
|
587
807
|
|
|
588
808
|
/* Utility for array list handling. */
|
|
589
|
-
static void suffix_object(cJSON *prev,cJSON *item)
|
|
809
|
+
static void suffix_object(cJSON *prev, cJSON *item)
|
|
810
|
+
{
|
|
811
|
+
prev->next = item;
|
|
812
|
+
item->prev = prev;
|
|
813
|
+
}
|
|
590
814
|
/* Utility for handling references. */
|
|
591
|
-
static cJSON *create_reference(cJSON *item)
|
|
815
|
+
static cJSON *create_reference(cJSON *item)
|
|
816
|
+
{
|
|
817
|
+
cJSON *ref = cJSON_New_Item(item);
|
|
818
|
+
memcpy(ref, item, sizeof(cJSON));
|
|
819
|
+
ref->string = 0;
|
|
820
|
+
ref->type |= cJSON_IsReference;
|
|
821
|
+
ref->next = ref->prev = 0;
|
|
822
|
+
return ref;
|
|
823
|
+
}
|
|
592
824
|
|
|
593
825
|
/* Add item to array/object. */
|
|
594
|
-
void
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
826
|
+
void cJSON_AddItemToArray(cJSON *array, cJSON *item)
|
|
827
|
+
{
|
|
828
|
+
cJSON *c = array->child;
|
|
829
|
+
if (!c) {
|
|
830
|
+
array->child = item;
|
|
831
|
+
} else {
|
|
832
|
+
while (c && c->next)
|
|
833
|
+
c = c->next;
|
|
834
|
+
suffix_object(c, item);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
|
|
838
|
+
{
|
|
839
|
+
if (item->string)
|
|
840
|
+
cJSON_free(item->string);
|
|
841
|
+
item->string = cJSON_strdup(string);
|
|
842
|
+
cJSON_AddItemToArray(object, item);
|
|
843
|
+
}
|
|
844
|
+
void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
|
|
845
|
+
{
|
|
846
|
+
cJSON_AddItemToArray(array, create_reference(item));
|
|
847
|
+
}
|
|
848
|
+
void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
|
|
849
|
+
{
|
|
850
|
+
cJSON_AddItemToObject(object, string, create_reference(item));
|
|
851
|
+
}
|
|
598
852
|
|
|
599
|
-
cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
853
|
+
cJSON *cJSON_DetachItemFromArray(cJSON *array, int which)
|
|
854
|
+
{
|
|
855
|
+
cJSON *c = array->child;
|
|
856
|
+
while (c && which > 0)
|
|
857
|
+
c = c->next, which--;
|
|
858
|
+
if (!c)
|
|
859
|
+
return 0;
|
|
860
|
+
if (c->prev)
|
|
861
|
+
c->prev->next = c->next;
|
|
862
|
+
if (c->next)
|
|
863
|
+
c->next->prev = c->prev;
|
|
864
|
+
if (c == array->child)
|
|
865
|
+
array->child = c->next;
|
|
866
|
+
c->prev = c->next = 0;
|
|
867
|
+
return c;
|
|
868
|
+
}
|
|
869
|
+
void cJSON_DeleteItemFromArray(cJSON *array, int which)
|
|
870
|
+
{
|
|
871
|
+
cJSON_Delete(cJSON_DetachItemFromArray(array, which));
|
|
872
|
+
}
|
|
873
|
+
cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string)
|
|
874
|
+
{
|
|
875
|
+
int i = 0;
|
|
876
|
+
cJSON *c = object->child;
|
|
877
|
+
while (c && cJSON_strcasecmp(c->string, string))
|
|
878
|
+
i++, c = c->next;
|
|
879
|
+
if (c)
|
|
880
|
+
return cJSON_DetachItemFromArray(object, i);
|
|
881
|
+
return 0;
|
|
882
|
+
}
|
|
883
|
+
void cJSON_DeleteItemFromObject(cJSON *object, const char *string)
|
|
884
|
+
{
|
|
885
|
+
cJSON_Delete(cJSON_DetachItemFromObject(object, string));
|
|
886
|
+
}
|
|
604
887
|
|
|
605
888
|
/* Replace array/object items with new ones. */
|
|
606
|
-
void
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
889
|
+
void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
|
|
890
|
+
{
|
|
891
|
+
cJSON *c = array->child;
|
|
892
|
+
while (c && which > 0)
|
|
893
|
+
c = c->next, which--;
|
|
894
|
+
if (!c)
|
|
895
|
+
return;
|
|
896
|
+
newitem->next = c->next;
|
|
897
|
+
newitem->prev = c->prev;
|
|
898
|
+
if (newitem->next)
|
|
899
|
+
newitem->next->prev = newitem;
|
|
900
|
+
if (c == array->child)
|
|
901
|
+
array->child = newitem;
|
|
902
|
+
else
|
|
903
|
+
newitem->prev->next = newitem;
|
|
904
|
+
c->next = c->prev = 0;
|
|
905
|
+
cJSON_Delete(c);
|
|
906
|
+
}
|
|
907
|
+
void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
|
|
908
|
+
{
|
|
909
|
+
int i = 0;
|
|
910
|
+
cJSON *c = object->child;
|
|
911
|
+
while (c && cJSON_strcasecmp(c->string, string))
|
|
912
|
+
i++, c = c->next;
|
|
913
|
+
if (c) {
|
|
914
|
+
newitem->string = cJSON_strdup(string);
|
|
915
|
+
cJSON_ReplaceItemInArray(object, i, newitem);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
610
918
|
|
|
611
919
|
/* Create basic types: */
|
|
612
|
-
cJSON *cJSON_CreateNull()
|
|
613
|
-
|
|
614
|
-
cJSON *
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
cJSON *
|
|
920
|
+
cJSON *cJSON_CreateNull()
|
|
921
|
+
{
|
|
922
|
+
cJSON *item = cJSON_New_Item(0);
|
|
923
|
+
item->type = cJSON_NULL;
|
|
924
|
+
return item;
|
|
925
|
+
}
|
|
926
|
+
cJSON *cJSON_CreateTrue()
|
|
927
|
+
{
|
|
928
|
+
cJSON *item = cJSON_New_Item(0);
|
|
929
|
+
item->type = cJSON_True;
|
|
930
|
+
return item;
|
|
931
|
+
}
|
|
932
|
+
cJSON *cJSON_CreateFalse()
|
|
933
|
+
{
|
|
934
|
+
cJSON *item = cJSON_New_Item(0);
|
|
935
|
+
item->type = cJSON_False;
|
|
936
|
+
return item;
|
|
937
|
+
}
|
|
938
|
+
cJSON *cJSON_CreateNumber(double num)
|
|
939
|
+
{
|
|
940
|
+
cJSON *item = cJSON_New_Item(0);
|
|
941
|
+
item->type = cJSON_Number;
|
|
942
|
+
item->valuedouble = num;
|
|
943
|
+
item->valueint = (int)num;
|
|
944
|
+
return item;
|
|
945
|
+
}
|
|
946
|
+
cJSON *cJSON_CreateString(const char *string)
|
|
947
|
+
{
|
|
948
|
+
cJSON *item = cJSON_New_Item(0);
|
|
949
|
+
item->type = cJSON_String;
|
|
950
|
+
item->valuestring = cJSON_strdup(string);
|
|
951
|
+
return item;
|
|
952
|
+
}
|
|
953
|
+
cJSON *cJSON_CreateArray()
|
|
954
|
+
{
|
|
955
|
+
cJSON *item = cJSON_New_Item(0);
|
|
956
|
+
item->type = cJSON_Array;
|
|
957
|
+
return item;
|
|
958
|
+
}
|
|
959
|
+
cJSON *cJSON_CreateObject()
|
|
960
|
+
{
|
|
961
|
+
cJSON *item = cJSON_New_Item(0);
|
|
962
|
+
item->type = cJSON_Object;
|
|
963
|
+
return item;
|
|
964
|
+
}
|
|
619
965
|
|
|
620
966
|
/* Create Arrays: */
|
|
621
|
-
cJSON *cJSON_CreateIntArray(int *numbers,
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
cJSON *
|
|
967
|
+
cJSON *cJSON_CreateIntArray(int *numbers, int count)
|
|
968
|
+
{
|
|
969
|
+
int i;
|
|
970
|
+
cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
|
|
971
|
+
for (i = 0; i < count; i++) {
|
|
972
|
+
n = cJSON_CreateNumber(numbers[i]);
|
|
973
|
+
if (!i)
|
|
974
|
+
a->child = n;
|
|
975
|
+
else
|
|
976
|
+
suffix_object(p, n);
|
|
977
|
+
p = n;
|
|
978
|
+
}
|
|
979
|
+
return a;
|
|
980
|
+
}
|
|
981
|
+
cJSON *cJSON_CreateFloatArray(float *numbers, int count)
|
|
982
|
+
{
|
|
983
|
+
int i;
|
|
984
|
+
cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
|
|
985
|
+
for (i = 0; i < count; i++) {
|
|
986
|
+
n = cJSON_CreateNumber(numbers[i]);
|
|
987
|
+
if (!i)
|
|
988
|
+
a->child = n;
|
|
989
|
+
else
|
|
990
|
+
suffix_object(p, n);
|
|
991
|
+
p = n;
|
|
992
|
+
}
|
|
993
|
+
return a;
|
|
994
|
+
}
|
|
995
|
+
cJSON *cJSON_CreateDoubleArray(double *numbers, int count)
|
|
996
|
+
{
|
|
997
|
+
int i;
|
|
998
|
+
cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
|
|
999
|
+
for (i = 0; i < count; i++) {
|
|
1000
|
+
n = cJSON_CreateNumber(numbers[i]);
|
|
1001
|
+
if (!i)
|
|
1002
|
+
a->child = n;
|
|
1003
|
+
else
|
|
1004
|
+
suffix_object(p, n);
|
|
1005
|
+
p = n;
|
|
1006
|
+
}
|
|
1007
|
+
return a;
|
|
1008
|
+
}
|
|
1009
|
+
cJSON *cJSON_CreateStringArray(const char **strings, int count)
|
|
1010
|
+
{
|
|
1011
|
+
int i;
|
|
1012
|
+
cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
|
|
1013
|
+
for (i = 0; i < count; i++) {
|
|
1014
|
+
n = cJSON_CreateString(strings[i]);
|
|
1015
|
+
if (!i)
|
|
1016
|
+
a->child = n;
|
|
1017
|
+
else
|
|
1018
|
+
suffix_object(p, n);
|
|
1019
|
+
p = n;
|
|
1020
|
+
}
|
|
1021
|
+
return a;
|
|
1022
|
+
}
|