Prepare for assimilation into core
authorMikko Rasa <tdb@tdb.fi>
Wed, 27 Jul 2011 05:49:01 +0000 (08:49 +0300)
committerMikko Rasa <tdb@tdb.fi>
Wed, 27 Jul 2011 05:49:01 +0000 (08:49 +0300)
17 files changed:
Build
source/dir.cpp [deleted file]
source/dir.h [deleted file]
source/fs/dir.cpp [new file with mode: 0644]
source/fs/dir.h [new file with mode: 0644]
source/fs/path.cpp [new file with mode: 0644]
source/fs/path.h [new file with mode: 0644]
source/fs/stat.cpp [new file with mode: 0644]
source/fs/stat.h [new file with mode: 0644]
source/fs/utils.cpp [new file with mode: 0644]
source/fs/utils.h [new file with mode: 0644]
source/path.cpp [deleted file]
source/path.h [deleted file]
source/stat.cpp [deleted file]
source/stat.h [deleted file]
source/utils.cpp [deleted file]
source/utils.h [deleted file]

diff --git a/Build b/Build
index b0e5881e9e96cae6f0b472ca51a43a8c071c320e..b44b8eba407f7cf9cca267bbc982a409f115ee1d 100644 (file)
--- a/Build
+++ b/Build
@@ -9,13 +9,13 @@ package "mspfs"
 
        headers "msp/fs"
        {
-               source "source";
+               source "source/fs";
                install true;
        };
 
        library "mspfs"
        {
-               source "source";
+               source "source/fs";
                install true;
        };
 
