From e6c5e68e2763557262fffdfcdf38607de8f7b777 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 4 Mar 2010 03:52:08 +0000 Subject: Remove Raul::Path::root, Raul::Path::prefix, and Raul:Path::scheme from public API. Add ability to modify root path from application code (before any paths are created). git-svn-id: http://svn.drobilla.net/lad/trunk/raul@2514 a436a847-0d15-0410-975c-d299462d15a1 --- raul/Path.hpp | 77 +++++++++++++++++++++++++++++++++++++---------------------- src/Path.cpp | 71 +++++++++++++++++++++++++++++++++++++++++------------- wscript | 5 ++-- 3 files changed, 106 insertions(+), 47 deletions(-) diff --git a/raul/Path.hpp b/raul/Path.hpp index 55f3926..746a493 100644 --- a/raul/Path.hpp +++ b/raul/Path.hpp @@ -31,16 +31,15 @@ namespace Raul { /** A URI which is a path (for example a filesystem or OSC path). - * - * A Path always has the special URI scheme "path:". * * This enforces that a Path is a valid path, where each fragment is a valid * Symbol, separated by exactly one slash (/). * * A path is divided by slashes (/). The first character MUST be a slash, and * the last character MUST NOT be a slash (except in the special case of the - * root path "/", which is the only valid single-character path). The path: - * scheme is added automatically (since a Patch is actually a URI). + * root path "/", which is the only valid single-character path). A Path + * is actually a URI, the relative path is appended to the root URI + * automatically, so a Patch can always be used as a URI. * * \ingroup raul */ @@ -55,37 +54,55 @@ public: std::string _path; }; - static const std::string scheme; - static const std::string prefix; - static const size_t prefix_len; - static const Path root; + /** Return the root path. + * The default root path is the URI "path:/" + * + * A Path is either the root path, or a child of a root path (i.e. the root + * path followed by a sequence of Symbols separated by '/') + */ + static const Path root(); + + /** Set the root path. + * The default root path is the URI "path:/" + * + * Note this should be done on application start up. Changing the root + * path while any Path objects exist will break things horribly; don't! + * + * The root can be set to any URI, there are no restrictions on valid + * characters and such like there are for relative paths (but it must be + * a valid URI, i.e. begin with a scheme, and in particular not begin + * with '/'). Relative paths are appended to the root path's URI, + * i.e. every Path, as a string, begins with the root URI. The part after + * that is a strict path (a sequence of Symbols separated by '/'). + */ + static void set_root(const Raul::URI& uri); + + static bool is_path(const Raul::URI& uri); /** Construct an uninitialzed path, because the STL is annoying. */ - Path() : URI(root) {} + Path() : URI(root()) {} /** Construct a Path from an std::string. * * It is a fatal error to construct a Path from an invalid string, * use is_valid first to check. */ - Path(const std::basic_string& path) - : URI((path.find(":") == std::string::npos) ? prefix + path : path) - { - if (!is_valid(str())) - throw BadPath(str()); - } + Path(const std::basic_string& path); /** Construct a Path from a C string. * * It is a fatal error to construct a Path from an invalid string, * use is_valid first to check. */ - Path(const char* cpath) - : URI((std::string(cpath).find(":") == std::string::npos) ? prefix + cpath : cpath) - { - if (!is_valid(str())) - throw BadPath(str()); - } + Path(const char* cpath); + + + /** Construct a Path from another path. + * + * This is faster than constructing a path from the other path's string + * representation, since validity checking is avoided. + */ + Path(const Path& copy) : URI(copy) {} static bool is_valid(const std::basic_string& path); @@ -99,7 +116,7 @@ public: static void replace_invalid_chars(std::string& str, size_t start, bool replace_slash = false); - bool is_root() const { return (*this) == root; } + bool is_root() const { return (*this) == root(); } bool is_child_of(const Path& parent) const; bool is_parent_of(const Path& child) const; @@ -123,7 +140,7 @@ public: * The empty string may be returned (if the path is the root path). */ inline const char* symbol() const { - if ((*this) != root) { + if ((*this) != root()) { const char* last_slash = strrchr(c_str(), '/'); if (last_slash) { return last_slash + 1; @@ -138,12 +155,13 @@ public: * This is the (deepest) "container path" for OSC paths. */ inline Path parent() const { - if ((*this) == root) { + if ((*this) == root()) { return *this; } else { const std::string str(this->str()); - const size_t last_slash = str.find_last_of('/'); - return (last_slash == prefix_len) ? root : str.substr(0, last_slash); + const size_t first_slash = str.find('/'); + const size_t last_slash = str.find_last_of('/'); + return (first_slash == last_slash) ? root() : str.substr(0, last_slash); } } @@ -174,7 +192,7 @@ public: */ inline const std::string base() const { std::string ret = str(); - if ((*this) == root && ret[ret.length() - 1] == '/') + if ((*this) == root() && ret[ret.length() - 1] == '/') return ret; else return ret + '/'; @@ -194,8 +212,11 @@ public: static bool descendant_comparator(const Path& parent, const Path& child) { return ( child == parent || (child.length() > parent.length() && (!std::strncmp(parent.c_str(), child.c_str(), parent.length()) - && (parent == root || child.str()[parent.length()] == '/'))) ); + && (parent == root() || child.str()[parent.length()] == '/'))) ); } + +private: + inline Path(bool unchecked, const URI& uri) : URI(uri) {} }; diff --git a/src/Path.cpp b/src/Path.cpp index c0eb0df..b0e6ec9 100644 --- a/src/Path.cpp +++ b/src/Path.cpp @@ -21,20 +21,54 @@ using namespace std; namespace Raul { -const string Path::scheme = "path"; -const string Path::prefix = Path::scheme + ":"; -const size_t Path::prefix_len = prefix.length(); -const Path Path::root = Path::prefix + "/"; +static URI root_uri("path:/"); + +const Path Path::root() { return Path(true, root_uri); } +void Path::set_root(const Raul::URI& uri) { root_uri = uri.str(); } + +bool +Path::is_path(const Raul::URI& uri) +{ + return uri.length() >= root_uri.length() + && uri.substr(0, root_uri.length()) == root_uri.str() + && Path::is_valid(uri.str()); +} + + +Path::Path(const std::basic_string& path) + : URI(path[0] == '/' ? root_uri.str() + path.substr(1) : path) +{ + if (!is_valid(str())) + throw BadPath(str()); +} + + +Path::Path(const char* cpath) + : URI(cpath[0] == '/' ? root_uri.str() + (cpath + 1) : cpath) +{ + if (!is_valid(str())) + throw BadPath(str()); +} + bool Path::is_valid(const std::basic_string& path_str) { - const size_t colon = path_str.find(":"); - const string path = (colon == string::npos) ? path_str : path_str.substr(colon + 1); + if (path_str.length() == 0) + return false; + + if (path_str == root_uri.str()) + return true; - if (path.length() == 0) + if (path_str[0] != '/' && + (path_str.length() < root_uri.length() + || path_str.substr(0, root_uri.length()) != root_uri.str())) return false; + const string path = (path_str[0] == '/') + ? path_str + : path_str.substr(root_uri.length() - 1); + // Must start with a / if (path[0] != '/') return false; @@ -66,29 +100,32 @@ Path::is_valid(const std::basic_string& path_str) /** Convert a string to a valid full path. * - * This will make a best effort at turning @a str into a complete, valid - * Path, and will always return one. + * The returned string is a valid relative path without the root prefix, + * i.e. the returned string starts with '/' followed by valid symbols, + * each separated by '/'. */ string Path::pathify(const std::basic_string& str) { if (str.length() == 0) - return root.str(); // this might not be wise? + return root().chop_scheme(); // this might not be wise? - string path = (str.substr(0, prefix_len) == prefix) ? str : prefix + str; - size_t start = prefix_len + 1; + const size_t first_slash = str.find('/'); + string path = (first_slash == string::npos) + ? string("/").append(str) + : str.substr(first_slash); // Must start with a / - if (path.at(start) != '/') + if (path.empty() || path[0] != '/') path = string("/").append(path); // Must not end with a slash unless "/" - if (path.length() > prefix_len + 1 && path.at(path.length()-1) == '/') - path = path.substr(0, path.length()-1); // chop trailing slash + if (path != "/" && path[path.length() - 1] == '/') + path = path.substr(0, path.length() - 1); // chop trailing slash - assert(path.find_last_of("/") != string::npos); + assert(path.find_last_of('/') != string::npos); - replace_invalid_chars(path, start, false); + replace_invalid_chars(path, 0, false); assert(is_valid(path)); diff --git a/wscript b/wscript index 56073c5..b8cc3a0 100644 --- a/wscript +++ b/wscript @@ -4,7 +4,7 @@ import Options import os # Version of this package (even if built as a child) -RAUL_VERSION = '0.6.4' +RAUL_VERSION = '0.6.5' # Library version (UNIX style major, minor, micro) # major increment <=> incompatible changes @@ -19,7 +19,8 @@ RAUL_VERSION = '0.6.4' # 0.6.2 = 5,0,0 (unreleased) # 0.6.3 = 6,0,0 (unreleased) # 0.6.4 = 7,0,0 (unreleased) -RAUL_LIB_VERSION = '7.0.0' +# 0.6.5 = 8,0,0 (unreleased) +RAUL_LIB_VERSION = '8.0.0' # Variables for 'waf dist' APPNAME = 'raul' -- cgit v1.2.1