/* This file is part of Raul. * Copyright (C) 2007-2009 Dave Robillard * * Raul is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * Raul is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef RAUL_PATH_HPP #define RAUL_PATH_HPP #include #include #include #include #include #include "raul/Symbol.hpp" #include "raul/URI.hpp" 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). * * \ingroup raul */ class Path : public URI { public: class BadPath : public std::exception { public: BadPath(const std::string& path) : _path(path) {} ~BadPath() throw() {} const char* what() const throw() { return _path.c_str(); } private: std::string _path; }; static const std::string scheme; static const std::string prefix; static const size_t prefix_len; static const std::string root_uri; /** Construct an uninitialzed path, because the STL is annoying. */ Path() : URI(root_uri) {} /** 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()); } /** 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()); } static bool is_valid(const std::basic_string& path); static bool is_valid_name(const std::basic_string& name) { return name.length() > 0 && name.find("/") == std::string::npos && is_valid(std::string("/").append(name)); } static std::string pathify(const std::basic_string& str); static std::string nameify(const std::basic_string& str); static void replace_invalid_chars(std::string& str, size_t start, bool replace_slash = false); bool is_root() const { return str() == root_uri; } bool is_child_of(const Path& parent) const; bool is_parent_of(const Path& child) const; Path child(const std::string& s) const { if (is_valid(s)) return std::string(base()) + Path(s).chop_scheme().substr(1); else return std::string(base()) + s; } Path operator+(const Path& p) const { return child(p); } /** Return the name of this object (everything after the last '/'). * This is the "method name" for OSC paths. * The empty string may be returned (if the path is "/"). */ inline std::string name() const { if (str() == root_uri) return ""; else return substr(find_last_of("/")+1); } /** Return the name of this object (everything after the last '/'). * This is the "method name" for OSC paths. * Note it is illegal to call this method on the path "/". */ inline Symbol symbol() const { return substr(find_last_of("/")+1); } /** Return the parent's path. * * Calling this on the path "/" will return "/". * This is the (deepest) "container path" for OSC paths. */ inline Path parent() const { if (str() == root_uri) { return str(); } else { size_t last_slash = find_last_of("/"); return (last_slash == prefix_len) ? root_uri : substr(0, last_slash); } } /** Return path relative to some base path (chop prefix) */ inline Path relative_to_base(const Path& base) const { if (str() == base) { return "/"; } else { assert(length() > base.length()); return substr(base.length() - 1); } } /** Return path with a trailing "/". * * Returned value is guaranteed to be a valid parent path, i.e. a valid * child path can be made using parent.base() + child_name. */ inline const std::string base() const { if (str() == root_uri) return str(); else return str() + "/"; } /** Return path with a trailing "/". * * Returned value is guaranteed to be a valid parent path, i.e. a valid * child path can be made using parent.base() + child_name. */ inline const std::string base_no_scheme() const { return base().substr(find(":") + 1); } /** Return true if \a child is equal to, or a descendant of \a parent */ 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.str() == root_uri || child[parent.length()] == '/'))) ); } }; } // namespace Raul #endif // RAUL_PATH_HPP