diff --git a/src/base/path.lua b/src/base/path.lua index 98de6835..a8637c15 100644 --- a/src/base/path.lua +++ b/src/base/path.lua @@ -32,51 +32,6 @@ end --- --- Get the absolute file path from a relative path. The requested --- file path doesn't actually need to exist. --- - - function path.getabsolute(p) - if type(p) == "table" then - local result = {} - for _, value in ipairs(p) do - table.insert(result, path.getabsolute(value)) - end - return result - end - - -- 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 - -- Environment variables embedded in the path need to be treated - -- as relative paths; path.join() makes them absolute - if (part:startswith("$") and n > 1) then - result = result .. "/" .. part - else - result = path.join(result, part) - end - 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. -- diff --git a/src/host/os_getcwd.c b/src/host/os_getcwd.c index 06c91a25..d1a4827f 100644 --- a/src/host/os_getcwd.c +++ b/src/host/os_getcwd.c @@ -9,26 +9,32 @@ int os_getcwd(lua_State* L) { char buffer[0x4000]; - char* ch; + if (do_getcwd(buffer, 0x4000)) { + lua_pushstring(L, buffer); + return 1; + } + else { + return 0; + } +} + + +int do_getcwd(char* buffer, size_t size) +{ int result; #if PLATFORM_WINDOWS result = (GetCurrentDirectory(0x4000, buffer) != 0); + if (result) { + char* ch; + for (ch = buffer; *ch != '\0'; ++ch) + { + if (*ch == '\\') *ch = '/'; + } + } #else result = (getcwd(buffer, 0x4000) != 0); #endif - if (!result) - return 0; - - /* convert to platform-neutral directory separators */ - for (ch = buffer; *ch != '\0'; ++ch) - { - if (*ch == '\\') *ch = '/'; - } - - lua_pushstring(L, buffer); - return 1; + return result; } - - diff --git a/src/host/path_getabsolute.c b/src/host/path_getabsolute.c new file mode 100644 index 00000000..3b2f6135 --- /dev/null +++ b/src/host/path_getabsolute.c @@ -0,0 +1,92 @@ +/** + * \file path_getabsolute.c + * \brief Returns an absolute version of a relative path. + * \author Copyright (c) 2002-2013 Jason Perkins and the Premake project + */ + +#include "premake.h" +#include + + +static void getabsolute(char* result, const char* value) +{ + int i; + char* ch; + char buffer[0x4000] = { '\0' }; + + /* if the path is not already absolute, base it on working dir */ + if (!do_isabsolute(value)) { + do_getcwd(buffer, 0x4000); + strcat(buffer, "/"); + } + + /* normalize the path */ + strcat(buffer, value); + for (ch = buffer; *ch != '\0'; ++ch) { + if (*ch == '\\') { + *ch = '/'; + } + } + + /* process it part by part */ + result[0] = '\0'; + if (buffer[0] == '/') { + strcat(result, "/"); + } + + ch = strtok(buffer, "/"); + while (ch) { + /* remove ".." */ + if (strcmp(ch, "..") == 0) { + i = strlen(result) - 2; + while (i >= 0 && result[i] != '/') { + --i; + } + if (i >= 0) { + result[i + 1] = '\0'; + } + } + + /* allow everything except "." */ + else if (strcmp(ch, ".") != 0) { + strcat(result, ch); + strcat(result, "/"); + } + + ch = strtok(NULL, "/"); + } + + /* remove trailing slash */ + i = strlen(result) - 1; + if (result[i] == '/') { + result[i] = '\0'; + } +} + + +int path_getabsolute(lua_State* L) +{ + char buffer[0x4000]; + + if (lua_istable(L, 1)) { + int i = 0; + lua_newtable(L); + lua_pushnil(L); + while (lua_next(L, 1)) { + const char* value = luaL_checkstring(L, 4); + getabsolute(buffer, value); + lua_pop(L, 1); + + lua_pushnumber(L, ++i); + lua_pushstring(L, buffer); + lua_settable(L, 2); + } + return 1; + } + else { + const char* value = luaL_checkstring(L, 1); + getabsolute(buffer, value); + lua_pushstring(L, buffer); + return 1; + } +} diff --git a/src/host/premake.c b/src/host/premake.c index 9a693412..b68a9ff7 100755 --- a/src/host/premake.c +++ b/src/host/premake.c @@ -35,6 +35,7 @@ extern const char* builtin_scripts[]; /* Built-in functions */ static const luaL_Reg path_functions[] = { + { "getabsolute", path_getabsolute }, { "isabsolute", path_isabsolute }, { "join", path_join }, { NULL, NULL } diff --git a/src/host/premake.h b/src/host/premake.h index 88131217..deca9ebb 100755 --- a/src/host/premake.h +++ b/src/host/premake.h @@ -48,11 +48,13 @@ /* Bootstrapping helper functions */ unsigned long do_hash(const char* str, int seed); +int do_getcwd(char* buffer, size_t size); int do_isabsolute(const char* path); int do_isfile(const char* filename); /* Built-in functions */ +int path_getabsolute(lua_State* L); int path_isabsolute(lua_State* L); int path_join(lua_State* L); int os_chdir(lua_State* L); diff --git a/tests/base/test_path.lua b/tests/base/test_path.lua index 7fa52e3f..0908ea90 100644 --- a/tests/base/test_path.lua +++ b/tests/base/test_path.lua @@ -1,7 +1,7 @@ -- -- tests/base/test_path.lua -- Automated test suite for the action list. --- Copyright (c) 2008-2010 Jason Perkins and the Premake project +-- Copyright (c) 2008-2013 Jason Perkins and the Premake project -- local suite = test.declare("path") @@ -11,41 +11,59 @@ -- path.getabsolute() tests -- - function suite.getabsolute_ReturnsCorrectPath_OnMissingSubdir() - local expected = path.translate(os.getcwd(), "/") .. "/a/b/c" + function suite.getabsolute_worksWithMissingSubdirs() + local expected = os.getcwd() .. "/a/b/c" test.isequal(expected, path.getabsolute("a/b/c")) end - function suite.getabsolute_RemovesDotDots_OnWindowsAbsolute() + function suite.getabsolute_removesDotDots_onWindows() test.isequal("c:/ProjectB/bin", path.getabsolute("c:/ProjectA/../ProjectB/bin")) end - function suite.getabsolute_RemovesDotDots_OnPosixAbsolute() + function suite.getabsolute_removesDotDots_OnPosix() test.isequal("/ProjectB/bin", path.getabsolute("/ProjectA/../ProjectB/bin")) end - function suite.getabsolute_OnTrailingSlash() - local expected = path.translate(os.getcwd(), "/") .. "/a/b/c" - test.isequal(expected, path.getabsolute("a/b/c/")) + function suite.getabsolute_limitsDotDots_onWindows() + test.isequal("c:/ProjectB/bin", path.getabsolute("c:/ProjectA/../../ProjectB/bin")) end - function suite.getabsolute_OnLeadingEnvVar() + function suite.getabsolute_limitsDotDots_OnPosix() + test.isequal("/ProjectB/bin", path.getabsolute("/ProjectA/../../ProjectB/bin")) + end + + function suite.getabsolute_removesDot() + test.isequal("/ProjectA/ProjectB/bin", path.getabsolute("/ProjectA/./ProjectB/bin")) + end + + function suite.getabsolute_removesTrailingSlash() + test.isequal("/a/b/c", path.getabsolute("/a/b/c/")) + end + + function suite.getabsolute_onLeadingEnvVar() test.isequal("$(HOME)/user", path.getabsolute("$(HOME)/user")) end - function suite.getabsolute_OnMultipleEnvVar() + function suite.getabsolute_onMultipleEnvVar() test.isequal("$(HOME)/$(USER)", path.getabsolute("$(HOME)/$(USER)")) end - function suite.getabsolute_OnTrailingEnvVar() - local expected = path.translate(os.getcwd(), "/") .. "/home/$(USER)" - test.isequal(expected, path.getabsolute("home/$(USER)")) + function suite.getabsolute_onTrailingEnvVar() + test.isequal("/home/$(USER)", path.getabsolute("/home/$(USER)")) end - function suite.getabsolute_OnLeadingEnvVarQuoted() + function suite.getabsolute_onLeadingEnvVarQuoted() test.isequal('"$(HOME)/user"', path.getabsolute('"$(HOME)/user"')) end + function suite.getabsolute_normalizesPaths() + test.isequal("c:/ProjectB/bin", path.getabsolute("c:\\ProjectB\\bin")) + end + + function suite.getabsolute_acceptsTables() + test.isequal({ "/a/b", "/c/d" }, path.getabsolute({ "/a/b", "/c/d" })) + end + -- -- path.getbasename() tests