2014-05-17 23:15:15 +02:00
|
|
|
/***********************************************************************
|
|
|
|
* OSXCross Compiler Wrapper *
|
2015-02-08 10:27:26 +01:00
|
|
|
* Copyright (C) 2014, 2015 by Thomas Poechtrager *
|
2014-05-17 23:15:15 +02:00
|
|
|
* t.poechtrager@gmail.com *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or *
|
|
|
|
* modify it under the terms of the GNU General Public License *
|
|
|
|
* as published by the Free Software Foundation; either version 2 *
|
|
|
|
* of the License, or (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* This program is distributed in the hope that it will be useful, *
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
* GNU General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program; if not, write to the Free Software *
|
|
|
|
* Foundation, Inc., *
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
#include "compat.h"
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <string>
|
|
|
|
#include <sstream>
|
|
|
|
#include <istream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <iostream>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
|
|
|
#include <climits>
|
|
|
|
#include <cassert>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
2015-05-02 21:49:23 +02:00
|
|
|
#include <unistd.h>
|
2014-05-17 23:15:15 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#else
|
|
|
|
#include <windows.h>
|
|
|
|
#include <tlhelp32.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
#include <mach-o/dyld.h>
|
|
|
|
#include <CoreServices/CoreServices.h>
|
|
|
|
#include <mach/mach.h>
|
|
|
|
#include <mach/mach_time.h>
|
|
|
|
#include <libproc.h>
|
|
|
|
#endif
|
|
|
|
|
2015-07-19 22:28:10 +02:00
|
|
|
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
2014-05-17 23:15:15 +02:00
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/user.h>
|
2015-07-19 22:28:10 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
2014-05-17 23:15:15 +02:00
|
|
|
#include <libutil.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "tools.h"
|
|
|
|
|
|
|
|
namespace tools {
|
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
//
|
|
|
|
// Terminal text colors
|
|
|
|
//
|
|
|
|
|
|
|
|
bool isTerminal() {
|
|
|
|
#ifndef _WIN32
|
|
|
|
static bool first = false;
|
|
|
|
static bool val;
|
|
|
|
|
|
|
|
if (!first) {
|
|
|
|
val = !!isatty(fileno(stderr));
|
|
|
|
first = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Executable path
|
|
|
|
//
|
|
|
|
|
2014-05-17 23:15:15 +02:00
|
|
|
char *getExecutablePath(char *buf, size_t len) {
|
|
|
|
char *p;
|
|
|
|
#ifdef __APPLE__
|
|
|
|
unsigned int l = len;
|
|
|
|
if (_NSGetExecutablePath(buf, &l) != 0)
|
|
|
|
return nullptr;
|
2015-07-19 22:28:10 +02:00
|
|
|
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
2014-05-17 23:15:15 +02:00
|
|
|
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
|
|
|
|
size_t l = len;
|
|
|
|
if (sysctl(mib, 4, buf, &l, nullptr, 0) != 0)
|
|
|
|
return nullptr;
|
2015-07-19 22:28:10 +02:00
|
|
|
#elif defined(__OpenBSD__)
|
|
|
|
int mib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV};
|
|
|
|
char **argv;
|
|
|
|
size_t l;
|
|
|
|
const char *comm;
|
|
|
|
int ok = 0;
|
|
|
|
if (sysctl(mib, 4, NULL, &l, NULL, 0) < 0)
|
|
|
|
abort();
|
|
|
|
argv = new char *[l];
|
|
|
|
if (sysctl(mib, 4, argv, &l, NULL, 0) < 0)
|
|
|
|
abort();
|
|
|
|
comm = argv[0];
|
|
|
|
if (*comm == '/' || *comm == '.') {
|
2015-07-19 23:19:31 +02:00
|
|
|
char *rpath;
|
|
|
|
if ((rpath = realpath(comm, NULL))) {
|
|
|
|
strlcpy(buf, rpath, len);
|
|
|
|
free(rpath);
|
2015-07-19 22:28:10 +02:00
|
|
|
ok = 1;
|
2015-07-19 23:19:31 +02:00
|
|
|
}
|
2015-07-19 22:28:10 +02:00
|
|
|
} else {
|
|
|
|
char *sp;
|
|
|
|
char *xpath = strdup(getenv("PATH"));
|
|
|
|
char *path = strtok_r(xpath, ":", &sp);
|
|
|
|
struct stat st;
|
|
|
|
if (!xpath)
|
|
|
|
abort();
|
|
|
|
while (path) {
|
|
|
|
snprintf(buf, len, "%s/%s", path, comm);
|
|
|
|
if (!stat(buf, &st) && (st.st_mode & S_IXUSR)) {
|
|
|
|
ok = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
path = strtok_r(NULL, ":", &sp);
|
|
|
|
}
|
|
|
|
free(xpath);
|
|
|
|
}
|
|
|
|
if (ok)
|
|
|
|
l = strlen(buf);
|
|
|
|
else
|
|
|
|
l = 0;
|
|
|
|
delete[] argv;
|
2014-05-17 23:15:15 +02:00
|
|
|
#elif defined(_WIN32)
|
|
|
|
size_t l = GetModuleFileName(nullptr, buf, (DWORD)len);
|
|
|
|
#else
|
|
|
|
ssize_t l = readlink("/proc/self/exe", buf, len);
|
2015-07-19 22:28:10 +02:00
|
|
|
assert(l > 0 && "/proc not mounted?");
|
2014-05-17 23:15:15 +02:00
|
|
|
#endif
|
|
|
|
if (l <= 0)
|
|
|
|
return nullptr;
|
|
|
|
buf[len - 1] = '\0';
|
2014-09-27 10:07:15 +02:00
|
|
|
p = strrchr(buf, PATHDIV);
|
2015-07-19 22:28:10 +02:00
|
|
|
if (p)
|
2014-05-17 23:15:15 +02:00
|
|
|
*p = '\0';
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::string &getParentProcessName() {
|
|
|
|
static std::string name;
|
|
|
|
#ifdef _WIN32
|
|
|
|
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
|
|
|
PROCESSENTRY32 pe;
|
|
|
|
|
|
|
|
auto zerope = [&]() {
|
|
|
|
memset(&pe, 0, sizeof(pe));
|
|
|
|
pe.dwSize = sizeof(PROCESSENTRY32);
|
|
|
|
};
|
|
|
|
|
|
|
|
zerope();
|
|
|
|
|
|
|
|
auto pid = GetCurrentProcessId();
|
|
|
|
decltype(pid) ppid = -1;
|
|
|
|
|
|
|
|
if (Process32First(h, &pe)) {
|
|
|
|
do {
|
|
|
|
if (pe.th32ProcessID == pid) {
|
|
|
|
ppid = pe.th32ParentProcessID;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (Process32Next(h, &pe));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppid != static_cast<decltype(ppid)>(-1)) {
|
|
|
|
PROCESSENTRY32 *ppe = nullptr;
|
|
|
|
zerope();
|
|
|
|
|
|
|
|
if (Process32First(h, &pe)) {
|
|
|
|
do {
|
|
|
|
if (pe.th32ProcessID == ppid) {
|
|
|
|
ppe = &pe;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (Process32Next(h, &pe));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppe) {
|
|
|
|
char *p = strrchr(ppe->szExeFile, '\\');
|
|
|
|
if (p) {
|
|
|
|
name = p + 1;
|
|
|
|
} else {
|
|
|
|
name = ppe->szExeFile;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CloseHandle(h);
|
|
|
|
|
|
|
|
if (!name.empty()) {
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
auto getName = [](const char * path)->const char * {
|
|
|
|
if (const char *p = strrchr(path, '/')) {
|
|
|
|
return p + 1;
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
};
|
|
|
|
auto ppid = getppid();
|
|
|
|
#ifdef __APPLE__
|
|
|
|
char path[PROC_PIDPATHINFO_MAXSIZE];
|
|
|
|
if (proc_pidpath(ppid, path, sizeof(path))) {
|
|
|
|
name = getName(path);
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
#elif defined(__FreeBSD__)
|
|
|
|
struct kinfo_proc *proc = kinfo_getproc(ppid);
|
|
|
|
if (proc) {
|
|
|
|
name = getName(proc->ki_comm);
|
|
|
|
free(proc);
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
std::stringstream file;
|
|
|
|
file << "/proc/" << ppid << "/comm";
|
|
|
|
if (getFileContent(file.str(), name)) {
|
|
|
|
if (!name.empty() && name.rbegin()[0] == '\n') {
|
|
|
|
name.resize(name.size() - 1);
|
|
|
|
}
|
|
|
|
return name;
|
|
|
|
} else {
|
2014-06-20 14:16:57 +02:00
|
|
|
clear(file);
|
2014-05-17 23:15:15 +02:00
|
|
|
file << "/proc/" << ppid << "/exe";
|
|
|
|
char buf[PATH_MAX + 1];
|
|
|
|
if (readlink(file.str().c_str(), buf, sizeof(buf)) > 0) {
|
|
|
|
buf[PATH_MAX] = '\0';
|
|
|
|
name = getName(buf);
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
name = "unknown";
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
std::string &fixPathDiv(std::string &path) {
|
|
|
|
for (auto &c : path) {
|
|
|
|
if (c == '/')
|
|
|
|
c = '\\';
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
|
|
// Environment
|
|
|
|
//
|
|
|
|
|
2014-12-24 10:52:24 +01:00
|
|
|
void concatEnvVariable(const char *var, const std::string &val) {
|
2014-05-17 23:15:15 +02:00
|
|
|
std::string nval = val;
|
|
|
|
if (char *oldval = getenv(var)) {
|
|
|
|
nval += ":";
|
|
|
|
nval += oldval;
|
|
|
|
}
|
|
|
|
setenv(var, nval.c_str(), 1);
|
|
|
|
}
|
|
|
|
|
2015-07-19 22:28:10 +02:00
|
|
|
std::string &escapePath(const std::string &path, std::string &escapedpath) {
|
|
|
|
for (const char *p = path.c_str(); *p; ++p) {
|
|
|
|
switch (*p) {
|
|
|
|
case '"':
|
|
|
|
case '\'':
|
|
|
|
case '\\':
|
|
|
|
case '$':
|
|
|
|
case '(':
|
|
|
|
case ')':
|
|
|
|
case ' ':
|
|
|
|
case ';':
|
|
|
|
case ':':
|
|
|
|
escapedpath += '\\';
|
|
|
|
}
|
|
|
|
escapedpath += *p;
|
|
|
|
}
|
|
|
|
return escapedpath;
|
|
|
|
}
|
|
|
|
|
|
|
|
void splitPath(const char *path, std::vector<std::string> &result) {
|
|
|
|
char *sp;
|
|
|
|
char *xpath = strdup(path);
|
|
|
|
char *p = strtok_r(xpath, ":", &sp);
|
|
|
|
if (!xpath)
|
|
|
|
abort();
|
|
|
|
while (p) {
|
|
|
|
result.push_back(p);
|
|
|
|
p = strtok_r(NULL, ":", &sp);
|
|
|
|
}
|
|
|
|
free(xpath);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string joinPath(const std::vector<std::string> &path) {
|
|
|
|
std::string tmp;
|
|
|
|
std::string escaped;
|
|
|
|
for (size_t i = 0; i < path.size(); ++i) {
|
|
|
|
escaped.clear();
|
|
|
|
tmp += escapePath(path[i], escaped);
|
|
|
|
if (i != path.size() - 1)
|
|
|
|
tmp += ":";
|
|
|
|
}
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool hasPath(const std::vector<std::string> &path, const char *find) {
|
|
|
|
for (const std::string &p : path)
|
|
|
|
if (p == find)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-05-17 23:15:15 +02:00
|
|
|
//
|
|
|
|
// Files and Directories
|
|
|
|
//
|
|
|
|
|
|
|
|
std::string *getFileContent(const std::string &file, std::string &content) {
|
|
|
|
std::ifstream f(file.c_str());
|
|
|
|
|
|
|
|
if (!f.is_open())
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
f.seekg(0, std::ios::end);
|
|
|
|
auto len = f.tellg();
|
|
|
|
f.seekg(0, std::ios::beg);
|
|
|
|
|
|
|
|
if (len != static_cast<decltype(len)>(-1))
|
|
|
|
content.reserve(static_cast<size_t>(f.tellg()));
|
|
|
|
|
|
|
|
content.assign(std::istreambuf_iterator<char>(f),
|
|
|
|
std::istreambuf_iterator<char>());
|
|
|
|
|
|
|
|
return &content;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool writeFileContent(const std::string &file, const std::string &content) {
|
|
|
|
std::ofstream f(file.c_str());
|
|
|
|
|
|
|
|
if (!f.is_open())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
f << content;
|
|
|
|
return f.good();
|
|
|
|
}
|
|
|
|
|
2015-08-22 23:15:27 +02:00
|
|
|
bool fileExists(const std::string &file) {
|
2014-05-17 23:15:15 +02:00
|
|
|
struct stat st;
|
2015-08-22 23:15:27 +02:00
|
|
|
return !stat(file.c_str(), &st);
|
2014-05-17 23:15:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool dirExists(const std::string &dir) {
|
|
|
|
struct stat st;
|
|
|
|
return !stat(dir.c_str(), &st) && S_ISDIR(st.st_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef bool (*listfilescallback)(const char *file);
|
|
|
|
|
|
|
|
bool isDirectory(const char *file, const char *prefix) {
|
|
|
|
struct stat st;
|
|
|
|
if (prefix) {
|
|
|
|
std::string tmp = prefix;
|
|
|
|
tmp += "/";
|
|
|
|
tmp += file;
|
|
|
|
return !stat(tmp.c_str(), &st) && S_ISDIR(st.st_mode);
|
|
|
|
} else {
|
|
|
|
return !stat(file, &st) && S_ISDIR(st.st_mode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool listFiles(const char *dir, std::vector<std::string> *files,
|
|
|
|
listfilescallback cmp) {
|
|
|
|
#ifndef _WIN32
|
|
|
|
DIR *d = opendir(dir);
|
|
|
|
dirent *de;
|
|
|
|
|
|
|
|
if (!d)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
while ((de = readdir(d))) {
|
|
|
|
if ((!cmp || cmp(de->d_name)) && files) {
|
|
|
|
files->push_back(de->d_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
closedir(d);
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
WIN32_FIND_DATA fdata;
|
|
|
|
HANDLE handle;
|
|
|
|
|
|
|
|
handle = FindFirstFile(dir, &fdata);
|
|
|
|
|
|
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
do {
|
|
|
|
if ((!cmp || cmp(fdata.cFileName)) && files) {
|
|
|
|
files->push_back(fdata.cFileName);
|
|
|
|
}
|
|
|
|
} while (FindNextFile(handle, &fdata));
|
|
|
|
|
|
|
|
FindClose(handle);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef bool (*realpathcmp)(const char *file, const struct stat &st);
|
|
|
|
|
|
|
|
bool isExecutable(const char *f, const struct stat &) {
|
|
|
|
return !access(f, F_OK | X_OK);
|
|
|
|
}
|
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
bool ignoreCCACHE(const char *f, const struct stat &) {
|
|
|
|
const char *name = getFileName(f);
|
|
|
|
return name && strstr(name, "ccache") != name;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool realPath(const char *file, std::string &result,
|
|
|
|
realpathcmp cmp1, realpathcmp cmp2) {
|
2014-05-17 23:15:15 +02:00
|
|
|
char *PATH = getenv("PATH");
|
|
|
|
const char *p = PATH ? PATH : "";
|
|
|
|
struct stat st;
|
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
result.clear();
|
|
|
|
|
2014-05-17 23:15:15 +02:00
|
|
|
do {
|
|
|
|
if (*p == ':')
|
|
|
|
++p;
|
|
|
|
|
|
|
|
while (*p && *p != ':')
|
2015-05-30 21:04:51 +02:00
|
|
|
result += *p++;
|
2014-05-17 23:15:15 +02:00
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
result += "/";
|
|
|
|
result += file;
|
2014-05-17 23:15:15 +02:00
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
if (!stat(result.c_str(), &st)) {
|
2014-05-17 23:15:15 +02:00
|
|
|
#ifndef _WIN32
|
2015-05-30 21:04:51 +02:00
|
|
|
char buf[PATH_MAX + 1];
|
2014-05-17 23:15:15 +02:00
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
if (realpath(result.c_str(), buf)) {
|
|
|
|
result.assign(buf);
|
|
|
|
} else {
|
|
|
|
ssize_t len;
|
|
|
|
char path[PATH_MAX];
|
|
|
|
size_t pathlen;
|
|
|
|
size_t n = 0;
|
|
|
|
|
|
|
|
pathlen = result.find_last_of(PATHDIV);
|
|
|
|
|
|
|
|
if (pathlen == std::string::npos)
|
|
|
|
pathlen = result.length();
|
|
|
|
else
|
|
|
|
++pathlen; // PATHDIV
|
|
|
|
|
|
|
|
memcpy(path, result.c_str(), pathlen); // not null terminated
|
|
|
|
|
|
|
|
while ((len = readlink(result.c_str(), buf, PATH_MAX)) != -1) {
|
|
|
|
if (buf[0] != PATHDIV) {
|
|
|
|
result.assign(path, pathlen);
|
|
|
|
result.append(buf, len);
|
|
|
|
} else {
|
|
|
|
result.assign(buf, len);
|
|
|
|
pathlen = strrchr(buf, PATHDIV) - buf + 1; // + 1: PATHDIV
|
|
|
|
memcpy(path, buf, pathlen);
|
|
|
|
}
|
|
|
|
if (++n >= 1000) {
|
|
|
|
err << result << ": too many levels of symbolic links"
|
|
|
|
<< err.endl();
|
|
|
|
result.clear();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-05-17 23:15:15 +02:00
|
|
|
#endif
|
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
if ((!cmp1 || cmp1(result.c_str(), st)) &&
|
|
|
|
(!cmp2 || cmp2(result.c_str(), st)))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
result.clear();
|
|
|
|
} while (*p);
|
2014-05-17 23:15:15 +02:00
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
return !result.empty();
|
|
|
|
}
|
2014-05-17 23:15:15 +02:00
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
bool getPathOfCommand(const char *command, std::string &result,
|
|
|
|
realpathcmp cmp) {
|
|
|
|
if (realPath(command, result, isExecutable, cmp))
|
|
|
|
stripFileName(result);
|
2014-05-17 23:15:15 +02:00
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
return !result.empty();
|
|
|
|
}
|
2014-05-17 23:15:15 +02:00
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
void stripFileName(std::string &path) {
|
|
|
|
size_t lastpathdiv = path.find_last_of(PATHDIV);
|
|
|
|
if (lastpathdiv != 0 && lastpathdiv != std::string::npos)
|
|
|
|
path.resize(lastpathdiv);
|
2014-05-17 23:15:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *getFileName(const char *file) {
|
2014-09-27 10:07:15 +02:00
|
|
|
const char *p = strrchr(file, PATHDIV);
|
2014-05-17 23:15:15 +02:00
|
|
|
|
|
|
|
if (!p)
|
|
|
|
p = file;
|
|
|
|
else
|
|
|
|
++p;
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *getFileExtension(const char *file) {
|
|
|
|
const char *p = strrchr(file, '.');
|
|
|
|
|
|
|
|
if (!p)
|
|
|
|
p = "";
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Time
|
|
|
|
//
|
|
|
|
|
|
|
|
time_type getNanoSeconds() {
|
|
|
|
#ifdef __APPLE__
|
|
|
|
union {
|
|
|
|
AbsoluteTime at;
|
|
|
|
time_type ull;
|
|
|
|
} tmp;
|
|
|
|
tmp.ull = mach_absolute_time();
|
|
|
|
Nanoseconds ns = AbsoluteToNanoseconds(tmp.at);
|
|
|
|
tmp.ull = UnsignedWideToUInt64(ns);
|
|
|
|
return tmp.ull;
|
|
|
|
#elif defined(__linux__)
|
|
|
|
struct timespec tp;
|
|
|
|
if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
|
|
|
|
return static_cast<time_type>((tp.tv_sec * 1000000000LL) + tp.tv_nsec);
|
|
|
|
#endif
|
|
|
|
struct timeval tv;
|
|
|
|
if (gettimeofday(&tv, nullptr) == 0)
|
|
|
|
return static_cast<time_type>((tv.tv_sec * 1000000000LL) +
|
|
|
|
(tv.tv_usec * 1000));
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// OSVersion
|
|
|
|
//
|
|
|
|
|
|
|
|
OSVersion parseOSVersion(const char *OSVer) {
|
|
|
|
const char *p = OSVer;
|
|
|
|
OSVersion OSNum;
|
|
|
|
|
|
|
|
OSNum.major = atoi(p);
|
|
|
|
|
|
|
|
while (*p && *p++ != '.')
|
|
|
|
;
|
|
|
|
if (!*p)
|
|
|
|
return OSNum;
|
|
|
|
|
|
|
|
OSNum.minor = atoi(p);
|
|
|
|
|
|
|
|
while (*p && *p++ != '.')
|
|
|
|
;
|
|
|
|
if (!*p)
|
|
|
|
return OSNum;
|
|
|
|
|
|
|
|
OSNum.patch = atoi(p);
|
|
|
|
return OSNum;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// OS Compat
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
int setenv(const char *name, const char *value, int overwrite) {
|
|
|
|
std::string buf;
|
|
|
|
(void)overwrite; // TODO
|
|
|
|
|
|
|
|
buf = name;
|
|
|
|
buf += '=';
|
|
|
|
buf += value;
|
|
|
|
|
|
|
|
return putenv(buf.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
int unsetenv(const char *name) { return setenv(name, "", 1); }
|
|
|
|
#endif
|
|
|
|
|
|
|
|
} // namespace tools
|