wishful/mods/wislib/lua5_1/io.lua
2025-02-07 14:39:37 -05:00

125 lines
4.5 KiB
Lua

--context is always -eq to the highest possible subfolder in the mods dir, this can be ether the mod or modpack root folder.
local DIR_DELIM = debug.getinfo(1, "S").source:match("[\\/]")
local context = debug and debug.getinfo(1, "S").source:match("mods[/\\][/\\]?([^/]*)") or "context"
local cwdpath = minetest and (minetest.get_modpath(minetest.get_current_modname()) .. DIR_DELIM .. "lua5_1") or debug.getinfo(1, "S").source:match("^(.+)[/\\]"):sub(2)
--setup lib env
local print = _G[context]["log"]
--some string function moved here, for more info see: string.lua
function string:trim()
return self:match("^%s*(.-)%s*$")
end
--[[
function string:split (p2Sep, p3Patern)
if p2Sep == nil then
p2Sep = "%s"
end
if p3Patern == nil then
p3Patern = table.concat({"([^", p2Sep, "]+)"}, "")
end
local returns = {}
for _ in string.gmatch(self, p3Patern) do
table.insert(returns, _)
end
return returns
end
--]]
function string:startsWith(p2Needle) -- self == haystack
return self:sub(1, #p2Needle) == p2Needle
end
function string:endsWith(p2Needle) -- self == haystack
return p2Needle == "" or self:sub(-#p2Needle) == p2Needle
end
function string:charCount(p2Char)
local count = 0
for _ in string.gmatch(self, p2Char) do
count = count + 1
end
return count
end
--end string.lua snipet
_G[context].colors ={
reset = "\27[0m",
red = "\27[31m",
green = "\27[32m",
yellow = "\27[33m",
blue = "\27[34m",
magenta = "\27[35m",
cyan = "\27[36m",
white= "\27[37m"
}
_G[context].forFileAsLines=function(filePath, funcHandle, ignoreReturn)
local file = io.open(filePath, "r")
--if file is context:open then
local returns = {}
if not file then error(_G[context].colors.red.."access error: reading non-existant file, @" .._G[context].colors.cyan ..filePath.._G[context].colors.reset) end
if file then
--itarate over each line and pass to funkyFunc
for line in file:lines() do
local linedata=line:trim()--:sub(1,-2) --remove spooky char at the end of a line. If file uses \r\n, it may require (1,-3)
linedata=funcHandle and (funcHandle(linedata)) or linedata --buggy:TODO
--this data subject to brakeages, test for errors here:
--print("<"..linedata..">")
if not ignoreReturn then --used for large files, to avoid memory bloat.
table.insert(returns, linedata)
end
end
file:close()
return returns
else
return {}
end
end
--
_G[context].forFileAsIniObj = function(filePath, ignoreHeaders)
local debug_print=false
local returns = {} --object to store data about ini file as a hashmap table
returns[""]={} --default object to store global values before a header tag('[' or ']') is found in the file stream
local rpointer = "" -- by default pointer set to "" by default
local _ = debug_print and print("<"..filePath..">")
local _ = _G[context].forFileAsLines(filePath, function (line)
--in ini, ';' may be used as a comment by default.
--in the future this may be abstracted into a larger function with more customization
if not line:startsWith(";") and string.charCount(line, " ") ~= #line and #line ~= 0 then --discard comments or empty lines
--if is header "[*]"
local _ = debug_print and print(line)
if line:match("^%[.*%]$") then
if not ignoreHeaders then
rpointer = line:sub(2,-2):trim() --remove [ and ] from the header and use as str:returnPointer
returns[rpointer]= returns[rpointer] or {}
end
--else if is key value pair "*=*"
elseif line:match("^.+=.+$") and line:charCount("=") == 1 then
local spointerarray = line:split("=")
spointerarray[1]=spointerarray[1]:trim()
spointerarray[2]=spointerarray[2]:trim()
--If parser fails due to missing '"', use raw string as a fall back.
--minetest.parse_json create an unmutable error with no way to prevent it,
--just return as string ill deal with this later. :(
--Upon reflection this function should always return a string,
--since it may be used in multiple use case and so should leave parsing decisions to the caller
--_G[context].parse(spointerarray[2]) or
returns[rpointer][spointerarray[1]] = spointerarray[2]
else --else is error
error(table.concat({"error reading: ", filePath, "@^", line, "$"},""))
end
end
end, true)
--if the global array table was never used, delete it.
if #returns[""] == 0 and true then
returns[""]=nil
end
return returns
end
--Why the fuck is "true" true in the context of a conditional, is lua just as bad as javascript?
assert(true == _G[context].parse(_G[context].forFileAsIniObj(cwdpath..DIR_DELIM.."test.ini", false)["testdata"]["success"]))