[grilo-plugins] lua-factory: Lua libraries for sources
- From: Juan A. Suarez Romero <jasuarez src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [grilo-plugins] lua-factory: Lua libraries for sources
- Date: Mon, 24 Feb 2014 23:35:18 +0000 (UTC)
commit 20c60d158d8d41b9137f97dba259442e6f2a19a2
Author: Victor Toso <me victortoso com>
Date: Thu Oct 31 22:59:30 2013 -0200
lua-factory: Lua libraries for sources
Include libraries for lua sources to use.
Core library:
- grl.callback: operation to return the content for user application;
- grl.fetch: A fetch operation that uses GrlNet to fetch web content;
- grl.get_options: Get options provided by application;
- grl.get_requested_keys: List of all requested keys;
- grl.get_media_keys: Current values of media, mainly for resolve op;
Json library:
- grl.json.string_to_table: parser using json-glib that gets a json
object as string and return its equivalent in a table;
https://bugzilla.gnome.org/show_bug.cgi?id=711243
configure.ac | 10 +-
src/lua-factory/Makefile.am | 1 +
src/lua-factory/grl-lua-library.c | 523 +++++++++++++++++++++++++++
src/lua-factory/grl-lua-library.h | 1 +
src/lua-factory/lua-library/lua-json.c | 168 +++++++++
src/lua-factory/lua-library/lua-libraries.h | 36 ++
6 files changed, 737 insertions(+), 2 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index abced34..73710e8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -842,6 +842,12 @@ AC_ARG_ENABLE(lua_factory,
if test "x$HAVE_LUA" = "xno"; then
AC_MSG_ERROR([lua not found, install it or use --disable-lua-factory])
fi
+ if test "x$HAVE_GRLNET" = "xno"; then
+ AC_MSG_ERROR([grilo-net not found, install it or use --disable-lua-factory])
+ fi
+ if test "x$HAVE_JSON_GLIB" = "xno"; then
+ AC_MSG_ERROR([json-glib-1.0 not found, install it or use --disable-lua-factory])
+ fi
;;
esac
],
@@ -864,9 +870,9 @@ LUA_FACTORY_PLUGIN_ID="grl-lua-factory"
AC_SUBST(LUA_FACTORY_PLUGIN_ID)
AC_DEFINE_UNQUOTED([LUA_FACTORY_PLUGIN_ID], ["$LUA_FACTORY_PLUGIN_ID"], [Lua Factory plugin ID])
-DEPS_LUA_FACTORY_CFLAGS="$DEPS_CFLAGS $LUA_CFLAGS"
+DEPS_LUA_FACTORY_CFLAGS="$DEPS_CFLAGS $LUA_CFLAGS $GRLNET_CFLAGS $JSON_CFLAGS"
AC_SUBST(DEPS_LUA_FACTORY_CFLAGS)
-DEPS_LUA_FACTORY_LIBS="$DEPS_LIBS $LUA_LIBS"
+DEPS_LUA_FACTORY_LIBS="$DEPS_LIBS $LUA_LIBS $GRLNET_LIBS $JSON_LIBS"
AC_SUBST(DEPS_LUA_FACTORY_LIBS)
LUA_FACTORY_SOURCE_LOCATION="grilo-plugins/${LUA_FACTORY_PLUGIN_ID}"
diff --git a/src/lua-factory/Makefile.am b/src/lua-factory/Makefile.am
index 0af5360..b4edeb0 100644
--- a/src/lua-factory/Makefile.am
+++ b/src/lua-factory/Makefile.am
@@ -26,6 +26,7 @@ libgrlluafactory_la_SOURCES = \
grl-lua-library.c \
grl-lua-library.h \
grl-lua-common.h \
+ lua-library/lua-json.c \
lua-library/lua-libraries.h
extdir = $(GRL_PLUGINS_DIR)
diff --git a/src/lua-factory/grl-lua-library.c b/src/lua-factory/grl-lua-library.c
index 4b6c3ed..f15f3d5 100644
--- a/src/lua-factory/grl-lua-library.c
+++ b/src/lua-factory/grl-lua-library.c
@@ -25,16 +25,529 @@
#include "grl-lua-common.h"
#include "grl-lua-library.h"
+#include "lua-library/lua-libraries.h"
#define GRL_LOG_DOMAIN_DEFAULT lua_library_log_domain
GRL_LOG_DOMAIN_STATIC (lua_library_log_domain);
+typedef struct _FetchOperation {
+ lua_State *L;
+ gchar *lua_cb;
+} FetchOperation;
+
+/* ================== Lua-Library utils/helpers ============================ */
+
+/* Top of the stack must be a table */
+static void
+grl_util_add_table_to_media (lua_State *L,
+ GrlMedia *media,
+ GrlKeyID key_id,
+ const gchar *key_name,
+ GType type)
+{
+ gint i = 0;
+ gint array_len = luaL_len (L, -1);
+
+ /* Remove all current values of this key, if any */
+ while (grl_data_length (GRL_DATA (media), key_id) > 0) {
+ grl_data_remove (GRL_DATA (media), key_id);
+ }
+
+ /* Insert new values */
+ for (i = 0; i < array_len; i++) {
+ lua_pushinteger (L, i + 1);
+ lua_gettable (L, -2);
+ switch (type) {
+ case G_TYPE_INT:
+ if (lua_isnumber (L, -1))
+ grl_data_add_int (GRL_DATA (media), key_id, lua_tointeger (L, -1));
+ break;
+
+ case G_TYPE_FLOAT:
+ if (lua_isnumber (L, -1))
+ grl_data_add_float (GRL_DATA (media), key_id, lua_tointeger (L, -1));
+ break;
+
+ case G_TYPE_STRING:
+ if (lua_isstring (L, -1))
+ grl_data_add_string (GRL_DATA (media), key_id, lua_tostring (L, -1));
+ break;
+
+ default:
+ GRL_DEBUG ("'%s' is being ignored when value is a table object",
+ key_name);
+ }
+ lua_pop (L, 1);
+ }
+}
+
+static GrlMedia *
+grl_util_build_media (lua_State *L,
+ GrlMedia *user_media)
+{
+ GrlRegistry *registry = NULL;
+ GrlMedia *media = user_media;
+
+ if (!lua_istable (L, 1)) {
+ if (!lua_isnil (L, 1))
+ GRL_DEBUG ("Media in wrong format (neither nil or table).");
+
+ return NULL;
+ }
+
+ if (media == NULL) {
+ lua_getfield (L, 1, "type");
+ if (lua_isstring (L, -1)) {
+ const gchar *media_type = lua_tostring (L, -1);
+
+ if (g_strcmp0 (media_type, "box") == 0)
+ media = grl_media_box_new ();
+ else if (g_strcmp0 (media_type, "image") == 0)
+ media = grl_media_image_new ();
+ else if (g_strcmp0 (media_type, "audio") == 0)
+ media = grl_media_audio_new ();
+ else if (g_strcmp0 (media_type, "video") == 0)
+ media = grl_media_video_new ();
+ }
+ media = (media == NULL) ? grl_media_new () : media;
+ lua_pop (L, 1);
+ }
+
+ registry = grl_registry_get_default ();
+ lua_pushnil (L);
+ while (lua_next (L, 1) != 0) {
+ GrlKeyID key_id = GRL_METADATA_KEY_INVALID;
+ gchar *key_name = g_strdup (lua_tostring (L, -2));
+ gchar *ptr = NULL;
+ GType type = G_TYPE_NONE;
+
+ /* Replace '_' to '-': convenient for the developer */
+ while ((ptr = strstr (key_name, "_")) != NULL) {
+ *ptr = '-';
+ }
+
+ key_id = grl_registry_lookup_metadata_key (registry, key_name);
+ if (key_id != GRL_METADATA_KEY_INVALID) {
+ type = grl_registry_lookup_metadata_key_type (registry, key_id);
+
+ switch (type) {
+ case G_TYPE_INT:
+ if (lua_isnumber (L, -1)) {
+ grl_data_set_int (GRL_DATA (media), key_id, lua_tointeger (L, -1));
+ } else if (lua_istable (L, -1)) {
+ grl_util_add_table_to_media (L, media, key_id, key_name, type);
+ } else {
+ GRL_WARNING ("'%s' is not compatible for '%s'",
+ lua_typename (L, -1), key_name);
+ }
+ break;
+
+ case G_TYPE_FLOAT:
+ if (lua_isnumber (L, -1)) {
+ grl_data_set_float (GRL_DATA (media), key_id, lua_tonumber (L, -1));
+ } else if (lua_istable (L, -1)) {
+ grl_util_add_table_to_media (L, media, key_id, key_name, type);
+ } else {
+ GRL_WARNING ("'%s' is not compatible for '%s'",
+ lua_typename (L, -1), key_name);
+ }
+ break;
+
+ case G_TYPE_STRING:
+ if (lua_isstring (L, -1)) {
+ grl_data_set_string (GRL_DATA (media), key_id, lua_tostring (L, -1));
+ } else if (lua_istable (L, -1)) {
+ grl_util_add_table_to_media (L, media, key_id, key_name, type);
+ } else {
+ GRL_WARNING ("'%s' is not compatible for '%s'",
+ lua_typename (L, -1), key_name);
+ }
+ break;
+
+ default:
+ if (type == G_TYPE_DATE_TIME) {
+ GDateTime *date = grl_date_time_from_iso8601 (lua_tostring (L, -1));
+ grl_data_set_boxed (GRL_DATA (media), key_id, date);
+ g_date_time_unref (date);
+ } else if (type == G_TYPE_BYTE_ARRAY) {
+ gsize size = luaL_len (L, -1);
+ const guint8 *binary = lua_tostring (L, -1);
+ grl_data_set_binary (GRL_DATA (media), key_id, binary, size);
+ } else {
+ GRL_DEBUG ("'%s' is being ignored as G_TYPE is not being handled.",
+ key_name);
+ }
+ }
+ }
+
+ g_free (key_name);
+ lua_pop (L, 1);
+ }
+ return media;
+}
+
+static void
+grl_util_fetch_done (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ gchar *data = NULL;
+ gsize length = 0;
+ GError *err = NULL;
+ FetchOperation *fo = (FetchOperation *) user_data;
+ lua_State *L = fo->L;
+
+ GRL_DEBUG ("fetch_done");
+
+ grl_net_wc_request_finish (GRL_NET_WC (source_object),
+ res, &data, &length, &err);
+
+ lua_getglobal (L, fo->lua_cb);
+ lua_pushlstring (L, data, length);
+
+ if (lua_pcall (L, 1, 0, 0)) {
+ GRL_WARNING ("%s (%s) '%s'", "calling source callback function fail",
+ fo->lua_cb, lua_tolstring (L, -1, NULL));
+ }
+ g_free (fo);
+}
+
+/* ================== Lua-Library methods ================================== */
+
+/**
+* grl.get_options
+*
+* @option: (string) Name of the option you want (e.g. count, flags).
+* @key: (string) Name of the key when option request it.
+* @return: The option or nil if none;
+*/
+static gint
+grl_l_operation_get_options (lua_State *L)
+{
+ OperationSpec *os = NULL;
+ const gchar *option = NULL;
+
+ luaL_argcheck (L, lua_isstring (L, 1), 1, "expecting option (string)");
+
+ os = grl_lua_library_load_operation_data (L);
+ option = lua_tostring (L, 1);
+
+ if (g_strcmp0 (option, "count") == 0) {
+ gint count = grl_operation_options_get_count (os->options);
+
+ lua_pushnumber (L, count);
+ return 1;
+ }
+
+ if (g_strcmp0 (option, "skip") == 0) {
+ guint skip = grl_operation_options_get_skip (os->options);
+
+ lua_pushnumber (L, skip);
+ return 1;
+ }
+
+ if (g_strcmp0 (option, "flags") == 0) {
+ GrlResolutionFlags flags = grl_operation_options_get_flags (os->options);
+
+ lua_pushnumber (L, (gint) flags);
+ return 1;
+ }
+
+ if (g_strcmp0 (option, "key-filter") == 0) {
+ GrlKeyID key;
+ GValue *value = NULL;
+ const gchar *key_name = NULL;
+ GrlRegistry *registry = grl_registry_get_default ();
+
+ luaL_argcheck (L, lua_isstring (L, 2), 2, "expecting key name");
+ key_name = lua_tostring (L, 2);
+
+ key = grl_registry_lookup_metadata_key (registry, key_name);
+ value = grl_operation_options_get_key_filter (os->options, key);
+ switch (grl_registry_lookup_metadata_key_type (registry, key)) {
+ case G_TYPE_INT:
+ (value) ? lua_pushnumber (L, g_value_get_int (value)) : lua_pushnil (L);
+ break;
+
+ case G_TYPE_FLOAT:
+ (value) ? lua_pushnumber (L, g_value_get_float (value)) : lua_pushnil (L);
+ break;
+
+ case G_TYPE_STRING:
+ (value) ? lua_pushstring (L, g_value_get_string (value)) : lua_pushnil (L);
+ break;
+
+ default:
+ GRL_DEBUG ("'%s' is being ignored as G_TYPE is not being handled.",
+ key_name);
+ }
+ return 1;
+ }
+
+ if (g_strcmp0 (option, "range-filter") == 0) {
+ GValue *min = NULL;
+ GValue *max = NULL;
+ GrlKeyID key;
+ const gchar *key_name = NULL;
+ GrlRegistry *registry = grl_registry_get_default ();
+
+ luaL_argcheck (L, lua_isstring (L, 3), 3, "expecting key name");
+ key_name = lua_tostring (L, 3);
+
+ key = grl_registry_lookup_metadata_key (registry, key_name);
+ if (key != GRL_METADATA_KEY_INVALID) {
+ grl_operation_options_get_key_range_filter (os->options, key, &min, &max);
+ switch (grl_registry_lookup_metadata_key_type (registry, key)) {
+ case G_TYPE_INT:
+ (min) ? lua_pushnumber (L, g_value_get_int (min)) : lua_pushnil (L);
+ (max) ? lua_pushnumber (L, g_value_get_int (max)) : lua_pushnil (L);
+ break;
+
+ case G_TYPE_FLOAT:
+ (min) ? lua_pushnumber (L, g_value_get_float (min)) : lua_pushnil (L);
+ (max) ? lua_pushnumber (L, g_value_get_float (max)) : lua_pushnil (L);
+ break;
+
+ case G_TYPE_STRING:
+ (min) ? lua_pushstring (L, g_value_get_string (min)) : lua_pushnil (L);
+ (max) ? lua_pushstring (L, g_value_get_string (max)) : lua_pushnil (L);
+ break;
+
+ default:
+ GRL_DEBUG ("'%s' is being ignored as G_TYPE is not being handled.",
+ key_name);
+ }
+ }
+ return 2;
+ }
+
+ luaL_error (L, "'%s' is not available nor implemented.", option);
+ return 0;
+}
+
+/**
+* grl.get_media_keys
+*
+* @return: array of all requested keys from application (may be empty);
+*/
+static gint
+grl_l_operation_get_keys (lua_State *L)
+{
+ OperationSpec *os = NULL;
+ GrlRegistry *registry = NULL;
+ GList *it = NULL;
+ GrlKeyID key_id;
+ const gchar *key_name = NULL;
+ gint i = 0;
+
+ os = grl_lua_library_load_operation_data (L);
+
+ registry = grl_registry_get_default ();
+ lua_newtable (L);
+ for (it = os->keys; it; it = g_list_next (it)) {
+ key_id = GRLPOINTER_TO_KEYID (it->data);
+ key_name = grl_registry_lookup_metadata_key_name (registry, key_id);
+ if (key_id != GRL_METADATA_KEY_INVALID) {
+ lua_pushinteger (L, i + 1);
+ lua_pushstring (L, key_name);
+ lua_settable (L, -3);
+ i = i + 1;
+ }
+ }
+ return 1;
+}
+
+/**
+* grl.get_media_keys
+*
+* @return: table with all keys/values of media (may be empty);
+*/
+static gint
+grl_l_media_get_keys (lua_State *L)
+{
+ OperationSpec *os = NULL;
+ GrlRegistry *registry = NULL;
+ GList *it = NULL;
+ GList *list_keys = NULL;
+ GrlKeyID key_id;
+ gchar *key_name = NULL;
+
+ os = grl_lua_library_load_operation_data (L);
+
+ registry = grl_registry_get_default ();
+ lua_newtable (L);
+ list_keys = grl_data_get_keys (GRL_DATA (os->media));
+ for (it = list_keys; it; it = g_list_next (it)) {
+ gchar *ptr = NULL;
+ GType type = G_TYPE_NONE;
+ key_id = GRLPOINTER_TO_KEYID (it->data);
+ key_name = g_strdup (grl_registry_lookup_metadata_key_name (registry,
+ key_id));
+ key_id = grl_registry_lookup_metadata_key (registry, key_name);
+
+ /* Replace '-' to '_': as a convenience for the developer */
+ while ((ptr = strstr (key_name, "-")) != NULL) {
+ *ptr = '_';
+ }
+
+ lua_pushstring (L, key_name);
+ g_free (key_name);
+ if (key_id != GRL_METADATA_KEY_INVALID) {
+ type = grl_registry_lookup_metadata_key_type (registry, key_id);
+ switch (type) {
+ case G_TYPE_INT:
+ lua_pushnumber (L, grl_data_get_int (GRL_DATA (os->media), key_id));
+ break;
+ case G_TYPE_FLOAT:
+ lua_pushnumber (L, grl_data_get_float (GRL_DATA (os->media), key_id));
+ break;
+ case G_TYPE_STRING:
+ lua_pushstring (L, grl_data_get_string (GRL_DATA (os->media), key_id));
+ break;
+ default:
+ if (type == G_TYPE_DATE_TIME) {
+ GDateTime *date = grl_data_get_boxed (GRL_DATA (os->media), key_id);
+ gchar *date_str = g_date_time_format (date, "%F %T");
+ lua_pushstring (L, date_str);
+ g_free(date_str);
+
+ } else {
+ GRL_DEBUG ("'%s' is being ignored as G_TYPE is not being handled.",
+ key_name);
+ lua_pop (L, 1);
+ continue;
+ }
+ }
+ lua_settable (L, -3);
+ }
+ }
+ g_list_free (list_keys);
+ return 1;
+}
+
+/**
+* grl.fetch
+*
+* @url: (string) The http url to GET the content.
+* @callback: (string) The function to be called after fetch is complete.
+* @return: Nothing.;
+*/
+static gint
+grl_l_fetch (lua_State *L)
+{
+ const gchar *url = NULL;
+ const gchar *lua_callback = NULL;
+ GrlNetWc *wc = NULL;
+ FetchOperation *fo = g_malloc (sizeof (FetchOperation));
+
+ luaL_argcheck (L, lua_isstring (L, 1), 1, "expecting url as string");
+ luaL_argcheck (L, lua_isstring (L, 2), 2,
+ "expecting callback function as string");
+
+ url = lua_tolstring (L, 1, NULL);
+ lua_callback = lua_tolstring (L, 2, NULL);
+
+ GRL_DEBUG ("grl.fetch() -> '%s'", url);
+
+ wc = grl_net_wc_new ();
+ if (lua_istable (L, 3)) {
+ /* Set GrlNetWc options */
+ lua_pushnil (L);
+ while (lua_next (L, 3) != 0) {
+ const gchar *key = lua_tostring (L, -2);
+ if (g_strcmp0 (key, "user-agent") == 0 ||
+ g_strcmp0 (key, "user_agent") == 0) {
+ const gchar *user_agent = lua_tostring (L, -1);
+ g_object_set (wc, "user-agent", user_agent, NULL);
+
+ } else if (g_strcmp0 (key, "cache-size") == 0 ||
+ g_strcmp0 (key, "cache_size") == 0) {
+ guint size = lua_tonumber (L, -1);
+ grl_net_wc_set_cache_size (wc, size);
+
+ } else if (g_strcmp0 (key, "cache") == 0) {
+ gboolean use_cache = lua_toboolean (L, -1);
+ grl_net_wc_set_cache (wc, use_cache);
+
+ } else if (g_strcmp0 (key, "throttling") == 0) {
+ guint throttling = lua_tonumber (L, -1);
+ grl_net_wc_set_throttling (wc, throttling);
+
+ } else if (g_strcmp0 (key, "loglevel") == 0) {
+ guint level = lua_tonumber (L, -1);
+ grl_net_wc_set_log_level (wc, level);
+
+ } else {
+ GRL_DEBUG ("GrlNetWc property not know: '%s'", key);
+ }
+ lua_pop (L, 1);
+ }
+ }
+
+ fo->L = L;
+ fo->lua_cb = g_strdup (lua_callback);
+
+ grl_net_wc_request_async (wc, url, NULL, grl_util_fetch_done, fo);
+ g_object_unref (wc);
+ return 1;
+}
+
+/**
+* grl.callback
+*
+* @media: (table) The media content to be returned.
+* @count: (number) Number of media remaining to the application.
+* @return: Nothing;
+*/
+static gint
+grl_l_callback (lua_State *L)
+{
+ gint nparam = 0;
+ gint count = 0;
+ OperationSpec *os = NULL;
+ GrlMedia *media = NULL;
+
+ GRL_DEBUG ("grl.callback()");
+
+ nparam = lua_gettop (L);
+ os = grl_lua_library_load_operation_data (L);
+ if (nparam > 0) {
+ media = (os->op_type == LUA_RESOLVE) ? os->media : NULL;
+ media = grl_util_build_media (L, media);
+ count = (lua_isnumber (L, 2)) ? lua_tonumber (L, 2) : 0;
+ }
+
+ switch (os->op_type) {
+ case LUA_RESOLVE:
+ os->cb.resolve (os->source, os->operation_id, media, os->user_data, NULL);
+ break;
+
+ default:
+ os->cb.result (os->source, os->operation_id, media,
+ count, os->user_data, NULL);
+ }
+
+ /* Free Operation Spec */
+ if (count == 0) {
+ g_list_free (os->keys);
+ g_object_unref (os->options);
+ g_slice_free (OperationSpec, os);
+ }
+
+ return 0;
+}
+
/* ================== Lua-Library initialization =========================== */
gint
luaopen_grilo (lua_State *L)
{
static const luaL_Reg library_fn[] = {
+ {"get_options", &grl_l_operation_get_options},
+ {"get_requested_keys", &grl_l_operation_get_keys},
+ {"get_media_keys", &grl_l_media_get_keys},
+ {"callback", &grl_l_callback},
+ {"fetch", &grl_l_fetch},
{NULL, NULL}
};
@@ -43,6 +556,16 @@ luaopen_grilo (lua_State *L)
GRL_DEBUG ("Loading grilo lua-library");
luaL_newlib (L, library_fn);
+ /* The following modules are restrict to Lua sources */
+ lua_pushstring (L, LUA_MODULES_NAME);
+ lua_newtable (L);
+
+ lua_pushstring (L, GRILO_LUA_LIBRARY_JSON);
+ luaopen_json (L);
+ lua_settable (L, -3);
+
+ /* Those modules are called in 'lua' table, inside 'grl' */
+ lua_settable (L, -3);
return 1;
}
diff --git a/src/lua-factory/grl-lua-library.h b/src/lua-factory/grl-lua-library.h
index 13e3ab1..b678f58 100644
--- a/src/lua-factory/grl-lua-library.h
+++ b/src/lua-factory/grl-lua-library.h
@@ -30,6 +30,7 @@
#define _GRL_LUA_LIBRARY_H_
#define GRILO_LUA_LIBRARY_NAME "grl"
+#define LUA_MODULES_NAME "lua"
#define LUA_ENV_TABLE "_G"
diff --git a/src/lua-factory/lua-library/lua-json.c b/src/lua-factory/lua-library/lua-json.c
new file mode 100644
index 0000000..c3f0640
--- /dev/null
+++ b/src/lua-factory/lua-library/lua-json.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2013 Victor Toso.
+ *
+ * Contact: Victor Toso <me victortoso com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "lua-libraries.h"
+
+#include <json-glib/json-glib.h>
+#include <glib-object.h>
+
+/* ================== Lua-Library Json Handlers ============================ */
+
+/* Save key/values on the table in the stack if the value is an
+ * object or an array, it calls recursively the function again.
+ *
+ * @param L, pointer to the L with nil on top of it;
+ * @param reader, pointed to the first element of main object;
+ *
+ * returns: the table in the stack with all json values
+ */
+static void
+build_table_from_json_reader (lua_State *L,
+ JsonReader *reader)
+{
+ const GError *err = json_reader_get_error (reader);
+ if (err != NULL) {
+ GRL_WARNING ("Error when building json: %s", err->message);
+ return;
+ }
+
+ if (lua_isnil (L, -1)) {
+ /* In the first execution of this recursive call, the main json object
+ * does not have a member name. The nil is in the top of the stack and
+ * it shall be converted to the table with json content */
+ lua_pop (L, 1);
+
+ } else if (lua_istable (L, -1)) {
+ const gchar *member_name = json_reader_get_member_name (reader);
+ if (member_name)
+ lua_pushstring (L, member_name);
+
+ } else if (!lua_isnumber (L, -1)) {
+ GRL_DEBUG ("getting value to either table or array");
+ return;
+ }
+
+ if (json_reader_is_object (reader)) {
+ guint index_member = 0;
+ guint num_members = json_reader_count_members (reader);
+
+ lua_createtable (L, num_members, 0);
+ for (index_member = 0; index_member < num_members; index_member++) {
+ json_reader_read_element (reader, index_member);
+ build_table_from_json_reader (L, reader);
+ json_reader_end_element (reader);
+ }
+
+ } else if (json_reader_is_array (reader)) {
+ guint index_element = 0;
+ guint num_elements = json_reader_count_elements (reader);
+
+ lua_createtable (L, num_elements, 0);
+ for (index_element = 0; index_element < num_elements; index_element++) {
+ json_reader_read_element (reader, index_element);
+ lua_pushnumber (L, index_element + 1);
+ build_table_from_json_reader (L, reader);
+ json_reader_end_element (reader);
+ }
+
+ } else if (json_reader_is_value (reader)) {
+ if (json_reader_get_null_value (reader)) {
+ lua_pushnil (L);
+ } else {
+ /* value of the element */
+ JsonNode *value = json_reader_get_value (reader);
+ switch (json_node_get_value_type (value)) {
+ case G_TYPE_STRING:
+ lua_pushstring (L, json_reader_get_string_value (reader));
+ break;
+ case G_TYPE_INT64:
+ lua_pushnumber (L, json_reader_get_int_value (reader));
+ break;
+ case G_TYPE_DOUBLE:
+ lua_pushnumber (L, json_reader_get_double_value (reader));
+ break;
+ case G_TYPE_BOOLEAN:
+ lua_pushnumber (L, json_reader_get_boolean_value (reader));
+ break;
+ default:
+ GRL_DEBUG ("'%d' (json-node-type) is not being handled",
+ (gint) json_node_get_value_type (value));
+ lua_pushnil (L);
+ }
+ }
+ }
+
+ if (lua_gettop (L) > 3) {
+ /* save this key/value on previous table */
+ lua_settable (L, -3);
+ }
+}
+
+/* grl.lua.json.string_to_table
+ *
+ * @json_str: (string) A Json object as a string.
+ *
+ * @return: All json content as a table.
+ */
+static gint
+grl_json_parse_string (lua_State *L)
+{
+ JsonParser *parser = NULL;
+ JsonReader *reader = NULL;
+ const gchar *json_str = NULL;
+ GError *err = NULL;
+
+ luaL_argcheck (L, lua_isstring (L, 1), 1, "json string expected");
+ json_str = lua_tostring (L, 1);
+
+ parser = json_parser_new ();
+ if (!json_parser_load_from_data (parser, json_str, -1, &err)) {
+ GRL_DEBUG ("Can't parse json string: '%s'", err->message);
+ g_error_free (err);
+ g_object_unref (parser);
+ return 0;
+ }
+
+ reader = json_reader_new (json_parser_get_root (parser));
+
+ /* The return of recursive function will be a table with all
+ * json content in it */
+ lua_pushnil (L);
+ build_table_from_json_reader (L, reader);
+
+ g_object_unref (reader);
+ g_object_unref (parser);
+
+ return 1;
+}
+
+gint
+luaopen_json (lua_State *L)
+{
+ static const luaL_Reg json_library_fn[] = {
+ {"string_to_table", &grl_json_parse_string},
+ {NULL, NULL}
+ };
+
+ luaL_newlib (L, json_library_fn);
+ return 1;
+}
diff --git a/src/lua-factory/lua-library/lua-libraries.h b/src/lua-factory/lua-library/lua-libraries.h
new file mode 100644
index 0000000..6905915
--- /dev/null
+++ b/src/lua-factory/lua-library/lua-libraries.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2013 Victor Toso.
+ *
+ * Contact: Victor Toso <me victortoso com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#include <grilo.h>
+
+#ifndef _GRL_LUA_LIBRARY_JSON_H_
+#define _GRL_LUA_LIBRARY_JSON_H_
+
+#define GRILO_LUA_LIBRARY_JSON "json"
+
+gint luaopen_json (lua_State *L);
+
+#endif /* _GRL_LUA_LIBRARY_JSON_H_ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]