-- -- path.lua -- Path manipulation functions. -- Copyright (c) 2002-2010 Jason Perkins and the Premake project -- -- -- Get the absolute file path from a relative path. The requested -- file path doesn't actually need to exist. -- function path.getabsolute(p) -- normalize the target path p = path.translate(p, "/") if (p == "") then p = "." end -- if the directory is already absolute I don't need to do anything local result = iif (path.isabsolute(p), nil, os.getcwd()) -- split up the supplied relative path and tackle it bit by bit for n, part in ipairs(p:explode("/", true)) do if (part == "" and n == 1) then result = "/" elseif (part == "..") then result = path.getdirectory(result) elseif (part ~= ".") then result = path.join(result, part) end end -- if I end up with a trailing slash remove it result = iif(result:endswith("/"), result:sub(1, -2), result) return result end -- -- 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 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 relative path from src to dest. -- function path.getrelative(src, dst) -- normalize the two paths src = path.getabsolute(src) dst = path.getabsolute(dst) -- same directory? if (src == dst) then return "." end -- dollar macro? Can't tell what the real path is; use absolute -- This enables paths like $(SDK_ROOT)/include to work correctly. if dst:startswith("$") then return dst end src = src .. "/" dst = dst .. "/" -- find the common leading directories local idx = 0 while (true) do local tst = src:find("/", idx + 1, true) if tst then if src:sub(1,tst) == dst:sub(1,tst) then idx = tst else break end else break end end -- if they have nothing in common return absolute path local first = src:find("/", 0, true) if idx <= first then return dst:sub(1, -2) end -- trim off the common directories from the front src = src:sub(idx + 1) dst = dst:sub(idx + 1) -- back up from dst to get to this common parent local result = "" idx = src:find("/") while (idx) do result = result .. "../" idx = src:find("/", idx + 1) end -- tack on the path down to the dst from here result = result .. dst -- remove the trailing slash return result:sub(1, -2) 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) local extensions = { ".c", ".s", ".m" } local ext = path.getextension(fname):lower() return table.contains(extensions, ext) end function path.iscppfile(fname) local extensions = { ".cc", ".cpp", ".cxx", ".c", ".s", ".m", ".mm" } local ext = path.getextension(fname):lower() return table.contains(extensions, ext) 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) local extensions = { ".rc" } local ext = path.getextension(fname):lower() return table.contains(extensions, ext) end -- -- Join two pieces of a path together into a single path. -- function path.join(leading, trailing) leading = leading or "" if (not trailing) then return leading end if (path.isabsolute(trailing)) then return trailing end if (leading == ".") then leading = "" end if (leading:len() > 0 and not leading:endswith("/")) then leading = leading .. "/" end return leading .. trailing 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