config.lua
--[[---------------------------------------------------------------------------
Functions for saving/loading config data
This module is a lua script (config.lua), you need to explicitly load it
with require('config')
@module config
]]
config = {}
config.configs = {}
config.__index = config
--[[---------------------------------------------------------------------------
Create a new config instance, filename will be determined automagically
@param default the default data values
@function create
]]
function config.create(default)
--determine the config filename automatically based on the script's filename
return create_internal(default, debug.getinfo(2,"S").short_src)
end
local create_internal = function(default,thisfile)
local cfg = {}
assert(thisfile ~= nil, "Could not determine script filename")
--capture between the last '/' and last '.' in the filename
local short_name = string.match(thisfile,"/([^/%.]+)%.[^/%.]+$")
cfg.filename = string.format("%s%s.cfg", dryos.config_dir.path,short_name)
assert(thisfile ~= cfg.filename, "Could not determine config filename")
cfg.default = default
setmetatable(cfg,config)
cfg.data = cfg:load()
table.insert(config.configs, cfg)
if event.config_save == nil then
event.config_save = function(unused)
for i,v in ipairs(config.configs) do
v:saving()
v:save()
end
end
end
return cfg
end
--[[---------------------------------------------------------------------------
@type config
]]
--[[---------------------------------------------------------------------------
Get/Set the data to store to configuration
@field data
]]
--[[---------------------------------------------------------------------------
Create a new config instance from a menu structure, filename will be determined
automagically
@param m the menu to create a config for
@function create_from_menu
]]
function config.create_from_menu(m)
local default = {}
--default values are simply the menu's default values
default[m.name] = m.value
if m.submenu ~= nil then
--todo: recurse into sub-submenus
for k,v in pairs(m.submenu) do
default[k] = v.value
end
end
local cfg = create_internal(default,debug.getinfo(2,"S").short_src)
cfg.menu = m
--copy back loaded data to the menu structure
m.value = cfg.data[m.name]
if m.submenu ~= nil then
--todo: recurse into sub-submenus
for k,v in pairs(m.submenu) do
v.value = cfg.data[k]
end
end
return cfg
end
--[[---------------------------------------------------------------------------
Load the config data from file (by executing the file)
@function load
]]
function config:load()
local status,result = pcall(dofile,self.filename)
if status and result ~= nil then
return result
else
print(result)
return self.default
end
end
--[[---------------------------------------------------------------------------
Called right before config data is saved to file, override this function to
update your config.data when the config is being saved
@function saving
]]
function config:saving()
--default implementation: save menu structure if there is one
if self.menu ~= nil then
self.data[self.menu.name] = self.menu.value
if self.menu.submenu ~= nil then
for k,v in pairs(self.menu.submenu) do
self.data[k] = v.value
end
end
end
end
--[[---------------------------------------------------------------------------
Manually save the config data to file (data is saved automatically when the
ML backend does it's config saving, so calling this function is unecessary
unless you want to do a manual save).
Whatever is in the 'data' field of this instance is saved. Only numbers,
strings and tables can be saved (no functions, threads or userdata)
@function save
]]
function config:save()
local f = io.open(self.filename,"w")
f:write("return ")
assert(f ~= nil, "Could not save config: "..self.filename)
config.serialize(f,self.data)
f:close()
end
--private
function config.serialize(f,o)
if type(o) == "number" then
f:write(o)
elseif type(o) == "string" then
f:write(string.format("%q", o))
elseif type(o) == "table" then
f:write("{\n")
for k,v in pairs(o) do
f:write(" [")
config.serialize(f,k)
f:write("] = ")
config.serialize(f,v)
f:write(",\n")
end
f:write("}\n")
else
--something we don't know how to serialize, just skip it
end
end
return config