Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ notes
packages
tags
tests/utf8.dat
_build
.vscode
111 changes: 87 additions & 24 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,68 @@
# Unix: export LUA_DIR=/home/user/pkg
# Windows: set LUA_DIR=c:\lua51

cmake_minimum_required(VERSION 3.14)
project(lua-cjson C)
cmake_minimum_required(VERSION 2.6)

option(USE_INTERNAL_FPCONV "Use internal strtod() / g_fmt() code for performance")
option(MULTIPLE_THREADS "Support multi-threaded apps with internal fpconv - recommended" ON)
option(USE_LUAU "Use Luau instead of standard Lua" OFF)
option(COMPILE_LUAU_TEST "Use Luau instead of standard Lua" OFF)

if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
FORCE)
endif()

find_package(Lua51 REQUIRED)
include_directories(${LUA_INCLUDE_DIR})
#add_compile_options(-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer)

#add_compile_options(-fsanitize=address)
#add_link_options(-fsanitize=address)

if(USE_LUAU)
add_library(cjson)
else()
add_library(cjson MODULE)
endif()

if(USE_LUAU)
include(FetchContent)
FetchContent_Declare(
luau
GIT_REPOSITORY https://github.com/luau-lang/luau.git
GIT_TAG origin/master
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
PATCH_COMMAND git apply ${CMAKE_CURRENT_SOURCE_DIR}/luau_extern_fix.patch
UPDATE_DISCONNECTED 1
)
set(LUAU_BUILD_CLI OFF CACHE BOOL "Build CLI" FORCE)
set(LUAU_BUILD_TESTS OFF CACHE BOOL "Build tests" FORCE)
set(LUAU_BUILD_WEB OFF CACHE BOOL "Build Web module" FORCE)
set(LUAU_WERROR OFF CACHE BOOL "Warnings as errors" FORCE)
set(LUAU_STATIC_CRT OFF CACHE BOOL "Link with the static CRT (/MT)" FORCE)
set(LUAU_EXTERN_C ON CACHE BOOL "Use extern C for all APIs" FORCE)
FetchContent_MakeAvailable(luau)
target_include_directories(cjson PRIVATE ${luau_SOURCE_DIR}/VM/include)
target_compile_definitions(cjson PUBLIC LUAU=1)
else ()
find_package(Lua51 REQUIRED)
target_include_directories(cjson PRIVATE ${LUA_INCLUDE_DIR})
endif()

if(NOT USE_INTERNAL_FPCONV)
# Use libc number conversion routines (strtod(), sprintf())
set(FPCONV_SOURCES fpconv.c)
target_sources(cjson PRIVATE fpconv.c)
else()
# Use internal number conversion routines
add_definitions(-DUSE_INTERNAL_FPCONV)
set(FPCONV_SOURCES g_fmt.c dtoa.c)
target_compile_definitions(cjson PRIVATE USE_INTERNAL_FPCONV)
target_sources(cjson PRIVATE g_fmt.c dtoa.c)

include(TestBigEndian)
TEST_BIG_ENDIAN(IEEE_BIG_ENDIAN)
if(IEEE_BIG_ENDIAN)
add_definitions(-DIEEE_BIG_ENDIAN)
target_compile_definitions(cjson PRIVATE IEEE_BIG_ENDIAN)
endif()

if(MULTIPLE_THREADS)
Expand All @@ -39,45 +74,73 @@ else()
message(FATAL_ERROR
"Pthreads not found - required by MULTIPLE_THREADS option")
endif()
add_definitions(-DMULTIPLE_THREADS)
target_compile_definitions(cjson PRIVATE MULTIPLE_THREADS)
target_link_libraries(cjson PRIVATE Threads::Threads)
endif()
endif()

# Handle platforms missing isinf() macro (Eg, some Solaris systems).
include(CheckSymbolExists)
CHECK_SYMBOL_EXISTS(isinf math.h HAVE_ISINF)
if(NOT HAVE_ISINF)
add_definitions(-DUSE_INTERNAL_ISINF)
target_compile_definitions(cjson PRIVATE USE_INTERNAL_ISINF)
endif()

set(_MODULE_LINK "${CMAKE_THREAD_LIBS_INIT}")
get_filename_component(_lua_lib_dir ${LUA_LIBRARY} PATH)
if(USE_LUAU)
target_link_libraries(cjson PRIVATE Luau.VM)
target_compile_definitions(cjson PRIVATE ENABLE_CJSON_GLOBAL)
else()
if(WIN32)
# Win32 modules need to be linked to the Lua library.
target_link_libraries(cjson PRIVATE ${LUA_LIBRARIES})
endif()
endif()

