90 lines
2.3 KiB
Lua
90 lines
2.3 KiB
Lua
-- Helper wrappring script for loading shared object libac.so (FFI interface)
|
|
-- from package.cpath instead of LD_LIBRARTY_PATH.
|
|
--
|
|
|
|
local ffi = require 'ffi'
|
|
ffi.cdef[[
|
|
void* ac_create(const char** str_v, unsigned int* strlen_v,
|
|
unsigned int v_len);
|
|
int ac_match2(void*, const char *str, int len);
|
|
void ac_free(void*);
|
|
]]
|
|
|
|
local _M = {}
|
|
|
|
local string_gmatch = string.gmatch
|
|
local string_match = string.match
|
|
|
|
local ac_lib = nil
|
|
local ac_create = nil
|
|
local ac_match = nil
|
|
local ac_free = nil
|
|
|
|
--[[ Find shared object file package.cpath, obviating the need of setting
|
|
LD_LIBRARY_PATH
|
|
]]
|
|
local function find_shared_obj(cpath, so_name)
|
|
for k, v in string_gmatch(cpath, "[^;]+") do
|
|
local so_path = string_match(k, "(.*/)")
|
|
if so_path then
|
|
-- "so_path" could be nil. e.g, the dir path component is "."
|
|
so_path = so_path .. so_name
|
|
|
|
-- Don't get me wrong, the only way to know if a file exist is
|
|
-- trying to open it.
|
|
local f = io.open(so_path)
|
|
if f ~= nil then
|
|
io.close(f)
|
|
return so_path
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function _M.load_ac_lib()
|
|
if ac_lib ~= nil then
|
|
return ac_lib
|
|
else
|
|
local so_path = find_shared_obj(package.cpath, "libac.so")
|
|
if so_path ~= nil then
|
|
ac_lib = ffi.load(so_path)
|
|
ac_create = ac_lib.ac_create
|
|
ac_match = ac_lib.ac_match2
|
|
ac_free = ac_lib.ac_free
|
|
return ac_lib
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Create an Aho-Corasick instance, and return the instance if it was
|
|
-- successful.
|
|
function _M.create_ac(dict)
|
|
local strnum = #dict
|
|
if ac_lib == nil then
|
|
_M.load_ac_lib()
|
|
end
|
|
|
|
local str_v = ffi.new("const char *[?]", strnum)
|
|
local strlen_v = ffi.new("unsigned int [?]", strnum)
|
|
|
|
for i = 1, strnum do
|
|
local s = dict[i]
|
|
str_v[i - 1] = s
|
|
strlen_v[i - 1] = #s
|
|
end
|
|
|
|
local ac = ac_create(str_v, strlen_v, strnum);
|
|
if ac ~= nil then
|
|
return ffi.gc(ac, ac_free)
|
|
end
|
|
end
|
|
|
|
-- Return nil if str doesn't match the dictionary, else return non-nil.
|
|
function _M.match(ac, str)
|
|
local r = ac_match(ac, str, #str);
|
|
if r >= 0 then
|
|
return r
|
|
end
|
|
end
|
|
|
|
return _M
|