lua-jsonc: new package

This package replaces luci-lib-jsonc, and also provides utility functions
for use from other C libraries.
This commit is contained in:
Matthias Schiffer 2018-01-18 12:33:16 +01:00
parent 309dacfa31
commit d14cedea14
No known key found for this signature in database
GPG Key ID: 16EF3F64CB201D9C
4 changed files with 284 additions and 0 deletions

28
libs/lua-jsonc/Makefile Normal file
View File

@ -0,0 +1,28 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=lua-jsonc
PKG_VERSION:=1
CMAKE_INSTALL:=1
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Package/lua-jsonc
SECTION:=libs
CATEGORY:=Libraries
TITLE:=JSON parsing and formatting library
DEPENDS:=+liblua +libjson-c
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Package/lua-jsonc/install
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_INSTALL_DIR)/usr/lib/* $(1)/usr/lib/
endef
$(eval $(call BuildPackage,lua-jsonc))

View File

@ -0,0 +1,16 @@
cmake_minimum_required(VERSION 3.0)
project(lua-jsonc C)
add_library(lua-jsonc SHARED lua-jsonc.c)
set_property(TARGET lua-jsonc PROPERTY COMPILE_FLAGS "-Wall -std=c99")
target_link_libraries(lua-jsonc json-c lua)
install(TARGETS lua-jsonc
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/lua-jsonc.h DESTINATION include)
install(DIRECTORY DESTINATION lib/lua)
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ../liblua-jsonc.so \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/lib/lua/jsonc.so)")

View File

@ -0,0 +1,230 @@
/*
Copyright 2015 Jo-Philipp Wich <jow@openwrt.org>
Copyright 2018 Matthias Schiffer <mschiffer@universe-factory.net>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "lua-jsonc.h"
#include <limits.h>
#include <lualib.h>
#include <lauxlib.h>
void lua_jsonc_push_json(lua_State *L, struct json_object *obj) {
int64_t i;
switch (json_object_get_type(obj)) {
case json_type_object:
lua_newtable(L);
json_object_object_foreach(obj, key, val) {
lua_jsonc_push_json(L, val);
lua_setfield(L, -2, key);
}
break;
case json_type_array:
lua_newtable(L);
for (size_t n = 0; n < json_object_array_length(obj); n++) {
lua_jsonc_push_json(L, json_object_array_get_idx(obj, n));
lua_rawseti(L, -2, n + 1);
}
break;
case json_type_boolean:
lua_pushboolean(L, json_object_get_boolean(obj));
break;
case json_type_int:
i = json_object_get_int64(obj);
if (i == (int64_t)(lua_Integer)i)
lua_pushinteger(L, i);
else
lua_pushnumber(L, i);
break;
case json_type_double:
lua_pushnumber(L, json_object_get_double(obj));
break;
case json_type_string:
lua_pushstring(L, json_object_get_string(obj));
break;
case json_type_null:
lua_pushnil(L);
break;
}
}
static int lua_jsonc_lua_test_array(lua_State *L, int index) {
int max = 0;
lua_pushnil(L);
/* check for non-integer keys */
while (lua_next(L, index)) {
if (lua_type(L, -2) != LUA_TNUMBER)
goto out;
lua_Number idx = lua_tonumber(L, -2);
if (idx != (lua_Number)(lua_Integer)idx)
goto out;
/* We only allow INT_MAX-1 keys to avoid overflows */
if (idx <= 0 || idx >= INT_MAX)
goto out;
if (idx > max)
max = idx;
lua_pop(L, 1);
}
/* check for holes */
for (int i = 1; i <= max; i++) {
lua_rawgeti(L, index, i);
int isnil = lua_isnil(L, -1);
lua_pop(L, 1);
if (isnil)
return -1;
}
return max;
out:
lua_pop(L, 2);
return -1;
}
struct json_object * lua_jsonc_tojson(lua_State *L, int index) {
lua_Number nd, ni;
struct json_object *obj;
const char *key;
int i, max;
switch (lua_type(L, index)) {
case LUA_TTABLE:
max = lua_jsonc_lua_test_array(L, index);
if (max >= 0) {
obj = json_object_new_array();
if (!obj)
return NULL;
for (i = 1; i <= max; i++) {
lua_rawgeti(L, index, i);
json_object_array_put_idx(
obj, i - 1, lua_jsonc_tojson(L, lua_gettop(L))
);
lua_pop(L, 1);
}
return obj;
}
obj = json_object_new_object();
if (!obj)
return NULL;
lua_pushnil(L);
while (lua_next(L, index)) {
lua_pushvalue(L, -2);
key = lua_tostring(L, -1);
if (key)
json_object_object_add(
obj, key, lua_jsonc_tojson(L, lua_gettop(L) - 1)
);
lua_pop(L, 2);
}
return obj;
case LUA_TNIL:
return NULL;
case LUA_TBOOLEAN:
return json_object_new_boolean(lua_toboolean(L, index));
case LUA_TNUMBER:
nd = lua_tonumber(L, index);
ni = lua_tointeger(L, index);
if (nd == ni)
return json_object_new_int(nd);
return json_object_new_double(nd);
case LUA_TSTRING:
return json_object_new_string(lua_tostring(L, index));
}
return NULL;
}
static int lua_jsonc_load(lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
struct json_object *obj = json_object_from_file(filename);
lua_jsonc_push_json(L, obj);
json_object_put(obj);
return 1;
}
static int lua_jsonc_parse(lua_State *L) {
const char *input = luaL_checkstring(L, 1);
struct json_object *obj = json_tokener_parse(input);
lua_jsonc_push_json(L, obj);
json_object_put(obj);
return 1;
}
static int lua_jsonc_stringify(lua_State *L) {
struct json_object *obj = lua_jsonc_tojson(L, 1);
int pretty = lua_toboolean(L, 2);
int flags = 0;
if (pretty)
flags |= JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED;
lua_pushstring(L, json_object_to_json_string_ext(obj, flags));
json_object_put(obj);
return 1;
}
static const luaL_reg R[] = {
{ "load", lua_jsonc_load },
{ "parse", lua_jsonc_parse },
{ "stringify", lua_jsonc_stringify },
{}
};
int luaopen_jsonc(lua_State *L) {
luaL_register(L, "jsonc", R);
return 1;
}

View File

@ -0,0 +1,10 @@
#ifndef LUA_JSONC_H_
#define LUA_JSONC_H_
#include <json-c/json.h>
#include <lua.h>
void lua_jsonc_push_json(lua_State *L, struct json_object *obj);
struct json_object * lua_jsonc_tojson(lua_State *L, int index);
#endif /* LUA_JSONC_H_ */