Skip to content

Instantly share code, notes, and snippets.

@kahrl
Created May 31, 2013 12:53
Show Gist options
  • Save kahrl/5684778 to your computer and use it in GitHub Desktop.
Save kahrl/5684778 to your computer and use it in GitHub Desktop.
diff --git a/src/filesys.cpp b/src/filesys.cpp
index 06b0e48..21f9f88 100644
--- a/src/filesys.cpp
+++ b/src/filesys.cpp
@@ -146,6 +146,11 @@ bool IsDir(std::string path)
(attr & FILE_ATTRIBUTE_DIRECTORY));
}
+bool IsDirDelimiter(char c)
+{
+ return c == '/' || c == '\\';
+}
+
bool RecursiveDelete(std::string path)
{
infostream<<"Recursively deleting \""<<path<<"\""<<std::endl;
@@ -335,6 +340,11 @@ bool IsDir(std::string path)
return ((statbuf.st_mode & S_IFDIR) == S_IFDIR);
}
+bool IsDirDelimiter(char c)
+{
+ return c == '/';
+}
+
bool RecursiveDelete(std::string path)
{
/*
@@ -448,16 +458,14 @@ bool RecursiveDeleteContent(std::string path)
bool CreateAllDirs(std::string path)
{
- size_t pos;
std::vector<std::string> tocreate;
std::string basepath = path;
while(!PathExists(basepath))
{
tocreate.push_back(basepath);
- pos = basepath.rfind(DIR_DELIM_C);
- if(pos == std::string::npos)
+ basepath = RemoveLastPathComponent(basepath);
+ if(basepath.empty())
break;
- basepath = basepath.substr(0,pos);
}
for(int i=tocreate.size()-1;i>=0;i--)
if(!CreateDir(tocreate[i]))
@@ -527,5 +535,83 @@ bool CopyDir(std::string source,std::string target)
}
}
+std::string RemoveLastPathComponent(std::string path,
+ std::string *removed, int count)
+{
+ if (removed)
+ *removed = "";
+
+ size_t remaining = path.size();
+
+ for (int i = 0; i < count; ++i){
+ // strip a dir delimiter
+ while(remaining != 0 && IsDirDelimiter(path[remaining-1]))
+ remaining--;
+ // strip a path component
+ size_t component_end = remaining;
+ while(remaining != 0 && !IsDirDelimiter(path[remaining-1]))
+ remaining--;
+ size_t component_start = remaining;
+ // strip a dir delimiter
+ while(remaining != 0 && IsDirDelimiter(path[remaining-1]))
+ remaining--;
+ if(removed){
+ std::string component = path.substr(component_start,
+ component_end - component_start);
+ if(i)
+ *removed = component + DIR_DELIM + *removed;
+ else
+ *removed = component;
+ }
+ }
+ return path.substr(0, remaining);
+}
+
+std::string RemoveRelativePathComponents(std::string path)
+{
+ size_t pos = path.size();
+ size_t dotdot_count = 0;
+ while(pos != 0){
+ size_t component_with_delim_end = pos;
+ // skip a dir delimiter
+ while(pos != 0 && IsDirDelimiter(path[pos-1]))
+ pos--;
+ // strip a path component
+ size_t component_end = pos;
+ while(pos != 0 && !IsDirDelimiter(path[pos-1]))
+ pos--;
+ size_t component_start = pos;
+
+ std::string component = path.substr(component_start, component_end - component_start);
+ bool remove_this_component = false;
+ if(component == "."){
+ remove_this_component = true;
+ }
+ else if(component == ".."){
+ remove_this_component = true;
+ dotdot_count += 1;
+ }
+ else if(dotdot_count != 0){
+ remove_this_component = true;
+ dotdot_count -= 1;
+ }
+
+ if(remove_this_component){
+ while(pos != 0 && IsDirDelimiter(path[pos-1]))
+ pos--;
+ path = path.substr(0, pos) + DIR_DELIM +
+ path.substr(component_with_delim_end, std::string::npos);
+ std::cerr<<"[component removed] "<<path<<std::endl;
+ pos++;
+ }
+ }
+
+ if(dotdot_count > 0)
+ return "";
+ else
+ return path;
+}
+
+
} // namespace fs
diff --git a/src/filesys.h b/src/filesys.h
index 15fa0ad..560d8d6 100644
--- a/src/filesys.h
+++ b/src/filesys.h
@@ -26,10 +26,8 @@
#ifdef _WIN32 // WINDOWS
#define DIR_DELIM "\\"
-#define DIR_DELIM_C '\\'
#else // POSIX
#define DIR_DELIM "/"
-#define DIR_DELIM_C '/'
#endif
namespace fs
@@ -49,6 +47,8 @@ struct DirListNode
bool IsDir(std::string path);
+bool IsDirDelimiter(char c);
+
// Only pass full paths to this one. True on success.
// NOTE: The WIN32 version returns always true.
bool RecursiveDelete(std::string path);
@@ -72,6 +72,18 @@ struct DirListNode
// Copy directory and all subdirectorys
bool CopyDir(std::string source,std::string target);
+// Remove last path component and the dir delimiter before and/or after it,
+// returns "" if there is only one path component.
+// removed: If non-NULL, receives the removed component(s).
+// count: Number of components to remove
+std::string RemoveLastPathComponent(std::string path,
+ std::string *removed = NULL, int count = 1);
+
+// Remove "." and ".." path components and for every ".." removed, remove
+// the last normal path component before it. Unlike AbsolutePath,
+// this does not resolve symlinks and check for existence of directories.
+std::string RemoveRelativePathComponents(std::string path);
+
//get absolute path from a given relative one
std::string AbsolutePath(std::string path);
diff --git a/src/map.cpp b/src/map.cpp
index d5ab8eb..434170a 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -3228,17 +3228,18 @@ v2s16 ServerMap::getSectorPos(std::string dirname)
{
unsigned int x, y;
int r;
- size_t spos = dirname.rfind(DIR_DELIM_C) + 1;
- assert(spos != std::string::npos);
- if(dirname.size() - spos == 8)
+ std::string component;
+ fs::RemoveLastPathComponent(dirname, &component, 1);
+ if(component.size() == 8)
{
// Old layout
- r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
+ r = sscanf(component.c_str(), "%4x%4x", &x, &y);
}
- else if(dirname.size() - spos == 3)
+ else if(component.size() == 3)
{
// New layout
- r = sscanf(dirname.substr(spos-4).c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
+ fs::RemoveLastPathComponent(dirname, &component, 2);
+ r = sscanf(component.c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
// Sign-extend the 12 bit values up to 16 bits...
if(x&0x800) x|=0xF000;
if(y&0x800) y|=0xF000;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment