Files
itgmania212121/Themes/_fallback/Scripts/01 IniFile.lua
T
Dan Guzek 666cdb40bd IniFile fix: checking for false ~= checking for nil
false is a perfectly valid setting for one of SM's ini files.  The code here needs to ensure that both the key (string) and the value (string, numeric, boolean) read from file exist.  It would previously halt if the value was set to false.  This fixes that by explicitly checking for nil.
2015-04-06 21:01:52 -04:00

135 lines
3.5 KiB
Lua

--[[
IniFile: basically a Lua rewrite of SM's IniFile class that serves as the
basis for the sm-ssc UserPrefs and ThemePrefs configuration systems.
Note that this is a namespace, not a class per se.
--]]
-- TODO: move this into a more general section
-- func takes a key and a value
function foreach_by_sorted_keys(tbl, keys, func)
table.sort(keys)
for _, key in ipairs(keys) do func(key, tbl[key]) end
end
function foreach_ordered( tbl, func )
local string_keys= {}
local number_keys= {}
-- First person to to use this on a table that uses something else as keys
-- gets to extend this function to cover more types. And a beating. -Kyz
for k,_ in pairs(tbl) do
if type(k) == "string" then
table.insert(string_keys, k)
elseif type(k) == "number" then
table.insert(number_keys, k)
end
end
-- iterate in sorted order
foreach_by_sorted_keys(tbl, number_keys, func)
foreach_by_sorted_keys(tbl, string_keys, func)
end
-- redeclared here for my sanity's sake
-- TODO: declare these as global variables
local RageFile =
{
READ = 1,
WRITE = 2,
STREAMED = 4,
SLOW_FLUSH = 8
}
-- IniFile namespace
IniFile =
{
StrToKeyVal = function( str )
local key, value = str:match( "(.+)=(.*)" )
-- key is always a string, but value may be num, bool, or nil.
-- do a few quick checks to see which one it is.
-- if it's a nil, convert it to an empty string and return
if value == nil then value = ""; return key, value; end
-- if it's a number, convert it in place and return
if tonumber(value) ~= nil then value = tonumber(value); return key, value; end
-- not a number, so let's try a boolean value
if value == "true" then value = true;
elseif value == "false" then value = false;
end
return key, value
end,
ReadFile = function( file_path )
Trace( "IniFile.ReadFile( " .. file_path .. " )" )
local file = RageFileUtil.CreateRageFile()
if not file:Open(file_path, RageFile.READ) then
Warn( string.format("ReadFile(%s): %s",file_path,file:GetError()) )
file:destroy()
return { } -- return a blank table
end
local tbl = { }
local current = tbl
while not file:AtEOF() do
local str = file:GetLine()
--ignore comments.
if not str:find("^%s*#") then
-- is this a section?
local sec = str:match( "%[(.+)%]" )
-- if so, set focus there; otherwise, try to
-- read a key/value pair (ignore blank lines)
if sec then
-- if this section doesn't exist, create it
tbl[sec] = tbl[sec] and tbl[sec] or { }
current = tbl[sec]
--Warn( "Switching section to " .. sec )
else
local k, v = IniFile.StrToKeyVal( str )
if k and v ~= nil then current[k] = v end
end
end
end
file:Close()
file:destroy()
return tbl
end,
WriteFile = function( file_path, tbl )
Trace( "IniFile.WriteFile( " .. file_path .. " )" )
local file = RageFileUtil.CreateRageFile()
if not file:Open(file_path, RageFile.WRITE) then
Warn( string.format("WriteFile(%s): %s",file_path.file:GetError()) )
file:destroy()
return false
end
-- declare functions so we can write with foreach_ordered
local function put_pair( k, v )
file:PutLine( string.format("%s=%s", k, tostring(v)) )
end
local function put_section( section, pair )
file:PutLine( "[" .. section .. "]" )
foreach_ordered( pair, put_pair )
file:PutLine("") -- put a blank line between sections
end
-- each base key is a section and its value is a
-- table of key-value pairs under that section.
foreach_ordered( tbl, put_section )
file:Close()
file:destroy()
return true
end
};