Improve path.getabsolute

- Allow optional second "relative to" argument to use as base for conversion
- Fix handling of paths like: $ORIGIN/../lib
This commit is contained in:
Jason Perkins 2013-10-12 16:18:54 -04:00
parent d7ff3629ed
commit 1e24b4790b
2 changed files with 48 additions and 8 deletions

31
src/host/path_getabsolute.c Normal file → Executable file
View File

@ -8,15 +8,21 @@
#include <string.h> #include <string.h>
static void getabsolute(char* result, const char* value) static void getabsolute(char* result, const char* value, const char* relative_to)
{ {
int i; int i;
char* ch; char* ch;
char* prev;
char buffer[0x4000] = { '\0' }; char buffer[0x4000] = { '\0' };
/* if the path is not already absolute, base it on working dir */ /* if the path is not already absolute, base it on working dir */
if (!do_isabsolute(value)) { if (!do_isabsolute(value)) {
do_getcwd(buffer, 0x4000); if (relative_to) {
strcpy(buffer, relative_to);
}
else {
do_getcwd(buffer, 0x4000);
}
strcat(buffer, "/"); strcat(buffer, "/");
} }
@ -30,10 +36,11 @@ static void getabsolute(char* result, const char* value)
strcat(result, "/"); strcat(result, "/");
} }
prev = NULL;
ch = strtok(buffer, "/"); ch = strtok(buffer, "/");
while (ch) { while (ch) {
/* remove ".." */ /* remove ".." where I can */
if (strcmp(ch, "..") == 0) { if (strcmp(ch, "..") == 0 && (prev == NULL || (prev[0] != '$' && strcmp(prev, "..") != 0))) {
i = strlen(result) - 2; i = strlen(result) - 2;
while (i >= 0 && result[i] != '/') { while (i >= 0 && result[i] != '/') {
--i; --i;
@ -41,6 +48,7 @@ static void getabsolute(char* result, const char* value)
if (i >= 0) { if (i >= 0) {
result[i + 1] = '\0'; result[i + 1] = '\0';
} }
ch = NULL;
} }
/* allow everything except "." */ /* allow everything except "." */
@ -49,6 +57,7 @@ static void getabsolute(char* result, const char* value)
strcat(result, "/"); strcat(result, "/");
} }
prev = ch;
ch = strtok(NULL, "/"); ch = strtok(NULL, "/");
} }
@ -62,26 +71,32 @@ static void getabsolute(char* result, const char* value)
int path_getabsolute(lua_State* L) int path_getabsolute(lua_State* L)
{ {
const char* relative_to;
char buffer[0x4000]; char buffer[0x4000];
relative_to = NULL;
if (lua_gettop(L) > 1 && !lua_isnil(L,2)) {
relative_to = luaL_checkstring(L, 2);
}
if (lua_istable(L, 1)) { if (lua_istable(L, 1)) {
int i = 0; int i = 0;
lua_newtable(L); lua_newtable(L);
lua_pushnil(L); lua_pushnil(L);
while (lua_next(L, 1)) { while (lua_next(L, 1)) {
const char* value = luaL_checkstring(L, 4); const char* value = luaL_checkstring(L, -1);
getabsolute(buffer, value); getabsolute(buffer, value, relative_to);
lua_pop(L, 1); lua_pop(L, 1);
lua_pushnumber(L, ++i); lua_pushnumber(L, ++i);
lua_pushstring(L, buffer); lua_pushstring(L, buffer);
lua_settable(L, 2); lua_settable(L, -4);
} }
return 1; return 1;
} }
else { else {
const char* value = luaL_checkstring(L, 1); const char* value = luaL_checkstring(L, 1);
getabsolute(buffer, value); getabsolute(buffer, value, relative_to);
lua_pushstring(L, buffer); lua_pushstring(L, buffer);
return 1; return 1;
} }

25
tests/base/test_path.lua Normal file → Executable file
View File

@ -64,6 +64,31 @@
test.isequal({ "/a/b", "/c/d" }, path.getabsolute({ "/a/b", "/c/d" })) test.isequal({ "/a/b", "/c/d" }, path.getabsolute({ "/a/b", "/c/d" }))
end end
function suite.getabsolute_withRelativeTo()
local relto = path.getdirectory(os.getcwd())
local expected = relto .. "/a/b/c"
test.isequal(expected, path.getabsolute("a/b/c", relto))
end
function suite.getabsolute_withRelativeTo_withTrailingSlashes()
local relto = path.getdirectory(os.getcwd())
local expected = relto .. "/a/b/c"
test.isequal(expected, path.getabsolute("a/b/c", relto .. "/"))
end
function suite.getabsolute_acceptsTables_withRelativeTo()
local relto = path.getdirectory(os.getcwd())
test.isequal({ relto .. "/a/b", relto .. "/c/d" }, path.getabsolute({ "a/b", "c/d" }, relto))
end
function suite.getabsolute_leavesDotDot_onShellVar()
test.isequal("$ORIGIN/../libs", path.getabsolute("$ORIGIN/../libs"))
end
function suite.getabsolute_leavesDotDot2_onShellVar()
test.isequal("$ORIGIN/../../libs", path.getabsolute("$ORIGIN/../../libs"))
end
-- --
-- path.getbasename() tests -- path.getbasename() tests