Lots of work done with xml parsing.

develop
Warmist 2012-03-04 14:45:15 +02:00
parent 1c90019de4
commit e8788d8872
7 changed files with 269 additions and 77 deletions

@ -19,6 +19,7 @@
#include "lua_VersionInfo.h" #include "lua_VersionInfo.h"
#include "functioncall.h" #include "functioncall.h"
#include "lua_FunctionCall.h" #include "lua_FunctionCall.h"
#include "lua_Offsets.h"
using std::vector; using std::vector;
using std::string; using std::string;
@ -48,6 +49,7 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand>
lua::RegisterMisc(st); lua::RegisterMisc(st);
lua::RegisterVersionInfo(st); lua::RegisterVersionInfo(st);
lua::RegisterFunctionCall(st); lua::RegisterFunctionCall(st);
lua::RegisterEngine(st);
#ifdef LINUX_BUILD #ifdef LINUX_BUILD
st.push(1); st.push(1);

@ -3,6 +3,9 @@ STD_STRING=0
DWORD=1 DWORD=1
WORD=2 WORD=2
BYTE=3 BYTE=3
QWORD=4
DOUBLE=5
FLOAT=6
function printd(...) function printd(...)
if DEBUG then if DEBUG then
print(...) print(...)
@ -94,6 +97,7 @@ function SetExecute(pos)
end end
-- engine bindings -- engine bindings
engine=engine or {} engine=engine or {}
--[=[ use default peek/pokes for now
engine.peekd=Process.readDWord engine.peekd=Process.readDWord
engine.poked=Process.writeDWord engine.poked=Process.writeDWord
engine.peekb=Process.readByte engine.peekb=Process.readByte
@ -106,7 +110,7 @@ engine.peekstr=Process.readCString
--engine.pokestr=Process.readCString --engine.pokestr=Process.readCString
engine.peekarb=Process.read engine.peekarb=Process.read
engine.pokearb=Process.write engine.pokearb=Process.write
--]=]
function engine.peek(offset,rtype) function engine.peek(offset,rtype)
if type(rtype)=="table" then if type(rtype)=="table" then
@ -117,13 +121,19 @@ function engine.peek(offset,rtype)
end end
end end
if rtype==STD_STRING then if rtype==STD_STRING then
return engine.peekstr(offset) return engine.peekstr2(offset)
elseif rtype==DWORD then elseif rtype==DWORD then
return engine.peekd(offset) return engine.peekd(offset)
elseif rtype==WORD then elseif rtype==WORD then
return engine.peekw(offset) return engine.peekw(offset)
elseif rtype==BYTE then elseif rtype==BYTE then
return engine.peekb(offset) return engine.peekb(offset)
elseif rtype==QWORD then
return engine.peekq(offset)
elseif rtype==FLOAT then
return engine.peekfloat(offset)
elseif rtype==DOUBLE then
return engine.peekdouble(offset)
else else
error("Invalid peek type") error("Invalid peek type")
return return
@ -138,13 +148,19 @@ function engine.poke(offset,rtype,val)
end end
end end
if rtype==STD_STRING then if rtype==STD_STRING then
return engine.pokestr(offset,val) return engine.pokestr2(offset,val)
elseif rtype==DWORD then elseif rtype==DWORD then
return engine.poked(offset,val) return engine.poked(offset,val)
elseif rtype==WORD then elseif rtype==WORD then
return engine.pokew(offset,val) return engine.pokew(offset,val)
elseif rtype==BYTE then elseif rtype==BYTE then
return engine.pokeb(offset,val) return engine.pokeb(offset,val)
elseif rtype==QWORD then
return engine.pokeq(offset,val)
elseif rtype==FLOAT then
return engine.pokefloat(offset,val)
elseif rtype==DOUBLE then
return engine.pokedouble(offset,val)
else else
error("Invalid poke type:"..tostring(rtype)) error("Invalid poke type:"..tostring(rtype))
return return

@ -60,12 +60,12 @@ table.insert(plugins,{"onfunction","run lua on some df function"})
loadall(plugins) loadall(plugins)
dofile_silent("dfusion/initcustom.lua") dofile_silent("dfusion/initcustom.lua")
print("Locating saves...") --[=[print("Locating saves...")
local str=engine.peekstr(0x1447A40+offsets.base()) local str=engine.peekstr(0x1447A40+offsets.base())
print("Current region:"..str) print("Current region:"..str)
str="data/save/"..str.."/dfusion/init.lua" str="data/save/"..str.."/dfusion/init.lua"
dofile_silent(str) dofile_silent(str)
--]=]
if not INIT then if not INIT then
mainmenu(plugins) mainmenu(plugins)
end end

