mirror of
https://github.com/libretro/RetroArch
synced 2025-01-30 03:32:46 +00:00
translated the lua converter to plain c
This commit is contained in:
parent
5fce3f4138
commit
bdd98d3ea3
@ -1,216 +0,0 @@
|
||||
local dat_obj = {}
|
||||
local match_key = nil
|
||||
|
||||
local function dat_lexer(f, fname)
|
||||
local line, err = f:read("*l")
|
||||
local location = {line_no = 1, column = 1, fname = fname}
|
||||
return function()
|
||||
local tok = nil
|
||||
while not tok do
|
||||
if not line then
|
||||
return nil
|
||||
end
|
||||
pre_space, tok, line = string.match(line, "^(%s*)(..-)([()]*%s.*)")
|
||||
if tok and string.match(tok, "^\"") then
|
||||
tok, line = string.match(tok..line, "^\"([^\"]-)\"(.*)")
|
||||
elseif tok and string.match(tok, "^[()]") then
|
||||
line = tok:sub(2) .. line
|
||||
tok = tok:sub(1,1)
|
||||
end
|
||||
location.column = location.column + #(pre_space or "")
|
||||
tok_loc = {
|
||||
line_no = location.line_no,
|
||||
column = location.column,
|
||||
fname = location.fname
|
||||
}
|
||||
if not line then
|
||||
line = f:read("*l")
|
||||
location.line_no = location.line_no + 1
|
||||
location.column = 1
|
||||
else
|
||||
location.column = location.column + #tok
|
||||
end
|
||||
end
|
||||
-- print(tok)
|
||||
return tok, tok_loc
|
||||
end
|
||||
end
|
||||
|
||||
local function dat_parse_table(lexer, start_loc)
|
||||
local res = {}
|
||||
local state = "key"
|
||||
local key = nil
|
||||
for tok, loc in lexer do
|
||||
if state == "key" then
|
||||
if tok == ")" then
|
||||
return res
|
||||
elseif tok == "(" then
|
||||
error(string.format(
|
||||
"%s:%d:%d: fatal error: Unexpected '(' instead of key",
|
||||
loc.fname,
|
||||
loc.line_no,
|
||||
loc.column
|
||||
))
|
||||
else
|
||||
key = tok
|
||||
state = "value"
|
||||
end
|
||||
else
|
||||
if tok == "(" then
|
||||
res[key] = dat_parse_table(lexer, loc)
|
||||
elseif tok == ")" then
|
||||
error(string.format(
|
||||
"%s:%d:%d: fatal error: Unexpected ')' instead of value",
|
||||
loc.fname,
|
||||
loc.line_no,
|
||||
loc.column
|
||||
))
|
||||
else
|
||||
res[key] = tok
|
||||
end
|
||||
state = "key"
|
||||
end
|
||||
end
|
||||
error(string.format(
|
||||
"%s:%d:%d: fatal error: Missing ')' for '('",
|
||||
start_loc.fname,
|
||||
start_loc.line_no,
|
||||
start_loc.column
|
||||
))
|
||||
end
|
||||
|
||||
local function dat_parser(lexer)
|
||||
local res = {}
|
||||
local state = "key"
|
||||
local key = nil
|
||||
local skip = true
|
||||
for tok, loc in lexer do
|
||||
if state == "key" then
|
||||
if tok == "game" then
|
||||
skip = false
|
||||
end
|
||||
state = "value"
|
||||
else
|
||||
if tok == "(" then
|
||||
local v = dat_parse_table(lexer, loc)
|
||||
if not skip then
|
||||
table.insert(res, v)
|
||||
skip = true
|
||||
end
|
||||
else
|
||||
error(string.format(
|
||||
"%s:%d:%d: fatal error: Expected '(' found '%s'",
|
||||
loc.fname,
|
||||
loc.line_no,
|
||||
loc.column,
|
||||
tok
|
||||
))
|
||||
end
|
||||
state = "key"
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
local function unhex(s)
|
||||
if not s then return nil end
|
||||
return (s:gsub('..', function (c)
|
||||
return string.char(tonumber(c, 16))
|
||||
end))
|
||||
end
|
||||
|
||||
local function get_match_key(mk, t)
|
||||
for p in string.gmatch(mk, "(%w+)[.]?") do
|
||||
if p == nil or t == nil then
|
||||
error("Invalid match key '"..mk.."'")
|
||||
end
|
||||
t = t[p]
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
table.update = function(a, b)
|
||||
for k,v in pairs(b) do
|
||||
a[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
function init(...)
|
||||
local args = {...}
|
||||
table.remove(args, 1)
|
||||
if #args == 0 then
|
||||
assert(dat_path, "dat file argument is missing")
|
||||
end
|
||||
|
||||
if #args > 1 then
|
||||
match_key = table.remove(args, 1)
|
||||
end
|
||||
|
||||
local dat_hash = {}
|
||||
for _, dat_path in ipairs(args) do
|
||||
local dat_file, err = io.open(dat_path, "r")
|
||||
if err then
|
||||
error("could not open dat file '" .. dat_path .. "':" .. err)
|
||||
end
|
||||
|
||||
print("Parsing dat file '" .. dat_path .. "'...")
|
||||
local objs = dat_parser(dat_lexer(dat_file, dat_path))
|
||||
dat_file:close()
|
||||
for _, obj in pairs(objs) do
|
||||
if match_key then
|
||||
local mk = get_match_key(match_key, obj)
|
||||
if mk == nil then
|
||||
error("missing match key '" .. match_key .. "' in one of the entries")
|
||||
end
|
||||
if dat_hash[mk] == nil then
|
||||
dat_hash[mk] = {}
|
||||
table.insert(dat_obj, dat_hash[mk])
|
||||
end
|
||||
table.update(dat_hash[mk], obj)
|
||||
else
|
||||
table.insert(dat_obj, obj)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function get_value()
|
||||
local t = table.remove(dat_obj)
|
||||
if not t then
|
||||
return
|
||||
else
|
||||
return {
|
||||
name = t.name,
|
||||
description = t.description,
|
||||
rom_name = t.rom.name,
|
||||
size = uint(tonumber(t.rom.size)),
|
||||
users = uint(tonumber(t.users)),
|
||||
releasemonth = uint(tonumber(t.releasemonth)),
|
||||
releaseyear = uint(tonumber(t.releaseyear)),
|
||||
rumble = uint(tonumber(t.rumble)),
|
||||
analog = uint(tonumber(t.analog)),
|
||||
|
||||
famitsu_rating = uint(tonumber(t.famitsu_rating)),
|
||||
edge_rating = uint(tonumber(t.edge_rating)),
|
||||
edge_issue = uint(tonumber(t.edge_issue)),
|
||||
edge_review = t.edge_review,
|
||||
|
||||
enhancement_hw = t.enhancement_hw,
|
||||
barcode = t.barcode,
|
||||
esrb_rating = t.esrb_rating,
|
||||
elspa_rating = t.elspa_rating,
|
||||
pegi_rating = t.pegi_rating,
|
||||
cero_rating = t.cero_rating,
|
||||
franchise = t.franchise,
|
||||
|
||||
developer = t.developer,
|
||||
publisher = t.publisher,
|
||||
origin = t.origin,
|
||||
|
||||
crc = binary(unhex(t.rom.crc)),
|
||||
md5 = binary(unhex(t.rom.md5)),
|
||||
sha1 = binary(unhex(t.rom.sha1)),
|
||||
serial = binary(t.serial or t.rom.serial),
|
||||
}
|
||||
end
|
||||
end
|
@ -1,12 +0,0 @@
|
||||
unsigned djb2( const char* str, unsigned len )
|
||||
{
|
||||
const unsigned char* aux = (const unsigned char*)str;
|
||||
unsigned hash = 5381;
|
||||
|
||||
while ( len-- )
|
||||
{
|
||||
hash = ( hash << 5 ) + hash + *aux++;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
#ifndef DJB2_H
|
||||
#define DJB2_H
|
||||
|
||||
unsigned djb2( const char* str, unsigned len );
|
||||
|
||||
#endif /* DJB2_H */
|
@ -1,100 +0,0 @@
|
||||
#include "lua_common.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int libretrodb_lua_to_rmsgpack_value(lua_State *L, int index,
|
||||
struct rmsgpack_dom_value * out)
|
||||
{
|
||||
size_t tmp_len;
|
||||
lua_Number tmp_num;
|
||||
struct rmsgpack_dom_value * tmp_value;
|
||||
int i, rv = -1;
|
||||
const char * tmp_string = NULL;
|
||||
char * tmp_buff = NULL;
|
||||
const int key_idx = -2;
|
||||
const int value_idx = -1;
|
||||
const int MAX_FIELDS = 100;
|
||||
|
||||
out->type = RDT_MAP;
|
||||
out->val.map.len = 0;
|
||||
out->val.map.items = calloc(MAX_FIELDS, sizeof(struct rmsgpack_dom_pair));
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, index - 1) != 0)
|
||||
{
|
||||
if (out->val.map.len > MAX_FIELDS)
|
||||
printf("skipping due to too many keys\n");
|
||||
else if (!lua_isstring(L, key_idx))
|
||||
printf("skipping non string key\n");
|
||||
else if (lua_isnil(L, value_idx))
|
||||
{
|
||||
/* Skipping nil value fields to save disk space */
|
||||
}
|
||||
else
|
||||
{
|
||||
i = out->val.map.len;
|
||||
tmp_buff = strdup(lua_tostring(L, key_idx));
|
||||
out->val.map.items[i].key.type = RDT_STRING;
|
||||
out->val.map.items[i].key.val.string.len = strlen(tmp_buff);
|
||||
out->val.map.items[i].key.val.string.buff = tmp_buff;
|
||||
|
||||
tmp_value = &out->val.map.items[i].value;
|
||||
switch (lua_type(L, value_idx))
|
||||
{
|
||||
case LUA_TNUMBER:
|
||||
tmp_num = lua_tonumber(L, value_idx);
|
||||
tmp_value->type = RDT_INT;
|
||||
tmp_value->val.int_ = tmp_num;
|
||||
break;
|
||||
case LUA_TBOOLEAN:
|
||||
tmp_value->type = RDT_BOOL;
|
||||
tmp_value->val.bool_ = lua_toboolean(L, value_idx);
|
||||
break;
|
||||
case LUA_TSTRING:
|
||||
tmp_buff = strdup(lua_tostring(L, value_idx));
|
||||
tmp_value->type = RDT_STRING;
|
||||
tmp_value->val.string.len = strlen(tmp_buff);
|
||||
tmp_value->val.string.buff = tmp_buff;
|
||||
break;
|
||||
case LUA_TTABLE:
|
||||
lua_getfield(L, value_idx, "binary");
|
||||
if (!lua_isstring(L, -1))
|
||||
{
|
||||
lua_pop(L, 1);
|
||||
lua_getfield(L, value_idx, "uint");
|
||||
if (!lua_isnumber(L, -1))
|
||||
{
|
||||
lua_pop(L, 1);
|
||||
goto set_nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp_num = lua_tonumber(L, -1);
|
||||
tmp_value->type = RDT_UINT;
|
||||
tmp_value->val.uint_ = tmp_num;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp_string = lua_tolstring(L, -1, &tmp_len);
|
||||
tmp_buff = malloc(tmp_len);
|
||||
memcpy(tmp_buff, tmp_string, tmp_len);
|
||||
tmp_value->type = RDT_BINARY;
|
||||
tmp_value->val.binary.len = tmp_len;
|
||||
tmp_value->val.binary.buff = tmp_buff;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
set_nil:
|
||||
tmp_value->type = RDT_NULL;
|
||||
}
|
||||
out->val.map.len++;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
rv = 0;
|
||||
return rv;
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
#ifndef __RARCHDB_LUA_COMMON_H__
|
||||
#define __RARCHDB_LUA_COMMON_H__
|
||||
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
#include "rmsgpack_dom.h"
|
||||
|
||||
int libretrodb_lua_to_rmsgpack_value(lua_State *L, int index, struct rmsgpack_dom_value *out);
|
||||
|
||||
#endif
|
@ -1,112 +0,0 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
#include "libretrodb.h"
|
||||
#include "lua_common.h"
|
||||
|
||||
int master_key = 1;
|
||||
|
||||
const char * LUA_COMMON = " \
|
||||
function binary(s) if s ~= nil then return {binary = s} else return nil end end \
|
||||
function uint(s) if s ~= nil then return {uint = s} else return nil end end \
|
||||
";
|
||||
|
||||
static int call_init(lua_State * L, int argc, const char ** argv)
|
||||
{
|
||||
int rv = -1;
|
||||
int i;
|
||||
|
||||
lua_getglobal(L, "init");
|
||||
for (i = 0; i < argc; i++)
|
||||
lua_pushstring(L, argv[i]);
|
||||
|
||||
if (lua_pcall(L, argc, 0, 0) != 0)
|
||||
{
|
||||
printf(
|
||||
"error running function `init': %s\n",
|
||||
lua_tostring(L, -1)
|
||||
);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int value_provider(void * ctx, struct rmsgpack_dom_value *out)
|
||||
{
|
||||
int rv = 0;
|
||||
lua_State * L = ctx;
|
||||
|
||||
lua_getglobal(L, "get_value");
|
||||
|
||||
if (lua_pcall(L, 0, 1, 0) != 0)
|
||||
{
|
||||
printf(
|
||||
"error running function `get_value': %s\n",
|
||||
lua_tostring(L, -1)
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
lua_State *L;
|
||||
const char *db_file;
|
||||
const char *lua_file;
|
||||
RFILE *dst;
|
||||
int rv = 0;
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
printf("usage:\n%s <db file> <lua file> [args ...]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
db_file = argv[1];
|
||||
lua_file = argv[2];
|
||||
L = luaL_newstate();
|
||||
|
||||
luaL_openlibs(L);
|
||||
luaL_dostring(L, LUA_COMMON);
|
||||
|
||||
if (luaL_dofile(L, lua_file) != 0)
|
||||
return 1;
|
||||
|
||||
call_init(L, argc - 2, (const char **) argv + 2);
|
||||
|
||||
dst = retro_fopen(db_file, RFILE_MODE_WRITE, -1);
|
||||
if (!dst)
|
||||
{
|
||||
printf(
|
||||
"Could not open destination file '%s': %s\n",
|
||||
db_file,
|
||||
strerror(errno)
|
||||
);
|
||||
rv = errno;
|
||||
goto clean;
|
||||
}
|
||||
|
||||
rv = libretrodb_create(dst, &value_provider, L);
|
||||
|
||||
clean:
|
||||
lua_close(L);
|
||||
retro_fclose(dst);
|
||||
return rv;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user