--[[
Copyright 2016 ARATA Mizuki
This file is part of ClutTeX.
ClutTeX is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ClutTeX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ClutTeX. If not, see <
http://www.gnu.org/licenses/>.
]]
-- pathutil module
local assert = assert
local select = select
local string = string
local string_find = string.find
local string_sub = string.sub
local string_match = string.match
local string_gsub = string.gsub
local filesys = require "lfs"
local function basename(path)
local i = 0
while true do
local j = string_find(path, "[\\/]", i + 1)
if j == nil then
return string_sub(path, i + 1)
elseif j == #path then
return string_sub(path, i + 1, -2)
end
i = j
end
end
-- TEST CODE
assert(basename("/path/to/file") == "file")
assert(basename("/path/to/directory/") == "directory")
assert(basename([[c:\path\to/directory\]]) == "directory")
assert(basename("/file") == "file")
assert(basename("file") == "file")
-- END TEST CODE
local function dirname(path)
local i = 0
while true do
local j = string_find(path, "[\\/]", i + 1)
if j == nil then
if i == 0 then
-- No directory portion
return "."
elseif i == 1 then
-- Root
return string_sub(path, 1, 1)
else
-- Directory portion without trailing slash
return string_sub(path, 1, i - 1)
end
end
i = j
end
end
-- TEST CODE
assert(dirname("/path/to/file") == "/path/to")
assert(dirname("/path/to/directory/") == "/path/to/directory")
assert(dirname([[c:/path\to/file]]) == [[c:/path\to]])
assert(dirname("/file") == "/")
assert(dirname("file") == ".")
-- END TEST CODE
local function parentdir(path)
local i = 0
while true do
local j = string_find(path, "[\\/]", i + 1)
if j == nil then
if i == 0 then
-- No directory portion
return "."
elseif i == 1 then
-- Root
return string_sub(path, 1, 1)
else
-- Directory portion without trailing slash
return string_sub(path, 1, i - 1)
end
elseif j == #path then
-- Directory portion without trailing slash
return string_sub(path, 1, i - 1)
end
i = j
end
end
-- TEST CODE
assert(parentdir("/path/to/file") == "/path/to")
assert(parentdir("/path/to/directory/") == "/path/to")
assert(parentdir("/file") == "/")
assert(parentdir("file") == ".")
-- END TEST CODE
local function trimext(path)
return (string_gsub(path, "%.[^\\/%.]*$", ""))
end
-- TEST CODE
assert(trimext("/path/to/file.ext") == "/path/to/file")
assert(trimext("/path/t.o/file") == "/path/t.o/file")
assert(trimext([[c:/path/t.o\file]]) == [[c:/path/t.o\file]])
assert(trimext("file.ext") == "file")
assert(trimext("file.e.xt") == "file.e")
assert(trimext("file.ext.") == "file.ext")
assert(trimext("file") == "file")
-- END TEST CODE
local function ext(path)
return string_match(path, "%.([^\\/%.]*)$") or ""
end
-- TEST CODE
assert(ext("/path/to/file.ext") == "ext")
assert(ext("/path/t.o/file") == "")
assert(ext([[c:/path/t.o\file]]) == "")
assert(ext("file.ext") == "ext")
assert(ext("file.e.xt") == "xt")
assert(ext("file.ext.") == "")
assert(ext("file") == "")
-- END TEST CODE
local function replaceext(path, newext)
local newpath, n = string_gsub(path, "%.([^\\/%.]*)$", function() return "." .. newext end)
if n == 0 then
return newpath .. "." .. newext
else
return newpath
end
end
-- TEST CODE
assert(replaceext("/path/to/file.ext", "tor") == "/path/to/file.tor")
assert(replaceext("/path/t.o/file", "tor") == "/path/t.o/file.tor")
assert(replaceext([[c:/path/t.o\file]], "tor") == [[c:/path/t.o\file.tor]])
assert(replaceext("file.ext", "tor") == "file.tor")
assert(replaceext("file.e.xt", "tor") == "file.e.tor")
assert(replaceext("file.ext.", "tor") == "file.ext.tor")
assert(replaceext("file", "tor") == "file.tor")
-- END TEST CODE
local function joinpath2(x, y)
local xd = x
local last = string_sub(x, -1)
if last ~= "/" and last ~= "\\" then
xd = x .. "\\"
end
if y == "." then
return xd
elseif y == ".." then
return dirname(x)
else
if string_match(y, "^%.[\\/]") then
return xd .. string_sub(y, 3)
else
return xd .. y
end
end
end
local function joinpath(...)
local n = select("#", ...)
if n == 2 then
return joinpath2(...)
elseif n == 0 then
return "."
elseif n == 1 then
return ...
else
return joinpath(joinpath2(...), select(3, ...))
end
end
-- TEST CODE
assert(joinpath("/path/", "to", "somewhere") == [[/path/to\somewhere]])
assert(joinpath("/path/", "to", "somewhere", "..") == [[/path/to]])
assert(joinpath("/path/", "to", "somewhere", "..", "elsewhere") == [[/path/to\elsewhere]])
assert(joinpath("/path/", "to", "./somewhere.txt") == "/path/to/somewhere.txt")
-- END TEST CODE
--
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
local function isabspath(path)
local init = string_sub(path, 1, 1)
return init == "\\" or init == "/" or string_match(path, "^%a:[/\\]")
end
local function abspath(path, cwd)
if isabspath(path) then
-- absolute path
return path
else
-- TODO: relative path with a drive letter is not supported
cwd = cwd or filesys.currentdir()
return joinpath2(cwd, path)
end
end
return {
basename = basename,
dirname = dirname,
parentdir = parentdir,
trimext = trimext,
ext = ext,
replaceext = replaceext,
join = joinpath,
abspath = abspath,
}