/* Copyright (C) 2007 Tim Mayberry This program 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. This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** * @namespace PBD::sys * * The API in this file is intended to be as close as possible to the * boost::filesystem API but implementing only the subset of it that is required * by ardour using the glib/glibmm file utility functions in the implementation. * * More information about boost::filesystem and the TR2 proposal at * * http://www.boost.org/libs/filesystem/doc/tr2_proposal.html * * Hopefully the boost::filesystem API will pass TR2 review etc and become part * of the C++ standard and this code can be removed, or we just end up using * the boost filesystem library when it matures a bit more. * * My reasons for writing this thin wrapper instead of using glib directly or * using boost::filesystem immediately are: * * - Using sys::path instead of strings and Glib::build_filename is more * convenient, terse and forces correct platform agnostic path building. * * - Using boost::filesystem on windows would mean converting between any UTF-8 * encoded strings(such as when selecting a file/directory in the gtk file * chooser) and the native file encoding (UTF-16). It would take some time * and testing to find out when this is required and the glib functions already * do this if necessary. * * - Using exceptions to indicate errors is more likely to uncover situations * where error conditions are being silently ignored(I've already encounted * a few examples of this in the ardour code). * * - Many of the glib file utility functions are not wrapped by glibmm so this * also provides what I think is a better API. * * - Using boost::filesystem directly means another library dependence and would * require more testing on windows because of the character encoding issue. * * - The boost::filesystem API changes a bit as part of the TR2 review process etc. */ #ifndef __filesystem_h__ #define __filesystem_h__ #include #include namespace PBD { namespace sys { class path { public: path() : m_path("") { } path(const path & p) : m_path(p.m_path) { } path(const std::string & s) : m_path(s) { } path(const char* s) : m_path(s) { } path& operator=(const path& p) { m_path = p.m_path; return *this;} path& operator=(const std::string& s) { m_path = s; return *this; } path& operator=(const char* s) { m_path = s; return *this; } path& operator/=(const path& rhs); path& operator/=(const std::string& s); path& operator/=(const char* s); const std::string to_string() const { return m_path; } /** * @return the last component of the path, if the path refers to * a file then it will be the entire filename including any extension. */ std::string leaf () const; /** * @returns the directory component of a path without any trailing * path separator or an empty string if the path has no directory * component(branch path). */ path branch_path () const; private: std::string m_path; }; class filesystem_error : public std::runtime_error { const int m_error_code; public: explicit filesystem_error(const std::string & what, int error_code=0) : std::runtime_error(what), m_error_code(error_code) { } int system_error() const { return m_error_code; } }; inline path operator/ (const path& lhs, const path& rhs) { return path(lhs) /= rhs; } /// @return true if path at p exists bool exists(const path & p); /// @return true if path at p is a directory. bool is_directory(const path & p); /** * Attempt to create a directory at p as if by the glib function g_mkdir * with a second argument of S_IRWXU|S_IRWXG|S_IRWXO * * @throw filesystem_error if mkdir fails for any other reason other than * the directory already exists. * * @return true If the directory p was created, otherwise false * * @post is_directory(p) */ bool create_directory(const path & p); /** * Attempt to create a directory at p as if by the glib function * g_mkdir_with_parents with a second argument of S_IRWXU|S_IRWXG|S_IRWXO * * @throw filesystem_error if g_mkdir_with_parents fails for any other * reason other than the directory already exists. * * @return true If the directory at p was created, otherwise false * * @post is_directory(p) */ bool create_directories(const path & p); /** * Attempt to delete the file at path p as if by the glib function * g_unlink. * * @return true if file existed prior to removing it, false if file * at p did not exist. * * @throw filesystem_error if removing the file failed for any other * reason other than the file did not exist. */ bool remove(const path & p); /** * Renames from_path to to_path as if by the glib function g_rename. */ void rename (const path& from_path, const path& to_path); /** * Attempt to copy the contents of the file from_path to a new file * at path to_path. * * @throw filesystem_error if from_path.empty() || to_path.empty() || * !exists(from_path) || !is_regular(from_path) || exists(to_path) */ void copy_file(const path & from_path, const path & to_path); /** * @return The substring of the filename component of the path, starting * at the beginning of the filename up to but not including the last dot. * * boost::filesystem::path::basename differs from g_path_get_basename and * ::basename and most other forms of basename in that it removes the * extension from the filename if the filename has one. */ std::string basename (const path& p); /** * @return If the filename contains a dot, return a substring of the * filename starting the rightmost dot to the end of the string, otherwise * an empty string. * * @param p a file path. */ std::string extension (const path& p); } // namespace sys } // namespace PBD #endif