2015-01-19 21:47:09 +00:00
|
|
|
#define LUA_LIB
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "lua.h"
|
|
|
|
#include "lauxlib.h"
|
|
|
|
|
2015-01-23 04:59:47 +00:00
|
|
|
#include "libretrodb.h"
|
2015-01-19 21:47:09 +00:00
|
|
|
#include "lua_common.h"
|
|
|
|
|
2016-01-23 00:33:44 +00:00
|
|
|
struct libretrodb
|
|
|
|
{
|
|
|
|
RFILE *fd;
|
|
|
|
uint64_t root;
|
|
|
|
uint64_t count;
|
|
|
|
uint64_t first_index_offset;
|
|
|
|
char path[1024];
|
|
|
|
};
|
|
|
|
|
2015-09-17 17:57:51 +00:00
|
|
|
static void push_rmsgpack_value(lua_State *L, struct rmsgpack_dom_value *value)
|
2015-09-17 05:04:37 +00:00
|
|
|
{
|
2015-09-17 17:57:51 +00:00
|
|
|
uint32_t i;
|
2015-01-19 21:47:09 +00:00
|
|
|
|
2015-09-21 09:42:41 +00:00
|
|
|
switch(value->type)
|
2015-09-17 17:57:51 +00:00
|
|
|
{
|
|
|
|
case RDT_INT:
|
2016-01-23 00:33:44 +00:00
|
|
|
lua_pushnumber(L, value->val.int_);
|
2015-09-17 17:57:51 +00:00
|
|
|
break;
|
|
|
|
case RDT_UINT:
|
2016-01-23 00:33:44 +00:00
|
|
|
lua_pushnumber(L, value->val.uint_);
|
2015-09-17 17:57:51 +00:00
|
|
|
break;
|
|
|
|
case RDT_BINARY:
|
2016-01-23 00:33:44 +00:00
|
|
|
lua_pushlstring(L, value->val.binary.buff, value->val.binary.len);
|
2015-09-17 17:57:51 +00:00
|
|
|
break;
|
|
|
|
case RDT_BOOL:
|
2016-01-23 00:33:44 +00:00
|
|
|
lua_pushboolean(L, value->val.bool_);
|
2015-09-17 17:57:51 +00:00
|
|
|
break;
|
|
|
|
case RDT_NULL:
|
|
|
|
lua_pushnil(L);
|
|
|
|
break;
|
|
|
|
case RDT_STRING:
|
2016-01-23 00:33:44 +00:00
|
|
|
lua_pushlstring(L, value->val.string.buff, value->val.binary.len);
|
2015-09-17 17:57:51 +00:00
|
|
|
break;
|
|
|
|
case RDT_MAP:
|
2016-01-23 00:33:44 +00:00
|
|
|
lua_createtable(L, 0, value->val.map.len);
|
|
|
|
for (i = 0; i < value->val.map.len; i++)
|
2015-09-17 17:57:51 +00:00
|
|
|
{
|
2016-01-23 00:33:44 +00:00
|
|
|
push_rmsgpack_value(L, &value->val.map.items[i].key);
|
|
|
|
push_rmsgpack_value(L, &value->val.map.items[i].value);
|
2015-09-17 17:57:51 +00:00
|
|
|
lua_settable(L, -3);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RDT_ARRAY:
|
2016-01-23 00:33:44 +00:00
|
|
|
lua_createtable(L, value->val.array.len, 0);
|
|
|
|
for (i = 0; i < value->val.array.len; i++)
|
2015-09-17 17:57:51 +00:00
|
|
|
{
|
2015-09-21 09:42:41 +00:00
|
|
|
lua_pushnumber(L, i + 1);
|
2016-01-23 00:33:44 +00:00
|
|
|
push_rmsgpack_value(L, &value->val.array.items[i]);
|
2015-09-17 17:57:51 +00:00
|
|
|
lua_settable(L, -3);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2015-01-19 21:47:09 +00:00
|
|
|
}
|
|
|
|
|
2015-09-17 17:57:51 +00:00
|
|
|
static int value_provider(void *ctx, struct rmsgpack_dom_value *out)
|
2015-09-17 05:04:37 +00:00
|
|
|
{
|
2015-09-28 14:57:07 +00:00
|
|
|
int rv = 0;
|
2015-09-17 17:57:51 +00:00
|
|
|
lua_State *L = ctx;
|
2015-01-19 21:47:09 +00:00
|
|
|
|
2015-09-17 05:04:37 +00:00
|
|
|
lua_getfield(L, LUA_REGISTRYINDEX, "testlib_get_value");
|
2015-01-19 21:47:09 +00:00
|
|
|
|
2015-09-17 05:04:37 +00:00
|
|
|
if (lua_pcall(L, 0, 1, 0) != 0)
|
|
|
|
{
|
|
|
|
printf(
|
|
|
|
"error running function `get_value': %s\n",
|
|
|
|
lua_tostring(L, -1)
|
|
|
|
);
|
|
|
|
}
|
2015-01-19 21:47:09 +00:00
|
|
|
|
2015-09-17 05:04:37 +00:00
|
|
|
if (lua_isnil(L, -1))
|
|
|
|
rv = 1;
|
|
|
|
else if (lua_istable(L, -1))
|
|
|
|
rv = libretrodb_lua_to_rmsgpack_value(L, -1, out);
|
|
|
|
else
|
|
|
|
printf("function `get_value' must return a table or nil\n");
|
|
|
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return rv;
|
2015-01-19 21:47:09 +00:00
|
|
|
}
|
|
|
|
|
2015-09-21 09:42:41 +00:00
|
|
|
static int create_db(lua_State *L)
|
2015-09-17 05:04:37 +00:00
|
|
|
{
|
2015-09-17 17:57:51 +00:00
|
|
|
RFILE *dst;
|
|
|
|
const char *db_file = luaL_checkstring(L, -2);
|
|
|
|
|
2015-09-17 05:04:37 +00:00
|
|
|
if (!lua_isfunction(L, -1))
|
|
|
|
{
|
|
|
|
lua_pushstring(L, "second argument must be a function");
|
|
|
|
lua_error(L);
|
|
|
|
}
|
|
|
|
lua_setfield(L, LUA_REGISTRYINDEX, "testlib_get_value");
|
2015-01-19 21:47:09 +00:00
|
|
|
|
2015-09-17 17:57:51 +00:00
|
|
|
dst = retro_fopen(db_file, RFILE_MODE_WRITE, -1);
|
|
|
|
if (!dst)
|
2015-09-17 05:04:37 +00:00
|
|
|
{
|
|
|
|
lua_pushstring(L, "Could not open destination file");
|
|
|
|
lua_error(L);
|
|
|
|
}
|
2015-01-19 21:47:09 +00:00
|
|
|
|
2015-09-28 21:00:22 +00:00
|
|
|
libretrodb_create(dst, &value_provider, L);
|
2015-09-17 17:57:51 +00:00
|
|
|
retro_fclose(dst);
|
|
|
|
|
2015-09-17 05:04:37 +00:00
|
|
|
return 0;
|
2015-01-19 21:47:09 +00:00
|
|
|
}
|
|
|
|
|
2015-09-21 09:42:41 +00:00
|
|
|
static int db_new(lua_State *L)
|
2015-09-17 05:04:37 +00:00
|
|
|
{
|
2015-09-17 17:57:51 +00:00
|
|
|
libretrodb_t *db = NULL;
|
|
|
|
const char *db_file = NULL;
|
2015-09-17 05:04:37 +00:00
|
|
|
int rv;
|
|
|
|
db_file = luaL_checkstring(L, -1);
|
|
|
|
db = lua_newuserdata(L, sizeof(libretrodb_t));
|
|
|
|
if ((rv = libretrodb_open(db_file, db)) == 0)
|
|
|
|
{
|
|
|
|
luaL_getmetatable(L, "RarchDB.DB");
|
|
|
|
lua_setmetatable(L, -2);
|
|
|
|
lua_pushnil(L);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, strerror(-rv));
|
|
|
|
}
|
|
|
|
return 2;
|
2015-01-19 21:47:09 +00:00
|
|
|
}
|
|
|
|
|
2016-01-23 00:33:44 +00:00
|
|
|
static libretrodb_t *checkdb(lua_State *L)
|
2015-09-17 17:57:51 +00:00
|
|
|
{
|
|
|
|
void *ud = luaL_checkudata(L, 1, "RarchDB.DB");
|
|
|
|
luaL_argcheck(L, ud != NULL, 1, "`RarchDB.DB' expected");
|
|
|
|
return ud;
|
|
|
|
}
|
|
|
|
|
2015-09-21 09:42:41 +00:00
|
|
|
static int db_close(lua_State *L)
|
2015-09-17 05:04:37 +00:00
|
|
|
{
|
2015-01-23 04:59:47 +00:00
|
|
|
libretrodb_t *db = checkdb(L);
|
|
|
|
libretrodb_close(db);
|
2015-01-19 21:47:09 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-21 09:42:41 +00:00
|
|
|
static int db_cursor_open(lua_State *L)
|
2015-09-17 05:04:37 +00:00
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
libretrodb_cursor_t *cursor = NULL;
|
|
|
|
libretrodb_t *db = checkdb(L);
|
2015-09-17 17:57:51 +00:00
|
|
|
cursor = lua_newuserdata(L, sizeof(libretrodb_t));
|
|
|
|
if ((rv = libretrodb_cursor_open(db, cursor, NULL)) == 0)
|
|
|
|
{
|
|
|
|
luaL_getmetatable(L, "RarchDB.Cursor");
|
|
|
|
lua_setmetatable(L, -2);
|
|
|
|
lua_pushnil(L);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, strerror(-rv));
|
|
|
|
}
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
2015-09-21 09:42:41 +00:00
|
|
|
static int db_query(lua_State *L)
|
2015-09-17 17:57:51 +00:00
|
|
|
{
|
|
|
|
libretrodb_t *db = checkdb(L);
|
|
|
|
const char *query = luaL_checkstring(L, -1);
|
|
|
|
const char *error = NULL;
|
|
|
|
libretrodb_query_t *q = libretrodb_query_compile(
|
|
|
|
db, query, strlen(query), &error);
|
|
|
|
|
2015-09-17 05:04:37 +00:00
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-28 21:00:22 +00:00
|
|
|
int rv;
|
|
|
|
libretrodb_cursor_t *cursor = lua_newuserdata(L, sizeof(libretrodb_t));
|
|
|
|
|
2015-09-17 05:04:37 +00:00
|
|
|
if ((rv = libretrodb_cursor_open(db, cursor, q)) == 0)
|
|
|
|
{
|
|
|
|
luaL_getmetatable(L, "RarchDB.Cursor");
|
|
|
|
lua_setmetatable(L, -2);
|
|
|
|
lua_pushnil(L);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, strerror(-rv));
|
|
|
|
}
|
|
|
|
libretrodb_query_free(q);
|
|
|
|
}
|
|
|
|
return 2;
|
2015-01-19 21:47:09 +00:00
|
|
|
}
|
2015-09-17 17:57:51 +00:00
|
|
|
|
2016-01-23 00:33:44 +00:00
|
|
|
static libretrodb_cursor_t *checkcursor(lua_State *L)
|
2015-09-17 05:04:37 +00:00
|
|
|
{
|
2015-09-17 17:57:51 +00:00
|
|
|
void *ud = luaL_checkudata(L, 1, "RarchDB.Cursor");
|
|
|
|
luaL_argcheck(L, ud != NULL, 1, "`RarchDB.Cursor' expected");
|
|
|
|
return ud;
|
2015-01-19 21:47:09 +00:00
|
|
|
}
|
2015-09-17 17:57:51 +00:00
|
|
|
|
2015-09-21 09:42:41 +00:00
|
|
|
static int cursor_close(lua_State *L)
|
2015-09-17 05:04:37 +00:00
|
|
|
{
|
2015-01-23 04:59:47 +00:00
|
|
|
libretrodb_cursor_t *cursor = checkcursor(L);
|
|
|
|
libretrodb_cursor_close(cursor);
|
2015-01-19 21:47:09 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-21 09:42:41 +00:00
|
|
|
static int cursor_read(lua_State *L)
|
2015-09-17 05:04:37 +00:00
|
|
|
{
|
|
|
|
libretrodb_cursor_t *cursor = checkcursor(L);
|
|
|
|
struct rmsgpack_dom_value value;
|
|
|
|
if (libretrodb_cursor_read_item(cursor, &value) == 0)
|
|
|
|
push_rmsgpack_value(L, &value);
|
|
|
|
else
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
2015-01-19 21:47:09 +00:00
|
|
|
}
|
|
|
|
|
2015-09-21 09:42:41 +00:00
|
|
|
static int cursor_iter(lua_State *L)
|
2015-09-17 05:04:37 +00:00
|
|
|
{
|
2015-09-17 17:57:51 +00:00
|
|
|
libretrodb_cursor_t *cursor = checkcursor(L);
|
2015-09-28 21:00:22 +00:00
|
|
|
|
|
|
|
(void)cursor;
|
|
|
|
|
2015-09-17 05:04:37 +00:00
|
|
|
luaL_getmetafield(L, -1, "read");
|
|
|
|
lua_pushvalue(L, -2);
|
|
|
|
return 2;
|
2015-01-19 21:47:09 +00:00
|
|
|
}
|
2015-09-17 17:57:51 +00:00
|
|
|
|
|
|
|
static const luaL_Reg testlib[] = {
|
|
|
|
{"create_db", create_db},
|
|
|
|
{"RarchDB", db_new},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct luaL_Reg cursor_mt [] = {
|
|
|
|
{"__gc", cursor_close},
|
|
|
|
{"read", cursor_read},
|
|
|
|
{"iter", cursor_iter},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct luaL_Reg libretrodb_mt [] = {
|
|
|
|
{"__gc", db_close},
|
|
|
|
{"list_all", db_cursor_open},
|
|
|
|
{"query", db_query},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
LUALIB_API int luaopen_testlib(lua_State *L)
|
|
|
|
{
|
|
|
|
luaL_newmetatable(L, "RarchDB.DB");
|
|
|
|
lua_pushstring(L, "__index");
|
|
|
|
lua_pushvalue(L, -2);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
luaL_openlib(L, NULL, libretrodb_mt, 0);
|
|
|
|
|
|
|
|
luaL_newmetatable(L, "RarchDB.Cursor");
|
|
|
|
lua_pushstring(L, "__index");
|
|
|
|
lua_pushvalue(L, -2);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
luaL_openlib(L, NULL, cursor_mt, 0);
|
|
|
|
|
|
|
|
luaL_register(L, "testlib", testlib);
|
|
|
|
return 1;
|
|
|
|
}
|