integrate platform sub-namespace into source code and documentation

this updates function calls to functions that have been moved from
the utils namepsace or the Info class to platform::
This commit is contained in:
Axel Kohlmeyer 2021-10-02 15:50:58 -04:00
parent 195fe81c60
commit 37bfe3d0ce
No known key found for this signature in database
GPG Key ID: D9B44E93BF0C375A
36 changed files with 207 additions and 473 deletions

View File

@ -435,6 +435,8 @@ INPUT = @LAMMPS_SOURCE_DIR@/utils.cpp \
@LAMMPS_SOURCE_DIR@/my_pool_chunk.cpp \
@LAMMPS_SOURCE_DIR@/my_pool_chunk.h \
@LAMMPS_SOURCE_DIR@/math_eigen.h \
@LAMMPS_SOURCE_DIR@/platform.h \
@LAMMPS_SOURCE_DIR@/platform.cpp \
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded

View File

@ -18,4 +18,5 @@ of time and requests from the LAMMPS user community.
Developer_plugins
Developer_unittest
Classes
Developer_platform
Developer_utils

View File

@ -0,0 +1,140 @@
Platform abstraction functions
------------------------------
The ``platform`` sub-namespace inside the ``LAMMPS_NS`` namespace
provides a collection of wrapper and convenience functions and utilities
that perform common tasks for which platform specific code would be
required or for which a more high-level abstraction would be convenient
and reduce duplicated code. This reduces redundant implementations and
encourages consistent behavior and thus has some overlap with the
:doc:`"utils" sub-namespace <Developer_utils>`.
Time functions
^^^^^^^^^^^^^^
.. doxygenfunction:: cputime
:project: progguide
.. doxygenfunction:: walltime
:project: progguide
Platform information functions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. doxygenfunction:: os_info
:project: progguide
.. doxygenfunction:: compiler_info
:project: progguide
.. doxygenfunction:: cxx_standard
:project: progguide
.. doxygenfunction:: openmp_standard
:project: progguide
.. doxygenfunction:: mpi_vendor
:project: progguide
.. doxygenfunction:: mpi_info
:project: progguide
File and path functions and global constants
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. doxygenvariable:: filepathsep
:project: progguide
.. doxygenvariable:: pathvarsep
:project: progguide
.. doxygenfunction:: guesspath
:project: progguide
.. doxygenfunction:: path_basename
:project: progguide
.. doxygenfunction:: path_join
:project: progguide
.. doxygenfunction:: file_is_readable
:project: progguide
.. doxygenfunction:: is_console
:project: progguide
.. doxygenfunction:: path_is_directory
:project: progguide
.. doxygenfunction:: current_directory
:project: progguide
.. doxygenfunction:: list_directory
:project: progguide
.. doxygenfunction:: chdir
:project: progguide
.. doxygenfunction:: mkdir
:project: progguide
.. doxygenfunction:: rmdir
:project: progguide
.. doxygenfunction:: unlink
:project: progguide
Standard I/O function wrappers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. doxygenfunction:: ftell
:project: progguide
.. doxygenfunction:: fseek
:project: progguide
.. doxygenfunction:: ftruncate
:project: progguide
.. doxygenfunction:: popen
:project: progguide
.. doxygenfunction:: pclose
:project: progguide
Environment variable functions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. doxygenfunction:: putenv
:project: progguide
.. doxygenfunction:: list_pathenv
:project: progguide
.. doxygenfunction:: find_exe_path
:project: progguide
Dynamically loaded object or library functions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. doxygenfunction:: dlopen
:project: progguide
.. doxygenfunction:: dlclose
:project: progguide
.. doxygenfunction:: dlsym
:project: progguide
Compressed file I/O functions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. doxygenfunction:: has_zip_extension
:project: progguide
.. doxygenfunction:: zip_read
:project: progguide
.. doxygenfunction:: zip_write
:project: progguide

View File