diff --git a/source/dir.cpp b/source/dir.cpp
deleted file mode 100644 (file)
index ad2e013..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/* $Id$
-
-This file is part of libmspfs
-Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#include <cstdlib>
-#include <cerrno>
-#include <dirent.h>
-#include <sys/stat.h>
-#ifdef WIN32
-#include <shlobj.h>
-#endif
-#include <msp/core/except.h>
-#include <msp/strings/regex.h>
-#include <msp/strings/utils.h>
-#include "dir.h"
-#include "path.h"
-#include "stat.h"
-#include "utils.h"
-
-using namespace std;
-
-namespace Msp {
-namespace FS {
-
-namespace
-{
-
-/**
-Helper function to determine the location of the program's executable.  Caches
-the last result to cut down filesystem access with repeated calls.
-*/
-const Path &get_bin_dir(const string &argv0)
-{
-       static string last_argv0;
-       static Path bin_dir;
-
-       if(!(argv0==last_argv0))
-       {
-               Path exe;
-               if(argv0.find('/')==string::npos)
-               {
-                       const char *path = getenv("PATH");
-                       vector<string> dirs = split(path, ':');
-                       for(vector<string>::const_iterator i=dirs.begin(); i!=dirs.end(); ++i)
-                               if(exists(Path(*i)/argv0))
-                               {
-                                       exe = realpath(Path(*i)/argv0);
-                                       break;
-                               }
-               }
-               else
-                       exe = realpath(argv0);
-
-               last_argv0 = argv0;
-               bin_dir = dirname(exe);
-       }
-
-       return bin_dir;
-}
-
-}
-
-void mkdir(const Path &path, int mode)
-{
-       int err;
-#ifdef WIN32
-       // The win32 version of this function doesn't take the mode argument.  Go figure.
-       (void)mode;
-       err = ::mkdir(path.str().c_str());
-#else
-       err = ::mkdir(path.str().c_str(), mode);
-#endif
-
-       if(err==-1)
-               throw SystemError("mkdir failed", errno);
-}
-
-void mkpath(const Path &path, int mode)
-{
-       Path p;
-       for(Path::Iterator i=path.begin(); i!=path.end(); ++i)
-       {
-               p /= *i;
-#ifdef WIN32
-               if(p.size()==1 && p.is_absolute())
-                       continue;
-#endif
-               struct stat st;
-               int err = stat(p, st);
-               if(err==0)
-               {
-                       if(!S_ISDIR(st.st_mode))
-                               throw Exception("A component exists and is not a directory");
-                       continue;
-               }
-               else if(errno!=ENOENT)
-                       throw SystemError("stat failed", errno);
-               else
-                       mkdir(p, mode);
-       }
-}
-
-void rmdir(const Path &path)
-{
-       if(::rmdir(path.str().c_str())==-1)
-               throw SystemError("rmdir failed", errno);
-}
-
-void rmdirs(const Path &path)
-{
-       list<string> files = list_files(path);
-       for(list<string>::iterator i=files.begin(); i!=files.end(); ++i)
-       {
-               Path p = path / *i;
-               struct stat st = stat(p.str().c_str());
-               if(S_ISDIR(st.st_mode))
-                       rmdirs(p);
-               else
-                       unlink(p);
-       }
-
-       rmdir(path);
-}
-
-list<string> list_files(const Path &path)
-{
-       return list_filtered(path, string());
-}
-
-list<string> list_filtered(const Path &path, const string &filter)
-{
-       Regex r_filter(filter);
-
-       list<string> result;
-       DIR *dir = opendir(path.str().c_str());
-       if(dir)
-       {
-               while(dirent *de = readdir(dir))
-               {
-                       const char *fn = de->d_name;
-                       if(fn[0]=='.' && (fn[1]==0 || (fn[1]=='.' && fn[2]==0))) 
-                               continue;
-                       if(r_filter.match(fn))
-                               result.push_back(fn);
-               }
-               closedir(dir);
-       }
-
-       return result;
-}
-
-Path getcwd()
-{
-       char buf[1024];
-       return ::getcwd(buf, sizeof(buf));
-}
-
-Path get_home_dir()
-{
-#ifdef WIN32
-       char home[MAX_PATH];
-       if(SHGetFolderPath(0, CSIDL_PERSONAL, 0, 0, home)==S_OK)
-               return home;
-#else
-       const char *home = getenv("HOME");
-       if(home)
-               return home;
-#endif
-       return ".";
-}
-
-Path get_user_data_dir(const string &appname)
-{
-#ifdef WIN32
-       char datadir[MAX_PATH];
-       if(SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, datadir)==S_OK)
-               return Path(datadir)/appname;
-       return ".";
-#else
-       return get_home_dir()/("."+appname);
-#endif
-}
-
-Path get_sys_conf_dir(const string &argv0)
-{
-       Path dir = get_bin_dir(argv0);
-
-       if(dir[-1]=="bin" || dir[-1]=="sbin")
-       {
-               dir /= "..";
-               if(dir[-1]=="usr")
-                       dir /= "..";
-               return dir/"etc";
-       }
-       else
-               return dir;
-}
-
-Path get_sys_data_dir(const string &argv0, const string &appname)
-{
-       Path dir = get_bin_dir(argv0);
-
-       if(dir[-1]=="bin" || dir[-1]=="sbin")
-               return dir/".."/"share"/appname;
-       else
-               return dir;
-}
-
-Path get_sys_lib_dir(const string &argv0, const string &appname)
-{
-       Path dir = get_bin_dir(argv0);
-
-       if(dir[-1]=="bin" || dir[-1]=="sbin")
-               return dir/".."/"lib"/appname;
-       else
-               return dir;
-}
-
-void chdir(const Path &path)
-{
-       if(::chdir(path.str().c_str())==-1)
-               throw SystemError("chdir failed", errno);
-}
-
-} // namespace FS
-} // namespace Msp
diff --git a/source/dir.h b/source/dir.h
deleted file mode 100644 (file)
index 53228cc..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/* $Id$
-
-This file is part of libmspfs
-Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#ifndef MSP_FS_DIR_H_
-#define MSP_FS_DIR_H_
-
-#include <list>
-#include <string>
-#include "path.h"
-
-namespace Msp {
-namespace FS {
-
-/// Creates a directory
-void mkdir(const Path &path, int mode);
-
-/// Creates a directory and any required parent directories
-void mkpath(const Path &path, int mode);
-
-/// Removes a directory, which must be empty
-void rmdir(const Path &path);
-
-/// Removes a directory and anything it contains
-void rmpath(const Path &path);
-
-/// Lists the contents of a directory
-std::list<std::string> list_files(const Path &path);
-
-/// Lists the contents of a directory, filtered with a regex
-std::list<std::string> list_filtered(const Path &path, const std::string &filter);
-
-/// Returns the current working directory
-Path getcwd();
-
-/// Returns the user's home directory
-Path get_home_dir();
-
-/// Returns a directory suitable for storing user-specific data
-Path get_user_data_dir(const std::string &appname);
-
-/// Returns a directory containing system-wide configuration
-Path get_sys_conf_dir(const std::string &argv0);
-
-/// Returns a directory containing immutable system-wide data
-Path get_sys_data_dir(const std::string &argv0, const std::string &appname);
-
-/// Returns a directory containing system-wide architecture-specific files
-Path get_sys_lib_dir(const std::string &argv0, const std::string &appname);
-
-/// Changes the current working directory
-void chdir(const Path &);
-
-} // namespace FS
-} // namespace Msp
-
-#endif
diff --git a/source/fs/dir.cpp b/source/fs/dir.cpp
new file mode 100644 (file)
index 0000000..ad2e013
--- /dev/null
@@ -0,0 +1,229 @@
+/* $Id$
+
+This file is part of libmspfs
+Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <cstdlib>
+#include <cerrno>
+#include <dirent.h>
+#include <sys/stat.h>
+#ifdef WIN32
+#include <shlobj.h>
+#endif
+#include <msp/core/except.h>
+#include <msp/strings/regex.h>
+#include <msp/strings/utils.h>
+#include "dir.h"
+#include "path.h"
+#include "stat.h"
+#include "utils.h"
+
+using namespace std;
+
+namespace Msp {
+namespace FS {
+
+namespace
+{
+
+/**
+Helper function to determine the location of the program's executable.  Caches
+the last result to cut down filesystem access with repeated calls.
+*/
+const Path &get_bin_dir(const string &argv0)
+{
+       static string last_argv0;
+       static Path bin_dir;
+
+       if(!(argv0==last_argv0))
+       {
+               Path exe;
+               if(argv0.find('/')==string::npos)
+               {
+                       const char *path = getenv("PATH");
+                       vector<string> dirs = split(path, ':');
+                       for(vector<string>::const_iterator i=dirs.begin(); i!=dirs.end(); ++i)
+                               if(exists(Path(*i)/argv0))
+                               {
+                                       exe = realpath(Path(*i)/argv0);
+                                       break;
+                               }
+               }
+               else
+                       exe = realpath(argv0);
+
+               last_argv0 = argv0;
+               bin_dir = dirname(exe);
+       }
+
+       return bin_dir;
+}
+
+}
+
+void mkdir(const Path &path, int mode)
+{
+       int err;
+#ifdef WIN32
+       // The win32 version of this function doesn't take the mode argument.  Go figure.
+       (void)mode;
+       err = ::mkdir(path.str().c_str());
+#else
+       err = ::mkdir(path.str().c_str(), mode);
+#endif
+
+       if(err==-1)
+               throw SystemError("mkdir failed", errno);
+}
+
+void mkpath(const Path &path, int mode)
+{
+       Path p;
+       for(Path::Iterator i=path.begin(); i!=path.end(); ++i)
+       {
+               p /= *i;
+#ifdef WIN32
+               if(p.size()==1 && p.is_absolute())
+                       continue;
+#endif
+               struct stat st;
+               int err = stat(p, st);
+               if(err==0)
+               {
+                       if(!S_ISDIR(st.st_mode))
+                               throw Exception("A component exists and is not a directory");
+                       continue;
+               }
+               else if(errno!=ENOENT)
+                       throw SystemError("stat failed", errno);
+               else
+                       mkdir(p, mode);
+       }
+}
+
+void rmdir(const Path &path)
+{
+       if(::rmdir(path.str().c_str())==-1)
+               throw SystemError("rmdir failed", errno);
+}
+
+void rmdirs(const Path &path)
+{
+       list<string> files = list_files(path);
+       for(list<string>::iterator i=files.begin(); i!=files.end(); ++i)
+       {
+               Path p = path / *i;
+               struct stat st = stat(p.str().c_str());
+               if(S_ISDIR(st.st_mode))
+                       rmdirs(p);
+               else
+                       unlink(p);
+       }
+
+       rmdir(path);
+}
+
+list<string> list_files(const Path &path)
+{
+       return list_filtered(path, string());
+}
+
+list<string> list_filtered(const Path &path, const string &filter)
+{
+       Regex r_filter(filter);
+
+       list<string> result;
+       DIR *dir = opendir(path.str().c_str());
+       if(dir)
+       {
+               while(dirent *de = readdir(dir))
+               {
+                       const char *fn = de->d_name;
+                       if(fn[0]=='.' && (fn[1]==0 || (fn[1]=='.' && fn[2]==0))) 
+                               continue;
+                       if(r_filter.match(fn))
+                               result.push_back(fn);
+               }
+               closedir(dir);
+       }
+
+       return result;
+}
+
+Path getcwd()
+{
+       char buf[1024];
+       return ::getcwd(buf, sizeof(buf));
+}
+
+Path get_home_dir()
+{
+#ifdef WIN32
+       char home[MAX_PATH];
+       if(SHGetFolderPath(0, CSIDL_PERSONAL, 0, 0, home)==S_OK)
+               return home;
+#else
+       const char *home = getenv("HOME");
+       if(home)
+               return home;
+#endif
+       return ".";
+}
+
+Path get_user_data_dir(const string &appname)
+{
+#ifdef WIN32
+       char datadir[MAX_PATH];
+       if(SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, datadir)==S_OK)
+               return Path(datadir)/appname;
+       return ".";
+#else
+       return get_home_dir()/("."+appname);
+#endif
+}
+
+Path get_sys_conf_dir(const string &argv0)
+{
+       Path dir = get_bin_dir(argv0);
+
+       if(dir[-1]=="bin" || dir[-1]=="sbin")
+       {
+               dir /= "..";
+               if(dir[-1]=="usr")
+                       dir /= "..";
+               return dir/"etc";
+       }
+       else
+               return dir;
+}
+
+Path get_sys_data_dir(const string &argv0, const string &appname)
+{
+       Path dir = get_bin_dir(argv0);
+
+       if(dir[-1]=="bin" || dir[-1]=="sbin")
+               return dir/".."/"share"/appname;
+       else
+               return dir;
+}
+
+Path get_sys_lib_dir(const string &argv0, const string &appname)
+{
+       Path dir = get_bin_dir(argv0);
+
+       if(dir[-1]=="bin" || dir[-1]=="sbin")
+               return dir/".."/"lib"/appname;
+       else
+               return dir;
+}
+
+void chdir(const Path &path)
+{
+       if(::chdir(path.str().c_str())==-1)
+               throw SystemError("chdir failed", errno);
+}
+
+} // namespace FS
+} // namespace Msp
diff --git a/source/fs/dir.h b/source/fs/dir.h
new file mode 100644 (file)
index 0000000..53228cc
--- /dev/null
@@ -0,0 +1,60 @@
+/* $Id$
+
+This file is part of libmspfs
+Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_FS_DIR_H_
+#define MSP_FS_DIR_H_
+
+#include <list>
+#include <string>
+#include "path.h"
+
+namespace Msp {
+namespace FS {
+
+/// Creates a directory
+void mkdir(const Path &path, int mode);
+
+/// Creates a directory and any required parent directories
+void mkpath(const Path &path, int mode);
+
+/// Removes a directory, which must be empty
+void rmdir(const Path &path);
+
+/// Removes a directory and anything it contains
+void rmpath(const Path &path);
+
+/// Lists the contents of a directory
+std::list<std::string> list_files(const Path &path);
+
+/// Lists the contents of a directory, filtered with a regex
+std::list<std::string> list_filtered(const Path &path, const std::string &filter);
+
+/// Returns the current working directory
+Path getcwd();
+
+/// Returns the user's home directory
+Path get_home_dir();
+
+/// Returns a directory suitable for storing user-specific data
+Path get_user_data_dir(const std::string &appname);
+
+/// Returns a directory containing system-wide configuration
+Path get_sys_conf_dir(const std::string &argv0);
+
+/// Returns a directory containing immutable system-wide data
+Path get_sys_data_dir(const std::string &argv0, const std::string &appname);
+
+/// Returns a directory containing system-wide architecture-specific files
+Path get_sys_lib_dir(const std::string &argv0, const std::string &appname);
+
+/// Changes the current working directory
+void chdir(const Path &);
+
+} // namespace FS
+} // namespace Msp
+
+#endif
diff --git a/source/fs/path.cpp b/source/fs/path.cpp
new file mode 100644 (file)
index 0000000..e514d36
--- /dev/null
@@ -0,0 +1,279 @@
+/* $Id$
+
+This file is part of libmspfs
+Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <msp/core/except.h>
+#include <msp/strings/utils.h>
+#include "path.h"
+#include "utils.h"
+
+using namespace std;
+
+namespace {
+
+inline bool is_windows_drive(const std::string &p)
+{ return (p.size()==2 && ((p[0]>='A' && p[0]<='Z') || (p[0]>='a' && p[0]<='z')) && p[1]==':'); }
+
+}
+
+namespace Msp {
+namespace FS {
+
+Path::Path()
+{ }
+
+Path::Path(const string &p)
+{
+       init(p);
+}
+
+Path::Path(const char *p)
+{
+       init(p);
+}
+
+unsigned Path::size() const
+{
+       if(path.empty())
+               return 0;
+       if(path.size()==1 && path[0]==DIRSEP)
+               return 1;
+
+       unsigned count = 1;
+       for(string::const_iterator i=path.begin(); i!=path.end(); ++i)
+               if(*i==DIRSEP) ++count;
+       return count;
+}
+
+bool Path::is_absolute() const
+{
+#ifdef WIN32
+       if(is_windows_drive((*this)[0]))
+               return true;
+#endif
+       if(path[0]==DIRSEP)
+               return true;
+       return false;
+}
+
+Path Path::subpath(unsigned start, unsigned count) const
+{
+       Path result;
+       Iterator i = begin();
+       for(unsigned j=0; (j<start && i!=end()); ++j)
+               ++i;
+       for(unsigned j=0; (j<count && i!=end()); ++j)
+       {
+               result /= *i;
+               ++i;
+       }
+       return result;
+}
+
+Path Path::operator/(const Path &p) const
+{
+       Path a = *this;
+       a /= p;
+       return a;
+}
+
+/**
+Attaches another path to the end of this one.  An absolute path replaces the
+existing data.  ".." elements annihilate the last component and "." elements
+are ignored.
+*/
+Path &Path::operator/=(const Path &p)
+{
+       if(p.is_absolute())
+               path = p.path;
+       else
+       {
+               for(Iterator i=p.begin(); i!=p.end(); ++i)
+                       add_component(*i);
+       }
+       return *this;
+}
+
+string Path::operator[](int n) const
+{
+       if(n>=0)
+       {
+               for(Iterator i=begin(); i!=end(); ++i, --n)
+                       if(!n)
+                               return *i;
+       }
+       else
+       {
+               for(Iterator i=end(); i!=begin();)
+               {
+                       --i;
+                       if(!++n)
+                               return *i;
+               }
+       }
+
+       throw InvalidParameterValue("Path component index out of range");
+}
+
+bool Path::operator==(const Path &p) const
+{
+#ifdef WIN32
+       return !strcasecmp(path, p.path);
+#else
+       return path==p.path;
+#endif
+}
+
+Path::Iterator Path::begin() const
+{
+       return Iterator(*this);
+}
+
+Path::Iterator Path::end() const
+{
+       Iterator i(*this);
+       i.start=i.end = std::string::npos;
+       return i;
+}
+
+void Path::init(const string &p)
+{
+       string::size_type start = 0;
+       if(p[0]=='/' || p[0]=='\\')
+               add_component(string(1, DIRSEP));
+       while(1)
+       {
+               string::size_type slash = p.find_first_of("/\\", start);
+               if(slash>start)
+                       add_component(p.substr(start, slash-start));
+               if(slash==string::npos)
+                       break;
+               start = slash+1;
+       }
+}
+
+/**
+Adds a single component to the path, emulating the cd command.  Fails horribly
+if comp contains a separator character.
+*/
+void Path::add_component(const string &comp)
+{
+       if(comp.empty())
+               ;
+       else if(comp.size()==1 && comp[0]==DIRSEP)
+       {
+               // Replace the path with the root directory
+#ifdef WIN32
+               unsigned slash = path.find(DIRSEP);
+               if(is_windows_drive(path.substr(0, slash)))
+                       path = path.substr(0, 2);
+               else
+#endif
+               path = comp;
+       }
+#ifdef WIN32
+       else if(is_windows_drive(comp))
+               path = comp;
+#endif
+       else if(comp=="..")
+       {
+               if(path.empty() || path==".")
+                       path = comp;
+               // .. in root directory is a no-op
+               else if(path.size()==1 && path[0]==DIRSEP)
+                       ;
+#ifdef WIN32
+               else if(is_windows_drive(path))
+                       ;
+#endif
+               else
+               {
+                       string::size_type slash = path.rfind(DIRSEP);
+                       string::size_type start = (slash==string::npos ? 0 : slash+1);
+                       if(!path.compare(start, string::npos, ".."))
+                       {
+                               // If the last component already is a .., add another
+                               path += DIRSEP;
+                               path += comp;
+                       }
+                       else if(slash==string::npos)
+                               path = ".";
+                       else
+                       {
+                               if(slash==0)
+                                       slash = 1;
+                               // Otherwise, erase the last component
+                               path.erase(slash, string::npos);
+                       }
+               }
+       }
+       else if(comp!="." || path.empty())
+       {
+               if(comp!="." && path.empty())
+                       path = ".";
+               if(path.size()>1 || (path.size()==1 && path[0]!=DIRSEP))
+                       path += DIRSEP;
+               path += comp;
+       }
+}
+
+
+Path::Iterator::Iterator(const Path &p):
+       path(p),
+       start(0)
+{
+       if(path.path.empty())
+               start=end = string::npos;
+       else if(path.path[0]==DIRSEP)
+               end = 1;
+#ifdef WIN32
+       else if(path.path.size()>2 && path.path[2]==DIRSEP && is_windows_drive(path.path.substr(0, 2)))
+               end = 2;
+#endif
+       else
+               end = path.path.find(DIRSEP);
+}
+
+Path::Iterator &Path::Iterator::operator++()
+{
+       start = end;
+       if(start>=path.path.size())
+               return *this;
+       if(path.path[start]==DIRSEP)
+               ++start;
+       end = path.path.find(DIRSEP, start);
+       return *this;
+}
+
+Path::Iterator &Path::Iterator::operator--()
+{
+       if(start==0)
+               return *this;
+
+       end = start;
+       if(end>1 && end<path.path.size() && path.path[end]!=DIRSEP)
+               --end;
+
+       start = path.path.rfind(DIRSEP, end-1);
+       if(start==string::npos)
+               start = 0;
+       else if(start<end-1)
+               ++start;
+
+       return *this;
+}
+
+string Path::Iterator::operator*() const
+{
+       if(start>=path.path.size())
+               return string();
+       if(start==end)
+               return string();
+       return path.path.substr(start, end-start);
+}
+
+} // namespace FS
+} // namespace Msp
diff --git a/source/fs/path.h b/source/fs/path.h
new file mode 100644 (file)
index 0000000..e560d3f
--- /dev/null
@@ -0,0 +1,95 @@
+/* $Id$
+
+This file is part of libmspfs
+Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_FS_PATH_H_
+#define MSP_FS_PATH_H_
+
+#include <ostream>
+#include <string>
+
+namespace Msp {
+namespace FS {
+
+enum
+{
+#ifdef WIN32
+       DIRSEP = '\\'
+#else
+       DIRSEP = '/'
+#endif
+};
+
+/**
+Stores a filesystem path.  Paths are always stored in a normalized form; there
+are never any "." or ".." components in the middle of the path, and relative
+paths always begin with a single "." component or a sequence ".." components.
+*/
+class Path
+{
+public:
+       class Iterator
+       {
+               friend class Path;
+
+       private:
+               const Path &path;
+               std::string::size_type start,end;
+
+               Iterator(const Path &);
+       public:
+               Iterator    &operator++();
+               Iterator    &operator--();
+               std::string operator*() const;
+               bool        operator==(const Iterator &i) const { return (start==i.start && end==i.end); }
+               bool        operator!=(const Iterator &i) const { return !(*this==i); }
+       };
+
+private:
+       std::string path;
+
+public:
+       Path();
+       Path(const std::string &);
+       Path(const char *);
+
+       const std::string &str() const { return path; }
+
+       /// Returns the number of components in the path.
+       unsigned    size() const;
+
+       bool        empty() const { return path.empty(); }
+
+       /// Determines whether the path starts from the root directory
+       bool is_absolute() const;
+
+       /// Extracts a range of components from the path.
+       Path subpath(unsigned start, unsigned count = static_cast<unsigned>(-1)) const;
+
+       /// Concatenates this path with another one, with usual filesystem semantics
+       Path operator/(const Path &p) const;
+       Path &operator/=(const Path &);
+
+       /**
+       Extracts a single component from the path.  Negative indices count from the
+       end of the path.
+       */
+       std::string operator[](int) const;
+
+       bool        operator==(const Path &) const;
+       Iterator    begin() const;
+       Iterator    end() const;
+private:
+       void init(const std::string &);
+       void add_component(const std::string &);
+};
+
+inline std::ostream &operator<<(std::ostream &o, const Path &p) { o<<p.str(); return o; }
+
+} // namespace FS
+} // namespace Msp
+
+#endif
diff --git a/source/fs/stat.cpp b/source/fs/stat.cpp
new file mode 100644 (file)
index 0000000..1dc46db
--- /dev/null
@@ -0,0 +1,83 @@
+/* $Id$
+
+This file is part of libmspfs
+Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <cerrno>
+#ifdef WIN32
+#include <io.h>
+#endif
+#include <msp/core/except.h>
+#include "path.h"
+#include "stat.h"
+
+namespace Msp {
+namespace FS {
+
+int stat(const Path &fn, struct stat &st)
+{
+       return ::stat(fn.str().c_str(), &st);
+}
+
+struct stat stat(const Path &fn)
+{
+       struct stat st;
+       if(stat(fn, st)==-1)
+               throw SystemError("stat failed", errno);
+       return st;
+}
+
+int lstat(const Path &fn, struct stat &st)
+{
+#ifdef WIN32
+       return stat(fn, st);
+#else
+       return ::lstat(fn.str().c_str(), &st);
+#endif
+}
+
+struct stat lstat(const Path &fn)
+{
+       struct stat st;
+       if(lstat(fn, st)==-1)
+               throw SystemError("lstat failed", errno);
+       return st;
+}
+
+bool exists(const Path &path)
+{
+       return access(path.str().c_str(), F_OK)==0;
+}
+
+bool is_reg(const Path &path)
+{
+       struct stat st;
+       if(stat(path, st)==0)
+               return S_ISREG(st.st_mode);
+       return false;
+}
+
+bool is_dir(const Path &path)
+{
+       struct stat st;
+       if(stat(path, st)==0)
+               return S_ISDIR(st.st_mode);
+       return false;
+}
+
+bool is_link(const Path &path)
+{
+#ifdef WIN32
+       (void)path;
+#else
+       struct stat st;
+       if(lstat(path, st)==0)
+               return S_ISLNK(st.st_mode);
+#endif
+       return false;
+}
+
+} // namespace FS
+} // namespace Msp
diff --git a/source/fs/stat.h b/source/fs/stat.h
new file mode 100644 (file)
index 0000000..55a1fec
--- /dev/null
@@ -0,0 +1,51 @@
+/* $Id$
+
+This file is part of libmspfs
+Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_FS_STAT_H_
+#define MSP_FS_STAT_H_
+
+#include <sys/stat.h>
+#include "path.h"
+
+namespace Msp {
+namespace FS {
+
+/**
+Gets information about a file.  Returns 0 on success or -1 on error.  This
+version can be used to check for file existence and get information in one
+call.
+*/
+int stat(const Path &fn, struct stat &st);
+
+/**
+Returns information about a file.  This version throws an exception if an error
+occurs.
+*/
+struct stat stat(const Path &fn);
+
+/// Gets information about a file, without following symbolic links
+int lstat(const Path &fn, struct stat &st);
+
+/// Returns information about a file, without following symbolic links
+struct stat lstat(const Path &fn);
+
+/// Tests for existence of a file
+bool exists(const Path &path);
+
+/// Tests whether a path refers to an existing regular file
+bool is_reg(const Path &path);
+
+/// Tests whether a path refers to an existing directory
+bool is_dir(const Path &path);
+
+/// Tests whether a path refers to a symbolic link
+bool is_link(const Path &path);
+
+} // namespace FS
+} // namespace Msp
+
+#endif
diff --git a/source/fs/utils.cpp b/source/fs/utils.cpp
new file mode 100644 (file)
index 0000000..694a8f1
--- /dev/null
@@ -0,0 +1,185 @@
+/* $Id$
+
+This file is part of libmspfs
+Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <cerrno>
+#include <cstdio>
+#include <msp/core/except.h>
+#ifndef WIN32
+#include <fnmatch.h>
+#else
+#include <msp/strings/glob.h>
+#endif
+#include <msp/strings/utils.h>
+#include "dir.h"
+#include "path.h"
+#include "stat.h"
+#include "utils.h"
+
+using namespace std;
+
+namespace Msp {
+namespace FS {
+
+string basename(const Path &p)
+{
+       return p[-1];
+}
+
+Path dirname(const Path &p)
+{
+       if(p.size()==1)
+       {
+               if(p.is_absolute())
+                       return p;
+               return ".";
+       }
+       return p.subpath(0, p.size()-1);
+}
+
+string basepart(const string &fn)
+{
+       unsigned dot = fn.rfind('.');
+       return fn.substr(0, dot);
+}
+
+string extpart(const string &fn)
+{
+       string::size_type dot = fn.rfind('.');
+       if(dot==string::npos)
+               return string();
+       return fn.substr(dot);
+}
+
+Path fix_case(const Path &path)
+{
+       bool found = true;
+       Path result;
+       for(Path::Iterator i=path.begin(); i!=path.end(); ++i)
+       {
+               if(!found || *i=="/")
+                       result /= *i;
+               else
+               {
+                       list<string> files;
+                       if(result.size())
+                               files = list_files(result);
+                       else
+                               files = list_files(".");
+
+                       found = false;
+                       for(list<string>::iterator j=files.begin(); (j!=files.end() && !found); ++j)
+                               if(!strcasecmp(*j,*i))
+                               {
+                                       result /= *j;
+                                       found = true;
+                               }
+
+                       if(!found)
+                               result /= *i;
+               }
+       }
+
+       return result;
+}
+
+Path readlink(const Path &link)
+{
+#ifdef WIN32
+       (void)link;
+       throw Exception("No symbolic links on win32");
+#else
+       char buf[4096];
+       int len = ::readlink(link.str().c_str(), buf, sizeof(buf));
+       if(len==-1)
+               throw SystemError("readlink failed", errno);
+       return string(buf, len);
+#endif
+}
+
+Path realpath(const Path &path)
+{
+#ifdef WIN32
+       if(path.is_absolute())
+               return path;
+       else
+               return getcwd()/path;
+#else
+       list<string> queue(path.begin(), path.end());
+       if(!path.is_absolute())
+       {
+               Path cwd = getcwd();
+               queue.insert(queue.begin(), cwd.begin(), cwd.end());
+       }
+
+       Path real;
+       unsigned n_links = 0;
+       while(!queue.empty())
+       {
+               Path next = real/queue.front();
+               queue.pop_front();
+
+               struct stat st = lstat(next);
+               if(S_ISLNK(st.st_mode))
+               {
+                       if(++n_links>64)
+                               throw Exception("Ludicrous amount of symlinks detected in realpath, giving up");
+                       Path link = readlink(next);
+                       queue.insert(queue.begin(), link.begin(), link.end());
+               }
+               else
+                       real = next;
+       }
+
+       return real;
+#endif
+}
+
+void rename(const Path &from, const Path &to)
+{
+       if(::rename(from.str().c_str(), to.str().c_str())==-1)
+               throw SystemError("rename failed", errno);
+}
+
+void unlink(const Path &path)
+{
+       if(::unlink(path.str().c_str())==-1)
+               throw SystemError("unlink failed", errno);
+}
+
+Path relative(const Path &path, const Path &base)
+{
+       Path::Iterator i = path.begin();
+       Path::Iterator j = base.begin();
+       for(; (i!=path.end() && j!=base.end() && *i==*j); ++i, ++j) ;
+
+       Path result;
+       for(; j!=base.end(); ++j)
+               result /= "..";
+       for(; i!=path.end(); ++i)
+               result /= *i;
+
+       return result;
+}
+
+int descendant_depth(const Path &path, const Path &parent)
+{
+       Path::Iterator i = path.begin();
+       Path::Iterator j = parent.begin();
+       for(; (i!=path.end() && j!=parent.end() && *i==*j); ++i, ++j) ;
+
+       if(j!=parent.end())
+               return -1;
+       
+       int result = 0;
+       for(; i!=path.end(); ++i)
+               ++result;
+
+       return result;
+}
+
+} // namespace FS
+} // namespace Msp
diff --git a/source/fs/utils.h b/source/fs/utils.h
new file mode 100644 (file)
index 0000000..6a4c55a
--- /dev/null
@@ -0,0 +1,62 @@
+/* $Id$
+
+This file is part of libmspfs
+Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_FS_UTILS_H_
+#define MSP_FS_UTILS_H_
+
+#include "path.h"
+
+namespace Msp {
+namespace FS {
+
+/// Extracts the last component of the path.
+std::string basename(const Path &);
+
+/// Removes the last component from the path.
+Path dirname(const Path &);
+
+/**
+Returns the base part of a filename.  This includes everything up to the last
+dot, but not the dot itself.
+*/
+std::string basepart(const std::string &);
+
+/**
+Returns the extension part of a filename.  This includes the last dot and
+everything after it.
+*/
+std::string extpart(const std::string &);
+
+/**
+Fixes the case of the given path to match files / directories on the
+filesystem.
+*/
+Path fix_case(const Path &path);
+
+/// Reads the contents of a symbolic link
+Path readlink(const Path &path);
+
+/// Resolves all symlinks from a path.  Will always return an absolute path.
+Path realpath(const Path &path);
+
+/// Removes a file
+void unlink(const Path &path);
+
+/// Renames a file.  Existing file, if any, is overwritten.
+void rename(const Path &from, const Path &to);
+
+/// Makes a path relative to some base path.  That is, base/result==path.
+Path relative(const Path &path, const Path &base);
+
+/** Determines how many levels a path is below another.  Returns -1 if path is
+not a descendant of parent. */
+int descendant_depth(const Path &path, const Path &parent);
+
+} // namespace FS
+} // namespace Msp
+
+#endif
diff --git a/source/path.cpp b/source/path.cpp
deleted file mode 100644 (file)
index e514d36..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-/* $Id$
-
-This file is part of libmspfs
-Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#include <msp/core/except.h>
-#include <msp/strings/utils.h>
-#include "path.h"
-#include "utils.h"
-
-using namespace std;
-
-namespace {
-
-inline bool is_windows_drive(const std::string &p)
-{ return (p.size()==2 && ((p[0]>='A' && p[0]<='Z') || (p[0]>='a' && p[0]<='z')) && p[1]==':'); }
-
-}
-
-namespace Msp {
-namespace FS {
-
-Path::Path()
-{ }
-
-Path::Path(const string &p)
-{
-       init(p);
-}
-
-Path::Path(const char *p)
-{
-       init(p);
-}
-
-unsigned Path::size() const
-{
-       if(path.empty())
-               return 0;
-       if(path.size()==1 && path[0]==DIRSEP)
-               return 1;
-
-       unsigned count = 1;
-       for(string::const_iterator i=path.begin(); i!=path.end(); ++i)
-               if(*i==DIRSEP) ++count;
-       return count;
-}
-
-bool Path::is_absolute() const
-{
-#ifdef WIN32
-       if(is_windows_drive((*this)[0]))
-               return true;
-#endif
-       if(path[0]==DIRSEP)
-               return true;
-       return false;
-}
-
-Path Path::subpath(unsigned start, unsigned count) const
-{
-       Path result;
-       Iterator i = begin();
-       for(unsigned j=0; (j<start && i!=end()); ++j)
-               ++i;
-       for(unsigned j=0; (j<count && i!=end()); ++j)
-       {
-               result /= *i;
-               ++i;
-       }
-       return result;
-}
-
-Path Path::operator/(const Path &p) const
-{
-       Path a = *this;
-       a /= p;
-       return a;
-}
-
-/**
-Attaches another path to the end of this one.  An absolute path replaces the
-existing data.  ".." elements annihilate the last component and "." elements
-are ignored.
-*/
-Path &Path::operator/=(const Path &p)
-{
-       if(p.is_absolute())
-               path = p.path;
-       else
-       {
-               for(Iterator i=p.begin(); i!=p.end(); ++i)
-                       add_component(*i);
-       }
-       return *this;
-}
-
-string Path::operator[](int n) const
-{
-       if(n>=0)
-       {
-               for(Iterator i=begin(); i!=end(); ++i, --n)
-                       if(!n)
-                               return *i;
-       }
-       else
-       {
-               for(Iterator i=end(); i!=begin();)
-               {
-                       --i;
-                       if(!++n)
-                               return *i;
-               }
-       }
-
-       throw InvalidParameterValue("Path component index out of range");
-}
-
-bool Path::operator==(const Path &p) const
-{
-#ifdef WIN32
-       return !strcasecmp(path, p.path);
-#else
-       return path==p.path;
-#endif
-}
-
-Path::Iterator Path::begin() const
-{
-       return Iterator(*this);
-}
-
-Path::Iterator Path::end() const
-{
-       Iterator i(*this);
-       i.start=i.end = std::string::npos;
-       return i;
-}
-
-void Path::init(const string &p)
-{
-       string::size_type start = 0;
-       if(p[0]=='/' || p[0]=='\\')
-               add_component(string(1, DIRSEP));
-       while(1)
-       {
-               string::size_type slash = p.find_first_of("/\\", start);
-               if(slash>start)
-                       add_component(p.substr(start, slash-start));
-               if(slash==string::npos)
-                       break;
-               start = slash+1;
-       }
-}
-
-/**
-Adds a single component to the path, emulating the cd command.  Fails horribly
-if comp contains a separator character.
-*/
-void Path::add_component(const string &comp)
-{
-       if(comp.empty())
-               ;
-       else if(comp.size()==1 && comp[0]==DIRSEP)
-       {
-               // Replace the path with the root directory
-#ifdef WIN32
-               unsigned slash = path.find(DIRSEP);
-               if(is_windows_drive(path.substr(0, slash)))
-                       path = path.substr(0, 2);
-               else
-#endif
-               path = comp;
-       }
-#ifdef WIN32
-       else if(is_windows_drive(comp))
-               path = comp;
-#endif
-       else if(comp=="..")
-       {
-               if(path.empty() || path==".")
-                       path = comp;
-               // .. in root directory is a no-op
-               else if(path.size()==1 && path[0]==DIRSEP)
-                       ;
-#ifdef WIN32
-               else if(is_windows_drive(path))
-                       ;
-#endif
-               else
-               {
-                       string::size_type slash = path.rfind(DIRSEP);
-                       string::size_type start = (slash==string::npos ? 0 : slash+1);
-                       if(!path.compare(start, string::npos, ".."))
-                       {
-                               // If the last component already is a .., add another
-                               path += DIRSEP;
-                               path += comp;
-                       }
-                       else if(slash==string::npos)
-                               path = ".";
-                       else
-                       {
-                               if(slash==0)
-                                       slash = 1;
-                               // Otherwise, erase the last component
-                               path.erase(slash, string::npos);
-                       }
-               }
-       }
-       else if(comp!="." || path.empty())
-       {
-               if(comp!="." && path.empty())
-                       path = ".";
-               if(path.size()>1 || (path.size()==1 && path[0]!=DIRSEP))
-                       path += DIRSEP;
-               path += comp;
-       }
-}
-
-
-Path::Iterator::Iterator(const Path &p):
-       path(p),
-       start(0)
-{
-       if(path.path.empty())
-               start=end = string::npos;
-       else if(path.path[0]==DIRSEP)
-               end = 1;
-#ifdef WIN32
-       else if(path.path.size()>2 && path.path[2]==DIRSEP && is_windows_drive(path.path.substr(0, 2)))
-               end = 2;
-#endif
-       else
-               end = path.path.find(DIRSEP);
-}
-
-Path::Iterator &Path::Iterator::operator++()
-{
-       start = end;
-       if(start>=path.path.size())
-               return *this;
-       if(path.path[start]==DIRSEP)
-               ++start;
-       end = path.path.find(DIRSEP, start);
-       return *this;
-}
-
-Path::Iterator &Path::Iterator::operator--()
-{
-       if(start==0)
-               return *this;
-
-       end = start;
-       if(end>1 && end<path.path.size() && path.path[end]!=DIRSEP)
-               --end;
-
-       start = path.path.rfind(DIRSEP, end-1);
-       if(start==string::npos)
-               start = 0;
-       else if(start<end-1)
-               ++start;
-
-       return *this;
-}
-
-string Path::Iterator::operator*() const
-{
-       if(start>=path.path.size())
-               return string();
-       if(start==end)
-               return string();
-       return path.path.substr(start, end-start);
-}
-
-} // namespace FS
-} // namespace Msp
diff --git a/source/path.h b/source/path.h
deleted file mode 100644 (file)
index e560d3f..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* $Id$
-
-This file is part of libmspfs
-Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#ifndef MSP_FS_PATH_H_
-#define MSP_FS_PATH_H_
-
-#include <ostream>
-#include <string>
-
-namespace Msp {
-namespace FS {
-
-enum
-{
-#ifdef WIN32
-       DIRSEP = '\\'
-#else
-       DIRSEP = '/'
-#endif
-};
-
-/**
-Stores a filesystem path.  Paths are always stored in a normalized form; there
-are never any "." or ".." components in the middle of the path, and relative
-paths always begin with a single "." component or a sequence ".." components.
-*/
-class Path
-{
-public:
-       class Iterator
-       {
-               friend class Path;
-
-       private:
-               const Path &path;
-               std::string::size_type start,end;
-
-               Iterator(const Path &);
-       public:
-               Iterator    &operator++();
-               Iterator    &operator--();
-               std::string operator*() const;
-               bool        operator==(const Iterator &i) const { return (start==i.start && end==i.end); }
-               bool        operator!=(const Iterator &i) const { return !(*this==i); }
-       };
-
-private:
-       std::string path;
-
-public:
-       Path();
-       Path(const std::string &);
-       Path(const char *);
-
-       const std::string &str() const { return path; }
-
-       /// Returns the number of components in the path.
-       unsigned    size() const;
-
-       bool        empty() const { return path.empty(); }
-
-       /// Determines whether the path starts from the root directory
-       bool is_absolute() const;
-
-       /// Extracts a range of components from the path.
-       Path subpath(unsigned start, unsigned count = static_cast<unsigned>(-1)) const;
-
-       /// Concatenates this path with another one, with usual filesystem semantics
-       Path operator/(const Path &p) const;
-       Path &operator/=(const Path &);
-
-       /**
-       Extracts a single component from the path.  Negative indices count from the
-       end of the path.
-       */
-       std::string operator[](int) const;
-
-       bool        operator==(const Path &) const;
-       Iterator    begin() const;
-       Iterator    end() const;
-private:
-       void init(const std::string &);
-       void add_component(const std::string &);
-};
-
-inline std::ostream &operator<<(std::ostream &o, const Path &p) { o<<p.str(); return o; }
-
-} // namespace FS
-} // namespace Msp
-
-#endif
diff --git a/source/stat.cpp b/source/stat.cpp
deleted file mode 100644 (file)
index 1dc46db..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/* $Id$
-
-This file is part of libmspfs
-Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#include <cerrno>
-#ifdef WIN32
-#include <io.h>
-#endif
-#include <msp/core/except.h>
-#include "path.h"
-#include "stat.h"
-
-namespace Msp {
-namespace FS {
-
-int stat(const Path &fn, struct stat &st)
-{
-       return ::stat(fn.str().c_str(), &st);
-}
-
-struct stat stat(const Path &fn)
-{
-       struct stat st;
-       if(stat(fn, st)==-1)
-               throw SystemError("stat failed", errno);
-       return st;
-}
-
-int lstat(const Path &fn, struct stat &st)
-{
-#ifdef WIN32
-       return stat(fn, st);
-#else
-       return ::lstat(fn.str().c_str(), &st);
-#endif
-}
-
-struct stat lstat(const Path &fn)
-{
-       struct stat st;
-       if(lstat(fn, st)==-1)
-               throw SystemError("lstat failed", errno);
-       return st;
-}
-
-bool exists(const Path &path)
-{
-       return access(path.str().c_str(), F_OK)==0;
-}
-
-bool is_reg(const Path &path)
-{
-       struct stat st;
-       if(stat(path, st)==0)
-               return S_ISREG(st.st_mode);
-       return false;
-}
-
-bool is_dir(const Path &path)
-{
-       struct stat st;
-       if(stat(path, st)==0)
-               return S_ISDIR(st.st_mode);
-       return false;
-}
-
-bool is_link(const Path &path)
-{
-#ifdef WIN32
-       (void)path;
-#else
-       struct stat st;
-       if(lstat(path, st)==0)
-               return S_ISLNK(st.st_mode);
-#endif
-       return false;
-}
-
-} // namespace FS
-} // namespace Msp
diff --git a/source/stat.h b/source/stat.h
deleted file mode 100644 (file)
index 55a1fec..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* $Id$
-
-This file is part of libmspfs
-Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#ifndef MSP_FS_STAT_H_
-#define MSP_FS_STAT_H_
-
-#include <sys/stat.h>
-#include "path.h"
-
-namespace Msp {
-namespace FS {
-
-/**
-Gets information about a file.  Returns 0 on success or -1 on error.  This
-version can be used to check for file existence and get information in one
-call.
-*/
-int stat(const Path &fn, struct stat &st);
-
-/**
-Returns information about a file.  This version throws an exception if an error
-occurs.
-*/
-struct stat stat(const Path &fn);
-
-/// Gets information about a file, without following symbolic links
-int lstat(const Path &fn, struct stat &st);
-
-/// Returns information about a file, without following symbolic links
-struct stat lstat(const Path &fn);
-
-/// Tests for existence of a file
-bool exists(const Path &path);
-
-/// Tests whether a path refers to an existing regular file
-bool is_reg(const Path &path);
-
-/// Tests whether a path refers to an existing directory
-bool is_dir(const Path &path);
-
-/// Tests whether a path refers to a symbolic link
-bool is_link(const Path &path);
-
-} // namespace FS
-} // namespace Msp
-
-#endif
diff --git a/source/utils.cpp b/source/utils.cpp
deleted file mode 100644 (file)
index 694a8f1..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/* $Id$
-
-This file is part of libmspfs
-Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#include <cerrno>
-#include <cstdio>
-#include <msp/core/except.h>
-#ifndef WIN32
-#include <fnmatch.h>
-#else
-#include <msp/strings/glob.h>
-#endif
-#include <msp/strings/utils.h>
-#include "dir.h"
-#include "path.h"
-#include "stat.h"
-#include "utils.h"
-
-using namespace std;
-
-namespace Msp {
-namespace FS {
-
-string basename(const Path &p)
-{
-       return p[-1];
-}
-
-Path dirname(const Path &p)
-{
-       if(p.size()==1)
-       {
-               if(p.is_absolute())
-                       return p;
-               return ".";
-       }
-       return p.subpath(0, p.size()-1);
-}
-
-string basepart(const string &fn)
-{
-       unsigned dot = fn.rfind('.');
-       return fn.substr(0, dot);
-}
-
-string extpart(const string &fn)
-{
-       string::size_type dot = fn.rfind('.');
-       if(dot==string::npos)
-               return string();
-       return fn.substr(dot);
-}
-
-Path fix_case(const Path &path)
-{
-       bool found = true;
-       Path result;
-       for(Path::Iterator i=path.begin(); i!=path.end(); ++i)
-       {
-               if(!found || *i=="/")
-                       result /= *i;
-               else
-               {
-                       list<string> files;
-                       if(result.size())
-                               files = list_files(result);
-                       else
-                               files = list_files(".");
-
-                       found = false;
-                       for(list<string>::iterator j=files.begin(); (j!=files.end() && !found); ++j)
-                               if(!strcasecmp(*j,*i))
-                               {
-                                       result /= *j;
-                                       found = true;
-                               }
-
-                       if(!found)
-                               result /= *i;
-               }
-       }
-
-       return result;
-}
-
-Path readlink(const Path &link)
-{
-#ifdef WIN32
-       (void)link;
-       throw Exception("No symbolic links on win32");
-#else
-       char buf[4096];
-       int len = ::readlink(link.str().c_str(), buf, sizeof(buf));
-       if(len==-1)
-               throw SystemError("readlink failed", errno);
-       return string(buf, len);
-#endif
-}
-
-Path realpath(const Path &path)
-{
-#ifdef WIN32
-       if(path.is_absolute())
-               return path;
-       else
-               return getcwd()/path;
-#else
-       list<string> queue(path.begin(), path.end());
-       if(!path.is_absolute())
-       {
-               Path cwd = getcwd();
-               queue.insert(queue.begin(), cwd.begin(), cwd.end());
-       }
-
-       Path real;
-       unsigned n_links = 0;
-       while(!queue.empty())
-       {
-               Path next = real/queue.front();
-               queue.pop_front();
-
-               struct stat st = lstat(next);
-               if(S_ISLNK(st.st_mode))
-               {
-                       if(++n_links>64)
-                               throw Exception("Ludicrous amount of symlinks detected in realpath, giving up");
-                       Path link = readlink(next);
-                       queue.insert(queue.begin(), link.begin(), link.end());
-               }
-               else
-                       real = next;
-       }
-
-       return real;
-#endif
-}
-
-void rename(const Path &from, const Path &to)
-{
-       if(::rename(from.str().c_str(), to.str().c_str())==-1)
-               throw SystemError("rename failed", errno);
-}
-
-void unlink(const Path &path)
-{
-       if(::unlink(path.str().c_str())==-1)
-               throw SystemError("unlink failed", errno);
-}
-
-Path relative(const Path &path, const Path &base)
-{
-       Path::Iterator i = path.begin();
-       Path::Iterator j = base.begin();
-       for(; (i!=path.end() && j!=base.end() && *i==*j); ++i, ++j) ;
-
-       Path result;
-       for(; j!=base.end(); ++j)
-               result /= "..";
-       for(; i!=path.end(); ++i)
-               result /= *i;
-
-       return result;
-}
-
-int descendant_depth(const Path &path, const Path &parent)
-{
-       Path::Iterator i = path.begin();
-       Path::Iterator j = parent.begin();
-       for(; (i!=path.end() && j!=parent.end() && *i==*j); ++i, ++j) ;
-
-       if(j!=parent.end())
-               return -1;
-       
-       int result = 0;
-       for(; i!=path.end(); ++i)
-               ++result;
-
-       return result;
-}
-
-} // namespace FS
-} // namespace Msp
diff --git a/source/utils.h b/source/utils.h
deleted file mode 100644 (file)
index 6a4c55a..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* $Id$
-
-This file is part of libmspfs
-Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#ifndef MSP_FS_UTILS_H_
-#define MSP_FS_UTILS_H_
-
-#include "path.h"
-
-namespace Msp {
-namespace FS {
-
-/// Extracts the last component of the path.
-std::string basename(const Path &);
-
-/// Removes the last component from the path.
-Path dirname(const Path &);
-
-/**
-Returns the base part of a filename.  This includes everything up to the last
-dot, but not the dot itself.
-*/
-std::string basepart(const std::string &);
-
-/**
-Returns the extension part of a filename.  This includes the last dot and
-everything after it.
-*/
-std::string extpart(const std::string &);
-
-/**
-Fixes the case of the given path to match files / directories on the
-filesystem.
-*/
-Path fix_case(const Path &path);
-
-/// Reads the contents of a symbolic link
-Path readlink(const Path &path);
-
-/// Resolves all symlinks from a path.  Will always return an absolute path.
-Path realpath(const Path &path);
-
-/// Removes a file
-void unlink(const Path &path);
-
-/// Renames a file.  Existing file, if any, is overwritten.
-void rename(const Path &from, const Path &to);
-
-/// Makes a path relative to some base path.  That is, base/result==path.
-Path relative(const Path &path, const Path &base);
-
-/** Determines how many levels a path is below another.  Returns -1 if path is
-not a descendant of parent. */
-int descendant_depth(const Path &path, const Path &parent);
-
-} // namespace FS
-} // namespace Msp
-
-#endif