Refactor the API
authorMikko Rasa <tdb@tdb.fi>
Sun, 20 Jul 2008 12:12:55 +0000 (12:12 +0000)
committerMikko Rasa <tdb@tdb.fi>
Sun, 20 Jul 2008 12:12:55 +0000 (12:12 +0000)
Shuffle things around a bit in Path

source/dir.cpp
source/dir.h
source/path.cpp
source/path.h
source/stat.cpp
source/stat.h
source/utils.cpp
source/utils.h

index c402ec99ee2d61e95e930b07552a0437cbc2e77d..9d23a1388015a89acf8e9ce36cf257c4fd8941a7 100644 (file)
@@ -9,7 +9,11 @@ Distributed under the LGPL
 #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 "dir.h"
 #include "path.h"
 #include "stat.h"
@@ -35,14 +39,6 @@ void mkdir(const Path &path, int mode)
                throw SystemError("mkdir failed", errno);
 }
 
-/**
-Creates a directory and any parent directories if needed.
-
-@param   path  The path to create
-@param   mode  Access mode for new directories
-
-@return  0 on success, -1 on error
-*/
 void mkpath(const Path &path, int mode)
 {
        Path p;
@@ -92,6 +88,13 @@ void rmdirs(const Path &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)
@@ -101,7 +104,8 @@ list<string> list_files(const Path &path)
                        const char *fn=de->d_name;
                        if(fn[0]=='.' && (fn[1]==0 || (fn[1]=='.' && fn[2]==0))) 
                                continue;
-                       result.push_back(fn);
+                       if(r_filter.match(fn))
+                               result.push_back(fn);
                }
                closedir(dir);
        }
@@ -117,13 +121,27 @@ Path getcwd()
 
 Path get_home_dir()
 {
-#ifndef WIN32
+#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 ".";
-#else
+}
+
+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
 }
 
index 25ec776b2b814f4616e32f9a83d59ebe18d3bb6e..3b68463ec36f37f5944ff63a65d54191b18d915f 100644 (file)
@@ -22,21 +22,27 @@ 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
+/// Removes a directory, which must be empty
 void rmdir(const Path &path);
 
 /// Removes a directory and anything it contains
-void rmdirs(const Path &path);
+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);
+
 /// Changes the current working directory
 void chdir(const Path &);
 
index 35641f852096c59d30f67b8c9b4f78b59cf0ef27..c0b91d6c82f8321df9c31acd1e045bd026a08304 100644 (file)
@@ -11,22 +11,39 @@ Distributed under the LGPL
 
 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 {
 
-/**
-Returns the number of components in the path.
-*/
+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]==DIRCHAR)
+       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==DIRCHAR) ++count;
+               if(*i==DIRSEP) ++count;
        return count;
 }
 
@@ -36,14 +53,11 @@ bool Path::is_absolute() const
        if(is_windows_drive((*this)[0]))
                return true;
 #endif
-       if(path[0]==DIRCHAR)
+       if(path[0]==DIRSEP)
                return true;
        return false;
 }
 
-/**
-Extracts the given component range from the path.
-*/
 Path Path::subpath(unsigned start, unsigned count) const
 {
        Path result;
@@ -58,6 +72,13 @@ Path Path::subpath(unsigned start, unsigned count) const
        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
@@ -75,27 +96,26 @@ Path &Path::operator/=(const Path &p)
        return *this;
 }
 
-/**
-Returns the path component at the specified index.  Negative indices count from
-the end of the path.
-*/
 string Path::operator[](int n) const
 {
        if(n>=0)
        {
                for(Iterator i=begin(); i!=end(); ++i, --n)
-                       if(!n) return *i;
+                       if(!n)
+                               return *i;
        }
        else
        {
                for(Iterator i=--end();; --i)
                {
-                       if(!++n) return *i;
-                       if(i==begin()) break;
+                       if(!++n)
+                               return *i;
+                       if(i==begin())
+                               break;
                }
        }
 
-       return "";
+       return string();
 }
 
 bool Path::operator==(const Path &p) const