if(APPLE)
set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS
"${CMAKE_SHARED_MODULE_CREATE_C_FLAGS} -undefined dynamic_lookup")
endif()

if(WIN32)
# Win32 modules need to be linked to the Lua library.
set(_MODULE_LINK ${LUA_LIBRARY} ${_MODULE_LINK})
set(_lua_module_dir "${_lua_lib_dir}")
# Windows sprintf()/strtod() handle NaN/inf differently. Not supported.
add_definitions(-DDISABLE_INVALID_NUMBERS)
else()
set(_lua_module_dir "${_lua_lib_dir}/lua/5.1")
target_compile_definitions(cjson PRIVATE DISABLE_INVALID_NUMBERS)
endif()

if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-Dinline=__inline)
add_definitions(-Dsnprintf=_snprintf)
add_definitions(-Dstrncasecmp=_strnicmp)
target_compile_definitions(cjson PRIVATE _CRT_SECURE_NO_WARNINGS)
target_compile_definitions(cjson PRIVATE inline=__inline)
target_compile_definitions(cjson PRIVATE snprintf=_snprintf)
target_compile_definitions(cjson PRIVATE strncasecmp=_strnicmp)
endif()

add_library(cjson MODULE lua_cjson.c strbuf.c ${FPCONV_SOURCES})
target_sources(cjson PRIVATE lua_cjson.c strbuf.c)
set_target_properties(cjson PROPERTIES PREFIX "")
target_link_libraries(cjson ${_MODULE_LINK})
install(TARGETS cjson DESTINATION "${_lua_module_dir}")
if(NOT USE_LUAU)
get_filename_component(_lua_lib_dir ${LUA_LIBRARY} PATH)
if(WIN32)
set(_lua_module_dir "${_lua_lib_dir}")
else()
set(_lua_module_dir "${_lua_lib_dir}/lua/5.1")
endif()
install(TARGETS cjson DESTINATION "${_lua_module_dir}")
endif()

if(COMPILE_LUAU_TEST)
if(NOT USE_LUAU)
message(FATAL_ERROR "Can not compile Luau test if Luau is not used")
endif()
enable_language(CXX)
add_executable(luau_test tests/luau_test.cpp)
target_link_libraries(luau_test PRIVATE
Luau.Compiler
Luau.VM
cjson
)
target_include_directories(luau_test PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${luau_SOURCE_DIR}/VM/include
${luau_SOURCE_DIR}/Compiler/include
)
endif()

# vi:ai et sw=4 ts=4:
97 changes: 82 additions & 15 deletions lua_cjson.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,17 @@
* difficult to know object/array sizes ahead of time.
*/

#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <math.h>
#include <limits.h>
#include <lua.h>
#ifdef LUAU
#include "lualib.h"
#else
#include <lauxlib.h>
#endif

#include "strbuf.h"
#include "fpconv.h"
Expand All @@ -50,6 +55,10 @@
#define CJSON_MODNAME "cjson"
#endif

#ifndef CJSON_SAFE_MODNAME
#define CJSON_SAFE_MODNAME "cjson_safe"
#endif

#ifndef CJSON_VERSION
#define CJSON_VERSION "2.1devel"
#endif
Expand Down Expand Up @@ -362,31 +371,29 @@ static int json_cfg_decode_invalid_numbers(lua_State *l)
return 1;
}

static void json_config_destructor(void* p)
{
json_config_t *cfg;
cfg = (json_config_t *)p;
if (cfg && cfg->encode_keep_buffer)
strbuf_free(&cfg->encode_buf);
}

static int json_destroy_config(lua_State *l)
{
json_config_t *cfg;

cfg = (json_config_t *)lua_touserdata(l, 1);
if (cfg)
strbuf_free(&cfg->encode_buf);
json_config_destructor(cfg);
cfg = NULL;

return 0;
}

static void json_create_config(lua_State *l)
static void json_config_init(json_config_t *cfg)
{
json_config_t *cfg;
int i;

cfg = (json_config_t *)lua_newuserdata(l, sizeof(*cfg));

/* Create GC method to clean up strbuf */
lua_newtable(l);
lua_pushcfunction(l, json_destroy_config);
lua_setfield(l, -2, "__gc");
lua_setmetatable(l, -2);


cfg->encode_sparse_convert = DEFAULT_SPARSE_CONVERT;
cfg->encode_sparse_ratio = DEFAULT_SPARSE_RATIO;
cfg->encode_sparse_safe = DEFAULT_SPARSE_SAFE;
Expand Down Expand Up @@ -447,6 +454,38 @@ static void json_create_config(lua_State *l)
cfg->escape2char['u'] = 'u'; /* Unicode parsing required */
}

