import files for platform namespace from standalone project w/o updating LAMMPS
This commit is contained in:
947
src/platform.cpp
Normal file
947
src/platform.cpp
Normal file
@ -0,0 +1,947 @@
|
||||
/* ----------------------------------------------------------------------
|
||||
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||
https://www.lammps.org/, Sandia National Laboratories
|
||||
Steve Plimpton, sjplimp@sandia.gov
|
||||
|
||||
Copyright (2003) Sandia Corporation. Under the terms of Contract
|
||||
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
||||
certain rights in this software. This software is distributed under
|
||||
the GNU General Public License.
|
||||
|
||||
See the README file in the top-level LAMMPS directory.
|
||||
------------------------------------------------------------------------- */
|
||||
/** \file platform.cpp
|
||||
* This file provides abstractions for a variety of platform specific
|
||||
* functionality in a namespace "platform". This is a companion to
|
||||
* the "utils" namespace with convenience and utility functions. */
|
||||
|
||||
#include "platform.h"
|
||||
#include "utils.h"
|
||||
|
||||
#if HAVE_MPI
|
||||
#include <mpi.h>
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// include system headers and tweak system settings
|
||||
#if defined(_WIN32)
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32_WINNT)
|
||||
#undef _WIN32_WINNT
|
||||
#endif
|
||||
|
||||
// target Windows version is windows 7 and later
|
||||
#define _WIN32_WINNT _WIN32_WINNT_WIN7
|
||||
#define PSAPI_VERSION 2
|
||||
|
||||
#include <direct.h>
|
||||
#include <io.h> // for _get_osfhandle()
|
||||
#include <sys/stat.h>
|
||||
#include <windows.h>
|
||||
|
||||
#else // not Windows ///////////////////////////////////////////////
|
||||
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <fcntl.h>
|
||||
#include <sys/syslimits.h>
|
||||
#endif
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cstring>
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/// Struct for listing on-the-fly compression/decompression commands
|
||||
struct zip_info {
|
||||
/// identifier for the different compression algorithms
|
||||
enum styles { NONE, GZIP, BZIP2, ZSTD, XZ, LZMA, LZ4 };
|
||||
const std::string extension; ///< filename extension for the current algorithm
|
||||
const std::string command; ///< command to perform compression or decompression
|
||||
const std::string zipflags; ///< flags to append to compress from stdin to stdout
|
||||
const std::string unzipflags; ///< flags to decompress file to stdout
|
||||
const int style; ///< compression style flag
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
static const std::vector<zip_info> zip_styles = {
|
||||
{"", "", "", "", zip_info::NONE},
|
||||
{"gz", "gzip", " > ", " -cdf ", zip_info::GZIP},
|
||||
{"bz2", "bzip2", " > ", " -cdf ", zip_info::BZIP2},
|
||||
{"zstd", "zstd", " -q > ", " -cdf ", zip_info::ZSTD},
|
||||
{"xz", "xz", " > ", " -cdf ", zip_info::XZ},
|
||||
{"lzma", "xz", " --format=lzma > ", " --format=lzma -cdf ", zip_info::LZMA},
|
||||
{"lz4", "lz4", " > ", " -cdf ", zip_info::LZ4},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static const zip_info &find_zip_type(const std::string &file)
|
||||
{
|
||||
std::size_t dot = file.find_last_of('.');
|
||||
if (dot != std::string::npos) {
|
||||
const std::string ext = file.substr(dot + 1);
|
||||
for (const auto &i : zip_styles) {
|
||||
if (i.extension == ext) return i;
|
||||
}
|
||||
}
|
||||
return zip_styles[0];
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
using namespace LAMMPS_NS;
|
||||
|
||||
// get CPU time
|
||||
|
||||
// clang-format off
|
||||
// clang compilers are optimizing this function too aggressively returning always 0
|
||||
#if defined(__clang__)
|
||||
[[clang::optnone]]
|
||||
#endif
|
||||
double platform::cputime()
|
||||
// clang-format on
|
||||
{
|
||||
double rv = 0.0;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// from MSD docs.
|
||||
FILETIME ct, et, kt, ut;
|
||||
union {
|
||||
FILETIME ft;
|
||||
uint64_t ui;
|
||||
} cpu;
|
||||
if (GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
|
||||
cpu.ft = ut;
|
||||
rv = cpu.ui * 0.0000001;
|
||||
}
|
||||
|
||||
#else /* ! _WIN32 */
|
||||
|
||||
struct rusage ru;
|
||||
if (getrusage(RUSAGE_SELF, &ru) == 0) {
|
||||
rv = (double) ru.ru_utime.tv_sec;
|
||||
rv += (double) ru.ru_utime.tv_usec * 0.000001;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
get wall time
|
||||
------------------------------------------------------------------------ */
|
||||
double platform::walltime()
|
||||
{
|
||||
double wtime;
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
wtime = GetTickCount64() * 0.001;
|
||||
|
||||
#else
|
||||
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, nullptr);
|
||||
wtime = 1.0 * tv.tv_sec + 1.0e-6 * tv.tv_usec;
|
||||
|
||||
#endif
|
||||
|
||||
return wtime;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
get Operating system and version info
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
std::string platform::os_info()
|
||||
{
|
||||
std::string buf;
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
// Get Windows Edition name from registry
|
||||
char value[1024];
|
||||
DWORD value_length = 1024;
|
||||
const char *subkey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
|
||||
const char *entry = "ProductName";
|
||||
RegGetValue(HKEY_LOCAL_MACHINE, subkey, entry, RRF_RT_REG_SZ, nullptr, &value,
|
||||
(LPDWORD) &value_length);
|
||||
// enforce zero termination
|
||||
value[1023] = '\0';
|
||||
buf = value;
|
||||
|
||||
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 += ", Windows ABI " + std::to_string(majorv) + "." + std::to_string(minorv) + " (" +
|
||||
std::to_string(buildv) + ") on ";
|
||||
|
||||
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
|
||||
buf = ut.sysname;
|
||||
|
||||
#if 0 // disable until this is integrated into LAMMPS and TextFileReader becomes available
|
||||
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
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
buf += std::string(" ") + ut.release + " " + ut.machine;
|
||||
#endif
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
identify C++ standard version
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
std::string platform::cxx_standard()
|
||||
{
|
||||
#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
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
identify compiler and its version
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
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__);
|
||||
#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 = "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;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
detect OpenMP standard
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
std::string platform::openmp_standard()
|
||||
{
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
identify MPI vendor from defines in the mpi.h file.
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
std::string platform::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)
|
||||
// Get Microsoft MPI version from registry
|
||||
char value[1024];
|
||||
DWORD value_length = 1024;
|
||||
const char *subkey = "SOFTWARE\\Microsoft\\MPI";
|
||||
const char *entry = "Version";
|
||||
auto rv = RegGetValueA(HKEY_LOCAL_MACHINE, subkey, entry, RRF_RT_REG_SZ, nullptr, &value,
|
||||
(LPDWORD) &value_length);
|
||||
std::string buf = "Microsoft MPI";
|
||||
if (rv == ERROR_SUCCESS) buf += std::string(" v") + value;
|
||||
return buf;
|
||||
#else
|
||||
return "Unknown MPI implementation";
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
detect MPI version info
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
std::string platform::mpi_info(int &major, int &minor)
|
||||
{
|
||||
int len = 0;
|
||||
#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
|
||||
constexpr int MAX_VERSION_STRING = 32;
|
||||
static char version[MAX_VERSION_STRING];
|
||||
strncpy(version, mpi_vendor().c_str(), MAX_VERSION_STRING);
|
||||
#endif
|
||||
|
||||
#if defined(MPI_VERSION)
|
||||
MPI_Get_version(&major, &minor);
|
||||
if (len > 80) {
|
||||
char *ptr = strchr(version + 80, '\n');
|
||||
if (ptr) *ptr = '\0';
|
||||
}
|
||||
#else
|
||||
major = 1;
|
||||
minor = 0;
|
||||
#endif
|
||||
return std::string(version);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
set environment variable
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int platform::putenv(const std::string &vardef)
|
||||
{
|
||||
if (vardef.size() == 0) return -1;
|
||||
|
||||
auto found = vardef.find_first_of('=');
|
||||
#ifdef _WIN32
|
||||
// must assign a value to variable with _putenv()
|
||||
if (found == std::string::npos)
|
||||
return _putenv(utils::strdup(vardef + "=1"));
|
||||
else
|
||||
return _putenv(utils::strdup(vardef));
|
||||
#else
|
||||
if (found == std::string::npos)
|
||||
return setenv(vardef.c_str(), "", 1);
|
||||
else
|
||||
return setenv(vardef.substr(0, found).c_str(), vardef.substr(found + 1).c_str(), 1);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
split a "path" environment variable into a list
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
std::vector<std::string> platform::list_pathenv(const std::string &var)
|
||||
{
|
||||
std::vector<std::string> dirs;
|
||||
const char *ptr = getenv(var.c_str());
|
||||
if (ptr == nullptr) return dirs;
|
||||
|
||||
std::string pathvar = ptr;
|
||||
std::size_t first = 0, next;
|
||||
while (true) {
|
||||
next = pathvar.find_first_of(pathvarsep, first);
|
||||
if (next == std::string::npos) {
|
||||
dirs.push_back(pathvar.substr(first));
|
||||
break;
|
||||
} else {
|
||||
dirs.push_back(pathvar.substr(first, next - first));
|
||||
first = next + 1;
|
||||
}
|
||||
}
|
||||
return dirs;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
find the full path name of an executable
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
std::string platform::find_exe_path(const std::string &cmd)
|
||||
{
|
||||
if (cmd.size() == 0) return "";
|
||||
auto pathdirs = list_pathenv("PATH");
|
||||
#ifdef _WIN32
|
||||
// windows always looks in "." and does it first
|
||||
pathdirs.insert(pathdirs.begin(), ".");
|
||||
#else
|
||||
struct stat info;
|
||||
#endif
|
||||
for (const auto &dir : pathdirs) {
|
||||
std::string exe = path_join(dir, cmd);
|
||||
#ifdef _WIN32
|
||||
const char *extensions[] = {".exe", ".com", ".bat", nullptr};
|
||||
for (auto ext = extensions; *ext != nullptr; ++ext) {
|
||||
auto exe_path = exe + *ext;
|
||||
if (file_is_readable(exe_path)) return exe_path;
|
||||
}
|
||||
#else
|
||||
memset(&info, 0, sizeof(info));
|
||||
if (stat(exe.c_str(), &info) != 0) continue;
|
||||
if ((info.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) != 0) return exe;
|
||||
#endif
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
wrapper functions for loading shared objects and libraries
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// open a shared object file
|
||||
void *platform::dlopen(const std::string &fname)
|
||||
{
|
||||
return (void *) LoadLibrary(fname.c_str());
|
||||
}
|
||||
|
||||
// close a shared object
|
||||
int platform::dlclose(void *handle)
|
||||
{
|
||||
/* FreeLibrary returns nonzero on success unlike dlclose() */
|
||||
return (FreeLibrary((HINSTANCE) handle) == 0);
|
||||
}
|
||||
|
||||
// resolve a symbol in shared object
|
||||
void *platform::dlsym(void *handle, const std::string &symbol)
|
||||
{
|
||||
return (void *) GetProcAddress((HINSTANCE) handle, symbol.c_str());
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// open a shared object file
|
||||
void *platform::dlopen(const std::string &fname)
|
||||
{
|
||||
return ::dlopen(fname.c_str(), RTLD_NOW);
|
||||
}
|
||||
|
||||
// close a shared object
|
||||
int platform::dlclose(void *handle)
|
||||
{
|
||||
return ::dlclose(handle);
|
||||
}
|
||||
|
||||
// resolve a symbol in shared object
|
||||
void *platform::dlsym(void *handle, const std::string &symbol)
|
||||
{
|
||||
return ::dlsym(handle, symbol.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/** 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. If the buffer is to 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. */
|
||||
|
||||
const char *platform::guesspath(FILE *fp, char *buf, int len)
|
||||
{
|
||||
// no point in guessing a path with a short buffer or NULL pointer as buffer
|
||||
if ((buf == nullptr) || (len < 16)) return nullptr;
|
||||
|
||||
// zero buffer and reserve last character in buffer for terminating '\0'
|
||||
memset(buf, 0, len);
|
||||
len--;
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
int fd = fileno(fp);
|
||||
// get pathname from /proc or copy (unknown)
|
||||
if (readlink((std::string("/proc/self/fd/") + std::to_string(fd)).c_str(), buf, len) <= 0)
|
||||
strncpy(buf, "(unknown)", len);
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
int fd = fileno(fp);
|
||||
char filepath[PATH_MAX];
|
||||
if (fcntl(fd, F_GETPATH, filepath) != -1)
|
||||
strncpy(buf, filepath, len);
|
||||
else
|
||||
strncpy(buf, "(unknown)", len);
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
char filepath[MAX_PATH];
|
||||
HANDLE h = (HANDLE) _get_osfhandle(_fileno(fp));
|
||||
if (GetFinalPathNameByHandleA(h, filepath, MAX_PATH, FILE_NAME_NORMALIZED) > 0)
|
||||
strncpy(buf, filepath, len);
|
||||
else
|
||||
strncpy(buf, "(unknown)", len);
|
||||
|
||||
#else // unsupported OS
|
||||
|
||||
strncpy(buf, "(unknown)", len);
|
||||
|
||||
#endif
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
detect terminal, e.g. for using a pager automatically
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
bool platform::is_console(FILE *fp)
|
||||
{
|
||||
if (!fp) return false;
|
||||
#if defined(_WIN32)
|
||||
return (_isatty(fileno(fp)) == 1);
|
||||
#else
|
||||
return (isatty(fileno(fp)) == 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
Get string with path to the current directory
|
||||
PATH_MAX may not be a compile time constant, so we must allocate and delete a buffer.
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
std::string platform::current_directory()
|
||||
{
|
||||
std::string cwd = "";
|
||||
|
||||
#if defined(_WIN32)
|
||||
char *buf = new char[MAX_PATH];
|
||||
if (_getcwd(buf, MAX_PATH)) { cwd = buf; }
|
||||
delete[] buf;
|
||||
#else
|
||||
char *buf = new char[PATH_MAX];
|
||||
if (::getcwd(buf, PATH_MAX)) { cwd = buf; }
|
||||
delete[] buf;
|
||||
#endif
|
||||
return cwd;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
check if a path is a directory
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
bool platform::path_is_directory(const std::string &path)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
struct _stat info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
if (_stat(path.c_str(), &info) != 0) return false;
|
||||
#else
|
||||
struct stat info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
if (stat(path.c_str(), &info) != 0) return false;
|
||||
#endif
|
||||
return ((info.st_mode & S_IFDIR) != 0);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
get directory listing in string vector
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
std::vector<std::string> platform::list_directory(const std::string &dir)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
if (!path_is_directory(dir)) return files;
|
||||
|
||||
#if defined(_WIN32)
|
||||
HANDLE handle;
|
||||
WIN32_FIND_DATA fd;
|
||||
std::string searchname = dir + filepathsep[0] + "*";
|
||||
handle = FindFirstFile(searchname.c_str(), &fd);
|
||||
if (handle == ((HANDLE) -1)) return files;
|
||||
while (FindNextFile(handle, &fd)) {
|
||||
std::string entry(fd.cFileName);
|
||||
if ((entry == "..") || (entry == ".")) continue;
|
||||
files.push_back(entry);
|
||||
}
|
||||
FindClose(handle);
|
||||
#else
|
||||
std::string dirname = dir + filepathsep[0];
|
||||
DIR *handle = opendir(dirname.c_str());
|
||||
if (handle == nullptr) return files;
|
||||
struct dirent *fd;
|
||||
while ((fd = readdir(handle)) != nullptr) {
|
||||
std::string entry(fd->d_name);
|
||||
if ((entry == "..") || (entry == ".")) continue;
|
||||
files.push_back(entry);
|
||||
}
|
||||
closedir(handle);
|
||||
#endif
|
||||
return files;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
Change current directory
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int platform::chdir(const std::string &path)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return ::_chdir(path.c_str());
|
||||
#else
|
||||
return ::chdir(path.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
Create a directory
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int platform::mkdir(const std::string &path)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return ::_mkdir(path.c_str());
|
||||
#else
|
||||
return ::mkdir(path.c_str(), S_IRWXU | S_IRGRP | S_IXGRP);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
Delete a directory and its contents recursively
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int platform::rmdir(const std::string &path)
|
||||
{
|
||||
// recurse through directory tree deleting files and directories
|
||||
auto entries = list_directory(path);
|
||||
for (const auto &entry : entries) {
|
||||
const auto newpath = path_join(path, entry);
|
||||
if (path_is_directory(newpath))
|
||||
rmdir(newpath);
|
||||
else
|
||||
unlink(newpath);
|
||||
}
|
||||
#if defined(_WIN32)
|
||||
return ::_rmdir(path.c_str());
|
||||
#else
|
||||
return ::rmdir(path.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
Delete a file
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int platform::unlink(const std::string &path)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return ::_unlink(path.c_str());
|
||||
#else
|
||||
return ::unlink(path.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
Get current file stream position
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
bigint platform::ftell(FILE *fp)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return (bigint)::_ftelli64(fp);
|
||||
#else
|
||||
return (bigint)::ftell(fp);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
Set current file stream position
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int platform::fseek(FILE *fp, bigint pos)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return ::_fseeki64(fp, (__int64) pos, SEEK_SET);
|
||||
#else
|
||||
return ::fseek(fp, (long) pos, SEEK_SET);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
Truncate opened file to given length
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int platform::ftruncate(FILE *fp, bigint length)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
HANDLE h = (HANDLE) _get_osfhandle(_fileno(fp));
|
||||
LARGE_INTEGER li_start, li_length;
|
||||
li_start.QuadPart = (int64_t) 0;
|
||||
li_length.QuadPart = (int64_t) length;
|
||||
if (SetFilePointerEx(h, li_start, NULL, FILE_CURRENT) &&
|
||||
SetFilePointerEx(h, li_length, NULL, FILE_BEGIN) && SetEndOfFile(h)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
platform::fseek(fp, length);
|
||||
return ::ftruncate(fileno(fp), (off_t) length);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
open pipe
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
FILE *platform::popen(const std::string &cmd, const std::string &mode)
|
||||
{
|
||||
FILE *fp = nullptr;
|
||||
#if defined(_WIN32)
|
||||
if (mode == "r")
|
||||
fp = ::_popen(cmd.c_str(), "rb");
|
||||
else if (mode == "w")
|
||||
fp = ::_popen(cmd.c_str(), "wb");
|
||||
#else
|
||||
if (mode == "r")
|
||||
fp = ::popen(cmd.c_str(), "r");
|
||||
else if (mode == "w")
|
||||
fp = ::popen(cmd.c_str(), "w");
|
||||
#endif
|
||||
return fp;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
close pipe
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int platform::pclose(FILE *fp)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return ::_pclose(fp);
|
||||
#else
|
||||
return ::pclose(fp);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
strip off leading part of path, return just the filename
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
std::string platform::path_basename(const std::string &path)
|
||||
{
|
||||
size_t start = path.find_last_of(platform::filepathsep);
|
||||
|
||||
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 platform::path_dirname(const std::string &path)
|
||||
{
|
||||
size_t start = path.find_last_of(platform::filepathsep);
|
||||
|
||||
if (start == std::string::npos) return ".";
|
||||
|
||||
return path.substr(0, start);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
join two paths.
|
||||
if one of the two is an empty string just return the other unmodified
|
||||
if the first string ends in the separator or the second begins with one, trim them
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
std::string platform::path_join(const std::string &a, const std::string &b)
|
||||
{
|
||||
if (a.empty()) return b;
|
||||
if (b.empty()) return a;
|
||||
|
||||
// remove trailing separator(s) in first part
|
||||
std::string joined = a;
|
||||
while (joined.find_last_of(platform::filepathsep) == joined.size() - 1) {
|
||||
for (const auto &s : platform::filepathsep)
|
||||
if (joined.back() == s) joined.pop_back();
|
||||
}
|
||||
|
||||
// skip over leading separator(s) in second part
|
||||
std::size_t skip = 0;
|
||||
while (b.find_first_of(platform::filepathsep, skip) == skip) ++skip;
|
||||
|
||||
// combine and return
|
||||
joined += platform::filepathsep[0] + b.substr(skip);
|
||||
return joined;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
try to open file for reading to prove if it exists and is accessible
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
bool platform::file_is_readable(const std::string &path)
|
||||
{
|
||||
FILE *fp = fopen(path.c_str(), "r");
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
check if filename has a known compression extension
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
bool platform::has_zip_extension(const std::string &file)
|
||||
{
|
||||
return find_zip_type(file).style != zip_info::NONE;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
open pipe to read a compressed file
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
FILE *platform::zip_read(const std::string &file)
|
||||
{
|
||||
FILE *fp = nullptr;
|
||||
|
||||
#if defined(LAMMPS_GZIP)
|
||||
auto zip = find_zip_type(file);
|
||||
if (zip.style == zip_info::NONE) return nullptr;
|
||||
|
||||
if (find_exe_path(zip.command).size())
|
||||
// put quotes around file name so that they may contain blanks
|
||||
fp = popen((zip.command + zip.unzipflags + "\"" + file + "\""), "r");
|
||||
#endif
|
||||
return fp;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
open pipe to write a compressed file
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
FILE *platform::zip_write(const std::string &file)
|
||||
{
|
||||
FILE *fp = nullptr;
|
||||
|
||||
#if defined(LAMMPS_GZIP)
|
||||
auto zip = find_zip_type(file);
|
||||
if (zip.style == zip_info::NONE) return nullptr;
|
||||
|
||||
if (find_exe_path(zip.command).size())
|
||||
// put quotes around file name so that they may contain blanks
|
||||
fp = popen((zip.command + zip.zipflags + "\"" + file + "\""), "w");
|
||||
#endif
|
||||
return fp;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
Reference in New Issue
Block a user