@@ -107,11 +127,23 @@ bool Path::operator==(const Path &p) const
 #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)
 {
        unsigned start=0;
        if(p[0]=='/' || p[0]=='\\')
-               add_component(string(1, DIRCHAR));
+               add_component(string(1, DIRSEP));
        while(1)
        {
                unsigned slash=p.find_first_of("/\\", start);
@@ -124,17 +156,18 @@ void Path::init(const string &p)
 }
 
 /**
-Adds a single component to the path, emulating the cd command.
+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]==DIRCHAR)
+       else if(comp.size()==1 && comp[0]==DIRSEP)
        {
                // Replace the path with the root directory
 #ifdef WIN32
-               unsigned slash=path.find(DIRCHAR);
+               unsigned slash=path.find(DIRSEP);
                if(is_windows_drive(path.substr(0, slash)))
                        path=path.substr(0, 2);
                else
@@ -150,7 +183,7 @@ void Path::add_component(const string &comp)
                if(path.empty())
                        path=comp;
                // .. in root directory is a no-op
-               else if(path.size()==1 && path[0]==DIRCHAR)
+               else if(path.size()==1 && path[0]==DIRSEP)
                        ;
 #ifdef WIN32
                else if(is_windows_drive(path))
@@ -158,12 +191,12 @@ void Path::add_component(const string &comp)
 #endif
                else
                {
-                       unsigned slash=path.rfind(DIRCHAR);
-                       unsigned start=(slash==string::npos)?0:slash+1;
+                       unsigned slash=path.rfind(DIRSEP);
+                       unsigned start=(slash==string::npos ? 0 : slash+1);
                        if(!path.compare(start, string::npos, ".."))
                        {
                                // If the last component already is a .., add another
-                               path+=DIRCHAR;
+                               path+=DIRSEP;
                                path+=comp;
                        }
                        else
@@ -175,54 +208,64 @@ void Path::add_component(const string &comp)
        {
                if(path==".")
                        path="";
-               if(path.size()>1 || (path.size()==1 && path[0]!=DIRCHAR))
-                       path+=DIRCHAR;
+               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]==DIRCHAR)
+       else if(path.path[0]==DIRSEP)
                end=1;
 #ifdef WIN32
-       else if(path.path.size()>2 && path.path[2]==DIRCHAR && is_windows_drive(path.path.substr(0, 2)))
+       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(DIRCHAR);
+               end=path.path.find(DIRSEP);
 }
 
 Path::Iterator &Path::Iterator::operator++()
 {
        start=end;
-       if(start>=path.path.size()) return *this;
-       if(path.path[start]==DIRCHAR) ++start;
-       end=path.path.find(DIRCHAR, start);
+       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==0) return *this;
-       if(end>1 && end<path.path.size() && path.path[end]!=DIRCHAR) --end;
-       start=path.path.rfind(DIRCHAR, end-1);
+       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 "";
-       if(start==end) return "";
+       if(start>=path.path.size())
+               return string();
+       if(start==end)
+               return string();
        return path.path.substr(start, end-start);
 }
 
index 082a1bae97c1f0e4a0b7d1e3e083ea74cf0da157..8c24f191394e5198d14fd7222f54f3c7bf1a6df6 100644 (file)
@@ -17,9 +17,9 @@ namespace FS {
 enum
 {
 #ifdef WIN32
-       DIRCHAR='\\'
+       DIRSEP='\\'
 #else
-       DIRCHAR='/'
+       DIRSEP='/'
 #endif
 };
 
@@ -28,38 +28,56 @@ class Path
 public:
        class Iterator
        {
+               friend class Path;
+
+       private:
+               const Path &path;
+               unsigned   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:
-               const Path &path;
-               unsigned   start,end;
+       };
 
-               Iterator(const Path &);
+private:
+       std::string path;
 
-               friend class Path;
-       };
+public:
+       Path();
+       Path(const std::string &);
+       Path(const char *);
 
-       Path() { }
-       Path(const std::string &p)     { init(p); }
-       Path(const char *p)            { init(p); }
        const std::string &str() const { return path; }
+
+       /// Returns the number of components in the path.
        unsigned    size() const;
+
        bool        empty() const { return path.empty(); }
-       bool        is_absolute() const;
-       Path        subpath(unsigned, unsigned =static_cast<unsigned>(-1)) const;
-       Path        operator/(const Path &p) const { Path a=*this; a/=p; return a; }
-       Path        &operator/=(const Path &);
+
+       /// 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 { return Iterator(*this); }
-       Iterator    end() const   { Iterator i(*this); i.start=i.end=std::string::npos; return i; }
+       Iterator    begin() const;
+       Iterator    end() const;
 private:
-       std::string path;
-
        void init(const std::string &);
        void add_component(const std::string &);
 };
index 5a0ee45ba20fe92e029ad2aa5ab73d089fd3f71c..3bfae74c348dc2429b135efc189878514c56d518 100644 (file)
@@ -6,6 +6,9 @@ Distributed under the LGPL
 */
 
 #include <cerrno>
+#ifdef WIN32
+#include <io.h>
+#endif
 #include <msp/core/except.h>
 #include "path.h"
 #include "stat.h"
@@ -31,6 +34,14 @@ 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;
index f6b13d431a340cddd256336a6e676e668f00c462..4970ff8634b9d1a1cf99061c1dc73f27e4054bc6 100644 (file)
@@ -31,6 +31,9 @@ struct stat stat(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);
 
index 5c8c8d4cdd08e899336b2bf8d15b3f0170a5be2b..0ca1d6064e1bd2cfcfa48bd8a3b649efc7333ca0 100644 (file)
@@ -22,11 +22,30 @@ using namespace std;
 namespace Msp {
 namespace FS {
 
-/**
-Fixes the case of the given path to match files / directories on the
-filesystem.  Intended to be used in programs that need to interact with
-emulated Windows programs.
-*/
+string basename(const Path &p)
+{
+       return p[-1];
+}
+
+Path dirname(const Path &p)
+{
+       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)
+{
+       unsigned dot=fn.rfind('.');
+       if(dot==string::npos)
+               return string();
+       return fn.substr(dot);
+}
+
 Path fix_case(const Path &path)
 {
        bool found=true;
@@ -65,25 +84,6 @@ void unlink(const Path &path)
                throw SystemError("unlink failed", errno);
 }
 
-Filename splitext(const string &fn)
-{
-       Filename result;
-       unsigned dot=fn.rfind('.');
-       result.base=fn.substr(0, dot);
-       if(dot!=string::npos)
-               result.ext=fn.substr(dot);
-       return result;
-}
-
-int fnmatch(const string &pat, const Path &fn)
-{
-#ifdef WIN32
-       return globcasematch(pat, fn.str());
-#else
-       return ::fnmatch(pat.c_str(), fn.str().c_str(), FNM_PATHNAME);
-#endif
-}
-
 Path relative(const Path &path, const Path &base)
 {
        Path::Iterator i=path.begin();
@@ -99,18 +99,5 @@ Path relative(const Path &path, const Path &base)
        return result;
 }
 
-/**
-Extracts the basename from the given path.  Same thing as Path::Path(p)[-1],
-but faster.
-*/
-string basename(const std::string &p)
-{
-       unsigned slash=p.rfind(DIRCHAR);
-       if(slash==string::npos)
-               return p;
-       else
-               return p.substr(slash+1);
-}
-
 } // namespace FS
 } // namespace Msp
index a828c92e3ed76e21a90efe22b3d7de2c985b7506..a6d956869bf633d531d35e24636b8b37519e35f4 100644 (file)
@@ -13,28 +13,36 @@ namespace FS {
 
 class Path;
 
-struct Filename
-{
-       std::string base;
-       std::string ext;
-};
+/// 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);
 
 /// Removes a file
 void unlink(const Path &path);
 
-Filename splitext(const std::string &);
-int fnmatch(const std::string &, const Path &);
-
 /// Makes a path relative to some base path.  That is, base/result==path.
 Path relative(const Path &path, const Path &base);
 
-std::string basename(const std::string &);
-
-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 FS
 } // namespace Msp