In addition to the standard modules installed with Family Historian, Lua has a range of additional modules available. In ƒh7 many of these are installed with the programme, but in ƒh6, they may need to be downloaded before use. See Lua References and Library Modules for details of which libraries are available and how.
If you require additional modules for ƒh6, please contact [email protected] requesting the module to be added to the repository.
Requires: lfs and luacom
Updated code (multiple sub-directories)
require 'lfs'
require 'luacom'
local function httpRequest(url)
local http = luacom.CreateObject("winhttp.winhttprequest.5.1")
http:Open("GET",url,false)
http:Send()
http:WaitForResponse(30)
return http
end -- local function httpRequest
function loadrequire(module,extended)
if not(extended) then extended = module end
local function installmodule(module,filename,size)
local function makesubdirs(path)
local sep, pStr = package.config:sub(1, 1), ""
for dir in path:gmatch("[^" .. sep .. "]+") do
pStr = pStr .. dir .. sep
lfs.mkdir(pStr)
end
end
local bmodule = false
if not(filename) then
filename = module..'.mod'
bmodule = true
end
local storein = fhGetContextInfo('CI_APP_DATA_FOLDER')..'\\Plugins\\'
-- Check if subdirectory needed
local path = string.match(filename, "(.-)[^/]-[^%.]+$")
if path ~= "" then
path = path:gsub('/','\\')
-- Create sub-directory
makesubdirs(storein..path)
end
local attr = lfs.attributes(storein..filename)
if attr and attr.mode == 'file' and attr.size == size then return true end
-- Get file down and install it
local url = "http://www.family-historian.co.uk/lnk/getpluginmodule.php?file="..filename
local isOK, reply = pcall(httpRequest,url)
if not isOK then
fhMessageBox(reply.."\nLoad Require module finds the Internet inaccessible.")
return false
end
local http = reply
local status = http.StatusText
if status == 'OK' then
length = http:GetResponseHeader('Content-Length')
data = http.ResponseBody
if bmodule then
local modlist = loadstring(http.ResponseBody)
for x,y in pairs(modlist()) do
if type(x) == 'number' and type(y) == 'string' then
x = y -- revert to original 'filename' ipairs modlist
y = 0
end -- otherwise use ['filename']=size pairs modlist
if not(installmodule(module,x,y)) then
break
end
end
else
local function OpenFile(strFileName,strMode)
local fileHandle, strError = io.open(strFileName,strMode)
if not fileHandle then
error("\n Unable to open file in \""..strMode.."\" mode. \n "..
strFileName.." \n "..tostring(strError).." \n")
end
return fileHandle
end -- OpenFile
local function SaveStringToFile(strString,strFileName)
local fileHandle = OpenFile(strFileName,"wb")
fileHandle:write(strString)
assert(fileHandle:close())
end -- SaveStringToFile
SaveStringToFile(data,storein..filename)
end
return true
else
fhMessageBox('An error occurred in Download, so please try later')
return false
end
end
local function requiref(module)
require(module)
end
local res, err = pcall(requiref,extended)
if err then
if err:match("module '"..extended:gsub("(%W)","%%%1").."' not found") then
local ans = fhMessageBox(
'This plugin requires '..module..' support, please click OK to download and install the module, which may take a few minutes in some systems',
'MB_OKCANCEL','MB_ICONEXCLAMATION')
if ans ~= 'OK' then
return false
end
if installmodule(module) then
package.loaded[extended] = nil -- Reset Failed Load
require(extended)
else
return false
end
else
fhMessageBox('Error from require("'..module..'") command:\n'..(err or ''))
return false
end
end
return true
end
Code (single sub-directory)
require 'lfs'
require 'luacom'
local function httpRequest(url)
local http = luacom.CreateObject("winhttp.winhttprequest.5.1")
http:Open("GET",url,false)
http:Send()
http:WaitForResponse(30)
return http
end -- local function httpRequest
function loadrequire(module,extended)
if not(extended) then extended = module end
local function installmodule(module,filename,size)
local bmodule = false
if not(filename) then
filename = module..'.mod'
bmodule = true
end
local storein = fhGetContextInfo('CI_APP_DATA_FOLDER')..'\\Plugins\\'
-- Check if subdirectory needed
local path = string.match(filename, "(.-)[^/]-[^%.]+$")
if path ~= "" then
path = path:gsub('/','\\')
-- Create sub-directory
lfs.mkdir(storein..path)
end
local attr = lfs.attributes(storein..filename)
if attr and attr.mode == 'file' and attr.size == size then return true end
-- Get file down and install it
local url = "http://www.family-historian.co.uk/lnk/getpluginmodule.php?file="..filename
local isOK, reply = pcall(httpRequest,url)
if not isOK then
fhMessageBox(reply.."\nLoad Require module finds the Internet inaccessible.")
return false
end
local http = reply
local status = http.StatusText
if status == 'OK' then
length = http:GetResponseHeader('Content-Length')
data = http.ResponseBody
if bmodule then
local modlist = loadstring(http.ResponseBody)
for x,y in pairs(modlist()) do
if type(x) == 'number' and type(y) == 'string' then
x = y -- revert to original 'filename' ipairs modlist
y = 0
end -- otherwise use ['filename']=size pairs modlist
if not(installmodule(module,x,y)) then
break
end
end
else
local function OpenFile(strFileName,strMode)
local fileHandle, strError = io.open(strFileName,strMode)
if not fileHandle then
error("\n Unable to open file in \""..strMode.."\" mode. \n "..
strFileName.." \n "..tostring(strError).." \n")
end
return fileHandle
end -- OpenFile
local function SaveStringToFile(strString,strFileName)
local fileHandle = OpenFile(strFileName,"wb")
fileHandle:write(strString)
assert(fileHandle:close())
end -- SaveStringToFile
SaveStringToFile(data,storein..filename)
end
return true
else
fhMessageBox('An error occurred in Download, so please try later')
return false
end
end
local function requiref(module)
require(module)
end
local res, err = pcall(requiref,extended)
if err then
if err:match("module '"..extended:gsub("(%W)","%%%1").."' not found") then
local ans = fhMessageBox(
'This plugin requires '..module..' support, please click OK to download and install the module, which may take a few minutes in some systems',
'MB_OKCANCEL','MB_ICONEXCLAMATION')
if ans ~= 'OK' then
return false
end
if installmodule(module) then
package.loaded[extended] = nil -- Reset Failed Load
require(extended)
else
return false
end
else
fhMessageBox('Error from require("'..module..'") command:\n'..(err or ''))
return false
end
end
return true
end
-
Usage
Instead of a simple require statement, use the following and the module will be checked for and installed if required.
-- Standard Modules if not( loadrequire( 'md5' ) ) then return end if not( loadrequire( 'zip' ) ) then return end -- LuaSql and other modules with extensions need the module to load to be specified e.g. if not( loadrequire( 'luasql', 'luasql.sqlite3' ) ) then return end if not( loadrequire( 'pl', 'pl.init' ) ) then return end pl = require 'pl.import_into'()