diff --git a/config.go b/config.go index 4eda27c3..f1bd3723 100644 --- a/config.go +++ b/config.go @@ -20,15 +20,21 @@ var LuaPath = "LUA_PATH" var LuaLDir string var LuaPathDefault string var LuaOS string +var LuaCDir string +var LuaCPathDefault string func init() { if os.PathSeparator == '/' { // unix-like LuaOS = "unix" LuaLDir = "/usr/local/share/lua/5.1" LuaPathDefault = "./?.lua;" + LuaLDir + "/?.lua;" + LuaLDir + "/?/init.lua" + LuaCDir = "/usr/local/lib/glua/5.1" + LuaCPathDefault = "./?.so;" + LuaCDir + "/?.so;" + LuaCDir + "/loadall.so;" } else { // windows LuaOS = "windows" LuaLDir = "!\\lua" LuaPathDefault = ".\\?.lua;" + LuaLDir + "\\?.lua;" + LuaLDir + "\\?\\init.lua" + LuaCDir = "!\\" + LuaPathDefault = ".\\?.dll;" + LuaCDir + "\\?.dll;" + LuaCDir + "\\?\\loadall.dll" } } diff --git a/loadlib.go b/loadlib.go index dc67e20d..c9fa7ba4 100644 --- a/loadlib.go +++ b/loadlib.go @@ -4,12 +4,16 @@ import ( "fmt" "os" "path/filepath" + "plugin" + "regexp" "strings" ) /* load lib {{{ */ -var loLoaders = []LGFunction{loLoaderPreload, loLoaderLua} +const loRegPrefix = "LOADLIB: " + +var loLoaders = []LGFunction{loLoaderPreload, loLoaderLua, loLoaderC} func loGetPath(env string, defpath string) string { path := os.Getenv(env) @@ -46,6 +50,58 @@ func loFindFile(L *LState, name, pname string) (string, string) { return "", strings.Join(messages, "\n\t") } +func loRegister(L *LState, path string) *LUserData { + rname := loRegPrefix + path + reg := L.Get(RegistryIndex).(*LTable) + r := reg.RawGetString(rname) + if r != LNil { + return r.(*LUserData) + } + plib := L.NewUserData() + plib.Value = nil + L.SetMetatable(plib, L.GetMetatable(reg)) + reg.RawSetString(rname, plib) + return plib +} + +func loSym(L *LState, ud *LUserData, sym string) (*LFunction, error) { + p := ud.Value.(*plugin.Plugin) + f, err := p.Lookup(sym) + if err != nil { + return nil, err + } + return L.NewFunction(f.(func(*LState) int)), nil +} + +func loLoadFunc(L *LState, path, sym string) (*LFunction, error) { + ud := loRegister(L, path) + if ud.Value == nil { + p, err := plugin.Open(path) + if err != nil { + return nil, err + } + ud.Value = p + } + + f, err := loSym(L, ud, sym) + if err != nil { + return nil, err + } + return f, nil +} + +func loMakeFuncName(s string) string { + re := regexp.MustCompile("^[^\\-]*\\-") + name := re.ReplaceAllString(s, "") + + re = regexp.MustCompile("\\.(\\w)") + + funcname := re.ReplaceAllStringFunc(name, func(s string) string { + return strings.ToUpper(re.FindStringSubmatch(s)[1]) + }) + return "LuaOpen" + strings.Title(funcname) +} + func OpenPackage(L *LState) int { packagemod := L.RegisterModule(LoadLibName, loFuncs) @@ -104,9 +160,37 @@ func loLoaderLua(L *LState) int { return 1 } +func loLoaderC(L *LState) int { + name := L.CheckString(1) + path, msg := loFindFile(L, name, "cpath") + if len(path) == 0 { + L.Push(LString(msg)) + return 1 + } + f, err := loLoadFunc(L, path, loMakeFuncName(name)) + if err != nil { + L.RaiseError(err.Error()) + } + L.Push(f) + return 1 +} + func loLoadLib(L *LState) int { - L.RaiseError("loadlib is not supported") - return 0 + path := L.CheckString(1) + init := L.CheckString(2) + f, err := loLoadFunc(L, path, init) + if err != nil { + L.Push(LNil) + L.Push(LString(err.Error())) + if strings.Contains(err.Error(), "plugin.Open") { + L.Push(LString("open")) + } else { + L.Push(LString("init")) + } + return 3 + } + L.Push(f) + return 1 } func loSeeAll(L *LState) int {