static int json_reset_config(lua_State *l)
{
json_config_t *cfg = json_arg_init(l, 0);

if (cfg){
if (cfg->encode_keep_buffer)
strbuf_free(&cfg->encode_buf);
json_config_init(cfg);
}

return 0;
}

static void json_create_config(lua_State *l)
{
json_config_t *cfg;

#ifdef LUAU
cfg = (json_config_t *)lua_newuserdatadtor(l, sizeof(*cfg), json_config_destructor);
#else
cfg = (json_config_t *)lua_newuserdata(l, sizeof(*cfg));

/* Create GC method to clean up strbuf */
lua_newtable(l);
lua_pushcfunction(l, json_destroy_config);
lua_setfield(l, -2, "__gc");
lua_setmetatable(l, -2);
#endif

json_config_init(cfg);
}

/* ===== ENCODING ===== */

static void json_encode_exception(lua_State *l, json_config_t *cfg, strbuf_t *json, int lindex,
Expand Down Expand Up @@ -1140,8 +1179,8 @@ static void json_decode_descend(lua_State *l, json_parse_t *json, int slots)
}

strbuf_free(json->tmp);
luaL_error(l, "Found too many nested data structures (%d) at character %d",
json->current_depth, json->ptr - json->data);
luaL_error(l, "Found too many nested data structures (%d) at character %lld",
json->current_depth, (long long int)(json->ptr - json->data));
}

static void json_parse_object_context(lua_State *l, json_parse_t *json)
Expand Down Expand Up @@ -1317,7 +1356,11 @@ static void luaL_setfuncs (lua_State *l, const luaL_Reg *reg, int nup)
for (; reg->name != NULL; reg++) { /* fill the table with given functions */
for (i = 0; i < nup; i++) /* copy upvalues to the top */
lua_pushvalue(l, -nup);
#ifdef LUAU
lua_pushcclosure(l, reg->func, reg->name, nup);
#else
lua_pushcclosure(l, reg->func, nup); /* closure with those upvalues */
#endif
lua_setfield(l, -(nup + 2), reg->name);
}
lua_pop(l, nup); /* remove upvalues */
Expand Down Expand Up @@ -1349,7 +1392,12 @@ static int json_protect_conversion(lua_State *l)

/* Since we are not using a custom error handler, the only remaining
* errors are memory related */
#ifdef LUAU
luaL_error(l, "Memory allocation error in CJSON protected call"); /* never returns */
return 0;
#else
return luaL_error(l, "Memory allocation error in CJSON protected call");
#endif
}

/* Return cjson module table */
Expand All @@ -1365,7 +1413,10 @@ static int lua_cjson_new(lua_State *l)
{ "encode_keep_buffer", json_cfg_encode_keep_buffer },
{ "encode_invalid_numbers", json_cfg_encode_invalid_numbers },
{ "decode_invalid_numbers", json_cfg_decode_invalid_numbers },
#ifndef ENABLE_CJSON_GLOBAL
{ "new", lua_cjson_new },
#endif
{ "reset", json_reset_config},
{ NULL, NULL }
};

Expand Down Expand Up @@ -1400,13 +1451,23 @@ static int lua_cjson_safe_new(lua_State *l)

lua_cjson_new(l);

#ifndef ENABLE_CJSON_GLOBAL
/* Fix new() method */
#ifdef LUAU
lua_pushcfunction(l, lua_cjson_safe_new, "lua_cjson_safe_new");
#else
lua_pushcfunction(l, lua_cjson_safe_new);
#endif
lua_setfield(l, -2, "new");
#endif

for (i = 0; func[i]; i++) {
lua_getfield(l, -1, func[i]);
#ifdef LUAU
lua_pushcclosure(l, json_protect_conversion, func[i], 1);
#else
lua_pushcclosure(l, json_protect_conversion, 1);
#endif
lua_setfield(l, -2, func[i]);
}

Expand All @@ -1431,6 +1492,12 @@ CJSON_EXPORT int luaopen_cjson_safe(lua_State *l)
{
lua_cjson_safe_new(l);

#ifdef ENABLE_CJSON_GLOBAL
/* Register a global "cjson_safe" table. */
lua_pushvalue(l, -1);
lua_setglobal(l, CJSON_SAFE_MODNAME);
#endif

/* Return cjson.safe table */
return 1;
}
Expand Down
13 changes: 13 additions & 0 deletions luau_cjson.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef LUA_CJSON_H
#define LUA_CJSON_H

/* Only use this header when using Luau */
#ifdef LUAU

#include "lua.h"

LUA_API int luaopen_cjson(lua_State *l);
LUA_API int luaopen_cjson_safe(lua_State *l);

#endif /* LUAU */
#endif /* LUA_CJSON_H */
Loading