aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKahrl <kahrl@gmx.net>2013-09-02 02:01:49 +0200
committerKahrl <kahrl@gmx.net>2013-09-02 02:20:08 +0200
commit1ecf51a13f434f5cbc0f6ccc1b9a2ac6402a895f (patch)
treee8ac8ced0ed73bd9a4a803dc703a213e3a9b91ec
parent71a6ffa76203a13b6cb0ec88b7ee57e04f809148 (diff)
downloadminetest-1ecf51a13f434f5cbc0f6ccc1b9a2ac6402a895f.tar.gz
minetest-1ecf51a13f434f5cbc0f6ccc1b9a2ac6402a895f.tar.bz2
minetest-1ecf51a13f434f5cbc0f6ccc1b9a2ac6402a895f.zip
Add minetest.parse_json, engine.parse_json
-rw-r--r--doc/lua_api.txt6
-rw-r--r--doc/menu_lua_api.txt2
-rw-r--r--src/script/common/c_content.cpp82
-rw-r--r--src/script/common/c_content.h6
-rw-r--r--src/script/lua_api/l_util.cpp42
-rw-r--r--src/script/lua_api/l_util.h3
6 files changed, 141 insertions, 0 deletions
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index bd465bbed..21cbcb822 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -1458,6 +1458,12 @@ minetest.get_content_id(name) -> integer
^ Gets the internal content ID of name
minetest.get_name_from_content_id(content_id) -> string
^ Gets the name of the content with that content ID
+minetest.parse_json(string[, nullvalue]) -> something
+^ Convert a string containing JSON data into the Lua equivalent
+^ nullvalue: returned in place of the JSON null; defaults to nil
+^ On success returns a table, a string, a number, a boolean or nullvalue
+^ On failure outputs an error message and returns nil
+^ Example: parse_json("[10, {\"a\":false}]") -> {[1] = 10, [2] = {a = false}}
minetest.serialize(table) -> string
^ Convert a table containing tables, strings, numbers, booleans and nils
into string form readable by minetest.deserialize
diff --git a/doc/menu_lua_api.txt b/doc/menu_lua_api.txt
index 014e689dc..d4bc093b0 100644
--- a/doc/menu_lua_api.txt
+++ b/doc/menu_lua_api.txt
@@ -174,6 +174,8 @@ engine.gettext(string) -> string
fgettext(string, ...) -> string
^ call engine.gettext(string), replace "$1"..."$9" with the given
^ extra arguments, call engine.formspec_escape and return the result
+engine.parse_json(string[, nullvalue]) -> something
+^ see minetest.parse_json (lua_api.txt)
dump(obj, dumped={})
^ Return object serialized as a string
string:split(separator)
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index 2e26adb76..3a3a70860 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tool.h"
#include "serverobject.h"
#include "mapgen.h"
+#include "json/json.h"
struct EnumString es_TileAnimationType[] =
{
@@ -998,3 +999,84 @@ bool read_schematic(lua_State *L, int index, DecoSchematic *dschem, Server *serv
return true;
}
+
+/******************************************************************************/
+// Returns depth of json value tree
+static int push_json_value_getdepth(const Json::Value &value)
+{
+ if (!value.isArray() && !value.isObject())
+ return 1;
+
+ int maxdepth = 0;
+ for (Json::Value::const_iterator it = value.begin();
+ it != value.end(); ++it) {
+ int elemdepth = push_json_value_getdepth(*it);
+ if (elemdepth > maxdepth)
+ maxdepth = elemdepth;
+ }
+ return maxdepth + 1;
+}
+// Recursive function to convert JSON --> Lua table
+static bool push_json_value_helper(lua_State *L, const Json::Value &value,
+ int nullindex)
+{
+ switch(value.type()) {
+ case Json::nullValue:
+ default:
+ lua_pushvalue(L, nullindex);
+ break;
+ case Json::intValue:
+ lua_pushinteger(L, value.asInt());
+ break;
+ case Json::uintValue:
+ lua_pushinteger(L, value.asUInt());
+ break;
+ case Json::realValue:
+ lua_pushnumber(L, value.asDouble());
+ break;
+ case Json::stringValue:
+ {
+ const char *str = value.asCString();
+ lua_pushstring(L, str ? str : "");
+ }
+ break;
+ case Json::booleanValue:
+ lua_pushboolean(L, value.asInt());
+ break;
+ case Json::arrayValue:
+ lua_newtable(L);
+ for (Json::Value::const_iterator it = value.begin();
+ it != value.end(); ++it) {
+ push_json_value_helper(L, *it, nullindex);
+ lua_rawseti(L, -2, it.index() + 1);
+ }
+ break;
+ case Json::objectValue:
+ lua_newtable(L);
+ for (Json::Value::const_iterator it = value.begin();
+ it != value.end(); ++it) {
+ const char *str = it.memberName();
+ lua_pushstring(L, str ? str : "");
+ push_json_value_helper(L, *it, nullindex);
+ lua_rawset(L, -3);
+ }
+ break;
+ }
+ return true;
+}
+// converts JSON --> Lua table; returns false if lua stack limit exceeded
+// nullindex: Lua stack index of value to use in place of JSON null
+bool push_json_value(lua_State *L, const Json::Value &value, int nullindex)
+{
+ if(nullindex < 0)
+ nullindex = lua_gettop(L) + 1 + nullindex;
+
+ int depth = push_json_value_getdepth(value);
+
+ // The maximum number of Lua stack slots used at each recursion level
+ // of push_json_value_helper is 2, so make sure there a depth * 2 slots
+ if (lua_checkstack(L, depth * 2))
+ return push_json_value_helper(L, value, nullindex);
+ else
+ return false;
+}
diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h
index 6d1dfe1d5..27019e29e 100644
--- a/src/script/common/c_content.h
+++ b/src/script/common/c_content.h
@@ -39,6 +39,8 @@ extern "C" {
#include "irrlichttypes_bloated.h"
#include "util/string.h"
+namespace Json { class Value; }
+
struct MapNode;
class INodeDefManager;
struct PointedThing;
@@ -145,6 +147,10 @@ bool read_schematic (lua_State *L, int index,
void luaentity_get (lua_State *L,u16 id);
+bool push_json_value (lua_State *L,
+ const Json::Value &value,
+ int nullindex);
+
extern struct EnumString es_TileAnimationType[];
#endif /* C_CONTENT_H_ */
diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp
index 0e4de9eee..30fa56c42 100644
--- a/src/script/lua_api/l_util.cpp
+++ b/src/script/lua_api/l_util.cpp
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tool.h"
#include "settings.h"
#include "main.h" //required for g_settings, g_settings_path
+#include "json/json.h"
// debug(...)
// Writes a line to dstream
@@ -138,6 +139,45 @@ int ModApiUtil::l_setting_save(lua_State *L)
return 0;
}
+// parse_json(str[, nullvalue])
+int ModApiUtil::l_parse_json(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ const char *jsonstr = luaL_checkstring(L, 1);
+
+ // Use passed nullvalue or default to nil
+ int nullindex = 2;
+ if (lua_isnone(L, nullindex)) {
+ lua_pushnil(L);
+ nullindex = lua_gettop(L);
+ }
+
+ Json::Value root;
+
+ {
+ Json::Reader reader;
+ std::istringstream stream(jsonstr);
+
+ if (!reader.parse(stream, root)) {
+ errorstream << "Failed to parse json data "
+ << reader.getFormattedErrorMessages();
+ errorstream << "data: \"" << jsonstr << "\""
+ << std::endl;
+ lua_pushnil(L);
+ return 1;
+ }
+ }
+
+ if (!push_json_value(L, root, nullindex)) {
+ errorstream << "Failed to parse json data, "
+ << "depth exceeds lua stack limit" << std::endl;
+ errorstream << "data: \"" << jsonstr << "\"" << std::endl;
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
// get_dig_params(groups, tool_capabilities[, time_from_last_punch])
int ModApiUtil::l_get_dig_params(lua_State *L)
{
@@ -191,6 +231,8 @@ void ModApiUtil::Initialize(lua_State *L, int top)
API_FCT(setting_getbool);
API_FCT(setting_save);
+ API_FCT(parse_json);
+
API_FCT(get_dig_params);
API_FCT(get_hit_params);
diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h
index b102e315b..71c55b342 100644
--- a/src/script/lua_api/l_util.h
+++ b/src/script/lua_api/l_util.h
@@ -59,6 +59,9 @@ private:
// setting_save()
static int l_setting_save(lua_State *L);
+ // parse_json(str[, nullvalue])
+ static int l_parse_json(lua_State *L);
+
// get_dig_params(groups, tool_capabilities[, time_from_last_punch])
static int l_get_dig_params(lua_State *L);