Initial import
This commit is contained in:
commit
b124d99c36
155 changed files with 49639 additions and 0 deletions
11
external/json/.gitignore
vendored
Normal file
11
external/json/.gitignore
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
*.html
|
||||
*.o
|
||||
*.so
|
||||
notes
|
||||
packages
|
||||
tags
|
||||
tests/utf8.dat
|
||||
*~
|
||||
*.swp
|
||||
go
|
||||
test_case.lua
|
63
external/json/.travis.yml
vendored
Normal file
63
external/json/.travis.yml
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
sudo: required
|
||||
dist: Focal
|
||||
|
||||
os: linux
|
||||
|
||||
language: c
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- cppcheck
|
||||
- valgrind
|
||||
- cpanminus
|
||||
- libipc-run3-perl
|
||||
- lua5.1
|
||||
- lua5.1-dev
|
||||
- cmake
|
||||
|
||||
cache:
|
||||
apt: true
|
||||
|
||||
env:
|
||||
global:
|
||||
- JOBS=3
|
||||
- LUAROCKS_VER=2.4.2
|
||||
matrix:
|
||||
#- LUA=1 LUA_DIR=/usr LUA_INCLUDE_DIR=$LUA_DIR/include/lua5.1
|
||||
- LUAJIT=1 LUA_DIR=/usr/local LUA_INCLUDE_DIR=$LUA_DIR/include/luajit-2.1 LUA_SUFFIX=--lua-suffix=jit
|
||||
|
||||
install:
|
||||
- sudo ln -s /usr/bin/cmake /usr/local/bin/cmake
|
||||
- if [ -n "$LUAJIT" ]; then git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git; fi
|
||||
- if [ -n "$LUAJIT" ]; then cd ./luajit2; fi
|
||||
- if [ -n "$LUAJIT" ]; then make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT' > build.log 2>&1 || (cat build.log && exit 1); fi
|
||||
- if [ -n "$LUAJIT" ]; then sudo make install > build.log 2>&1 || (cat build.log && exit 1); fi
|
||||
- if [ -n "$LUAJIT" ]; then cd ..; fi
|
||||
- if [ -n "$LUAJIT" ]; then sudo ln -s $LUA_DIR/bin/luajit $LUA_DIR/bin/lua; fi
|
||||
- sudo cpanm --notest Test::Base Test::LongString > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- wget https://luarocks.github.io/luarocks/releases/luarocks-$LUAROCKS_VER.tar.gz
|
||||
- tar -zxf luarocks-$LUAROCKS_VER.tar.gz
|
||||
- cd luarocks-$LUAROCKS_VER
|
||||
- ./configure --with-lua=$LUA_DIR --with-lua-include=$LUA_INCLUDE_DIR $LUA_SUFFIX
|
||||
- make build
|
||||
- sudo make install
|
||||
- cd ..
|
||||
|
||||
script:
|
||||
- cppcheck -i ./luajit2 --force --error-exitcode=1 --enable=warning . > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- bash runtests.sh
|
||||
- make
|
||||
- prove -Itests tests
|
||||
- TEST_LUA_USE_VALGRIND=1 prove -Itests tests > build.log 2>&1; export e=$?
|
||||
- cat build.log
|
||||
- grep -E '^==[0-9]+==' build.log; if [ "$?" == 0 ]; then exit 1; else exit $e; fi
|
||||
- cmake -DUSE_INTERNAL_FPCONV=1 .
|
||||
- make
|
||||
- prove -Itests tests
|
||||
- TEST_LUA_USE_VALGRIND=1 prove -Itests tests > build.log 2>&1; export e=$?
|
||||
- cat build.log
|
||||
- grep -E '^==[0-9]+==' build.log; if [ "$?" == 0 ]; then exit 1; else exit $e; fi
|
20
external/json/LICENSE
vendored
Normal file
20
external/json/LICENSE
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
|
||||
|
||||
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.
|
40
external/json/Makefile
vendored
Normal file
40
external/json/Makefile
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
##### Available defines for CJSON_CFLAGS #####
|
||||
##
|
||||
## USE_INTERNAL_ISINF: Workaround for Solaris platforms missing isinf().
|
||||
## DISABLE_INVALID_NUMBERS: Permanently disable invalid JSON numbers:
|
||||
## NaN, Infinity, hex.
|
||||
##
|
||||
## Optional built-in number conversion uses the following defines:
|
||||
## USE_INTERNAL_FPCONV: Use builtin strtod/dtoa for numeric conversions.
|
||||
## IEEE_BIG_ENDIAN: Required on big endian architectures.
|
||||
## MULTIPLE_THREADS: Must be set when Lua CJSON may be used in a
|
||||
## multi-threaded application. Requries _pthreads_.
|
||||
|
||||
##### Build defaults #####
|
||||
CC = cc
|
||||
AR = ar rcu
|
||||
CFLAGS = -O2 -Wall -Wno-unused-function -pedantic -fpic -DNDEBUG -I../../lua-5.4
|
||||
OBJS = dtoa.o fpconv.o g_fmt.o lua_cjson.o strbuf.o
|
||||
|
||||
##### End customisable sections #####
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: cjson.a
|
||||
|
||||
cjson.a: ${OBJS}
|
||||
${AR} $@ ${OBJS}
|
||||
|
||||
dtoa.o:
|
||||
${CC} ${CFLAGS} -o $@ -c dtoa.c
|
||||
fpconv.o:
|
||||
${CC} ${CFLAGS} -o $@ -c fpconv.c
|
||||
g_fmt.o:
|
||||
${CC} ${CFLAGS} -o $@ -c g_fmt.c
|
||||
lua_cjson.o:
|
||||
${CC} ${CFLAGS} -o $@ -c lua_cjson.c
|
||||
strbuf.o:
|
||||
${CC} ${CFLAGS} -o $@ -c strbuf.c
|
||||
|
||||
clean:
|
||||
rm -f cjson.a ${OBJS}
|
208
external/json/README.md
vendored
Normal file
208
external/json/README.md
vendored
Normal file
|
@ -0,0 +1,208 @@
|
|||
Name
|
||||
====
|
||||
|
||||
lua-cjson - Fast JSON encoding/parsing
|
||||
|
||||
Table of Contents
|
||||
=================
|
||||
|
||||
* [Name](#name)
|
||||
* [Description](#description)
|
||||
* [Additions to mpx/lua](#additions)
|
||||
* [encode_empty_table_as_object](#encode_empty_table_as_object)
|
||||
* [empty_array](#empty_array)
|
||||
* [array_mt](#array_mt)
|
||||
* [empty_array_mt](#empty_array_mt)
|
||||
* [encode_number_precision](#encode_number_precision)
|
||||
* [encode_escape_forward_slash](#encode_escape_forward_slash)
|
||||
* [decode_array_with_array_mt](#decode_array_with_array_mt)
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
This fork of [mpx/lua-cjson](https://github.com/mpx/lua-cjson) is included in
|
||||
the [OpenResty](https://openresty.org/) bundle and includes a few bugfixes and
|
||||
improvements, especially to facilitate the encoding of empty tables as JSON Arrays.
|
||||
|
||||
Please refer to the [lua-cjson documentation](http://www.kyne.com.au/~mark/software/lua-cjson.php)
|
||||
for standard usage, this README only provides informations regarding this fork's additions.
|
||||
|
||||
See [`mpx/master..openresty/master`](https://github.com/mpx/lua-cjson/compare/master...openresty:master)
|
||||
for the complete history of changes.
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
Additions
|
||||
=========
|
||||
|
||||
encode_empty_table_as_object
|
||||
----------------------------
|
||||
**syntax:** `cjson.encode_empty_table_as_object(true|false|"on"|"off")`
|
||||
|
||||
Change the default behavior when encoding an empty Lua table.
|
||||
|
||||
By default, empty Lua tables are encoded as empty JSON Objects (`{}`). If this is set to false,
|
||||
empty Lua tables will be encoded as empty JSON Arrays instead (`[]`).
|
||||
|
||||
This method either accepts a boolean or a string (`"on"`, `"off"`).
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
empty_array
|
||||
-----------
|
||||
**syntax:** `cjson.empty_array`
|
||||
|
||||
A lightuserdata, similar to `cjson.null`, which will be encoded as an empty JSON Array by
|
||||
`cjson.encode()`.
|
||||
|
||||
For example, since `encode_empty_table_as_object` is `true` by default:
|
||||
|
||||
```lua
|
||||
local cjson = require "cjson"
|
||||
|
||||
local json = cjson.encode({
|
||||
foo = "bar",
|
||||
some_object = {},
|
||||
some_array = cjson.empty_array
|
||||
})
|
||||
```
|
||||
|
||||
This will generate:
|
||||
|
||||
```json
|
||||
{
|
||||
"foo": "bar",
|
||||
"some_object": {},
|
||||
"some_array": []
|
||||
}
|
||||
```
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
array_mt
|
||||
--------
|
||||
**syntax:** `setmetatable({}, cjson.array_mt)`
|
||||
|
||||
When lua-cjson encodes a table with this metatable, it will systematically
|
||||
encode it as a JSON Array. The resulting, encoded Array will contain the array
|
||||
part of the table, and will be of the same length as the `#` operator on that
|
||||
table. Holes in the table will be encoded with the `null` JSON value.
|
||||
|
||||
Example:
|
||||
|
||||
```lua
|
||||
local t = { "hello", "world" }
|
||||
setmetatable(t, cjson.array_mt)
|
||||
cjson.encode(t) -- ["hello","world"]
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```lua
|
||||
local t = {}
|
||||
t[1] = "one"
|
||||
t[2] = "two"
|
||||
t[4] = "three"
|
||||
t.foo = "bar"
|
||||
setmetatable(t, cjson.array_mt)
|
||||
cjson.encode(t) -- ["one","two",null,"three"]
|
||||
```
|
||||
|
||||
This value was introduced in the `2.1.0.5` release of this module.
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
empty_array_mt
|
||||
--------------
|
||||
**syntax:** `setmetatable({}, cjson.empty_array_mt)`
|
||||
|
||||
A metatable which can "tag" a table as a JSON Array in case it is empty (that is, if the
|
||||
table has no elements, `cjson.encode()` will encode it as an empty JSON Array).
|
||||
|
||||
Instead of:
|
||||
|
||||
```lua
|
||||
local function serialize(arr)
|
||||
if #arr < 1 then
|
||||
arr = cjson.empty_array
|
||||
end
|
||||
|
||||
return cjson.encode({some_array = arr})
|
||||
end
|
||||
```
|
||||
|
||||
This is more concise:
|
||||
|
||||
```lua
|
||||
local function serialize(arr)
|
||||
setmetatable(arr, cjson.empty_array_mt)
|
||||
|
||||
return cjson.encode({some_array = arr})
|
||||
end
|
||||
```
|
||||
|
||||
Both will generate:
|
||||
|
||||
```json
|
||||
{
|
||||
"some_array": []
|
||||
}
|
||||
```
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
encode_number_precision
|
||||
-----------------------
|
||||
**syntax:** `cjson.encode_number_precision(precision)`
|
||||
|
||||
This fork allows encoding of numbers with a `precision` up to 16 decimals (vs. 14 in mpx/lua-cjson).
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
encode_escape_forward_slash
|
||||
---------------------------
|
||||
**syntax:** `cjson.encode_escape_forward_slash(enabled)`
|
||||
|
||||
**default:** true
|
||||
|
||||
If enabled, forward slash '/' will be encoded as '\\/'.
|
||||
|
||||
If disabled, forward slash '/' will be encoded as '/' (no escape is applied).
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
decode_array_with_array_mt
|
||||
--------------------------
|
||||
**syntax:** `cjson.decode_array_with_array_mt(enabled)`
|
||||
|
||||
**default:** false
|
||||
|
||||
If enabled, JSON Arrays decoded by `cjson.decode` will result in Lua
|
||||
tables with the [`array_mt`](#array_mt) metatable. This can ensure a 1-to-1
|
||||
relationship between arrays upon multiple encoding/decoding of your
|
||||
JSON data with this module.
|
||||
|
||||
If disabled, JSON Arrays will be decoded to plain Lua tables, without
|
||||
the `array_mt` metatable.
|
||||
|
||||
The `enabled` argument is a boolean.
|
||||
|
||||
Example:
|
||||
|
||||
```lua
|
||||
local cjson = require "cjson"
|
||||
|
||||
-- default behavior
|
||||
local my_json = [[{"my_array":[]}]]
|
||||
local t = cjson.decode(my_json)
|
||||
cjson.encode(t) -- {"my_array":{}} back to an object
|
||||
|
||||
-- now, if this behavior is enabled
|
||||
cjson.decode_array_with_array_mt(true)
|
||||
|
||||
local my_json = [[{"my_array":[]}]]
|
||||
local t = cjson.decode(my_json)
|
||||
cjson.encode(t) -- {"my_array":[]} properly re-encoded as an array
|
||||
```
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
9
external/json/THANKS
vendored
Normal file
9
external/json/THANKS
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
The following people have helped with bug reports, testing and/or
|
||||
suggestions:
|
||||
|
||||
- Louis-Philippe Perron (@loopole)
|
||||
- Ondřej Jirman
|
||||
- Steve Donovan <steve.j.donovan@gmail.com>
|
||||
- Zhang "agentzh" Yichun <agentzh@gmail.com>
|
||||
|
||||
Thanks!
|
6205
external/json/dtoa.c
vendored
Normal file
6205
external/json/dtoa.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
78
external/json/dtoa_config.h
vendored
Normal file
78
external/json/dtoa_config.h
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
#ifndef _DTOA_CONFIG_H
|
||||
#define _DTOA_CONFIG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Ensure dtoa.c does not USE_LOCALE. Lua CJSON must not use locale
|
||||
* aware conversion routines. */
|
||||
#undef USE_LOCALE
|
||||
|
||||
/* dtoa.c should not touch errno, Lua CJSON does not use it, and it
|
||||
* may not be threadsafe */
|
||||
#define NO_ERRNO
|
||||
|
||||
#define Long int32_t
|
||||
#define ULong uint32_t
|
||||
#define Llong int64_t
|
||||
#define ULLong uint64_t
|
||||
|
||||
#ifdef IEEE_BIG_ENDIAN
|
||||
#define IEEE_MC68k
|
||||
#else
|
||||
#define IEEE_8087
|
||||
#endif
|
||||
|
||||
#define MALLOC xmalloc
|
||||
|
||||
static void *xmalloc(size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = malloc(size);
|
||||
if (!p) {
|
||||
fprintf(stderr, "Out of memory");
|
||||
abort();
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
#ifdef MULTIPLE_THREADS
|
||||
|
||||
/* Enable locking to support multi-threaded applications */
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t private_dtoa_lock[2] = {
|
||||
PTHREAD_MUTEX_INITIALIZER,
|
||||
PTHREAD_MUTEX_INITIALIZER
|
||||
};
|
||||
|
||||
#define dtoa_get_threadno pthread_self
|
||||
void
|
||||
set_max_dtoa_threads(unsigned int n);
|
||||
|
||||
#define ACQUIRE_DTOA_LOCK(n) do { \
|
||||
int r = pthread_mutex_lock(&private_dtoa_lock[n]); \
|
||||
if (r) { \
|
||||
fprintf(stderr, "pthread_mutex_lock failed with %d\n", r); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define FREE_DTOA_LOCK(n) do { \
|
||||
int r = pthread_mutex_unlock(&private_dtoa_lock[n]); \
|
||||
if (r) { \
|
||||
fprintf(stderr, "pthread_mutex_unlock failed with %d\n", r);\
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* MULTIPLE_THREADS */
|
||||
|
||||
#endif /* _DTOA_CONFIG_H */
|
||||
|
||||
/* vi:ai et sw=4 ts=4:
|
||||
*/
|
211
external/json/fpconv.c
vendored
Normal file
211
external/json/fpconv.c
vendored
Normal file
|
@ -0,0 +1,211 @@
|
|||
/* fpconv - Floating point conversion routines
|
||||
*
|
||||
* Copyright (c) 2011-2012 Mark Pulford <mark@kyne.com.au>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* JSON uses a '.' decimal separator. strtod() / sprintf() under C libraries
|
||||
* with locale support will break when the decimal separator is a comma.
|
||||
*
|
||||
* fpconv_* will around these issues with a translation buffer if required.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fpconv.h"
|
||||
|
||||
/* Workaround for MSVC */
|
||||
#ifdef _MSC_VER
|
||||
#define inline __inline
|
||||
#define snprintf sprintf_s
|
||||
#endif
|
||||
|
||||
/* Lua CJSON assumes the locale is the same for all threads within a
|
||||
* process and doesn't change after initialisation.
|
||||
*
|
||||
* This avoids the need for per thread storage or expensive checks
|
||||
* for call. */
|
||||
static char locale_decimal_point = '.';
|
||||
|
||||
/* In theory multibyte decimal_points are possible, but
|
||||
* Lua CJSON only supports UTF-8 and known locales only have
|
||||
* single byte decimal points ([.,]).
|
||||
*
|
||||
* localconv() may not be thread safe (=>crash), and nl_langinfo() is
|
||||
* not supported on some platforms. Use sprintf() instead - if the
|
||||
* locale does change, at least Lua CJSON won't crash. */
|
||||
static void fpconv_update_locale(void)
|
||||
{
|
||||
char buf[8];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%g", 0.5);
|
||||
|
||||
/* Failing this test might imply the platform has a buggy dtoa
|
||||
* implementation or wide characters */
|
||||
if (buf[0] != '0' || buf[2] != '5' || buf[3] != 0) {
|
||||
fprintf(stderr, "Error: wide characters found or printf() bug.");
|
||||
abort();
|
||||
}
|
||||
|
||||
locale_decimal_point = buf[1];
|
||||
}
|
||||
|
||||
/* Check for a valid number character: [-+0-9a-yA-Y.]
|
||||
* Eg: -0.6e+5, infinity, 0xF0.F0pF0
|
||||
*
|
||||
* Used to find the probable end of a number. It doesn't matter if
|
||||
* invalid characters are counted - strtod() will find the valid
|
||||
* number if it exists. The risk is that slightly more memory might
|
||||
* be allocated before a parse error occurs. */
|
||||
static inline int valid_number_character(char ch)
|
||||
{
|
||||
char lower_ch;
|
||||
|
||||
if ('0' <= ch && ch <= '9')
|
||||
return 1;
|
||||
if (ch == '-' || ch == '+' || ch == '.')
|
||||
return 1;
|
||||
|
||||
/* Hex digits, exponent (e), base (p), "infinity",.. */
|
||||
lower_ch = ch | 0x20;
|
||||
if ('a' <= lower_ch && lower_ch <= 'y')
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate the size of the buffer required for a strtod locale
|
||||
* conversion. */
|
||||
static int strtod_buffer_size(const char *s)
|
||||
{
|
||||
const char *p = s;
|
||||
|
||||
while (valid_number_character(*p))
|
||||
p++;
|
||||
|
||||
return p - s;
|
||||
}
|
||||
|
||||
/* Similar to strtod(), but must be passed the current locale's decimal point
|
||||
* character. Guaranteed to be called at the start of any valid number in a string */
|
||||
double fpconv_strtod(const char *nptr, char **endptr)
|
||||
{
|
||||
char localbuf[FPCONV_G_FMT_BUFSIZE];
|
||||
char *buf, *endbuf, *dp;
|
||||
int buflen;
|
||||
double value;
|
||||
|
||||
/* System strtod() is fine when decimal point is '.' */
|
||||
if (locale_decimal_point == '.')
|
||||
return strtod(nptr, endptr);
|
||||
|
||||
buflen = strtod_buffer_size(nptr);
|
||||
if (!buflen) {
|
||||
/* No valid characters found, standard strtod() return */
|
||||
*endptr = (char *)nptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Duplicate number into buffer */
|
||||
if (buflen >= FPCONV_G_FMT_BUFSIZE) {
|
||||
/* Handle unusually large numbers */
|
||||
buf = malloc(buflen + 1);
|
||||
if (!buf) {
|
||||
fprintf(stderr, "Out of memory");
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
/* This is the common case.. */
|
||||
buf = localbuf;
|
||||
}
|
||||
memcpy(buf, nptr, buflen);
|
||||
buf[buflen] = 0;
|
||||
|
||||
/* Update decimal point character if found */
|
||||
dp = strchr(buf, '.');
|
||||
if (dp)
|
||||
*dp = locale_decimal_point;
|
||||
|
||||
value = strtod(buf, &endbuf);
|
||||
*endptr = (char *)&nptr[endbuf - buf];
|
||||
if (buflen >= FPCONV_G_FMT_BUFSIZE)
|
||||
free(buf);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* "fmt" must point to a buffer of at least 6 characters */
|
||||
static void set_number_format(char *fmt, int precision)
|
||||
{
|
||||
int d1, d2, i;
|
||||
|
||||
assert(1 <= precision && precision <= 16);
|
||||
|
||||
/* Create printf format (%.14g) from precision */
|
||||
d1 = precision / 10;
|
||||
d2 = precision % 10;
|
||||
fmt[0] = '%';
|
||||
fmt[1] = '.';
|
||||
i = 2;
|
||||
if (d1) {
|
||||
fmt[i++] = '0' + d1;
|
||||
}
|
||||
fmt[i++] = '0' + d2;
|
||||
fmt[i++] = 'g';
|
||||
fmt[i] = 0;
|
||||
}
|
||||
|
||||
/* Assumes there is always at least 32 characters available in the target buffer */
|
||||
int fpconv_g_fmt(char *str, double num, int precision)
|
||||
{
|
||||
char buf[FPCONV_G_FMT_BUFSIZE];
|
||||
char fmt[6];
|
||||
int len;
|
||||
char *b;
|
||||
|
||||
set_number_format(fmt, precision);
|
||||
|
||||
/* Pass through when decimal point character is dot. */
|
||||
if (locale_decimal_point == '.')
|
||||
return snprintf(str, FPCONV_G_FMT_BUFSIZE, fmt, num);
|
||||
|
||||
/* snprintf() to a buffer then translate for other decimal point characters */
|
||||
len = snprintf(buf, FPCONV_G_FMT_BUFSIZE, fmt, num);
|
||||
|
||||
/* Copy into target location. Translate decimal point if required */
|
||||
b = buf;
|
||||
do {
|
||||
*str++ = (*b == locale_decimal_point ? '.' : *b);
|
||||
} while(*b++);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void fpconv_init(void)
|
||||
{
|
||||
fpconv_update_locale();
|
||||
}
|
||||
|
||||
/* vi:ai et sw=4 ts=4:
|
||||
*/
|
32
external/json/fpconv.h
vendored
Normal file
32
external/json/fpconv.h
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* Lua CJSON floating point conversion routines */
|
||||
|
||||
/* Buffer required to store the largest string representation of a double.
|
||||
*
|
||||
* Longest double printed with %.14g is 21 characters long:
|
||||
* -1.7976931348623e+308 */
|
||||
# define FPCONV_G_FMT_BUFSIZE 32
|
||||
|
||||
#ifdef USE_INTERNAL_FPCONV
|
||||
#ifdef MULTIPLE_THREADS
|
||||
#include "dtoa_config.h"
|
||||
#include <unistd.h>
|
||||
static inline void fpconv_init()
|
||||
{
|
||||
// Add one to try and avoid core id multiplier alignment
|
||||
set_max_dtoa_threads((sysconf(_SC_NPROCESSORS_CONF) + 1) * 3);
|
||||
}
|
||||
#else
|
||||
static inline void fpconv_init()
|
||||
{
|
||||
/* Do nothing - not required */
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
extern void fpconv_init(void);
|
||||
#endif
|
||||
|
||||
extern int fpconv_g_fmt(char*, double, int);
|
||||
extern double fpconv_strtod(const char*, char**);
|
||||
|
||||
/* vi:ai et sw=4 ts=4:
|
||||
*/
|
111
external/json/g_fmt.c
vendored
Normal file
111
external/json/g_fmt.c
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
/****************************************************************
|
||||
*
|
||||
* The author of this software is David M. Gay.
|
||||
*
|
||||
* Copyright (c) 1991, 1996 by Lucent Technologies.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose without fee is hereby granted, provided that this entire notice
|
||||
* is included in all copies of any software which is or includes a copy
|
||||
* or modification of this software and in all copies of the supporting
|
||||
* documentation for such software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||
*
|
||||
***************************************************************/
|
||||
|
||||
/* g_fmt(buf,x) stores the closest decimal approximation to x in buf;
|
||||
* it suffices to declare buf
|
||||
* char buf[32];
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern char *dtoa(double, int, int, int *, int *, char **);
|
||||
extern int g_fmt(char *, double, int);
|
||||
extern void freedtoa(char*);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
fpconv_g_fmt(char *b, double x, int precision)
|
||||
{
|
||||
register int i, k;
|
||||
register char *s;
|
||||
int decpt, j, sign;
|
||||
char *b0, *s0, *se;
|
||||
|
||||
b0 = b;
|
||||
#ifdef IGNORE_ZERO_SIGN
|
||||
if (!x) {
|
||||
*b++ = '0';
|
||||
*b = 0;
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
s = s0 = dtoa(x, 2, precision, &decpt, &sign, &se);
|
||||
if (sign)
|
||||
*b++ = '-';
|
||||
if (decpt == 9999) /* Infinity or Nan */ {
|
||||
while((*b++ = *s++));
|
||||
/* "b" is used to calculate the return length. Decrement to exclude the
|
||||
* Null terminator from the length */
|
||||
b--;
|
||||
goto done0;
|
||||
}
|
||||
if (decpt <= -4 || decpt > precision) {
|
||||
*b++ = *s++;
|
||||
if (*s) {
|
||||
*b++ = '.';
|
||||
while((*b = *s++))
|
||||
b++;
|
||||
}
|
||||
*b++ = 'e';
|
||||
/* sprintf(b, "%+.2d", decpt - 1); */
|
||||
if (--decpt < 0) {
|
||||
*b++ = '-';
|
||||
decpt = -decpt;
|
||||
}
|
||||
else
|
||||
*b++ = '+';
|
||||
for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10);
|
||||
for(;;) {
|
||||
i = decpt / k;
|
||||
*b++ = i + '0';
|
||||
if (--j <= 0)
|
||||
break;
|
||||
decpt -= i*k;
|
||||
decpt *= 10;
|
||||
}
|
||||
*b = 0;
|
||||
}
|
||||
else if (decpt <= 0) {
|
||||
*b++ = '0';
|
||||
*b++ = '.';
|
||||
for(; decpt < 0; decpt++)
|
||||
*b++ = '0';
|
||||
while((*b++ = *s++));
|
||||
b--;
|
||||
}
|
||||
else {
|
||||
while((*b = *s++)) {
|
||||
b++;
|
||||
if (--decpt == 0 && *s)
|
||||
*b++ = '.';
|
||||
}
|
||||
for(; decpt > 0; decpt--)
|
||||
*b++ = '0';
|
||||
*b = 0;
|
||||
}
|
||||
done0:
|
||||
freedtoa(s0);
|
||||
#ifdef IGNORE_ZERO_SIGN
|
||||
done:
|
||||
#endif
|
||||
return b - b0;
|
||||
}
|
312
external/json/lua/cjson/util.lua
vendored
Normal file
312
external/json/lua/cjson/util.lua
vendored
Normal file
|
@ -0,0 +1,312 @@
|
|||
local json = require "cjson"
|
||||
|
||||
local unpack = unpack or table.unpack
|
||||
|
||||
local maxn = table.maxn or function(t)
|
||||
local max = 0
|
||||
for k,v in pairs(t) do
|
||||
if type(k) == "number" and k > max then
|
||||
max = k
|
||||
end
|
||||
end
|
||||
return max
|
||||
end
|
||||
|
||||
local _one_of_mt = {}
|
||||
|
||||
local function one_of(t)
|
||||
setmetatable(t, _one_of_mt)
|
||||
return t
|
||||
end
|
||||
|
||||
local function is_one_of(t)
|
||||
return type(t) == "table" and getmetatable(t) == _one_of_mt
|
||||
end
|
||||
|
||||
-- Various common routines used by the Lua CJSON package
|
||||
--
|
||||
-- Mark Pulford <mark@kyne.com.au>
|
||||
|
||||
-- Determine with a Lua table can be treated as an array.
|
||||
-- Explicitly returns "not an array" for very sparse arrays.
|
||||
-- Returns:
|
||||
-- -1 Not an array
|
||||
-- 0 Empty table
|
||||
-- >0 Highest index in the array
|
||||
local function is_array(table)
|
||||
local max = 0
|
||||
local count = 0
|
||||
for k, v in pairs(table) do
|
||||
if type(k) == "number" then
|
||||
if k > max then max = k end
|
||||
count = count + 1
|
||||
else
|
||||
return -1
|
||||
end
|
||||
end
|
||||
if max > count * 2 then
|
||||
return -1
|
||||
end
|
||||
|
||||
return max
|
||||
end
|
||||
|
||||
local serialise_value
|
||||
|
||||
local function serialise_table(value, indent, depth)
|
||||
local spacing, spacing2, indent2
|
||||
if indent then
|
||||
spacing = "\n" .. indent
|
||||
spacing2 = spacing .. " "
|
||||
indent2 = indent .. " "
|
||||
else
|
||||
spacing, spacing2, indent2 = " ", " ", false
|
||||
end
|
||||
depth = depth + 1
|
||||
if depth > 50 then
|
||||
return "Cannot serialise any further: too many nested tables"
|
||||
end
|
||||
|
||||
local max = is_array(value)
|
||||
|
||||
local comma = false
|
||||
local prefix = "{"
|
||||
if is_one_of(value) then
|
||||
prefix = "ONE_OF{"
|
||||
end
|
||||
local fragment = { prefix .. spacing2 }
|
||||
if max > 0 then
|
||||
-- Serialise array
|
||||
for i = 1, max do
|
||||
if comma then
|
||||
table.insert(fragment, "," .. spacing2)
|
||||
end
|
||||
table.insert(fragment, serialise_value(value[i], indent2, depth))
|
||||
comma = true
|
||||
end
|
||||
elseif max < 0 then
|
||||
-- Serialise table
|
||||
for k, v in pairs(value) do
|
||||
if comma then
|
||||
table.insert(fragment, "," .. spacing2)
|
||||
end
|
||||
table.insert(fragment,
|
||||
("[%s] = %s"):format(serialise_value(k, indent2, depth),
|
||||
serialise_value(v, indent2, depth)))
|
||||
comma = true
|
||||
end
|
||||
end
|
||||
table.insert(fragment, spacing .. "}")
|
||||
|
||||
return table.concat(fragment)
|
||||
end
|
||||
|
||||
function serialise_value(value, indent, depth)
|
||||
if indent == nil then indent = "" end
|
||||
if depth == nil then depth = 0 end
|
||||
|
||||
if value == json.null then
|
||||
return "json.null"
|
||||
elseif type(value) == "string" then
|
||||
return ("%q"):format(value)
|
||||
elseif type(value) == "nil" or type(value) == "number" or
|
||||
type(value) == "boolean" then
|
||||
return tostring(value)
|
||||
elseif type(value) == "table" then
|
||||
return serialise_table(value, indent, depth)
|
||||
else
|
||||
return "\"<" .. type(value) .. ">\""
|
||||
end
|
||||
end
|
||||
|
||||
local function file_load(filename)
|
||||
local file
|
||||
if filename == nil then
|
||||
file = io.stdin
|
||||
else
|
||||
local err
|
||||
file, err = io.open(filename, "rb")
|
||||
if file == nil then
|
||||
error(("Unable to read '%s': %s"):format(filename, err))
|
||||
end
|
||||
end
|
||||
local data = file:read("*a")
|
||||
|
||||
if filename ~= nil then
|
||||
file:close()
|
||||
end
|
||||
|
||||
if data == nil then
|
||||
error("Failed to read " .. filename)
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
local function file_save(filename, data)
|
||||
local file
|
||||
if filename == nil then
|
||||
file = io.stdout
|
||||
else
|
||||
local err
|
||||
file, err = io.open(filename, "wb")
|
||||
if file == nil then
|
||||
error(("Unable to write '%s': %s"):format(filename, err))
|
||||
end
|
||||
end
|
||||
file:write(data)
|
||||
if filename ~= nil then
|
||||
file:close()
|
||||
end
|
||||
end
|
||||
|
||||
local function compare_values(val1, val2)
|
||||
if is_one_of(val2) then
|
||||
for _, option in ipairs(val2) do
|
||||
if compare_values(val1, option) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local type1 = type(val1)
|
||||
local type2 = type(val2)
|
||||
if type1 ~= type2 then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check for NaN
|
||||
if type1 == "number" and val1 ~= val1 and val2 ~= val2 then
|
||||
return true
|
||||
end
|
||||
|
||||
if type1 ~= "table" then
|
||||
return val1 == val2
|
||||
end
|
||||
|
||||
-- check_keys stores all the keys that must be checked in val2
|
||||
local check_keys = {}
|
||||
for k, _ in pairs(val1) do
|
||||
check_keys[k] = true
|
||||
end
|
||||
|
||||
for k, v in pairs(val2) do
|
||||
if not check_keys[k] then
|
||||
return false
|
||||
end
|
||||
|
||||
if not compare_values(val1[k], val2[k]) then
|
||||
return false
|
||||
end
|
||||
|
||||
check_keys[k] = nil
|
||||
end
|
||||
for k, _ in pairs(check_keys) do
|
||||
-- Not the same if any keys from val1 were not found in val2
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local test_count_pass = 0
|
||||
local test_count_total = 0
|
||||
|
||||
local function run_test_summary()
|
||||
return test_count_pass, test_count_total
|
||||
end
|
||||
|
||||
local function run_test(testname, func, input, should_work, output)
|
||||
local function status_line(name, status, value)
|
||||
local statusmap = { [true] = ":success", [false] = ":error" }
|
||||
if status ~= nil then
|
||||
name = name .. statusmap[status]
|
||||
end
|
||||
print(("[%s] %s"):format(name, serialise_value(value, false)))
|
||||
end
|
||||
|
||||
local result = {}
|
||||
local tmp = { pcall(func, unpack(input)) }
|
||||
local success = tmp[1]
|
||||
for i = 2, maxn(tmp) do
|
||||
result[i - 1] = tmp[i]
|
||||
end
|
||||
|
||||
local correct = false
|
||||
if success == should_work and compare_values(result, output) then
|
||||
correct = true
|
||||
test_count_pass = test_count_pass + 1
|
||||
end
|
||||
test_count_total = test_count_total + 1
|
||||
|
||||
local teststatus = { [true] = "PASS", [false] = "FAIL" }
|
||||
print(("==> Test [%d] %s: %s"):format(test_count_total, testname,
|
||||
teststatus[correct]))
|
||||
|
||||
status_line("Input", nil, input)
|
||||
if not correct then
|
||||
status_line("Expected", should_work, output)
|
||||
end
|
||||
status_line("Received", success, result)
|
||||
print()
|
||||
|
||||
return correct, result
|
||||
end
|
||||
|
||||
local function run_test_group(tests)
|
||||
local function run_helper(name, func, input)
|
||||
if type(name) == "string" and #name > 0 then
|
||||
print("==> " .. name)
|
||||
end
|
||||
-- Not a protected call, these functions should never generate errors.
|
||||
func(unpack(input or {}))
|
||||
print()
|
||||
end
|
||||
|
||||
for _, v in ipairs(tests) do
|
||||
-- Run the helper if "should_work" is missing
|
||||
if v[4] == nil then
|
||||
run_helper(unpack(v))
|
||||
else
|
||||
run_test(unpack(v))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Run a Lua script in a separate environment
|
||||
local function run_script(script, env)
|
||||
local env = env or {}
|
||||
local func
|
||||
|
||||
-- Use setfenv() if it exists, otherwise assume Lua 5.2 load() exists
|
||||
if _G.setfenv then
|
||||
func = loadstring(script)
|
||||
if func then
|
||||
setfenv(func, env)
|
||||
end
|
||||
else
|
||||
func = load(script, nil, nil, env)
|
||||
end
|
||||
|
||||
if func == nil then
|
||||
error("Invalid syntax.")
|
||||
end
|
||||
func()
|
||||
|
||||
return env
|
||||
end
|
||||
|
||||
-- Export functions
|
||||
return {
|
||||
serialise_value = serialise_value,
|
||||
file_load = file_load,
|
||||
file_save = file_save,
|
||||
compare_values = compare_values,
|
||||
run_test_summary = run_test_summary,
|
||||
run_test = run_test,
|
||||
run_test_group = run_test_group,
|
||||
run_script = run_script,
|
||||
one_of = one_of
|
||||
}
|
||||
|
||||
-- vi:ai et sw=4 ts=4:
|
14
external/json/lua/json2lua.lua
vendored
Executable file
14
external/json/lua/json2lua.lua
vendored
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env lua
|
||||
|
||||
-- usage: json2lua.lua [json_file]
|
||||
--
|
||||
-- Eg:
|
||||
-- echo '[ "testing" ]' | ./json2lua.lua
|
||||
-- ./json2lua.lua test.json
|
||||
|
||||
local json = require "cjson"
|
||||
local util = require "cjson.util"
|
||||
|
||||
local json_text = util.file_load(arg[1])
|
||||
local t = json.decode(json_text)
|
||||
print(util.serialise_value(t))
|
20
external/json/lua/lua2json.lua
vendored
Executable file
20
external/json/lua/lua2json.lua
vendored
Executable file
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env lua
|
||||
|
||||
-- usage: lua2json.lua [lua_file]
|
||||
--
|
||||
-- Eg:
|
||||
-- echo '{ "testing" }' | ./lua2json.lua
|
||||
-- ./lua2json.lua test.lua
|
||||
|
||||
local json = require "cjson"
|
||||
local util = require "cjson.util"
|
||||
|
||||
local env = {
|
||||
json = { null = json.null },
|
||||
null = json.null
|
||||
}
|
||||
|
||||
local t = util.run_script("data = " .. util.file_load(arg[1]), env)
|
||||
print(json.encode(t.data))
|
||||
|
||||
-- vi:ai et sw=4 ts=4:
|
1710
external/json/lua_cjson.c
vendored
Normal file
1710
external/json/lua_cjson.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
251
external/json/strbuf.c
vendored
Normal file
251
external/json/strbuf.c
vendored
Normal file
|
@ -0,0 +1,251 @@
|
|||
/* strbuf - String buffer routines
|
||||
*
|
||||
* Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "strbuf.h"
|
||||
|
||||
static void die(const char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
vfprintf(stderr, fmt, arg);
|
||||
va_end(arg);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
void strbuf_init(strbuf_t *s, int len)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (len <= 0)
|
||||
size = STRBUF_DEFAULT_SIZE;
|
||||
else
|
||||
size = len + 1; /* \0 terminator */
|
||||
|
||||
s->buf = NULL;
|
||||
s->size = size;
|
||||
s->length = 0;
|
||||
s->increment = STRBUF_DEFAULT_INCREMENT;
|
||||
s->dynamic = 0;
|
||||
s->reallocs = 0;
|
||||
s->debug = 0;
|
||||
|
||||
s->buf = malloc(size);
|
||||
if (!s->buf)
|
||||
die("Out of memory");
|
||||
|
||||
strbuf_ensure_null(s);
|
||||
}
|
||||
|
||||
strbuf_t *strbuf_new(int len)
|
||||
{
|
||||
strbuf_t *s;
|
||||
|
||||
s = malloc(sizeof(strbuf_t));
|
||||
if (!s)
|
||||
die("Out of memory");
|
||||
|
||||
strbuf_init(s, len);
|
||||
|
||||
/* Dynamic strbuf allocation / deallocation */
|
||||
s->dynamic = 1;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void strbuf_set_increment(strbuf_t *s, int increment)
|
||||
{
|
||||
/* Increment > 0: Linear buffer growth rate
|
||||
* Increment < -1: Exponential buffer growth rate */
|
||||
if (increment == 0 || increment == -1)
|
||||
die("BUG: Invalid string increment");
|
||||
|
||||
s->increment = increment;
|
||||
}
|
||||
|
||||
static inline void debug_stats(strbuf_t *s)
|
||||
{
|
||||
if (s->debug) {
|
||||
fprintf(stderr, "strbuf(%lx) reallocs: %d, length: %d, size: %d\n",
|
||||
(long)s, s->reallocs, s->length, s->size);
|
||||
}
|
||||
}
|
||||
|
||||
/* If strbuf_t has not been dynamically allocated, strbuf_free() can
|
||||
* be called any number of times strbuf_init() */
|
||||
void strbuf_free(strbuf_t *s)
|
||||
{
|
||||
debug_stats(s);
|
||||
|
||||
if (s->buf) {
|
||||
free(s->buf);
|
||||
s->buf = NULL;
|
||||
}
|
||||
if (s->dynamic)
|
||||
free(s);
|
||||
}
|
||||
|
||||
char *strbuf_free_to_string(strbuf_t *s, int *len)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
debug_stats(s);
|
||||
|
||||
strbuf_ensure_null(s);
|
||||
|
||||
buf = s->buf;
|
||||
if (len)
|
||||
*len = s->length;
|
||||
|
||||
if (s->dynamic)
|
||||
free(s);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int calculate_new_size(strbuf_t *s, int len)
|
||||
{
|
||||
int reqsize, newsize;
|
||||
|
||||
if (len <= 0)
|
||||
die("BUG: Invalid strbuf length requested");
|
||||
|
||||
/* Ensure there is room for optional NULL termination */
|
||||
reqsize = len + 1;
|
||||
|
||||
/* If the user has requested to shrink the buffer, do it exactly */
|
||||
if (s->size > reqsize)
|
||||
return reqsize;
|
||||
|
||||
newsize = s->size;
|
||||
if (s->increment < 0) {
|
||||
/* Exponential sizing */
|
||||
while (newsize < reqsize)
|
||||
newsize *= -s->increment;
|
||||
} else if (s->increment != 0) {
|
||||
/* Linear sizing */
|
||||
newsize = ((newsize + s->increment - 1) / s->increment) * s->increment;
|
||||
}
|
||||
|
||||
return newsize;
|
||||
}
|
||||
|
||||
|
||||
/* Ensure strbuf can handle a string length bytes long (ignoring NULL
|
||||
* optional termination). */
|
||||
void strbuf_resize(strbuf_t *s, int len)
|
||||
{
|
||||
int newsize;
|
||||
|
||||
newsize = calculate_new_size(s, len);
|
||||
|
||||
if (s->debug > 1) {
|
||||
fprintf(stderr, "strbuf(%lx) resize: %d => %d\n",
|
||||
(long)s, s->size, newsize);
|
||||
}
|
||||
|
||||
s->size = newsize;
|
||||
s->buf = realloc(s->buf, s->size);
|
||||
if (!s->buf)
|
||||
die("Out of memory");
|
||||
s->reallocs++;
|
||||
}
|
||||
|
||||
void strbuf_append_string(strbuf_t *s, const char *str)
|
||||
{
|
||||
int space, i;
|
||||
|
||||
space = strbuf_empty_length(s);
|
||||
|
||||
for (i = 0; str[i]; i++) {
|
||||
if (space < 1) {
|
||||
strbuf_resize(s, s->length + 1);
|
||||
space = strbuf_empty_length(s);
|
||||
}
|
||||
|
||||
s->buf[s->length] = str[i];
|
||||
s->length++;
|
||||
space--;
|
||||
}
|
||||
}
|
||||
|
||||
/* strbuf_append_fmt() should only be used when an upper bound
|
||||
* is known for the output string. */
|
||||
void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
int fmt_len;
|
||||
|
||||
strbuf_ensure_empty_length(s, len);
|
||||
|
||||
va_start(arg, fmt);
|
||||
fmt_len = vsnprintf(s->buf + s->length, len, fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (fmt_len < 0)
|
||||
die("BUG: Unable to convert number"); /* This should never happen.. */
|
||||
|
||||
s->length += fmt_len;
|
||||
}
|
||||
|
||||
/* strbuf_append_fmt_retry() can be used when the there is no known
|
||||
* upper bound for the output string. */
|
||||
void strbuf_append_fmt_retry(strbuf_t *s, const char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
int fmt_len, try;
|
||||
int empty_len;
|
||||
|
||||
/* If the first attempt to append fails, resize the buffer appropriately
|
||||
* and try again */
|
||||
for (try = 0; ; try++) {
|
||||
va_start(arg, fmt);
|
||||
/* Append the new formatted string */
|
||||
/* fmt_len is the length of the string required, excluding the
|
||||
* trailing NULL */
|
||||
empty_len = strbuf_empty_length(s);
|
||||
/* Add 1 since there is also space to store the terminating NULL. */
|
||||
fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (fmt_len <= empty_len)
|
||||
break; /* SUCCESS */
|
||||
if (try > 0)
|
||||
die("BUG: length of formatted string changed");
|
||||
|
||||
strbuf_resize(s, s->length + fmt_len);
|
||||
}
|
||||
|
||||
s->length += fmt_len;
|
||||
}
|
||||
|
||||
/* vi:ai et sw=4 ts=4:
|
||||
*/
|
165
external/json/strbuf.h
vendored
Normal file
165
external/json/strbuf.h
vendored
Normal file
|
@ -0,0 +1,165 @@
|
|||
/* strbuf - String buffer routines
|
||||
*
|
||||
* Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Workaround for MSVC */
|
||||
#ifdef _MSC_VER
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
/* Size: Total bytes allocated to *buf
|
||||
* Length: String length, excluding optional NULL terminator.
|
||||
* Increment: Allocation increments when resizing the string buffer.
|
||||
* Dynamic: True if created via strbuf_new()
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char *buf;
|
||||
int size;
|
||||
int length;
|
||||
int increment;
|
||||
int dynamic;
|
||||
int reallocs;
|
||||
int debug;
|
||||
} strbuf_t;
|
||||
|
||||
#ifndef STRBUF_DEFAULT_SIZE
|
||||
#define STRBUF_DEFAULT_SIZE 1023
|
||||
#endif
|
||||
#ifndef STRBUF_DEFAULT_INCREMENT
|
||||
#define STRBUF_DEFAULT_INCREMENT -2
|
||||
#endif
|
||||
|
||||
/* Initialise */
|
||||
extern strbuf_t *strbuf_new(int len);
|
||||
extern void strbuf_init(strbuf_t *s, int len);
|
||||
extern void strbuf_set_increment(strbuf_t *s, int increment);
|
||||
|
||||
/* Release */
|
||||
extern void strbuf_free(strbuf_t *s);
|
||||
extern char *strbuf_free_to_string(strbuf_t *s, int *len);
|
||||
|
||||
/* Management */
|
||||
extern void strbuf_resize(strbuf_t *s, int len);
|
||||
static int strbuf_empty_length(strbuf_t *s);
|
||||
static int strbuf_length(strbuf_t *s);
|
||||
static char *strbuf_string(strbuf_t *s, int *len);
|
||||
static void strbuf_ensure_empty_length(strbuf_t *s, int len);
|
||||
static char *strbuf_empty_ptr(strbuf_t *s);
|
||||
static void strbuf_extend_length(strbuf_t *s, int len);
|
||||
static void strbuf_set_length(strbuf_t *s, int len);
|
||||
|
||||
/* Update */
|
||||
extern void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...);
|
||||
extern void strbuf_append_fmt_retry(strbuf_t *s, const char *format, ...);
|
||||
static void strbuf_append_mem(strbuf_t *s, const char *c, int len);
|
||||
extern void strbuf_append_string(strbuf_t *s, const char *str);
|
||||
static void strbuf_append_char(strbuf_t *s, const char c);
|
||||
static void strbuf_ensure_null(strbuf_t *s);
|
||||
|
||||
/* Reset string for before use */
|
||||
static inline void strbuf_reset(strbuf_t *s)
|
||||
{
|
||||
s->length = 0;
|
||||
}
|
||||
|
||||
static inline int strbuf_allocated(strbuf_t *s)
|
||||
{
|
||||
return s->buf != NULL;
|
||||
}
|
||||
|
||||
/* Return bytes remaining in the string buffer
|
||||
* Ensure there is space for a NULL terminator. */
|
||||
static inline int strbuf_empty_length(strbuf_t *s)
|
||||
{
|
||||
return s->size - s->length - 1;
|
||||
}
|
||||
|
||||
static inline void strbuf_ensure_empty_length(strbuf_t *s, int len)
|
||||
{
|
||||
if (len > strbuf_empty_length(s))
|
||||
strbuf_resize(s, s->length + len);
|
||||
}
|
||||
|
||||
static inline char *strbuf_empty_ptr(strbuf_t *s)
|
||||
{
|
||||
return s->buf + s->length;
|
||||
}
|
||||
|
||||
static inline void strbuf_set_length(strbuf_t *s, int len)
|
||||
{
|
||||
s->length = len;
|
||||
}
|
||||
|
||||
static inline void strbuf_extend_length(strbuf_t *s, int len)
|
||||
{
|
||||
s->length += len;
|
||||
}
|
||||
|
||||
static inline int strbuf_length(strbuf_t *s)
|
||||
{
|
||||
return s->length;
|
||||
}
|
||||
|
||||
static inline void strbuf_append_char(strbuf_t *s, const char c)
|
||||
{
|
||||
strbuf_ensure_empty_length(s, 1);
|
||||
s->buf[s->length++] = c;
|
||||
}
|
||||
|
||||
static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c)
|
||||
{
|
||||
s->buf[s->length++] = c;
|
||||
}
|
||||
|
||||
static inline void strbuf_append_mem(strbuf_t *s, const char *c, int len)
|
||||
{
|
||||
strbuf_ensure_empty_length(s, len);
|
||||
memcpy(s->buf + s->length, c, len);
|
||||
s->length += len;
|
||||
}
|
||||
|
||||
static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len)
|
||||
{
|
||||
memcpy(s->buf + s->length, c, len);
|
||||
s->length += len;
|
||||
}
|
||||
|
||||
static inline void strbuf_ensure_null(strbuf_t *s)
|
||||
{
|
||||
s->buf[s->length] = 0;
|
||||
}
|
||||
|
||||
static inline char *strbuf_string(strbuf_t *s, int *len)
|
||||
{
|
||||
if (len)
|
||||
*len = s->length;
|
||||
|
||||
return s->buf;
|
||||
}
|
||||
|
||||
/* vi:ai et sw=4 ts=4:
|
||||
*/
|
Loading…
Add table
Add a link
Reference in a new issue