Files
winamp/Src/external_dependencies/openmpt-trunk/include/genie/src/base/path.lua
2024-09-24 14:54:57 +02:00

401 lines
8.0 KiB
Lua
Vendored

--
-- path.lua
-- Path manipulation functions.
-- Copyright (c) 2002-2010 Jason Perkins and the Premake project
--
--
-- Retrieve the filename portion of a path, without any extension.
--
function path.getbasename(p)
local name = path.getname(p)
local i = name:findlast(".", true)
if (i) then
return name:sub(1, i - 1)
else
return name
end
end
--
-- Retrieve the path, without any extension.
--
function path.removeext(name)
local i = name:findlast(".", true)
if (i) then
return name:sub(1, i - 1)
else
return name
end
end
--
-- Retrieve the directory portion of a path, or an empty string if
-- the path does not include a directory.
--
function path.getdirectory(p)
local i = p:findlast("/", true)
if (i) then
if i > 1 then i = i - 1 end
return p:sub(1, i)
else
return "."
end
end
--
-- Retrieve the drive letter, if a Windows path.
--
function path.getdrive(p)
local ch1 = p:sub(1,1)
local ch2 = p:sub(2,2)
if ch2 == ":" then
return ch1
end
end
--
-- Retrieve the file extension.
--
function path.getextension(p)
local i = p:findlast(".", true)
if (i) then
return p:sub(i)
else
return ""
end
end
--
-- Retrieve the filename portion of a path.
--
function path.getname(p)
local i = p:findlast("[/\\]")
if (i) then
return p:sub(i + 1)
else
return p
end
end
--
-- Returns the common base directory of two paths.
--
function path.getcommonbasedir(a, b)
a = path.getdirectory(a)..'/'
b = path.getdirectory(b)..'/'
-- find the common leading directories
local idx = 0
while (true) do
local tst = a:find('/', idx + 1, true)
if tst then
if a:sub(1,tst) == b:sub(1,tst) then
idx = tst
else
break
end
else
break
end
end
-- idx is the index of the last sep before path string 'a' ran out or didn't match.
local result = ''
if idx > 1 then
result = a:sub(1, idx - 1) -- Remove the trailing slash to be consistent with other functions.
end
return result
end
--
-- Returns true if the filename has a particular extension.
--
-- @param fname
-- The file name to test.
-- @param extensions
-- The extension(s) to test. Maybe be a string or table.
--
function path.hasextension(fname, extensions)
local fext = path.getextension(fname):lower()
if type(extensions) == "table" then
for _, extension in pairs(extensions) do
if fext == extension then
return true
end
end
return false
else
return (fext == extensions)
end
end
--
-- Returns true if the filename represents a C/C++ source code file. This check
-- is used to prevent passing non-code files to the compiler in makefiles. It is
-- not foolproof, but it has held up well. I'm open to better suggestions.
--
function path.iscfile(fname)
return path.hasextension(fname, { ".c", ".m" })
end
function path.iscppfile(fname)
return path.hasextension(fname, { ".cc", ".cpp", ".cxx", ".c++", ".c", ".m", ".mm" })
end
function path.iscxfile(fname)
return path.hasextension(fname, ".cx")
end
function path.isobjcfile(fname)
return path.hasextension(fname, { ".m", ".mm" })
end
function path.iscppheader(fname)
return path.hasextension(fname, { ".h", ".hh", ".hpp", ".hxx" })
end
function path.iscppmodule(fname)
return path.hasextension(fname, { ".ixx", ".cppm" })
end
function path.isappxmanifest(fname)
return path.hasextension(fname, ".appxmanifest")
end
function path.isandroidbuildfile(fname)
return path.getname(fname) == "AndroidManifest.xml"
end
function path.isnatvis(fname)
return path.hasextension(fname, ".natvis")
end
function path.isasmfile(fname)
return path.hasextension(fname, { ".asm", ".s", ".S" })
end
function path.isvalafile(fname)
return path.hasextension(fname, ".vala")
end
function path.isgresource(fname)
local ending = ".gresource.xml"
return ending == "" or fname:sub(-#ending) == ending
end
function path.isswiftfile(fname)
return path.hasextension(fname, ".swift")
end
function path.issourcefile(fname)
return path.iscfile(fname)
or path.iscppfile(fname)
or path.iscxfile(fname)
or path.isasmfile(fname)
or path.isvalafile(fname)
or path.isswiftfile(fname)
end
function path.issourcefilevs(fname)
return path.hasextension(fname, { ".cc", ".cpp", ".cxx", ".c++", ".c" })
or path.iscxfile(fname)
or path.iscppmodule(fname)
end
--
-- Returns true if the filename represents a compiled object file. This check
-- is used to support object files in the "files" list for archiving.
--
function path.isobjectfile(fname)
return path.hasextension(fname, { ".o", ".obj" })
end
--
-- Returns true if the filename represents a Windows resource file. This check
-- is used to prevent passing non-resources to the compiler in makefiles.
--
function path.isresourcefile(fname)
return path.hasextension(fname, ".rc")
end
--
-- Returns true if the filename represents a Windows image file.
--
function path.isimagefile(fname)
local extensions = { ".png" }
local ext = path.getextension(fname):lower()
return table.contains(extensions, ext)
end
--
-- Join one or more pieces of a path together into a single path.
--
-- @param ...
-- One or more path strings.
-- @return
-- The joined path.
--
function path.join(...)
local arg={...}
local numargs = select("#", ...)
if numargs == 0 then
return "";
end
local allparts = {}
for i = numargs, 1, -1 do
local part = select(i, ...)
if part and #part > 0 and part ~= "." then
-- trim off trailing slashes
while part:endswith("/") do
part = part:sub(1, -2)
end
table.insert(allparts, 1, part)
if path.isabsolute(part) then
break
end
end
end
return table.concat(allparts, "/")
end
--
-- Takes a path which is relative to one location and makes it relative
-- to another location instead.
--
function path.rebase(p, oldbase, newbase)
p = path.getabsolute(path.join(oldbase, p))
p = path.getrelative(newbase, p)
return p
end
--
-- Convert the separators in a path from one form to another. If `sep`
-- is nil, then a platform-specific separator is used.
--
function path.translate(p, sep)
if (type(p) == "table") then
local result = { }
for _, value in ipairs(p) do
table.insert(result, path.translate(value))
end
return result
else
if (not sep) then
if (os.is("windows")) then
sep = "\\"
else
sep = "/"
end
end
local result = p:gsub("[/\\]", sep)
return result
end
end
--
-- Converts from a simple wildcard syntax, where * is "match any"
-- and ** is "match recursive", to the corresponding Lua pattern.
--
-- @param pattern
-- The wildcard pattern to convert.
-- @returns
-- The corresponding Lua pattern.
--
function path.wildcards(pattern)
-- Escape characters that have special meanings in Lua patterns
pattern = pattern:gsub("([%+%.%-%^%$%(%)%%])", "%%%1")
-- Replace wildcard patterns with special placeholders so I don't
-- have competing star replacements to worry about
pattern = pattern:gsub("%*%*", "\001")
pattern = pattern:gsub("%*", "\002")
-- Replace the placeholders with their Lua patterns
pattern = pattern:gsub("\001", ".*")
pattern = pattern:gsub("\002", "[^/]*")
return pattern
end
--
-- remove any dot ("./", "../") patterns from the start of the path
--
function path.trimdots(p)
local changed
repeat
changed = true
if p:startswith("./") then
p = p:sub(3)
elseif p:startswith("../") then
p = p:sub(4)
else
changed = false
end
until not changed
return p
end
--
-- Takes a path which is relative to one location and makes it relative
-- to another location instead.
--
function path.rebase(p, oldbase, newbase)
p = path.getabsolute(path.join(oldbase, p))
p = path.getrelative(newbase, p)
return p
end
--
-- Replace the file extension.
--
function path.replaceextension(p, newext)
local ext = path.getextension(p)
if not ext then
return p
end
if #newext > 0 and not newext:findlast(".", true) then
newext = "."..newext
end
return p:match("^(.*)"..ext.."$")..newext
end