implemented platform specific code

implemented filesys module
added an rfind function to globals.lua
This commit is contained in:
Hersi 2022-08-11 03:15:01 +02:00
parent 0e49837e18
commit 90580a9b61
6 changed files with 277 additions and 0 deletions

17
scripts/api/filesys.lua Normal file
View File

@ -0,0 +1,17 @@
require "api.platform"
local FileSys = require "api.platform.filesys_impl"
if os.name() == Platform.WINDOWS then
require "api.platform.win.filesys"
elseif os.name() == Platform.LINUX then
require "api.platform.linux.filesys"
elseif os.name() == Platform.MACOS then
game.Log("MacOS specific implementation missing, loading linux filesys module", game.LOGGER_WARNING)
require "api.platform.linux.filesys"
else
game.Log("OS Platform not recognized, loading linux filesys module", game.LOGGER_WARNING)
require "api.platform.linux.filesys"
end
return FileSys

39
scripts/api/platform.lua Normal file
View File

@ -0,0 +1,39 @@
---@note setup code from: https://stackoverflow.com/a/30960054
local BinaryFormat = package.cpath:match("%p[\\|/]?%p(%a+)")
if BinaryFormat == "dll" then
function os.name()
return "Windows"
end
elseif BinaryFormat == "so" then
function os.name()
return "Linux"
end
elseif BinaryFormat == "dylib" then
function os.name()
return "MacOS"
end
end
BinaryFormat = nil
Platform = {
WINDOWS = "Windows",
LINUX = "Linux",
MACOS = "MacOS"
}
---Get OS platform lua is running on
function GetPlatform()
return os.name()
end
---Merge base module table with implementation table, overwriting base
---@param base any
---@param implementation any
function MergeModules(base, implementation)
for key, value in pairs(implementation) do
base[key] = value
end
end

View File

@ -0,0 +1,126 @@
require "common.globals"
---@class FileSys
local FileSys = {
__name = "FileSys",
sep = "/"
}
---Return a normalized absolutized version of `path`
---@param path string
---@return string
function FileSys.abspath(path)
return FileSys.normpath(FileSys.join(FileSys.getcwd(), path))
end
---Return the base name of `path`
---@param path string
---@return string
function FileSys.basename(path)
return string.sub(path, string.rfind(path, FileSys.sep, 1, true) + 1)
end
---Return the directory name of `path`
---@param path string
---@return string
function FileSys.dirname(path)
return FileSys.split(path)[1]
end
---Return true if `path` refers to an existing path
---@param path string
---@return boolean, string?
function FileSys.exists(path)
local ok, err, code = os.rename(path, path)
if not ok then
game.Log("err: "..err..", code: "..code, game.LOGGER_DEBUG)
if code == 13 then
-- Permission denied, but it exists
return true
end
end
return ok, err
end
---Return a string representing the current working directory
---@return string
function FileSys.getcwd()
assert(false, FileSys.__name .. ".getcwd() : Not Implemented")
return ""
end
---Join one or more path components with the platform specific separator
---@param path string
---@param ... string
---@return string
function FileSys.join(path, ...)
local vargs = { select(1, ...) }
local joinedpath = path
for _, value in ipairs(vargs) do
joinedpath = joinedpath .. FileSys.sep .. value
end
return joinedpath
end
---Normalize `path`, collapse redundant separators and up references
---@param path string
---@return string
function FileSys.normpath(path)
local sep = FileSys.sep
--remove multiple slashes
path = path:gsub("("..sep..")"..sep.."+", "%1")
--remove './'
path = path:gsub("%."..sep, "")
--remove all up references
local count = 0
local upRefPattern = "%w+"..sep.."%.%."..sep
repeat
path, count = path:gsub(upRefPattern, "")
until count ~= 0
--remove last slash
path = path:gsub("(.-)"..sep.."$", "%1")
return path
end
---Return a relative filepath to `path`, optionally relative to `relativeTo`
---@param path string
---@param relativeTo? string
---@return string
function FileSys.relpath(path, relativeTo)
relativeTo = relativeTo or FileSys.getcwd()
path = path:sub(path:find(relativeTo, 1, true)[2] + 1)
return path
end
---Return a list of files and directory names in `path`
---@param path string
---@return string[]
function FileSys.scandir(path)
assert(false, FileSys.__name .. ".scandir() : Not Implemented")
return {}
end
---Split `path` to (head, tail), tail is the last component, head is everything else
---@param path string
---@return string, string
function FileSys.split(path)
local lastSep = path:rfind(FileSys.sep, 1, true)
return path:sub(1, lastSep), path:sub(lastSep + 1)
end
---Split `path` to (root, ext), such that `root + ext == path`, ext is either empty or starts with a '.'
---@param path string
---@return string, string
function FileSys.splitext(path)
local lastSep = path:rfind(".", 1, true)
return path:sub(1, lastSep - 1), path:sub(lastSep)
end
return FileSys

View File

@ -0,0 +1,37 @@
local FileSys = require "api.platform.filesys_impl"
FileSys.sep = "/"
function FileSys.getcwd()
local cwd, popen = "", io.popen
local pfile, err = popen("pwd")
if not pfile or err ~= 0 then
game.Log(tostring(FileSys) .. ".getcwd() : popen failed executing " .. tostring(err), game.LOGGER_ERROR)
return nil
end
cwd = pfile:read()
pfile:close()
return cwd
end
function FileSys.scandir(path)
local i, t, popen = 0, {}, io.popen
local pfile, err = popen('find "' .. path .. '" -maxdepth 1 -print0')
if not pfile or err ~= 0 then
game.Log(tostring(FileSys) .. ".scandir() : popen failed executing " .. tostring(err), game.LOGGER_ERROR)
return nil
end
for filename in pfile:lines() do
i = i + 1
t[i] = filename
end
pfile:close()
return t
end

View File

@ -0,0 +1,46 @@
local FileSys = require "api.platform.filesys_impl"
FileSys.sep = "\\"
function FileSys.getcwd()
local cwd, popen = "", io.popen
local pfile, err = popen("cd")
if not pfile or err ~= 0 then
game.Log(tostring(FileSys) .. ".getcwd() : popen failed executing " .. tostring(err), game.LOGGER_ERROR)
return nil
end
cwd = pfile:read()
pfile:close()
return cwd
end
local baseNormpath = FileSys.normpath
function FileSys.normpath(path)
path = baseNormpath(path)
path = path:gsub("/", "\\")
return path
end
function FileSys.scandir(path)
local i, t, popen = 0, {}, io.popen
local pfile, err = popen('dir "' .. path .. '" /b /ad')
if not pfile or err ~= 0 then
game.Log(tostring(FileSys) .. ".scandir() : popen failed executing " .. tostring(err), game.LOGGER_ERROR)
return nil
end
for filename in pfile:lines() do
i = i + 1
t[i] = filename
end
pfile:close()
return t
end

View File

@ -8,3 +8,15 @@ game.MOUSE_MIDDLE = 2
game.KNOB_LEFT = 0 game.KNOB_LEFT = 0
game.KNOB_RIGHT = 1 game.KNOB_RIGHT = 1
-- some cool extensions to the builtins ----------------------------------------
---Looks for the last match of pattern in the string.
---@param s string
---@param pattern string
---@param init? integer
---@param plain? boolean
function string.rfind(s, pattern, init, plain)
pattern = pattern:reverse()
return s:len() - s:reverse():find(pattern, init, plain) + 1
end