@ -170,11 +170,11 @@ end
]]-- ]]--
ptr_Creature={} ptr_Creature={}
local posoff=VersionInfo.getGroup("Creatures"):getGroup("creature"):getOffset("position") local posoff=0 --VersionInfo.getGroup("Creatures"):getGroup("creature"):getOffset("position")
ptr_Creature.x={off=posoff,rtype=WORD} --ok ptr_Creature.x={off=posoff,rtype=WORD} --ok
ptr_Creature.y={off=posoff+2,rtype=WORD} --ok ptr_Creature.y={off=posoff+2,rtype=WORD} --ok
ptr_Creature.z={off=posoff+4,rtype=WORD} --ok ptr_Creature.z={off=posoff+4,rtype=WORD} --ok
ptr_Creature.flags={off=VersionInfo.getGroup("Creatures"):getGroup("creature"):getOffset("flags1"),rtype=ptt_dfflag.new(10)} ptr_Creature.flags={off=0,rtype=ptt_dfflag.new(10)}
ptr_Creature.name={off=0,rtype=ptt_dfstring} ptr_Creature.name={off=0,rtype=ptt_dfstring}
ptr_Creature.ID={off=252,rtype=DWORD} --ok i guess ptr_Creature.ID={off=252,rtype=DWORD} --ok i guess
ptr_Creature.followID={off=592,rtype=DWORD} --ok ptr_Creature.followID={off=592,rtype=DWORD} --ok