@ -7,7 +7,9 @@ a collection of convenience functions and utilities that perform common
tasks that are required repeatedly throughout the LAMMPS code like
reading or writing to files with error checking or translation of
strings into specific types of numbers with checking for validity. This
reduces redundant implementations and encourages consistent behavior.
reduces redundant implementations and encourages consistent behavior and
thus has some overlap with the :doc:`"platform" sub-namespace
<Developer_platform>`.
I/O with status check and similar functions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -143,21 +145,6 @@ and parsing files or arguments.
.. doxygenfunction:: is_double
:project: progguide
File and path functions
^^^^^^^^^^^^^^^^^^^^^^^^^
.. doxygenfunction:: guesspath
:project: progguide
.. doxygenfunction:: path_basename
:project: progguide
.. doxygenfunction:: path_join
:project: progguide
.. doxygenfunction:: file_is_readable
:project: progguide
Potential file functions
^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -57,7 +57,7 @@ velocities. See the doc pages for the individual fixes and for the
assign a temperature compute to a thermostatting fix.
For example, you can apply a thermostat only to atoms in a spatial
region by using it in conjuction with :doc:`compute temp/region
region by using it in conjunction with :doc:`compute temp/region
<compute_temp_region>`. Or you can apply a thermostat to only the x
and z components of velocity by using it with :doc:`compute
temp/partial <compute_temp_partial>`. Of you could thermostat only

View File

@ -1135,6 +1135,7 @@ Germann
Germano
gerolf
Gerolf
getrusage
Gershgorin
getter
gettimeofday
@ -1809,6 +1810,7 @@ lyon
Lysogorskiy
Lyulin
lz
lzma
Maaravi
MACHDYN
machdyn
@ -2762,6 +2764,7 @@ REAXFF
ReaxFF
reaxff
rebo
recurse
recursing
Ree
refactored

View File

@ -274,7 +274,7 @@ void DumpNetCDF::openfile()
if (append_flag && !multifile) {
// Fixme! Perform checks if dimensions and variables conform with
// data structure standard.
if (not utils::file_is_readable(filecurrent))
if (not platform::file_is_readable(filecurrent))
error->all(FLERR, "cannot append to non-existent file {}",filecurrent);
if (singlefile_opened) return;

View File

@ -272,7 +272,7 @@ void DumpNetCDFMPIIO::openfile()
if (append_flag && !multifile) {
// Fixme! Perform checks if dimensions and variables conform with
// data structure standard.
if (not utils::file_is_readable(filecurrent))
if (not platform::file_is_readable(filecurrent))
error->all(FLERR, "cannot append to non-existent file {}", filecurrent);
MPI_Offset index[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS];

View File

@ -270,7 +270,7 @@ void Bond::write_file(int narg, char **arg)
// write out a line with "DATE:" and "UNITS:" tags
// - if the file already exists, print a message about appending
// while printing the date and check that units are consistent.
if (utils::file_is_readable(table_file)) {
if (platform::file_is_readable(table_file)) {
std::string units = utils::get_potential_units(table_file,"table");
if (!units.empty() && (units != update->unit_style)) {
error->one(FLERR,"Trying to append to a table file with UNITS: {} while units are {}",

View File

@ -282,7 +282,7 @@ void Info::command(int narg, char **arg)
fmt::print(out,"Git info: {} / {} / {}\n",
lmp->git_branch, lmp->git_descriptor,lmp->git_commit);
fmt::print(out,"\nOS information: {}\n\n",get_os_info());
fmt::print(out,"\nOS information: {}\n\n",platform::os_info());
fmt::print(out,"sizeof(smallint): {}-bit\n"
"sizeof(imageint): {}-bit\n"
@ -292,7 +292,7 @@ void Info::command(int narg, char **arg)
sizeof(tagint)*8, sizeof(bigint)*8);
fmt::print(out,"\nCompiler: {} with {}\nC++ standard: {}\n",
get_compiler_info(),get_openmp_info(),get_cxx_info());
platform::compiler_info(),platform::openmp_standard(),platform::cxx_standard());
fputs("\nActive compile time flags:\n\n",out);
if (has_gzip_support()) fputs("-DLAMMPS_GZIP\n",out);
@ -353,7 +353,7 @@ void Info::command(int narg, char **arg)
if (flags & COMM) {
int major,minor;
std::string version = get_mpi_info(major,minor);
std::string version = platform::mpi_info(major,minor);
fmt::print(out,"\nCommunication information:\n"
"MPI library level: MPI v{}.{}\n"
@ -1266,200 +1266,6 @@ bool Info::has_accelerator_feature(const std::string &package,
return false;
}
/* ---------------------------------------------------------------------- */
#define _INFOBUF_SIZE 256
std::string Info::get_os_info()
{
std::string buf;
#if defined(_WIN32)
DWORD fullversion,majorv,minorv,buildv=0;
fullversion = GetVersion();
majorv = (DWORD) (LOBYTE(LOWORD(fullversion)));
minorv = (DWORD) (HIBYTE(LOWORD(fullversion)));
if (fullversion < 0x80000000)
buildv = (DWORD) (HIWORD(fullversion));
buf = fmt::format("Windows {}.{} ({}) on ",majorv,minorv,buildv);
SYSTEM_INFO si;
GetSystemInfo(&si);
switch (si.wProcessorArchitecture) {
case PROCESSOR_ARCHITECTURE_AMD64:
buf += "x86_64";
break;
case PROCESSOR_ARCHITECTURE_ARM:
buf += "arm";
break;
case PROCESSOR_ARCHITECTURE_IA64:
buf += "ia64";
break;
case PROCESSOR_ARCHITECTURE_INTEL:
buf += "i386";
break;
default:
buf += "(unknown)";
}
#else
struct utsname ut;
uname(&ut);
// try to get OS distribution name, if available
std::string distro = ut.sysname;
if (utils::file_is_readable("/etc/os-release")) {
try {
TextFileReader reader("/etc/os-release","");
while (1) {
auto words = reader.next_values(0,"=");
if ((words.count() > 1) && (words.next_string() == "PRETTY_NAME")) {
distro += " " + utils::trim(words.next_string());
break;
}
}
} catch (std::exception &e) {
; // EOF but keyword not found
}
}
buf = fmt::format("{} {} on {}", distro, ut.release, ut.machine);
#endif
return buf;
}
std::string Info::get_compiler_info()
{
std::string buf;
#if defined(__INTEL_LLVM_COMPILER)
constexpr double version = static_cast<double>(__INTEL_LLVM_COMPILER)*0.01;
buf = fmt::format("Intel LLVM C++ {:.1f} / {}", version, __VERSION__);
#elif defined(__ibmxl__)
buf = fmt::format("IBM XL C/C++ (Clang) {}.{}.{}",
__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__);
#elif defined(__clang__)
buf = fmt::format("Clang C++ {}", __VERSION__);
#elif defined(__PGI)
buf = fmt::format("PGI C++ {}.{}",__PGIC__, __PGIC_MINOR__);
#elif defined(__INTEL_COMPILER)
double version = static_cast<double>(__INTEL_COMPILER)*0.01;
buf = fmt::format("Intel Classic C++ {:.2f}.{} / {}", version,
__INTEL_COMPILER_UPDATE, __VERSION__);
#elif defined(__MINGW64__)
buf = fmt::format("MinGW-w64 64bit {}.{} / GNU C++ {}", __MINGW64_VERSION_MAJOR,
__MINGW64_VERSION_MINOR, __VERSION__);
#elif defined(__MINGW32__)
buf = fmt::format("MinGW-w64 32bit {}.{} / GNU C++ {}", __MINGW32_MAJOR_VERSION,
__MINGW32_MINOR_VERSION, __VERSION__);
#elif defined(__GNUC__)
buf = fmt::format("GNU C++ {}", __VERSION__);
#elif defined(_MSC_VER) && (_MSC_VER > 1920) && (_MSC_VER < 2000)
constexpr int major = _MSC_VER / 100;
constexpr int minor = _MSC_VER - major *100;
buf = fmt::format("Microsoft Visual Studio 20{}, C/C++ {}.{}", major, major-5, minor);
#else
buf = "(Unknown)";
#endif
return buf;
}
std::string Info::get_openmp_info()
{
#if !defined(_OPENMP)
return "OpenMP not enabled";
#else
// Supported OpenMP version corresponds to the release date of the
// specifications as posted at https://www.openmp.org/specifications/
#if _OPENMP > 202011
return "OpenMP newer than version 5.1";
#elif _OPENMP == 202011
return "OpenMP 5.1";
#elif _OPENMP == 201811
return "OpenMP 5.0";
#elif _OPENMP == 201611
return "OpenMP 5.0 preview 1";
#elif _OPENMP == 201511
return "OpenMP 4.5";
#elif _OPENMP == 201307
return "OpenMP 4.0";
#elif _OPENMP == 201107
return "OpenMP 3.1";
#elif _OPENMP == 200805
return "OpenMP 3.0";
#elif _OPENMP == 200505
return "OpenMP 2.5";
#elif _OPENMP == 200203
return "OpenMP 2.0";
#else
return "unknown OpenMP version";
#endif
#endif
}
std::string Info::get_mpi_vendor() {
#if defined(MPI_STUBS)
return "MPI STUBS";
#elif defined(OPEN_MPI)
return "Open MPI";
#elif defined(MPICH_NAME)
return "MPICH";
#elif defined(I_MPI_VERSION)
return "Intel MPI";
#elif defined(PLATFORM_MPI)
return "Platform MPI";
#elif defined(HP_MPI)
return "HP MPI";
#elif defined(MSMPI_VER)
return "Microsoft MPI";
#else
return "Unknown MPI implementation";
#endif
}
std::string Info::get_mpi_info(int &major, int &minor)
{
int len;
#if (defined(MPI_VERSION) && (MPI_VERSION > 2)) || defined(MPI_STUBS)
static char version[MPI_MAX_LIBRARY_VERSION_STRING];
MPI_Get_library_version(version,&len);
#else
static char version[32];
strcpy(version,get_mpi_vendor().c_str());
len = strlen(version);
#endif
MPI_Get_version(&major,&minor);
if (len > 80) {
char *ptr = strchr(version+80,'\n');
if (ptr) *ptr = '\0';
}
return std::string(version);
}
std::string Info::get_cxx_info()
{
#if __cplusplus > 202002L
return "newer than C++20";
#elif __cplusplus == 202002L
return "C++20";
#elif __cplusplus == 201703L
return "C++17";
#elif __cplusplus == 201402L
return "C++14";
#elif __cplusplus == 201103L
return "C++11";
#elif __cplusplus == 199711L
return "C++98";
#else
return "unknown";
#endif
}
std::string Info::get_accelerator_info(const std::string &package)
{
std::string mesg("");

View File

@ -48,13 +48,6 @@ class Info : public Command {
const std::string &);
static bool has_gpu_device();
static std::string get_gpu_device_info();
static std::string get_os_info();
static std::string get_compiler_info();
static std::string get_openmp_info();
static std::string get_mpi_vendor();
static std::string get_mpi_info(int &, int &);
static std::string get_cxx_info();
static std::string get_accelerator_info(const std::string &pkg = "");
void get_memory_info(double *);

View File

@ -1340,14 +1340,14 @@ void LAMMPS::print_config(FILE *fp)
const char *pkg;
int ncword, ncline = 0;
fmt::print(fp,"OS: {}\n\n",Info::get_os_info());
fmt::print(fp,"OS: {}\n\n",platform::os_info());
fmt::print(fp,"Compiler: {} with {}\nC++ standard: {}\n",
Info::get_compiler_info(),Info::get_openmp_info(),
Info::get_cxx_info());
platform::compiler_info(),platform::openmp_standard(),
platform::cxx_standard());
int major,minor;
std::string infobuf = Info::get_mpi_info(major,minor);
std::string infobuf = platform::mpi_info(major,minor);
fmt::print(fp,"MPI v{}.{}: {}\n\n",major,minor,infobuf);
fmt::print(fp,"Accelerator configuration:\n\n{}\n",

View File

@ -4394,9 +4394,9 @@ void lammps_get_os_info(char *buffer, int buf_size)
{
if (buf_size <=0) return;
buffer[0] = buffer[buf_size-1] = '\0';
std::string txt = Info::get_os_info() + "\n";
txt += Info::get_compiler_info();
txt += " with " + Info::get_openmp_info() + "\n";
std::string txt = platform::os_info() + "\n";
txt += platform::compiler_info();
txt += " with " + platform::openmp_standard() + "\n";
strncpy(buffer, txt.c_str(), buf_size-1);
}

View File

@ -1799,7 +1799,7 @@ void Pair::write_file(int narg, char **arg)
// write out a line with "DATE:" and "UNITS:" tags
// - if the file already exists, print a message about appending
// while printing the date and check that units are consistent.
if (utils::file_is_readable(table_file)) {
if (platform::file_is_readable(table_file)) {
std::string units = utils::get_potential_units(table_file,"table");
if (!units.empty() && (units != update->unit_style)) {
error->one(FLERR,"Trying to append to a table file "

View File

@ -224,7 +224,7 @@ std::string platform::os_info()
buf = ut.sysname;
#if 0 // disable until this is integrated into LAMMPS and TextFileReader becomes available
if (utils::file_is_readable("/etc/os-release")) {
if (platform::file_is_readable("/etc/os-release")) {
try {
TextFileReader reader("/etc/os-release","");
while (1) {
@ -275,7 +275,6 @@ std::string platform::cxx_standard()
std::string platform::compiler_info()
{
std::string buf = "(Unknown)";
#if 0 // disable for now untile merged into LAMMPS and fmt:: becomes available
#if defined(__INTEL_LLVM_COMPILER)
double version = static_cast<double>(__INTEL_LLVM_COMPILER)*0.01;
buf = fmt::format("Intel LLVM C++ {:.1f} / {}", version, __VERSION__);
@ -304,7 +303,6 @@ std::string platform::compiler_info()
buf = "Microsoft Visual Studio 20" + std::to_string(major) + ", C/C++ " + std::to_string(major-5) + "." + std::to_string(minor);
#else
buf = "(Unknown)";
#endif
#endif
return buf;
}
@ -543,9 +541,9 @@ void *platform::dlsym(void *handle, const std::string &symbol)
/** On Linux the folder /proc/self/fd holds symbolic links to the actual
* pathnames associated with each open file descriptor of the current process.
* On macOS the same kind of information can be obtained using ``fcntl(fd,F_GETPATH,buf)``.
* On MacOS the same kind of information can be obtained using ``fcntl(fd,F_GETPATH,buf)``.
* On Windows we use ``GetFinalPathNameByHandleA()`` which is available with
* Windows Vista and later. If the buffer is to small (< 16 bytes) a null pointer is returned.
* Windows Vista and later. If the buffer is too small (< 16 bytes) a null pointer is returned.
*
* This function is used to provide a filename with error messages in functions
* where the filename is not passed as an argument, but the FILE * pointer. */

View File

@ -125,7 +125,7 @@ namespace platform {
* after this call
*
* \param handle handle to an opened shared object
* \return 0 if succesful, non-zero of not */
* \return 0 if successful, non-zero of not */
int dlclose(void *handle);
@ -158,7 +158,7 @@ namespace platform {
/*! Try to detect pathname from FILE pointer.
*
* Currently only supported on Linux and macOS, otherwise will report "(unknown)".
* Currently only supported on Linux and MacOS, otherwise will report "(unknown)".
*
* \param fp FILE pointer struct from STDIO library for which we want to detect the name
* \param buf storage buffer for pathname. output will be truncated if not large enough
@ -193,7 +193,7 @@ namespace platform {
* This provides a list of strings of the entries in the directory
* without the leading path name while also skipping over ".." and ".".
*
* \param path path to directory
* \param dir path to directory
* \return vector with strings of all directory entries */
std::vector<std::string> list_directory(const std::string &dir);
@ -203,7 +203,7 @@ namespace platform {
* This function will traverse the list of directories in the PATH
* environment variable and look for the executable *cmd*. If the
* file exists and is executable the full path is returned as string,
* otherwise and emptry string is returned.
* otherwise and empty string is returned.
*
* On Windows the *cmd* string must not include and extension as
* this function will automatically append the extensions ".exe",
@ -268,7 +268,7 @@ namespace platform {
int fseek(FILE *fp, bigint pos);
/*! Truncate file to a given length and reposition file pointer
/*! Truncate file to a given length and re-position file pointer
*
* \param fp FILE pointer of the given file
* \param length length to which the file is being truncated to

View File

@ -30,6 +30,7 @@
#include "lammps.h" // IWYU pragma: export
#include "utils.h" // IWYU pragma: export
#include "fmt/format.h" // IWYU pragma: export
#include "platform.h" // IWYU pragma: export
namespace LAMMPS_NS {

View File

@ -308,7 +308,7 @@ void ReadData::command(int narg, char **arg)
// check if data file is available and readable
if (!utils::file_is_readable(arg[0]))
if (!platform::file_is_readable(arg[0]))
error->all(FLERR,fmt::format("Cannot open file {}: {}",
arg[0], utils::getsyserror()));

View File

@ -540,8 +540,8 @@ std::string ReadRestart::file_search(const std::string &inpfile)
{
// separate inpfile into dir + filename
auto dirname = utils::path_dirname(inpfile);
auto filename = utils::path_basename(inpfile);
auto dirname = platform::path_dirname(inpfile);
auto filename = platform::path_basename(inpfile);
// if filename contains "%" replace "%" with "base"
@ -574,7 +574,7 @@ std::string ReadRestart::file_search(const std::string &inpfile)
if (maxnum < 0) error->one(FLERR,"Found no restart file matching pattern");
filename.replace(filename.find('*'),1,std::to_string(maxnum));
}
return utils::path_join(dirname,filename);
return platform::path_join(dirname,filename);
}
/* ----------------------------------------------------------------------

View File

@ -165,44 +165,6 @@ std::string utils::getsyserror()
return std::string(strerror(errno));
}
/** On Linux the folder /proc/self/fd holds symbolic links to the actual
* pathnames associated with each open file descriptor of the current process.
* On MacOS the same kind of information can be obtained using ``fcntl(fd,F_GETPATH,buf)``.
* On Windows we use ``GetFinalPathNameByHandleA()`` which is available with
* Windows Vista and later.
*
* This function is used to provide a filename with error messages in functions
* where the filename is not passed as an argument, but the FILE * pointer.
*/
const char *utils::guesspath(char *buf, int len, FILE *fp)
{
memset(buf, 0, len);
#if defined(__linux__)
int fd = fileno(fp);
// get pathname from /proc or copy (unknown)
if (readlink(fmt::format("/proc/self/fd/{}", fd).c_str(), buf, len - 1) <= 0)
strncpy(buf, "(unknown)", len - 1);
#elif defined(__APPLE__)
int fd = fileno(fp);
char filepath[PATH_MAX];
if (fcntl(fd, F_GETPATH, filepath) != -1)
strncpy(buf, filepath, len - 1);
else
strncpy(buf, "(unknown)", len - 1);
#elif defined(_WIN32)
char filepath[MAX_PATH];
HANDLE h = (HANDLE) _get_osfhandle(_fileno(fp));
if (GetFinalPathNameByHandleA(h, filepath, PATH_MAX, FILE_NAME_NORMALIZED) > 0)
strncpy(buf, filepath, len - 1);
else
strncpy(buf, "(unknown)", len - 1);
#else
strncpy(buf, "(unknown)", len - 1);
#endif
return buf;
}
// read line into buffer. if line is too long keep reading until EOL or EOF
// but return only the first part with a newline at the end.
@ -256,7 +218,7 @@ void utils::sfgets(const char *srcname, int srcline, char *s, int size, FILE *fp
std::string errmsg;
// try to figure out the file name from the file pointer
if (!filename) filename = guesspath(buf, MAXPATHLENBUF, fp);
if (!filename) filename = platform::guesspath(fp, buf, MAXPATHLENBUF);
if (feof(fp)) {
errmsg = "Unexpected end of file while reading file '";
@ -285,7 +247,7 @@ void utils::sfread(const char *srcname, int srcline, void *s, size_t size, size_
std::string errmsg;
// try to figure out the file name from the file pointer
if (!filename) filename = guesspath(buf, MAXPATHLENBUF, fp);
if (!filename) filename = platform::guesspath(fp, buf, MAXPATHLENBUF);
if (feof(fp)) {
errmsg = "Unexpected end of file while reading file '";
@ -920,7 +882,7 @@ size_t utils::count_words(const std::string &text, const std::string &separators
size_t utils::trim_and_count_words(const std::string &text, const std::string &separators)
{
return utils::count_words(utils::trim_comment(text), separators);
return utils::count_words(trim_comment(text), separators);
}
/* ----------------------------------------------------------------------
@ -1065,71 +1027,6 @@ bool utils::is_id(const std::string &str)
return true;
}
/* ----------------------------------------------------------------------
strip off leading part of path, return just the filename
------------------------------------------------------------------------- */
std::string utils::path_basename(const std::string &path)
{
#if defined(_WIN32)
size_t start = path.find_last_of("/\\");
#else
size_t start = path.find_last_of('/');
#endif
if (start == std::string::npos) {
start = 0;
} else {
start += 1;
}
return path.substr(start);
}
/* ----------------------------------------------------------------------
Return only the leading part of a path, return just the directory
------------------------------------------------------------------------- */
std::string utils::path_dirname(const std::string &path)
{
#if defined(_WIN32)
size_t start = path.find_last_of("/\\");
#else
size_t start = path.find_last_of('/');
#endif
if (start == std::string::npos) return ".";
return path.substr(0, start);
}
/* ----------------------------------------------------------------------
join two paths
------------------------------------------------------------------------- */
std::string utils::path_join(const std::string &a, const std::string &b)
{
#if defined(_WIN32)
return fmt::format("{}\\{}", a, b);
#else
return fmt::format("{}/{}", a, b);
#endif
}
/* ----------------------------------------------------------------------
try to open file for reading
------------------------------------------------------------------------- */
bool utils::file_is_readable(const std::string &path)
{
FILE *fp = fopen(path.c_str(), "r");
if (fp) {
fclose(fp);
return true;
}
return false;
}
/* ----------------------------------------------------------------------
try to find potential file as specified by name
search current directory and the LAMMPS_POTENTIALS directory if
@ -1139,9 +1036,9 @@ bool utils::file_is_readable(const std::string &path)
std::string utils::get_potential_file_path(const std::string &path)
{
std::string filepath = path;
std::string filename = utils::path_basename(path);
std::string filename = platform::path_basename(path);
if (utils::file_is_readable(filepath)) {
if (platform::file_is_readable(filepath)) {
return filepath;
} else {
// try the environment variable directory
@ -1154,11 +1051,11 @@ std::string utils::get_potential_file_path(const std::string &path)
Tokenizer dirs(var, ":");
#endif
while (dirs.has_next()) {
auto pot = utils::path_basename(filepath);
auto pot = platform::path_basename(filepath);
auto dir = dirs.next();
filepath = utils::path_join(dir, pot);
filepath = platform::path_join(dir, pot);
if (utils::file_is_readable(filepath)) { return filepath; }
if (platform::file_is_readable(filepath)) { return filepath; }
}
}
}

View File

@ -417,49 +417,6 @@ namespace utils {
bool is_id(const std::string &str);
/*! Try to detect pathname from FILE pointer.
*
* Currently supported on Linux, MacOS, and Windows, otherwise will report "(unknown)".
*
* \param buf storage buffer for pathname. output will be truncated if not large enough
* \param len size of storage buffer. output will be truncated to this length - 1
* \param fp FILE pointer struct from STDIO library for which we want to detect the name
* \return pointer to the storage buffer, i.e. buf */
const char *guesspath(char *buf, int len, FILE *fp);
/*! Strip off leading part of path, return just the filename
*
* \param path file path
* \return file name */
std::string path_basename(const std::string &path);
/*! Return the directory part of a path. Return "." if empty
*
* \param path file path
* \return directory name */
std::string path_dirname(const std::string &path);
/*! Join two pathname segments
*
* This uses the forward slash '/' character unless LAMMPS is compiled
* for Windows where it used the equivalent backward slash '\\'.
*
* \param a first path
* \param b second path
* \return combined path */
std::string path_join(const std::string &a, const std::string &b);
/*! Check if file exists and is readable
*
* \param path file path
* \return true if file exists and is readable */
bool file_is_readable(const std::string &path);
/*! Determine full path of potential file. If file is not found in current directory,
* search directories listed in LAMMPS_POTENTIALS environment variable
*

View File

@ -6,6 +6,7 @@
// This software is distributed under the GNU General Public License.
#include "library.h"
#include "platform.h"
#include "utils.h"
#include <cstring>
@ -785,8 +786,8 @@ int main(int argc, char **argv)
std::string input_file;
if ((argc > 1) && (argv[1][0] != '-')) {
--argc;
input_file = utils::path_basename(argv[1]);
chdir(utils::path_dirname(input_file).c_str());
input_file = platform::path_basename(argv[1]);
chdir(platform::path_dirname(input_file).c_str());
for (int i = 1; i < argc; ++i)
argv[i] = argv[i + 1];
}

View File

@ -316,7 +316,7 @@ int main(int argc, char **argv)
MPI_Init(&argc, &argv);
::testing::InitGoogleMock(&argc, argv);
if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
std::cout << "Warning: using OpenMPI without exceptions. "
"Death tests will be skipped\n";

View File

@ -684,7 +684,7 @@ int main(int argc, char **argv)
MPI_Init(&argc, &argv);
::testing::InitGoogleMock(&argc, argv);
if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
std::cout << "Warning: using OpenMPI without exceptions. "
"Death tests will be skipped\n";

View File

@ -20,7 +20,6 @@
#include "lammps.h"
#include "lattice.h"
#include "region.h"
#include "utils.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@ -631,7 +630,7 @@ int main(int argc, char **argv)
MPI_Init(&argc, &argv);
::testing::InitGoogleMock(&argc, argv);
if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
std::cout << "Warning: using OpenMPI without exceptions. "
"Death tests will be skipped\n";

View File

@ -686,7 +686,7 @@ int main(int argc, char **argv)
MPI_Init(&argc, &argv);
::testing::InitGoogleMock(&argc, argv);
if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
std::cout << "Warning: using OpenMPI without exceptions. "
"Death tests will be skipped\n";

View File

@ -20,7 +20,6 @@
#include "input.h"
#include "output.h"
#include "update.h"
#include "utils.h"
#include "variable.h"
#include "../testing/core.h"
@ -217,7 +216,7 @@ TEST_F(SimpleCommandsTest, Quit)
TEST_FAILURE(".*ERROR: Expected integer .*", command("quit xxx"););
// the following tests must be skipped with OpenMPI due to using threads
if (Info::get_mpi_vendor() == "Open MPI") GTEST_SKIP();
if (platform::mpi_vendor() == "Open MPI") GTEST_SKIP();
ASSERT_EXIT(command("quit"), ExitedWithCode(0), "");
ASSERT_EXIT(command("quit 9"), ExitedWithCode(9), "");
}
@ -528,7 +527,7 @@ int main(int argc, char **argv)
MPI_Init(&argc, &argv);
::testing::InitGoogleMock(&argc, argv);
if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
std::cout << "Warning: using OpenMPI without exceptions. "
"Death tests will be skipped\n";

View File

@ -517,7 +517,7 @@ int main(int argc, char **argv)
MPI_Init(&argc, &argv);
::testing::InitGoogleMock(&argc, argv);
if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
std::cout << "Warning: using OpenMPI without exceptions. "
"Death tests will be skipped\n";

View File

@ -128,7 +128,7 @@ int main(int argc, char **argv)
MPI_Init(&argc, &argv);
::testing::InitGoogleMock(&argc, argv);
if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
std::cout << "Warning: using OpenMPI without exceptions. "
"Death tests will be skipped\n";

View File

@ -325,7 +325,7 @@ TEST_F(LAMMPS_kokkos, InitMembers)
TEST(LAMMPS_init, OpenMP)
{
if (!LAMMPS::is_installed_pkg("OPENMP")) GTEST_SKIP();
if (Info::get_openmp_info() == "OpenMP not enabled") GTEST_SKIP();
if (platform::openmp_standard() == "OpenMP not enabled") GTEST_SKIP();
FILE *fp = fopen("in.lammps_empty", "w");
fputs("\n", fp);

View File

@ -491,7 +491,7 @@ int main(int argc, char **argv)
MPI_Init(&argc, &argv);
::testing::InitGoogleMock(&argc, argv);
if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
std::cout << "Warning: using OpenMPI without exceptions. "
"Death tests will be skipped\n";

View File

@ -17,7 +17,6 @@
#include "input.h"
#include "lammps.h"
#include "molecule.h"
#include "utils.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@ -257,7 +256,7 @@ int main(int argc, char **argv)
MPI_Init(&argc, &argv);
::testing::InitGoogleMock(&argc, argv);
if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
std::cout << "Warning: using OpenMPI without exceptions. "
"Death tests will be skipped\n";

View File

@ -326,7 +326,7 @@ int main(int argc, char **argv)
MPI_Init(&argc, &argv);
::testing::InitGoogleMock(&argc, argv);
if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
std::cout << "Warning: using OpenMPI without exceptions. "
"Death tests will be skipped\n";

View File

@ -160,7 +160,7 @@ int main(int argc, char **argv)
MPI_Init(&argc, &argv);
::testing::InitGoogleMock(&argc, argv);
if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
std::cout << "Warning: using OpenMPI without exceptions. "
"Death tests will be skipped\n";

View File

@ -17,6 +17,7 @@
#include "info.h"
#include "input.h"
#include "lammps.h"
#include "platform.h"
#include "variable.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@ -36,7 +37,7 @@ using ::testing::MatchesRegex;
auto mesg = ::testing::internal::GetCapturedStdout(); \
ASSERT_THAT(mesg, MatchesRegex(errmsg)); \
} else { \
if (Info::get_mpi_vendor() != "Open MPI") { \
if (platform::mpi_vendor() != "Open MPI") { \
::testing::internal::CaptureStdout(); \
ASSERT_DEATH({__VA_ARGS__}, ""); \
auto mesg = ::testing::internal::GetCapturedStdout(); \

View File

@ -13,14 +13,12 @@
#include "lmptype.h"
#include "pointers.h"
#include "utils.h"
#include "tokenizer.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <cerrno>
#include <cstdio>
#include <string>
#include <vector>
@ -721,54 +719,6 @@ TEST(Utils, boundsbig_case3)
ASSERT_EQ(nhi, -1);
}
TEST(Utils, guesspath)
{
char buf[256];
FILE *fp = fopen("test_guesspath.txt", "w");
#if defined(__linux__) || defined(__APPLE__) || defined(_WIN32)
const char *path = utils::guesspath(buf, sizeof(buf), fp);
ASSERT_THAT(path, EndsWith("test_guesspath.txt"));
#else
const char *path = utils::guesspath(buf, sizeof(buf), fp);
ASSERT_THAT(path, EndsWith("(unknown)"));
#endif
fclose(fp);
}
TEST(Utils, path_join)
{
#if defined(_WIN32)
ASSERT_THAT(utils::path_join("c:\\parent\\folder", "filename"),
Eq("c:\\parent\\folder\\filename"));
#else
ASSERT_THAT(utils::path_join("/parent/folder", "filename"), Eq("/parent/folder/filename"));
#endif
}
TEST(Utils, path_basename)
{
#if defined(_WIN32)
ASSERT_THAT(utils::path_basename("c:\\parent\\folder\\filename"), Eq("filename"));
ASSERT_THAT(utils::path_basename("folder\\"), Eq(""));
ASSERT_THAT(utils::path_basename("c:/parent/folder/filename"), Eq("filename"));
#else
ASSERT_THAT(utils::path_basename("/parent/folder/filename"), Eq("filename"));
ASSERT_THAT(utils::path_basename("/parent/folder/"), Eq(""));
#endif
}
TEST(Utils, path_dirname)
{
#if defined(_WIN32)
ASSERT_THAT(utils::path_dirname("c:/parent/folder/filename"), Eq("c:/parent/folder"));
ASSERT_THAT(utils::path_dirname("c:\\parent\\folder\\filename"), Eq("c:\\parent\\folder"));
ASSERT_THAT(utils::path_dirname("c:filename"), Eq("."));
#else
ASSERT_THAT(utils::path_dirname("/parent/folder/filename"), Eq("/parent/folder"));
#endif
ASSERT_THAT(utils::path_dirname("filename"), Eq("."));
}
TEST(Utils, getsyserror)
{
#if defined(__linux__)
@ -792,16 +742,16 @@ TEST(Utils, potential_file)
fputs("# CONTRIBUTOR: Pippo\n", fp);
fclose(fp);
ASSERT_TRUE(utils::file_is_readable("ctest1.txt"));
ASSERT_TRUE(utils::file_is_readable("ctest2.txt"));
ASSERT_FALSE(utils::file_is_readable("no_such_file.txt"));
ASSERT_TRUE(platform::file_is_readable("ctest1.txt"));
ASSERT_TRUE(platform::file_is_readable("ctest2.txt"));
ASSERT_FALSE(platform::file_is_readable("no_such_file.txt"));
ASSERT_THAT(utils::get_potential_file_path("ctest1.txt"), Eq("ctest1.txt"));
ASSERT_THAT(utils::get_potential_file_path("no_such_file.txt"), Eq(""));
const char *folder = getenv("LAMMPS_POTENTIALS");
if (folder != nullptr) {
std::string path = utils::path_join(folder, "Cu_u3.eam");
std::string path = platform::path_join(folder, "Cu_u3.eam");
EXPECT_THAT(utils::get_potential_file_path("Cu_u3.eam"), Eq(path));
EXPECT_THAT(utils::get_potential_units(path, "EAM"), Eq("metal"));
}