Port path.getabsolute() from Lua to C

This commit is contained in:
Jason Perkins 2013-01-04 10:18:47 -05:00
parent b25c12f2b6
commit c94073fc7e
6 changed files with 147 additions and 73 deletions

View File

@ -32,51 +32,6 @@
end 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. -- Retrieve the filename portion of a path, without any extension.
-- --

View File

@ -9,26 +9,32 @@
int os_getcwd(lua_State* L) int os_getcwd(lua_State* L)
{ {
char buffer[0x4000]; 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; int result;
#if PLATFORM_WINDOWS #if PLATFORM_WINDOWS
result = (GetCurrentDirectory(0x4000, buffer) != 0); result = (GetCurrentDirectory(0x4000, buffer) != 0);
if (result) {
char* ch;
for (ch = buffer; *ch != '\0'; ++ch)
{
if (*ch == '\\') *ch = '/';
}
}
#else #else
result = (getcwd(buffer, 0x4000) != 0); result = (getcwd(buffer, 0x4000) != 0);
#endif #endif
if (!result) return result;
return 0;
/* convert to platform-neutral directory separators */
for (ch = buffer; *ch != '\0'; ++ch)
{
if (*ch == '\\') *ch = '/';
}
lua_pushstring(L, buffer);
return 1;
} }

View File

@ -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 <string.h>
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;
}
}

View File

@ -35,6 +35,7 @@ extern const char* builtin_scripts[];
/* Built-in functions */ /* Built-in functions */
static const luaL_Reg path_functions[] = { static const luaL_Reg path_functions[] = {
{ "getabsolute", path_getabsolute },
{ "isabsolute", path_isabsolute }, { "isabsolute", path_isabsolute },
{ "join", path_join }, { "join", path_join },
{ NULL, NULL } { NULL, NULL }

View File

@ -48,11 +48,13 @@
/* Bootstrapping helper functions */ /* Bootstrapping helper functions */
unsigned long do_hash(const char* str, int seed); 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_isabsolute(const char* path);
int do_isfile(const char* filename); int do_isfile(const char* filename);
/* Built-in functions */ /* Built-in functions */
int path_getabsolute(lua_State* L);
int path_isabsolute(lua_State* L); int path_isabsolute(lua_State* L);
int path_join(lua_State* L); int path_join(lua_State* L);
int os_chdir(lua_State* L); int os_chdir(lua_State* L);

View File

@ -1,7 +1,7 @@
-- --
-- tests/base/test_path.lua -- tests/base/test_path.lua
-- Automated test suite for the action list. -- 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") local suite = test.declare("path")
@ -11,41 +11,59 @@
-- path.getabsolute() tests -- path.getabsolute() tests
-- --
function suite.getabsolute_ReturnsCorrectPath_OnMissingSubdir() function suite.getabsolute_worksWithMissingSubdirs()
local expected = path.translate(os.getcwd(), "/") .. "/a/b/c" local expected = os.getcwd() .. "/a/b/c"
test.isequal(expected, path.getabsolute("a/b/c")) test.isequal(expected, path.getabsolute("a/b/c"))
end end
function suite.getabsolute_RemovesDotDots_OnWindowsAbsolute() function suite.getabsolute_removesDotDots_onWindows()
test.isequal("c:/ProjectB/bin", path.getabsolute("c:/ProjectA/../ProjectB/bin")) test.isequal("c:/ProjectB/bin", path.getabsolute("c:/ProjectA/../ProjectB/bin"))
end end
function suite.getabsolute_RemovesDotDots_OnPosixAbsolute() function suite.getabsolute_removesDotDots_OnPosix()
test.isequal("/ProjectB/bin", path.getabsolute("/ProjectA/../ProjectB/bin")) test.isequal("/ProjectB/bin", path.getabsolute("/ProjectA/../ProjectB/bin"))
end end
function suite.getabsolute_OnTrailingSlash() function suite.getabsolute_limitsDotDots_onWindows()
local expected = path.translate(os.getcwd(), "/") .. "/a/b/c" test.isequal("c:/ProjectB/bin", path.getabsolute("c:/ProjectA/../../ProjectB/bin"))
test.isequal(expected, path.getabsolute("a/b/c/"))
end 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")) test.isequal("$(HOME)/user", path.getabsolute("$(HOME)/user"))
end end
function suite.getabsolute_OnMultipleEnvVar() function suite.getabsolute_onMultipleEnvVar()
test.isequal("$(HOME)/$(USER)", path.getabsolute("$(HOME)/$(USER)")) test.isequal("$(HOME)/$(USER)", path.getabsolute("$(HOME)/$(USER)"))
end end
function suite.getabsolute_OnTrailingEnvVar() function suite.getabsolute_onTrailingEnvVar()
local expected = path.translate(os.getcwd(), "/") .. "/home/$(USER)" test.isequal("/home/$(USER)", path.getabsolute("/home/$(USER)"))
test.isequal(expected, path.getabsolute("home/$(USER)"))
end end
function suite.getabsolute_OnLeadingEnvVarQuoted() function suite.getabsolute_onLeadingEnvVarQuoted()
test.isequal('"$(HOME)/user"', path.getabsolute('"$(HOME)/user"')) test.isequal('"$(HOME)/user"', path.getabsolute('"$(HOME)/user"'))
end 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 -- path.getbasename() tests