@ -24,47 +24,96 @@ types.building=sometype
]=] ]=]
function parseTree(t) function parseTree(t)
for k,v in ipairs(t) do for k,v in ipairs(t) do
if v.xarg~=nil and v.xarg["type-name"]~=nil and v.label=="ld:global-type" then if v.xarg~=nil and v.xarg["type-name"]~=nil and v.label=="ld:global-type" then
local name=v.xarg["type-name"]; local name=v.xarg["type-name"];
print("Parsing:"..name) if(types[name]==nil) then
for kk,vv in pairs(v.xarg) do --print("Parsing:"..name)
print("\t"..kk.." "..tostring(vv)) --for kk,vv in pairs(v.xarg) do
-- print("\t"..kk.." "..tostring(vv))
--end
types[name]=makeType(v)
--print("found "..name.." or type:"..v.xarg.meta or v.xarg.base)
end end
types[name]=makeType(v)
print("found "..name.." or type:"..v.xarg.meta or v.xarg.base)
end end
end end
end end
function parseTreeGlobals(t)
local glob={}
print("Parsing global-objects")
for k,v in ipairs(t) do
if v.xarg~=nil and v.label=="ld:global-object" then
local name=v.xarg["name"];
--print("Parsing:"..name)
local subitem=v[1]
if subitem==nil then
error("Global-object subitem is nil:"..name)
end
local ret=makeType(subitem)
if ret==nil then
error("Make global returned nil!")
end
glob[name]=ret
end
end
--print("Printing globals:")
--for k,v in pairs(glob) do
-- print(k)
--end
return glob
end
function findAndParse(tname) function findAndParse(tname)
for k,v in ipairs(main_tree) do for k,v in ipairs(main_tree) do
local name=v.xarg["type-name"]; local name=v.xarg["type-name"];
if v.xarg~=nil and v.xarg["type-name"]~=nil and v.label=="ld:global-type" then if v.xarg~=nil and v.xarg["type-name"]~=nil and v.label=="ld:global-type" then
if(name ==tname) then if(name ==tname) then
print("Parsing:"..name) --print("Parsing:"..name)
for kk,vv in pairs(v.xarg) do --for kk,vv in pairs(v.xarg) do
print("\t"..kk.." "..tostring(vv)) -- print("\t"..kk.." "..tostring(vv))
end --end
types[name]=makeType(v) types[name]=makeType(v)
end end
--print("found "..name.." or type:"..v.xarg.meta or v.xarg.base) --print("found "..name.." or type:"..v.xarg.meta or v.xarg.base)
end end
end end
end end
df={}
df.types=rawget(df,"types") or {} --temporary measure for debug
local df_meta={}
function df_meta:__index(key)
local addr=VersionInfo.getAddress(key)
local vartype=rawget(df,"types")[key];
if addr==nil then
error("No such global address exist")
elseif vartype==nil then
error("No such global type exist")
else
return type_read(vartype,addr)
end
end
function df_meta:__newindex(key,val)
local addr=VersionInfo.getAddress(key)
local vartype=rawget(df,"types")[key];
if addr==nil then
error("No such global address exist")
elseif vartype==nil then
error("No such global type exist")
else
return type_write(vartype,addr,val)
end
end
setmetatable(df,df_meta)
-------------------------------- --------------------------------
types=types or {} types=types or {}
dofile("dfusion/patterns/xml_angavrilov.lua") dofile("dfusion/patterns/xml_angavrilov.lua")
-- [=[
main_tree=parseXmlFile("dfusion/patterns/supplementary.xml")[1] main_tree=parseXmlFile("dfusion/patterns/supplementary.xml")[1]
parseTree(main_tree) parseTree(main_tree)
main_tree=parseXmlFile("dfusion/patterns/codegen.out.xml")[1] main_tree=parseXmlFile("dfusion/patterns/codegen.out.xml")[1]
parseTree(main_tree) parseTree(main_tree)
rawset(df,"types",parseTreeGlobals(main_tree))
--]=]
--[=[labels={} --[=[labels={}
for k,v in ipairs(t) do for k,v in ipairs(t) do
labels[v.label]=labels[v.label] or {meta={}} labels[v.label]=labels[v.label] or {meta={}}

@ -1,15 +1,16 @@
function type_read(valtype,address) function type_read(valtype,address)
if type(valtype)~= "table" then if valtype.issimple then
return engine.peek(valtype,address) print("Simple read:"..tostring(valtype.ctype))
return engine.peek(address,valtype.ctype)
else else
return valtype:makewrap(address) return valtype:makewrap(address)
end end
end end
function type_write(valtype,address,val) function type_write(valtype,address,val)
if type(valtype)~= "table" then if altype.issimple then
engine.poke(valtype,address,val) engine.poke(address,valtype.ctype,val)
else else
engine.poke(DWORD,address,rawget(val,"ptr")) engine.poke(address,DWORD,rawget(val,"ptr"))
end end
end end
function first_of_type(node,labelname) function first_of_type(node,labelname)
@ -65,6 +66,9 @@ xtypes["static-array"]=sarr
simpletypes={} simpletypes={}
simpletypes["s-float"]={FLOAT,4}
simpletypes.int64_t={QWORD,8}
simpletypes.uint32_t={DWORD,4} simpletypes.uint32_t={DWORD,4}
simpletypes.uint16_t={WORD,2} simpletypes.uint16_t={WORD,2}
simpletypes.uint8_t={BYTE,1} simpletypes.uint8_t={BYTE,1}
@ -78,6 +82,7 @@ function getSimpleType(typename)
local o={} local o={}
o.ctype=simpletypes[typename][1] o.ctype=simpletypes[typename][1]
o.size=simpletypes[typename][2] o.size=simpletypes[typename][2]
o.issimple=true
return o return o
end end
local type_enum={} local type_enum={}
@ -130,7 +135,7 @@ function type_class.new(node)
local t_name="" local t_name=""
local name=v.xarg.name or v.xarg["anon-name"] or ("unk_"..k) local name=v.xarg.name or v.xarg["anon-name"] or ("unk_"..k)
print("\t"..k.." "..name.."->"..v.xarg.meta.." ttype:"..v.label) --print("\t"..k.." "..name.."->"..v.xarg.meta.." ttype:"..v.label)
local ttype=makeType(v) local ttype=makeType(v)
--for k,v in pairs(ttype) do --for k,v in pairs(ttype) do
@ -206,11 +211,49 @@ xtypes["pointer"]=type_class
--stl-vector (beginptr,endptr,allocptr) --stl-vector (beginptr,endptr,allocptr)
--df-flagarray (ptr,size) --df-flagarray (ptr,size)
xtypes.containers={} xtypes.containers={}
local dfarr={}
dfarr.__index=dfarr
function dfarr.new(node)
local o={}
setmetatable(o,dfarr)
o.size=8
return o
end
function dfarr:makewrap(address)
local o={}
o.mtype=self
o.ptr=address
setmetatable(o,self.wrap)
return o
end
dfarr.wrap={}
function dfarr.wrap:__index(key)
local num=tonumber(key)
local mtype=rawget(self,"mtype")
local size=type_read(rawget(self,"ptr")+4,DWORD)
error("TODO make __index for dfarray")
if num~=nil and num<sizethen then
return type_read(mtype.ctype,num*mtype.ctype.size+rawget(self,"ptr"))
else
error("invalid key to df-flagarray")
end
end
function dfarr.wrap:__newindex(key,val)
local num=tonumber(key)
error("TODO make __index for dfarray")
if num~=nil and num<rawget(self,"mtype").count then
return type_write(mtype.ctype,num*mtype.ctype.size+rawget(self,"ptr"),val)
else
error("invalid key to static-array")
end
end
xtypes.containers["df-array"]=dfarr
local farr={} local farr={}
farr.__index=farr farr.__index=farr
function farr.new(node) function farr.new(node)
local o={} local o={}
setmetatable(o,sarr) setmetatable(o,farr)
o.size=8 o.size=8
return o return o
end end
@ -246,10 +289,10 @@ end
xtypes.containers["df-flagarray"]=farr xtypes.containers["df-flagarray"]=farr
local stl_vec={} local stl_vec={}
stl_vec.__index=farr stl_vec.__index=stl_vec
function stl_vec.new(node) function stl_vec.new(node)
local o={} local o={}
setmetatable(o,sarr) setmetatable(o,stl_vec)
o.size=12 o.size=12
local titem=first_of_type(node,"ld:item") local titem=first_of_type(node,"ld:item")
if titem~=nil then if titem~=nil then
@ -290,8 +333,58 @@ function stl_vec.wrap:__newindex(key,val)
error("invalid key to static-array") error("invalid key to static-array")
end end
end end
xtypes.containers["stl-vector"]=stl_vec xtypes.containers["stl-vector"]=stl_vec
local stl_vec_bit={}
stl_vec_bit.__index=stl_vec_bit
function stl_vec_bit.new(node)
local o={}
setmetatable(o,stl_vec_bit)
o.size=20
return o
end
function stl_vec_bit:makewrap(address)
local o={}
o.mtype=self
o.ptr=address
setmetatable(o,self.wrap)
return o
end
stl_vec_bit.wrap={}
function stl_vec_bit.wrap:__index(key)
local num=tonumber(key)
local mtype=rawget(self,"item_type")
local ptr=rawget(self,"ptr")
local p_begin=type_read(ptr,DWORD)
local p_end=type_read(ptr+4,DWORD)
--allocend=type_read(ptr+8,DWORD)
error("TODO make __index for stl_vec_bit")
if num~=nil and num<sizethen then
return type_read(mtype.ctype,num*mtype.ctype.size+rawget(self,"ptr"))
else
error("invalid key to df-flagarray")
end
end
function stl_vec_bit.wrap:__newindex(key,val)
local num=tonumber(key)
error("TODO make __index for stl_vec_bit")
if num~=nil and num<rawget(self,"mtype").count then
return type_write(mtype.ctype,num*mtype.ctype.size+rawget(self,"ptr"),val)
else
error("invalid key to static-array")
end
end
xtypes.containers["stl-bit-vector"]=stl_vec_bit
--------------------------------------------
local bytes_pad={}
bytes_pad.__index=bytes_pad
function bytes_pad.new(node)
local o={}
setmetatable(o,bytes_pad)
o.size=tonumber(node.xarg.size)
return o
end
xtypes["bytes"]=bytes_pad
-------------------------------------------- --------------------------------------------
parser={} parser={}
parser["ld:global-type"]=function (node) parser["ld:global-type"]=function (node)
@ -332,7 +425,7 @@ parser["ld:field"]=function (node)
elseif meta=="pointer" then elseif meta=="pointer" then
return xtypes["pointer"].new(node) return xtypes["pointer"].new(node)
elseif meta=="bytes" then elseif meta=="bytes" then
error("TODO make bytes") return xtypes["bytes"].new(node)
else else
error("Unknown meta:"..meta) error("Unknown meta:"..meta)
end end
@ -341,7 +434,7 @@ parser["ld:item"]=parser["ld:field"]
function makeType(node,overwrite) function makeType(node,overwrite)
local label=overwrite or node.label local label=overwrite or node.label
if parser[label] ~=nil then if parser[label] ~=nil then
print("Make Type with:"..label) --print("Make Type with:"..label)
local ret=parser[label](node) local ret=parser[label](node)
if ret==nil then if ret==nil then
error("Error parsing:"..label.." nil returned!") error("Error parsing:"..label.." nil returned!")

@ -1,19 +1,19 @@
#include "lua_Offsets.h" #include "lua_Offsets.h"
#include <string.h> #include <string.h>
#include <stdint.h>
//TODO make a seperate module with peeks/pokes and page permisions (linux/windows spec) //TODO make a seperate module with peeks/pokes and page permisions (linux/windows spec)
//TODO maybe remove alltogether- use DFHack::Process instead? //TODO maybe remove alltogether- use DFHack::Process instead?
unsigned char peekb(size_t offset) template <typename T>
{ T engine_peek(size_t offset)
return *((unsigned char*)(offset));
}
unsigned short peekw(size_t offset)
{ {
return *((unsigned short*)(offset)); return *(reinterpret_cast<T*>(offset));
} }
unsigned peekd(size_t offset) template <typename T>
void engine_poke(size_t offset,T val)
{ {
return *((unsigned*)(offset)); *(reinterpret_cast<T*>(offset))=val;
} }
void peekarb(size_t offset, void *mem,size_t size) void peekarb(size_t offset, void *mem,size_t size)
{ {
memcpy(mem,(void*)offset,size); memcpy(mem,(void*)offset,size);
@ -22,18 +22,6 @@ void peekstr(size_t offset, char* buf, size_t maxsize)
{ {
strncpy(buf,(char*)offset,maxsize); strncpy(buf,(char*)offset,maxsize);
} }
void pokeb(size_t offset,unsigned char val)
{
*((unsigned char*)(offset))=val;
}
void pokew(size_t offset,unsigned short val)
{
*((unsigned short*)(offset))=val;
}
void poked(size_t offset,unsigned val)
{
*((unsigned*)(offset))=val;
}
void pokearb(size_t offset, void *mem,size_t size) void pokearb(size_t offset, void *mem,size_t size)
{ {
memcpy((void*)offset,mem,size); memcpy((void*)offset,mem,size);
@ -42,31 +30,42 @@ void pokestr(size_t offset, char* buf, size_t maxsize)
{ {
strncpy((char*)offset,buf,maxsize); strncpy((char*)offset,buf,maxsize);
} }
template <typename T>
T peek(size_t offset) //prob lower performance
{
T tmp;
peekarb(offset,&tmp,sizeof(T));
return tmp;
}
//// lua stuff here //// lua stuff here
static int lua_peekb(lua_State *L) static int lua_peekb(lua_State *L)
{ {
lua::state st(L); lua::state st(L);
st.push(peekb(st.as<size_t>(1))); st.push(engine_peek<uint8_t>(st.as<size_t>(1)));
return 1;
}
static int lua_peekw(lua_State *L)
{
lua::state st(L);
st.push(engine_peek<uint16_t>(st.as<size_t>(1)));
return 1; return 1;
} }
static int lua_peekd(lua_State *L) static int lua_peekd(lua_State *L)
{ {
lua::state st(L); lua::state st(L);
st.push(peekd(st.as<size_t>(1))); st.push(engine_peek<uint32_t>(st.as<size_t>(1)));
return 1; return 1;
} }
static int lua_peekw(lua_State *L) static int lua_peekq(lua_State *L)
{
lua::state st(L);
st.push(engine_peek<uint64_t>(st.as<size_t>(1)));
return 1;
}
static int lua_peekfloat(lua_State *L)
{
lua::state st(L);
st.push(engine_peek<float>(st.as<size_t>(1)));
return 1;
}
static int lua_peekdouble(lua_State *L)
{ {
lua::state st(L); lua::state st(L);
st.push(peekw(st.as<size_t>(1))); st.push(engine_peek<double>(st.as<size_t>(1)));
return 1; return 1;
} }
static int lua_peekarb(lua_State *L) static int lua_peekarb(lua_State *L)
@ -88,38 +87,53 @@ static int lua_peekstr(lua_State *L)
delete [] buf; delete [] buf;
return 1; return 1;
} }
/*static int lua_peekarb(lua_State *L) static int lua_peekstr2(lua_State *L)
{ {
lua::state st(L); lua::state st(L);
st.push(peekarb(st.as<DWORD>(1))); st.push(engine_peek<std::string>(st.as<size_t>(1)));
return 1; return 1;
}*/ }
static int lua_pokeb(lua_State *L) static int lua_pokeb(lua_State *L)
{ {
lua::state st(L); lua::state st(L);
pokeb(st.as<size_t>(1),st.as<size_t>(2)); engine_poke<uint8_t>(st.as<size_t>(1),st.as<uint8_t>(2));
return 0;
}
static int lua_pokew(lua_State *L)
{
lua::state st(L);
engine_poke<uint16_t>(st.as<size_t>(1),st.as<uint16_t>(2));
return 0; return 0;
} }
static int lua_poked(lua_State *L) static int lua_poked(lua_State *L)
{ {
lua::state st(L); lua::state st(L);
poked(st.as<size_t>(1),st.as<size_t>(2)); engine_poke<uint32_t>(st.as<size_t>(1),st.as<uint32_t>(2));
return 0; return 0;
} }
static int lua_pokew(lua_State *L) static int lua_pokeq(lua_State *L)
{ {
lua::state st(L); lua::state st(L);
pokew(st.as<size_t>(1),st.as<size_t>(2)); engine_poke<uint64_t>(st.as<size_t>(1),st.as<uint64_t>(2));
return 0;
}
static int lua_pokefloat(lua_State *L)
{
lua::state st(L);
engine_poke<float>(st.as<size_t>(1),st.as<float>(2));
return 0;
}
static int lua_pokedouble(lua_State *L)
{
lua::state st(L);
engine_poke<double>(st.as<size_t>(1),st.as<double>(2));
return 0; return 0;
} }
static int lua_pokearb(lua_State *L) static int lua_pokearb(lua_State *L)
{ {
lua::state st(L); lua::state st(L);
void *p=(void *)lua_touserdata(L, 2);//st.as<lua::userdata>(2); void *p=(void *)lua_touserdata(L, 2);//st.as<lua::userdata>(2);
size_t size=st.as<size_t>(3); size_t size=st.as<size_t>(3);
pokearb(st.as<size_t>(1),p,size); pokearb(st.as<size_t>(1),p,size);
return 0; return 0;
} }
@ -130,18 +144,36 @@ static int lua_pokestr(lua_State *L)
pokestr(st.as<size_t>(1),(char*)trg.c_str(),trg.size()); pokestr(st.as<size_t>(1),(char*)trg.c_str(),trg.size());
return 0; return 0;
} }
static int lua_pokestr2(lua_State *L)
{
lua::state st(L);
std::string trg=st.as<std::string>(2);
engine_poke<std::string>(st.as<size_t>(1),trg);
return 0;
}
const luaL_Reg lua_engine_func[]= const luaL_Reg lua_engine_func[]=
{ {
{"peekb",lua_peekb}, {"peekb",lua_peekb},
{"peekw",lua_peekw}, {"peekw",lua_peekw},
{"peekd",lua_peekd}, {"peekd",lua_peekd},
{"peekq",lua_peekq},
{"peekfloat",lua_peekfloat},
{"peekdouble",lua_peekdouble},
{"peekarb",lua_peekarb}, {"peekarb",lua_peekarb},
{"peekstr",lua_peekstr}, {"peekstr",lua_peekstr},
{"peekstr2",lua_peekstr2},
{"pokeb",lua_pokeb}, {"pokeb",lua_pokeb},
{"pokew",lua_pokew}, {"pokew",lua_pokew},
{"poked",lua_poked}, {"poked",lua_poked},
{"pokeq",lua_pokeq},
{"pokefloat",lua_pokefloat},
{"pokedouble",lua_pokedouble},
{"pokearb",lua_pokearb}, {"pokearb",lua_pokearb},
{"pokestr",lua_pokestr}, {"pokestr",lua_pokestr},
{"pokestr2",lua_pokestr2},
{NULL,NULL} {NULL,NULL}
}; };