return searchName;
}
+/*! \brief
+ * Returns whether given path contains files from `share/top/`.
+ *
+ * Only checks for a single file that has an uncommon enough name.
+ */
+bool isAcceptableLibraryPath(const std::string &path)
+{
+ return Path::exists(Path::join(path, "gurgle.dat"));
+}
+
+/*! \brief
+ * Returns whether given path prefix contains files from `share/top/`.
+ *
+ * \param[in] path Path prefix to check.
+ * \param[out] result If return value is `true`, the pointee is set to the
+ * actual data directory. Otherwise, the pointee is not modified.
+ * \returns `true` if \p path contains the data files.
+ *
+ * Checks whether \p path could be the installation prefix where `share/top/`
+ * files have been installed: appends the relative installation path of the
+ * data files and calls isAcceptableLibraryPath().
+ */
+bool isAcceptableLibraryPathPrefix(const std::string &path, std::string *result)
+{
+ std::string testPath = Path::join(path, GMXLIB_SEARCH_DIR);
+ if (isAcceptableLibraryPath(testPath))
+ {
+ *result = testPath;
+ return true;
+ }
+ return false;
+}
+
+/*! \brief
+ * Returns a fallback data path.
+ *
+ * Checks a few standard locations for the data files before returning a
+ * configure-time hard-coded path. The hard-coded path is preferred if it
+ * actually contains the data files, though.
+ */
+std::string findFallbackLibraryDataPath()
+{
+#ifndef GMX_NATIVE_WINDOWS
+ if (!isAcceptableLibraryPath(GMXLIB_FALLBACK))
+ {
+ std::string foundPath;
+ if (isAcceptableLibraryPathPrefix("/usr/local", &foundPath))
+ {
+ return foundPath;
+ }
+ if (isAcceptableLibraryPathPrefix("/usr", &foundPath))
+ {
+ return foundPath;
+ }
+ if (isAcceptableLibraryPathPrefix("/opt", &foundPath))
+ {
+ return foundPath;
+ }
+ }
+#endif
+ return GMXLIB_FALLBACK;
+}
+
+/*! \brief
+ * Finds the library data files based on path of the binary.
+ *
+ * \param[in] binaryPath Absolute path to the binary.
+ * \returns Path to the `share/top/` data files.
+ *
+ * The search based on the path only works if the binary is in the same
+ * relative path as the installed \Gromacs binaries. If the binary is
+ * somewhere else, a hard-coded fallback is used. This doesn't work if the
+ * binaries are somewhere else than the path given during configure time...
+ *
+ * Extra logic is present to allow running binaries from the build tree such
+ * that they use up-to-date data files from the source tree.
+ */
+std::string findDefaultLibraryDataPath(const std::string &binaryPath)
+{
+ // If the input path is not absolute, the binary could not be found.
+ // Don't search anything.
+ if (Path::isAbsolute(binaryPath))
+ {
+ // Remove the executable name.
+ std::string searchPath = Path::getParentPath(binaryPath);
+ // If running directly from the build tree, try to use the source
+ // directory.
+#if (defined CMAKE_SOURCE_DIR && defined CMAKE_BINARY_DIR)
+ if (Path::startsWith(searchPath, CMAKE_BINARY_DIR))
+ {
+ std::string testPath = Path::join(CMAKE_SOURCE_DIR, "share/top");
+ if (isAcceptableLibraryPath(testPath))
+ {
+ return testPath;
+ }
+ }
+#endif
+
+ // Use the executable path to (try to) find the library dir.
+ while (!searchPath.empty())
+ {
+ std::string testPath = Path::join(searchPath, GMXLIB_SEARCH_DIR);
+ if (isAcceptableLibraryPath(testPath))
+ {
+ return testPath;
+ }
+ searchPath = Path::getParentPath(searchPath);
+ }
+ }
+
+ // End of smart searching. If we didn't find it in our parent tree,
+ // or if the program name wasn't set, return a fallback.
+ return findFallbackLibraryDataPath();
+}
+
//! \}
} // namespace
Impl(int argc, const char *const argv[],
ExecutableEnvironmentPointer env);
+ /*! \brief
+ * Finds the full binary path if it isn't searched yet.
+ *
+ * Sets \a fullBinaryPath_ if it isn't set yet.
+ *
+ * The \a binaryPathMutex_ should be locked by the caller before
+ * calling this function.
+ */
+ void findBinaryPath() const;
+
ExecutableEnvironmentPointer executableEnv_;
std::string invokedName_;
std::string programName_;
std::string displayName_;
std::string commandLine_;
mutable std::string fullBinaryPath_;
+ mutable std::string defaultLibraryDataPath_;
mutable tMPI::mutex binaryPathMutex_;
};
ExecutableEnvironmentPointer env)
: executableEnv_(move(env))
{
- invokedName_ = (argc != 0 ? argv[0] : "");
- programName_ = Path::splitToPathAndFilename(invokedName_).second;
- programName_ = stripSuffixIfPresent(programName_, ".exe");
+ invokedName_ = (argc != 0 ? argv[0] : "");
+ programName_ = Path::getFilename(invokedName_);
+ programName_ = stripSuffixIfPresent(programName_, ".exe");
commandLine_ = quoteIfNecessary(programName_.c_str());
for (int i = 1; i < argc; ++i)
}
}
+void CommandLineProgramContext::Impl::findBinaryPath() const
+{
+ if (fullBinaryPath_.empty())
+ {
+ fullBinaryPath_ = findFullBinaryPath(invokedName_, *executableEnv_);
+ fullBinaryPath_ = Path::normalize(Path::resolveSymlinks(fullBinaryPath_));
+ // TODO: Investigate/Consider using a dladdr()-based solution.
+ // Potentially less portable, but significantly simpler, and also works
+ // with user binaries even if they are located in some arbitrary location,
+ // as long as shared libraries are used.
+ }
+}
+
/********************************************************************
* CommandLineProgramContext
*/
const char *CommandLineProgramContext::fullBinaryPath() const
{
tMPI::lock_guard<tMPI::mutex> lock(impl_->binaryPathMutex_);
- if (impl_->fullBinaryPath_.empty())
+ impl_->findBinaryPath();
+ return impl_->fullBinaryPath_.c_str();
+}
+
+const char *CommandLineProgramContext::defaultLibraryDataPath() const
+{
+ tMPI::lock_guard<tMPI::mutex> lock(impl_->binaryPathMutex_);
+ if (impl_->defaultLibraryDataPath_.empty())
{
- impl_->fullBinaryPath_ =
- Path::normalize(
- Path::resolveSymlinks(
- findFullBinaryPath(impl_->invokedName_,
- *impl_->executableEnv_)));
- // TODO: Investigate/Consider using a dladdr()-based solution.
- // Potentially less portable, but significantly simpler, and also works
- // with user binaries even if they are located in some arbitrary location,
- // as long as shared libraries are used.
+ impl_->findBinaryPath();
+ impl_->defaultLibraryDataPath_ =
+ Path::normalize(findDefaultLibraryDataPath(impl_->fullBinaryPath_));
}
- return impl_->fullBinaryPath_.c_str();
+ return impl_->defaultLibraryDataPath_.c_str();
}
} // namespace gmx
*/
virtual const char *displayName() const;
/*! \brief
- * Returns the full command line used to invoke the binary.
+ * Returns the full path of the running binary.
*
- * Does not throw.
+ * \throws std::bad_alloc if out of memory.
+ * \throws tMPI::system_error on thread synchronization errors.
+ *
+ * Returns argv[0] if there was an error in finding the absolute path.
*/
- virtual const char *commandLine() const;
-
+ virtual const char *fullBinaryPath() const;
/*! \brief
- * Returns the full path of the invoked binary.
+ * Returns the default path for \Gromacs data files.
*
* \throws std::bad_alloc if out of memory.
* \throws tMPI::system_error on thread synchronization errors.
*
- * Returns argv[0] if there was an error in finding the absolute path.
+ * Returns a hardcoded path set during configuration time if there is
+ * an error in finding the library data files.
*/
- virtual const char *fullBinaryPath() const;
+ virtual const char *defaultLibraryDataPath() const;
+ /*! \brief
+ * Returns the full command line used to invoke the binary.
+ *
+ * Does not throw.
+ */
+ virtual const char *commandLine() const;
private:
class Impl;
}
-static gmx_bool search_subdirs(const char *parent, char *libdir)
-{
- char *ptr;
- gmx_bool found;
-
- /* Search a few common subdirectory names for the gromacs library dir */
- sprintf(libdir, "%s%cshare%ctop%cgurgle.dat", parent,
- DIR_SEPARATOR, DIR_SEPARATOR, DIR_SEPARATOR);
- found = gmx_fexist(libdir);
- if (!found)
- {
- sprintf(libdir, "%s%c%s%cgurgle.dat", parent,
- DIR_SEPARATOR, GMXLIB_SEARCH_DIR, DIR_SEPARATOR);
- found = gmx_fexist(libdir);
- }
-
- /* Remove the gurgle.dat part from libdir if we found something */
- if (found)
- {
- ptr = strrchr(libdir, DIR_SEPARATOR); /* slash or backslash always present, no check necessary */
- *ptr = '\0';
- }
- return found;
-}
-
-
-void get_libdir(char *libdir)
+char *low_gmxlibfn(const char *file, gmx_bool bAddCWD, gmx_bool bFatal)
{
- // TODO: There is a potential buffer overrun in the way libdir is passed in.
+ bool bEnvIsSet = false;
try
{
- std::string fullPath = gmx::getProgramContext().fullBinaryPath();
-
- // If running directly from the build tree, try to use the source
- // directory.
-#if (defined CMAKE_SOURCE_DIR && defined CMAKE_BINARY_DIR)
- // TODO: Consider adding Path::startsWith(), as this may not work as
- // expected.
- if (gmx::startsWith(fullPath, CMAKE_BINARY_DIR))
+ if (bAddCWD && gmx_fexist(file))
+ {
+ return gmx_strdup(file);
+ }
+ else
{
- if (search_subdirs(CMAKE_SOURCE_DIR, libdir))
+ std::string libpath;
+ // GMXLIB can be a path.
+ const char *lib = getenv("GMXLIB");
+ if (lib != NULL)
{
- return;
+ bEnvIsSet = true;
+ libpath = lib;
+ }
+ else
+ {
+ libpath = gmx::getProgramContext().defaultLibraryDataPath();
}
- }
-#endif
- // Remove the executable name
- fullPath = gmx::Path::splitToPathAndFilename(fullPath).first;
- // Now we have the full path to the gromacs executable.
- // Use it to find the library dir.
- while (!fullPath.empty())
- {
- if (search_subdirs(fullPath.c_str(), libdir))
+ std::vector<std::string> pathEntries;
+ gmx::Path::splitPathEnvironment(libpath, &pathEntries);
+ std::vector<std::string>::const_iterator i;
+ for (i = pathEntries.begin(); i != pathEntries.end(); ++i)
{
- return;
+ std::string testPath = gmx::Path::join(*i, file);
+ if (gmx::Path::exists(testPath))
+ {
+ return gmx_strdup(testPath.c_str());
+ }
}
- fullPath = gmx::Path::splitToPathAndFilename(fullPath).first;
}
}
GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
-
- /* End of smart searching. If we didn't find it in our parent tree,
- * or if the program name wasn't set, at least try some standard
- * locations before giving up, in case we are running from e.g.
- * a users home directory. This only works on unix or cygwin...
- */
- bool found = false;
-#ifndef GMX_NATIVE_WINDOWS
- if (!found)
+ if (bFatal)
{
- found = search_subdirs("/usr/local", libdir);
- }
- if (!found)
- {
- found = search_subdirs("/usr", libdir);
- }
- if (!found)
- {
- found = search_subdirs("/opt", libdir);
- }
-#endif
- if (!found)
- {
- strcpy(libdir, GMXLIB_FALLBACK);
- }
-}
-
-
-char *low_gmxlibfn(const char *file, gmx_bool bAddCWD, gmx_bool bFatal)
-{
- char *ret;
- char *lib, *dir;
- char buf[1024];
- char libpath[GMX_PATH_MAX];
- gmx_bool env_is_set = FALSE;
- char *s, tmppath[GMX_PATH_MAX];
-
- /* GMXLIB can be a path now */
- lib = getenv("GMXLIB");
- if (lib != NULL)
- {
- env_is_set = TRUE;
- strncpy(libpath, lib, GMX_PATH_MAX);
- }
- else
- {
- get_libdir(libpath);
- }
-
- ret = NULL;
- if (bAddCWD && gmx_fexist(file))
- {
- ret = gmx_strdup(file);
- }
- else
- {
- strncpy(tmppath, libpath, GMX_PATH_MAX);
- s = tmppath;
- while (ret == NULL && (dir = gmx_strsep(&s, PATH_SEPARATOR)) != NULL)
+ if (bEnvIsSet)
{
- sprintf(buf, "%s%c%s", dir, DIR_SEPARATOR, file);
- if (gmx_fexist(buf))
- {
- ret = gmx_strdup(buf);
- }
+ gmx_fatal(FARGS,
+ "Library file %s not found %sin your GMXLIB path.",
+ file, bAddCWD ? "in current dir nor " : "");
}
- if (ret == NULL && bFatal)
+ else
{
- if (env_is_set)
- {
- gmx_fatal(FARGS,
- "Library file %s not found %sin your GMXLIB path.",
- file, bAddCWD ? "in current dir nor " : "");
- }
- else
- {
- gmx_fatal(FARGS,
- "Library file %s not found %sin default directories.\n"
- "(You can set the directories to search with the GMXLIB path variable)",
- file, bAddCWD ? "in current dir nor " : "");
- }
+ gmx_fatal(FARGS,
+ "Library file %s not found %sin default directories.\n"
+ "(You can set the directories to search with the GMXLIB path variable)",
+ file, bAddCWD ? "in current dir nor " : "");
}
}
-
- return ret;
+ return NULL;
}
-
-
-
-
FILE *low_libopen(const char *file, gmx_bool bFatal)
{
FILE *ff;
/* Native windows uses backslash path separators.
* Cygwin and everybody else in the world use slash.
- * When reading the PATH environment variable, Unix separates entries
- * with colon, while windows uses semicolon.
*/
#include "../utility/gmx_header_config.h"
#ifdef GMX_NATIVE_WINDOWS
#define DIR_SEPARATOR '\\'
-#define PATH_SEPARATOR ";"
#else
#define DIR_SEPARATOR '/'
-#define PATH_SEPARATOR ":"
#endif
gmx_directory_close(gmx_directory_t gmxdir);
-
-void get_libdir(char *libdir);
-
char *low_gmxlibfn(const char *file, gmx_bool bAddCWD, gmx_bool bFatal);
FILE *low_libopen(const char *file, gmx_bool bFatal);
printCopyright(fp);
fprintf(fp, "\n");
}
- fprintf(fp, "%sGROMACS: %s, %s%s%s\n", prefix, name,
+ fprintf(fp, "%sGROMACS: %s, %s%s%s\n", prefix, name,
GromacsVersion(), precisionString, suffix);
const char *const binaryPath = programContext.fullBinaryPath();
if (binaryPath != NULL && binaryPath[0] != '\0')
{
- fprintf(fp, "%sExecutable: %s%s\n", prefix, binaryPath, suffix);
+ fprintf(fp, "%sExecutable: %s%s\n", prefix, binaryPath, suffix);
+ }
+ const char *const libraryPath = programContext.defaultLibraryDataPath();
+ if (libraryPath != NULL && libraryPath[0] != '\0')
+ {
+ fprintf(fp, "%sLibrary dir: %s%s\n", prefix, libraryPath, suffix);
}
const char *const commandLine = programContext.commandLine();
if (commandLine != NULL && commandLine[0] != '\0')
*
* Copyright (c) 1991-2000, University of Groningen, The Netherlands.
* Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
return _strtoi64(str, endptr, 10);
#endif
}
-
-char *gmx_strsep(char **stringp, const char *delim)
-{
- char *ret;
- int len = strlen(delim);
- int i, j = 0;
- int found = 0;
-
- if (!*stringp)
- {
- return NULL;
- }
- ret = *stringp;
- do
- {
- if ( (*stringp)[j] == '\0')
- {
- found = 1;
- *stringp = NULL;
- break;
- }
- for (i = 0; i < len; i++)
- {
- if ( (*stringp)[j] == delim[i])
- {
- (*stringp)[j] = '\0';
- *stringp = *stringp+j+1;
- found = 1;
- break;
- }
- }
- j++;
- }
- while (!found);
-
- return ret;
-}
#include "fflibutil.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/path.h"
+#include "gromacs/utility/programcontext.h"
+
const char *fflib_forcefield_dir_ext()
{
return ".ff";
char ***filenames,
char ***filenames_short)
{
- char *lib, *dir;
- char *libpath;
- gmx_bool env_is_set;
- int len_fe, len_name;
- char **fns, **fns_short;
- char dir_print[GMX_PATH_MAX];
- char *s, fn_dir[GMX_PATH_MAX];
- gmx_directory_t dirhandle;
- char nextname[STRLEN];
- int n, n_thisdir, rc;
-
- len_fe = strlen(file_end);
-
- env_is_set = FALSE;
- if (ffdir != NULL)
+ char **fns = NULL, **fns_short = NULL;
+ int n = 0;
+ try
{
- /* Search in current dir and ffdir */
- libpath = gmxlibfn(ffdir);
- }
- else
- {
- /* GMXLIB can be a path now */
- lib = getenv("GMXLIB");
- snew(libpath, GMX_PATH_MAX);
- if (bAddCWD)
- {
- sprintf(libpath, "%s%s", ".", PATH_SEPARATOR);
- }
- if (lib != NULL)
+ std::vector<std::string> libPaths;
+ bool bEnvIsSet = false;
+
+ if (ffdir != NULL)
{
- env_is_set = TRUE;
- strncat(libpath, lib, GMX_PATH_MAX);
+ /* Search ffdir in current dir and library dirs */
+ libPaths.push_back(gmxlibfn(ffdir));
}
else
{
- get_libdir(libpath + strlen(libpath));
+ /* GMXLIB can be a path now */
+ if (bAddCWD)
+ {
+ libPaths.push_back(".");
+ }
+ const char *lib = getenv("GMXLIB");
+ if (lib != NULL)
+ {
+ bEnvIsSet = true;
+ gmx::Path::splitPathEnvironment(lib, &libPaths);
+ }
+ else
+ {
+ libPaths.push_back(gmx::getProgramContext().defaultLibraryDataPath());
+ }
}
- }
- s = libpath;
- n = 0;
- fns = NULL;
- fns_short = NULL;
- /* Loop over all the entries in libpath */
- while ((dir = gmx_strsep(&s, PATH_SEPARATOR)) != NULL)
- {
- rc = gmx_directory_open(&dirhandle, dir);
- if (rc == 0)
- {
- strcpy(dir_print, dir);
- n_thisdir = 0;
- while (gmx_directory_nextfile(dirhandle, nextname, STRLEN-1) == 0)
+ const int len_fe = strlen(file_end);
+
+ std::vector<std::string>::const_iterator i;
+ for (i = libPaths.begin(); i != libPaths.end(); ++i)
+ {
+ const char *dir = i->c_str();
+ gmx_directory_t dirhandle;
+ const int rc = gmx_directory_open(&dirhandle, dir);
+ if (rc == 0)
{
- nextname[STRLEN-1] = 0;
- if (debug)
- {
- fprintf(debug, "dir '%s' %d file '%s'\n",
- dir, n_thisdir, nextname);
- }
- len_name = strlen(nextname);
- /* What about case sensitivity? */
- if (len_name >= len_fe &&
- strcmp(nextname+len_name-len_fe, file_end) == 0)
+ char nextname[STRLEN];
+ int n_thisdir = 0;
+ while (gmx_directory_nextfile(dirhandle, nextname, STRLEN-1) == 0)
{
- /* We have a match */
- srenew(fns, n+1);
- sprintf(fn_dir, "%s%c%s",
- dir_print, DIR_SEPARATOR, nextname);
+ nextname[STRLEN-1] = 0;
+ if (debug)
+ {
+ fprintf(debug, "dir '%s' %d file '%s'\n",
+ dir, n_thisdir, nextname);
+ }
+ const int len_name = strlen(nextname);
+ /* What about case sensitivity? */
+ if (len_name >= len_fe &&
+ strcmp(nextname+len_name-len_fe, file_end) == 0)
+ {
+ char fn_dir[GMX_PATH_MAX];
+ /* We have a match */
+ srenew(fns, n+1);
+ sprintf(fn_dir, "%s%c%s", dir, DIR_SEPARATOR, nextname);
- /* Copy the file name, possibly including the path. */
- fns[n] = strdup(fn_dir);
+ /* Copy the file name, possibly including the path. */
+ fns[n] = strdup(fn_dir);
- if (ffdir == NULL)
- {
- /* We are searching in a path.
- * Use the relative path when we use share/top
- * from the installation.
- * Add the full path when we use the current
- * working directory of GMXLIB.
- */
- srenew(fns_short, n+1);
- if (strcmp(dir, ".") == 0 || env_is_set)
- {
- fns_short[n] = strdup(fn_dir);
- }
- else
+ if (ffdir == NULL)
{
- fns_short[n] = strdup(nextname);
+ /* We are searching in a path.
+ * Use the relative path when we use share/top
+ * from the installation.
+ * Add the full path when we use the current
+ * working directory of GMXLIB.
+ */
+ srenew(fns_short, n+1);
+ if (strcmp(dir, ".") == 0 || bEnvIsSet)
+ {
+ fns_short[n] = strdup(fn_dir);
+ }
+ else
+ {
+ fns_short[n] = strdup(nextname);
+ }
}
+ n++;
+ n_thisdir++;
}
- n++;
- n_thisdir++;
}
- }
- gmx_directory_close(dirhandle);
+ gmx_directory_close(dirhandle);
- sort_filenames(n_thisdir,
- fns+n-n_thisdir,
- fns_short == NULL ? NULL : fns_short+n-n_thisdir);
+ sort_filenames(n_thisdir,
+ fns+n-n_thisdir,
+ fns_short == NULL ? NULL : fns_short+n-n_thisdir);
+ }
}
}
-
- sfree(libpath);
+ GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
if (n == 0 && bFatalError)
{
*
* Copyright (c) 1991-2000, University of Groningen, The Netherlands.
* Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2012,2013, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
/** Return value for gmx_wcmatch() when there is no match. */
#define GMX_NO_WCMATCH 1
-/** Our implementation of strsep, the thread-safe replacement for strtok. */
-char *gmx_strsep(char **stringp, const char *delim);
-
/*! \brief
* Wraps lines, optionally indenting lines.
*
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2011,2012,2013, by the GROMACS development team, led by
+ * Copyright (c) 2011,2012,2013,2014, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
*/
#include "gromacs/utility/path.h"
+#include <cctype>
#include <cerrno>
#include <cstdlib>
#include <cstring>
#endif
#include "gromacs/fileio/futil.h"
+#include "gromacs/utility/stringutil.h"
namespace
{
+//! \addtogroup module_utility
+//! \{
+
//! Directory separator to use when joining paths.
const char cDirSeparator = '/';
//! Directory separators to use when parsing paths.
const char cDirSeparators[] = "/\\";
+/*! \var cPathSeparator
+ * \brief
+ * Separator to use to split the PATH environment variable.
+ *
+ * When reading the PATH environment variable, Unix separates entries
+ * with colon, while windows uses semicolon.
+ */
+#ifdef GMX_NATIVE_WINDOWS
+const char cPathSeparator = ';';
+#else
+const char cPathSeparator = ':';
+#endif
//! Check whether a given character is a directory separator.
bool isDirSeparator(char chr)
return std::strchr(cDirSeparators, chr);
}
+//! \}
+
} // namespace
namespace gmx
return isAbsolute(path.c_str());
}
+bool Path::startsWith(const std::string &path, const std::string &prefix)
+{
+ return gmx::startsWith(normalize(path), normalize(prefix));
+}
+
std::string Path::join(const std::string &path1,
const std::string &path2)
{
return path1 + cDirSeparator + path2 + cDirSeparator + path3;
}
-std::pair<std::string, std::string>
-Path::splitToPathAndFilename(const std::string &path)
+std::string Path::getParentPath(const std::string &path)
{
size_t pos = path.find_last_of(cDirSeparators);
if (pos == std::string::npos)
{
- return std::make_pair(std::string(), path);
+ return std::string();
}
- return std::make_pair(path.substr(0, pos), path.substr(pos+1));
+ return path.substr(0, pos);
+}
+
+std::string Path::getFilename(const std::string &path)
+{
+ size_t pos = path.find_last_of(cDirSeparators);
+ if (pos == std::string::npos)
+ {
+ return path;
+ }
+ return path.substr(pos+1);
}
std::string Path::normalize(const std::string &path)
{
std::string result(path);
+ // TODO: Remove . and .. entries.
if (DIR_SEPARATOR != '/')
{
std::replace(result.begin(), result.end(), '/', DIR_SEPARATOR);
}
+#ifdef GMX_NATIVE_WINDOWS
+ if (std::isalpha(result[0]) && result[1] == ':')
+ {
+ result[0] = std::toupper(result[0]);
+ }
+#endif
return result;
}
void Path::splitPathEnvironment(const std::string &pathEnv,
std::vector<std::string> *result)
{
- size_t prevPos = 0;
- size_t separator;
+ size_t prevPos = 0;
+ size_t separator;
do
{
- separator = pathEnv.find_first_of(PATH_SEPARATOR, prevPos);
+ separator = pathEnv.find(cPathSeparator, prevPos);
result->push_back(pathEnv.substr(prevPos, separator - prevPos));
prevPos = separator + 1;
}
}
else
{
- result = join(splitToPathAndFilename(result).first, buf);
+ result = join(getParentPath(result), buf);
}
}
#endif
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2011,2012,2013, by the GROMACS development team, led by
+ * Copyright (c) 2011,2012,2013,2014, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
static bool containsDirectory(const std::string &path);
static bool isAbsolute(const char *path);
static bool isAbsolute(const std::string &path);
+ static bool startsWith(const std::string &path,
+ const std::string &prefix);
static std::string join(const std::string &path1,
const std::string &path2);
static std::string join(const std::string &path1,
const std::string &path2,
const std::string &path3);
- static std::pair<std::string, std::string>
- splitToPathAndFilename(const std::string &path);
static std::string normalize(const std::string &path);
+ static std::string getParentPath(const std::string &path);
+ static std::string getFilename(const std::string &path);
static bool exists(const char *path);
static bool exists(const std::string &path);
virtual const char *programName() const { return "GROMACS"; }
virtual const char *displayName() const { return "GROMACS"; }
virtual const char *fullBinaryPath() const { return ""; }
+ virtual const char *defaultLibraryDataPath() const { return ""; }
virtual const char *commandLine() const { return ""; }
};
/*! \brief
* Returns the full path of the running binary.
*
+ * This is mainly used for informational purposes. There are no
+ * constraints on contents, except that it should not be `NULL`.
+ * Currently, this is also used for sanity checks in checkpointing.
+ *
* The implementation can provide an empty string if the path to the
- * binary is not available. In such a case, some functionality in the
- * library may be lost.
- * Currently, this is used for locating \Gromacs data files, and for
- * sanity checks in checkpointing.
+ * binary is not available. In such a case, the information is not
+ * shown.
*/
virtual const char *fullBinaryPath() const = 0;
+ /*! \brief
+ * Returns the default path for \Gromacs data files.
+ *
+ * This path is used to locate the data files that are in `share/top/`
+ * in the source directory.
+ * The implementation can provide an empty string if the path is not
+ * available; in such a case, functions that require data files may
+ * fail.
+ */
+ virtual const char *defaultLibraryDataPath() const = 0;
/*! \brief
* Returns the full command line used to invoke the binary.
*