diff options
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-1.9/src/FilePath.cpp')
-rw-r--r-- | Build/source/texk/dvisvgm/dvisvgm-1.9/src/FilePath.cpp | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-1.9/src/FilePath.cpp b/Build/source/texk/dvisvgm/dvisvgm-1.9/src/FilePath.cpp new file mode 100644 index 00000000000..92922d99354 --- /dev/null +++ b/Build/source/texk/dvisvgm/dvisvgm-1.9/src/FilePath.cpp @@ -0,0 +1,258 @@ +/************************************************************************* +** FilePath.cpp ** +** ** +** This file is part of dvisvgm -- the DVI to SVG converter ** +** Copyright (C) 2005-2014 Martin Gieseking <martin.gieseking@uos.de> ** +** ** +** 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 3 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, see <http://www.gnu.org/licenses/>. ** +*************************************************************************/ + +#include <config.h> +#include <cctype> +#include "FilePath.h" +#include "FileSystem.h" +#include "MessageException.h" +#include "macros.h" + +using namespace std; + + +/** Removes redundant slashes from a given path. */ +static string& single_slashes (string &str) { + size_t pos=0; + while ((pos = str.find("//", pos)) != string::npos) + str.replace(pos, 2, "/"); + return str; +} + + +#ifdef __WIN32__ +static char strip_drive_letter (string &path) { + char letter = 0; + if (path.length() >= 2 && path[1] == ':' && isalpha(path[0])) { + letter = tolower(path[0]); + path.erase(0, 2); + } + return letter; +} + + +static char adapt_current_path (string &path, char target_drive) { + if (char current_drive = strip_drive_letter(path)) { + if (target_drive != current_drive) { + if (target_drive == 0) + target_drive = current_drive; + if (path.empty() || path[0] != '/') { + if (FileSystem::chdir((string(1, target_drive) + ":").c_str())) { + path.insert(0, FileSystem::getcwd()+"/"); + strip_drive_letter(path); + } + else + throw MessageException("drive " + string(1, target_drive) + ": not accessible"); + } + } + } + return target_drive; +} + + +static void tolower (string &str) { + for (size_t i=0; i < str.length(); ++i) + str[i] = tolower(str[i]); +} +#endif + + +/** Constructs a FilePath object from a given path. Relative paths are + * relative to the current working directory. + * @param[in] path absolute or relative path to a file or directory */ +FilePath::FilePath (const string &path) { + init(path, !FileSystem::isDirectory(path.c_str()), FileSystem::getcwd()); +} + + +/** Constructs a FilePath object. + * @param[in] path absolute or relative path to a file or directory + * @param[in] isfile true if 'path' references a file, false if a directory is referenced + * @param[in] current_dir if 'path' is a relative path expression it will be related to 'current_dir' */ +FilePath::FilePath (const string &path, bool isfile, string current_dir) { + init(path, isfile, current_dir); +} + + +/** Initializes a FilePath object. This method should be called by the constructors only. + * @param[in] path absolute or relative path to a file or directory + * @param[in] isfile true if 'path' references a file, false if a directory is referenced + * @param[in] current_dir if 'path' is a relative path expression it will be related to 'current_dir' */ +void FilePath::init (string path, bool isfile, string current_dir) { + single_slashes(path); + single_slashes(current_dir); +#ifdef __WIN32__ + tolower(path); + path = FileSystem::adaptPathSeperators(path); + _drive = strip_drive_letter(path); +#endif + if (isfile) { + size_t pos = path.rfind('/'); + _fname = path.substr((pos == string::npos) ? 0 : pos+1); + if (pos != string::npos) + path.erase(pos); + else + path.clear(); + } + if (current_dir.empty()) + current_dir = FileSystem::getcwd(); +#ifdef __WIN32__ + tolower(current_dir); + _drive = adapt_current_path(current_dir, _drive); +#endif + if (!path.empty()) { + if (path[0] == '/') + current_dir.clear(); + else if (current_dir[0] != '/') + current_dir = "/"; + else { + FilePath curr(current_dir, false, "/"); + current_dir = curr.absolute(); +#ifdef __WIN32__ + adapt_current_path(current_dir, _drive); +#endif + } + } + path.insert(0, current_dir + "/"); + string elem; + FORALL (path, string::const_iterator, it) { + if (*it == '/') { + add(elem); + elem.clear(); + } + else + elem += *it; + } + add(elem); +} + + +/** Adds a location step to the current path. */ +void FilePath::add (const string &dir) { + if (dir == ".." && !_dirs.empty()) + _dirs.pop_back(); + else if (dir.length() > 0 && dir != ".") + _dirs.push_back(dir); +} + + +/** Returns the suffix of the filename. If FilePath represents the + * location of a directory (and not of a file) an empty string + * is returned. */ +string FilePath::suffix () const { + size_t start = 0; + // ignore leading dots + while (start < _fname.length() && _fname[start] == '.') + start++; + string sub = _fname.substr(start); + size_t pos = sub.rfind('.'); + if (pos != string::npos && pos < sub.length()-1) + return sub.substr(pos+1); + return ""; +} + + +/** Changes the suffix of the filename. If FilePath represents the + * location of a directory (and not of a file) nothing happens. + * @param[in] s new suffix */ +void FilePath::suffix (const string &s) { + if (!_fname.empty()) { + string current_suffix = suffix(); + if (!current_suffix.empty()) + _fname.erase(_fname.length()-current_suffix.length()-1); + _fname += "."+s; + } +} + + +/** Returns the filename without suffix. + * Example: FilePath("/a/b/c.def", true) == "c" */ +string FilePath::basename () const { + if (!_fname.empty()) { + size_t len = suffix().length(); + if (len > 0) + len++; // strip dot too + return _fname.substr(0, _fname.length()-len); + } + return ""; +} + + +/** Returns the absolute path string of this FilePath. + * @param[in] with_filename if false, the filename is omitted + * @return the absolute path string */ +string FilePath::absolute (bool with_filename) const { + string path; + FORALL (_dirs, ConstIterator, it) { + path += "/" + *it; + } + if (path.empty()) + path = "/"; + if (with_filename && !_fname.empty()) + path += "/"+_fname; +#ifdef __WIN32__ + if (_drive) + path.insert(0, string(1, _drive) + ":"); +#endif + return single_slashes(path); +} + + +/** Returns a path string of this FilePath relative to reldir. If we wanted to + * navigate from /a/b/c/d to /a/b/e/f using the shell command "cd", we could do that + * with the relative path argument: "cd ../../e/f". This function returns such a relative + * path. Example: FilePath("/a/b/e/f").relative("/a/b/c/d") => "../../e/f". + * @param[in] reldir absolute path to a directory + * @param[in] with_filename if false, the filename is omitted + * @return the relative path string */ +string FilePath::relative (string reldir, bool with_filename) const { + if (reldir.empty()) + reldir = FileSystem::getcwd(); +#ifdef __WIN32__ + adapt_current_path(reldir, _drive); +#endif + if (reldir[0] != '/') + return absolute(); + FilePath rel(reldir, false); + string path; +#ifdef __WIN32__ + if (rel._drive && _drive && rel._drive != _drive) + path += string(1, _drive) + ":"; +#endif + ConstIterator i = _dirs.begin(); + ConstIterator j = rel._dirs.begin(); + while (i != _dirs.end() && j != rel._dirs.end() && *i == *j) + ++i, ++j; + for (; j != rel._dirs.end(); ++j) + path += "../"; + for (; i != _dirs.end(); ++i) + path += *i + "/"; + if (!path.empty()) + path.erase(path.length()-1, 1); // remove trailing slash + if (with_filename && !_fname.empty()) { + if (!path.empty() && path != "/") + path += "/"; + path += _fname; + } + if (path.empty()) + path = "."; + return single_slashes(path); +} + |