--[[ 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 . ]] -- 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, }