icinga2/lib/base/utility.cpp
Michael Friedrich 1eb77b0cd7 Replace recursive implementation with a forward loop in Utility::MkDirP()
That way we always move into the tree, but not start in the deepest
level and may limit the tree level too in the future, if required.

Solves the Win32 implementation by moving the general mkdir() call into
Utility::MkDir().

refs #6328
2014-06-13 09:10:35 +02:00

1135 lines
26 KiB
C++

/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* 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 St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "base/utility.hpp"
#include "base/convert.hpp"
#include "base/application.hpp"
#include "base/logger_fwd.hpp"
#include "base/exception.hpp"
#include "base/socket.hpp"
#include "base/utility.hpp"
#include <mmatch.h>
#include <boost/lexical_cast.hpp>
#include <boost/foreach.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/trim.hpp>
#ifdef __FreeBSD__
# include <pthread_np.h>
#endif /* __FreeBSD__ */
#ifndef _MSC_VER
# include <cxxabi.h>
#endif /* _MSC_VER */
using namespace icinga;
boost::thread_specific_ptr<String> Utility::m_ThreadName;
boost::thread_specific_ptr<unsigned int> Utility::m_RandSeed;
boost::thread_specific_ptr<bool> Utility::m_LoadingLibrary;
boost::thread_specific_ptr<std::vector<boost::function<void(void)> > > Utility::m_DeferredInitializers;
/**
* Demangles a symbol name.
*
* @param sym The symbol name.
* @returns A human-readable version of the symbol name.
*/
String Utility::DemangleSymbolName(const String& sym)
{
String result = sym;
#ifndef _MSC_VER
int status;
char *realname = abi::__cxa_demangle(sym.CStr(), 0, 0, &status);
if (realname != NULL) {
result = String(realname);
free(realname);
}
#else /* _MSC_VER */
CHAR output[256];
if (UnDecorateSymbolName(sym.CStr(), output, sizeof(output), UNDNAME_COMPLETE) > 0)
result = output;
#endif /* _MSC_VER */
return result;
}
/**
* Returns a human-readable type name of a type_info object.
*
* @param ti A type_info object.
* @returns The type name of the object.
*/
String Utility::GetTypeName(const std::type_info& ti)
{
return DemangleSymbolName(ti.name());
}
/**
* Looks up source file name and line number information for the specified
* ELF executable and RVA.
*
* @param exe The ELF file.
* @param rva The RVA.
* @returns Source file and line number.
*/
String Utility::Addr2Line(const String& exe, uintptr_t rva)
{
#ifndef _WIN32
std::ostringstream msgbuf;
msgbuf << "addr2line -s -e " << Application::GetExePath(exe) << " " << std::hex << rva << " 2>/dev/null";
String args = msgbuf.str();
FILE *fp = popen(args.CStr(), "r");
if (!fp)
return "RVA: " + Convert::ToString(rva);
char buffer[512] = {};
fgets(buffer, sizeof(buffer), fp);
fclose(fp);
String line = buffer;
boost::algorithm::trim_right(line);
if (line.GetLength() == 0)
return "RVA: " + Convert::ToString(rva);
return line;
#else /* _WIN32 */
return String();
#endif /* _WIN32 */
}
String Utility::GetSymbolName(const void *addr)
{
#ifdef HAVE_DLADDR
Dl_info dli;
if (dladdr(addr, &dli) > 0)
return dli.dli_sname;
#endif /* HAVE_DLADDR */
#ifdef _WIN32
char buffer[sizeof(SYMBOL_INFO)+MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
DWORD64 dwAddress = (DWORD64)addr;
DWORD64 dwDisplacement;
IMAGEHLP_LINE64 line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (SymFromAddr(GetCurrentProcess(), dwAddress, &dwDisplacement, pSymbol)) {
char output[256];
if (UnDecorateSymbolName(pSymbol->Name, output, sizeof(output), UNDNAME_COMPLETE))
return String(output) + "+" + Convert::ToString(dwDisplacement);
else
return String(pSymbol->Name) + "+" + Convert::ToString(dwDisplacement);
}
#endif /* _WIN32 */
return "(unknown function)";
}
String Utility::GetSymbolSource(const void *addr)
{
#ifdef HAVE_DLADDR
Dl_info dli;
if (dladdr(addr, &dli) > 0) {
uintptr_t rva = reinterpret_cast<uintptr_t>(addr) - reinterpret_cast<uintptr_t>(dli.dli_fbase);
return Addr2Line(dli.dli_fname, rva);
}
#endif /* HAVE_DLADDR */
#ifdef _WIN32
char buffer[sizeof(SYMBOL_INFO)+MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
DWORD64 dwAddress = (DWORD64)addr;
DWORD dwDisplacement;
IMAGEHLP_LINE64 line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (SymGetLineFromAddr64(GetCurrentProcess(), dwAddress, &dwDisplacement, &line))
return String(line.FileName) + ":" + Convert::ToString(line.LineNumber);
#endif /* _WIN32 */
return "(unknown file/line)";
}
/**
* Performs wildcard pattern matching.
*
* @param pattern The wildcard pattern.
* @param text The String that should be checked.
* @returns true if the wildcard pattern matches, false otherwise.
*/
bool Utility::Match(const String& pattern, const String& text)
{
return (match(pattern.CStr(), text.CStr()) == 0);
}
/**
* Returns the directory component of a path. See dirname(3) for details.
*
* @param path The full path.
* @returns The directory.
*/
String Utility::DirName(const String& path)
{
char *dir;
#ifdef _WIN32
String dupPath = path;
/* PathRemoveFileSpec doesn't properly handle forward slashes. */
BOOST_FOREACH(char& ch, dupPath) {
if (ch == '/')
ch = '\\';
}
dir = strdup(dupPath.CStr());
#else /* _WIN32 */
dir = strdup(path.CStr());
#endif /* _WIN32 */
if (dir == NULL)
BOOST_THROW_EXCEPTION(std::bad_alloc());
String result;
#ifndef _WIN32
result = dirname(dir);
#else /* _WIN32 */
if (!PathRemoveFileSpec(dir)) {
free(dir);
BOOST_THROW_EXCEPTION(win32_error()
<< boost::errinfo_api_function("PathRemoveFileSpec")
<< errinfo_win32_error(GetLastError()));
}
result = dir;
if (result.IsEmpty())
result = ".";
#endif /* _WIN32 */
free(dir);
return result;
}
/**
* Returns the file component of a path. See basename(3) for details.
*
* @param path The full path.
* @returns The filename.
*/
String Utility::BaseName(const String& path)
{
char *dir = strdup(path.CStr());
String result;
if (dir == NULL)
BOOST_THROW_EXCEPTION(std::bad_alloc());
#ifndef _WIN32
result = basename(dir);
#else /* _WIN32 */
result = PathFindFileName(dir);
#endif /* _WIN32 */
free(dir);
return result;
}
/**
* Null deleter. Used as a parameter for the shared_ptr constructor.
*
* @param - The object that should be deleted.
*/
void Utility::NullDeleter(void *)
{
/* Nothing to do here. */
}
/**
* Returns the current UNIX timestamp including fractions of seconds.
*
* @returns The current time.
*/
double Utility::GetTime(void)
{
#ifdef _WIN32
FILETIME cft;
GetSystemTimeAsFileTime(&cft);
ULARGE_INTEGER ucft;
ucft.HighPart = cft.dwHighDateTime;
ucft.LowPart = cft.dwLowDateTime;
SYSTEMTIME est = { 1970, 1, 4, 1, 0, 0, 0, 0};
FILETIME eft;
SystemTimeToFileTime(&est, &eft);
ULARGE_INTEGER ueft;
ueft.HighPart = eft.dwHighDateTime;
ueft.LowPart = eft.dwLowDateTime;
return ((ucft.QuadPart - ueft.QuadPart) / 10000) / 1000.0;
#else /* _WIN32 */
struct timeval tv;
if (gettimeofday(&tv, NULL) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("gettimeofday")
<< boost::errinfo_errno(errno));
}
return tv.tv_sec + tv.tv_usec / 1000000.0;
#endif /* _WIN32 */
}
/**
* Returns the ID of the current process.
*
* @returns The PID.
*/
pid_t Utility::GetPid(void)
{
#ifndef _WIN32
return getpid();
#else /* _WIN32 */
return GetCurrentProcessId();
#endif /* _WIN32 */
}
/**
* Sleeps for the specified amount of time.
*
* @param timeout The timeout in seconds.
*/
void Utility::Sleep(double timeout)
{
#ifndef _WIN32
usleep(timeout * 1000 * 1000);
#else /* _WIN32 */
::Sleep(timeout * 1000);
#endif /* _WIN32 */
}
/**
* Loads the specified library.
*
* @param library The name of the library.
*/
#ifdef _WIN32
HMODULE
#else /* _WIN32 */
void *
#endif /* _WIN32 */
Utility::LoadExtensionLibrary(const String& library)
{
String path;
#if defined(_WIN32)
path = library + ".dll";
#elif defined(__APPLE__)
path = "lib" + library + ".dylib";
#else /* __APPLE__ */
path = "lib" + library + ".so";
#endif /* _WIN32 */
Log(LogInformation, "Utility", "Loading library '" + path + "'");
#ifdef _WIN32
HMODULE hModule = LoadLibrary(path.CStr());
if (hModule == NULL) {
BOOST_THROW_EXCEPTION(win32_error()
<< boost::errinfo_api_function("LoadLibrary")
<< errinfo_win32_error(GetLastError())
<< boost::errinfo_file_name(path));
}
#else /* _WIN32 */
void *hModule = dlopen(path.CStr(), RTLD_NOW);
if (hModule == NULL) {
BOOST_THROW_EXCEPTION(std::runtime_error("Could not load library '" + path + "': " + dlerror()));
}
#endif /* _WIN32 */
ExecuteDeferredInitializers();
return hModule;
}
void Utility::ExecuteDeferredInitializers(void)
{
if (!m_DeferredInitializers.get())
return;
BOOST_FOREACH(const boost::function<void(void)>& callback, *m_DeferredInitializers.get())
callback();
m_DeferredInitializers.reset();
}
void Utility::AddDeferredInitializer(const boost::function<void(void)>& callback)
{
if (!m_DeferredInitializers.get())
m_DeferredInitializers.reset(new std::vector<boost::function<void(void)> >());
m_DeferredInitializers.get()->push_back(callback);
}
/**
* Generates a new unique ID.
*
* @returns The new unique ID.
*/
String Utility::NewUniqueID(void)
{
static boost::mutex mutex;
static int next_id = 0;
/* I'd much rather use UUIDs but RHEL is way too cool to have
* a semi-recent version of boost. Yay. */
String id;
char buf[128];
if (gethostname(buf, sizeof(buf)) == 0)
id = String(buf) + "-";
id += Convert::ToString((long)Utility::GetTime()) + "-";
{
boost::mutex::scoped_lock lock(mutex);
id += Convert::ToString(next_id);
next_id++;
}
return id;
}
/**
* Calls the specified callback for each file matching the path specification.
*
* @param pathSpec The path specification.
* @param callback The callback which is invoked for each matching file.
* @param type The file type (a combination of GlobFile and GlobDirectory)
*/
bool Utility::Glob(const String& pathSpec, const boost::function<void (const String&)>& callback, int type)
{
std::vector<String> files, dirs;
#ifdef _WIN32
HANDLE handle;
WIN32_FIND_DATA wfd;
handle = FindFirstFile(pathSpec.CStr(), &wfd);
if (handle == INVALID_HANDLE_VALUE) {
DWORD errorCode = GetLastError();
if (errorCode == ERROR_FILE_NOT_FOUND)
return false;
BOOST_THROW_EXCEPTION(win32_error()
<< boost::errinfo_api_function("FindFirstFile")
<< errinfo_win32_error(errorCode)
<< boost::errinfo_file_name(pathSpec));
}
do {
if (strcmp(wfd.cFileName, ".") == 0 || strcmp(wfd.cFileName, "..") == 0)
continue;
String path = DirName(pathSpec) + "/" + wfd.cFileName;
if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (type & GlobDirectory))
dirs.push_back(path);
else if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (type & GlobFile))
files.push_back(path);
} while (FindNextFile(handle, &wfd));
if (!FindClose(handle)) {
BOOST_THROW_EXCEPTION(win32_error()
<< boost::errinfo_api_function("FindClose")
<< errinfo_win32_error(GetLastError()));
}
#else /* _WIN32 */
glob_t gr;
int rc = glob(pathSpec.CStr(), GLOB_ERR | GLOB_NOSORT, NULL, &gr);
if (rc < 0) {
if (rc == GLOB_NOMATCH)
return false;
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("glob")
<< boost::errinfo_errno(errno)
<< boost::errinfo_file_name(pathSpec));
}
if (gr.gl_pathc == 0) {
globfree(&gr);
return false;
}
size_t left;
char **gp;
for (gp = gr.gl_pathv, left = gr.gl_pathc; left > 0; gp++, left--) {
struct stat statbuf;
if (stat(*gp, &statbuf) < 0)
continue;
if (!S_ISDIR(statbuf.st_mode) && !S_ISREG(statbuf.st_mode))
continue;
if (S_ISDIR(statbuf.st_mode) && (type & GlobDirectory))
dirs.push_back(*gp);
else if (!S_ISDIR(statbuf.st_mode) && (type & GlobFile))
files.push_back(*gp);
}
globfree(&gr);
#endif /* _WIN32 */
std::sort(files.begin(), files.end());
BOOST_FOREACH(const String& cpath, files) {
callback(cpath);
}
std::sort(dirs.begin(), dirs.end());
BOOST_FOREACH(const String& cpath, dirs) {
callback(cpath);
}
return true;
}
/**
* Calls the specified callback for each file in the specified directory
* or any of its child directories if the file name matches the specified
* pattern.
*
* @param path The path.
* @param pattern The pattern.
* @param callback The callback which is invoked for each matching file.
* @param type The file type (a combination of GlobFile and GlobDirectory)
*/
bool Utility::GlobRecursive(const String& path, const String& pattern, const boost::function<void (const String&)>& callback, int type)
{
std::vector<String> files, dirs, alldirs;
#ifdef _WIN32
HANDLE handle;
WIN32_FIND_DATA wfd;
String pathSpec = path + "/*";
handle = FindFirstFile(pathSpec.CStr(), &wfd);
if (handle == INVALID_HANDLE_VALUE) {
DWORD errorCode = GetLastError();
if (errorCode == ERROR_FILE_NOT_FOUND)
return false;
BOOST_THROW_EXCEPTION(win32_error()
<< boost::errinfo_api_function("FindFirstFile")
<< errinfo_win32_error(errorCode)
<< boost::errinfo_file_name(pathSpec));
}
do {
if (strcmp(wfd.cFileName, ".") == 0 || strcmp(wfd.cFileName, "..") == 0)
continue;
String cpath = path + "/" + wfd.cFileName;
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
alldirs.push_back(cpath);
if (!Utility::Match(pattern, wfd.cFileName))
continue;
if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (type & GlobFile))
files.push_back(cpath);
if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (type & GlobDirectory))
dirs.push_back(cpath);
} while (FindNextFile(handle, &wfd));
if (!FindClose(handle)) {
BOOST_THROW_EXCEPTION(win32_error()
<< boost::errinfo_api_function("FindClose")
<< errinfo_win32_error(GetLastError()));
}
#else /* _WIN32 */
DIR *dirp;
dirp = opendir(path.CStr());
if (dirp == NULL)
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("opendir")
<< boost::errinfo_errno(errno)
<< boost::errinfo_file_name(path));
while (dirp) {
dirent ent, *pent;
if (readdir_r(dirp, &ent, &pent) < 0) {
closedir(dirp);
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("readdir_r")
<< boost::errinfo_errno(errno)
<< boost::errinfo_file_name(path));
}
if (!pent)
break;
if (strcmp(ent.d_name, ".") == 0 || strcmp(ent.d_name, "..") == 0)
continue;
String cpath = path + "/" + ent.d_name;
struct stat statbuf;
if (lstat(cpath.CStr(), &statbuf) < 0)
continue;
if (S_ISDIR(statbuf.st_mode))
alldirs.push_back(cpath);
if (!Utility::Match(pattern, ent.d_name))
continue;
if (S_ISDIR(statbuf.st_mode) && (type & GlobDirectory))
dirs.push_back(cpath);
if (!S_ISDIR(statbuf.st_mode) && (type & GlobFile))
files.push_back(cpath);
}
closedir(dirp);
#endif /* _WIN32 */
std::sort(files.begin(), files.end());
BOOST_FOREACH(const String& cpath, files) {
callback(cpath);
}
std::sort(dirs.begin(), dirs.end());
BOOST_FOREACH(const String& cpath, dirs) {
callback(cpath);
}
std::sort(alldirs.begin(), alldirs.end());
BOOST_FOREACH(const String& cpath, alldirs) {
GlobRecursive(cpath, pattern, callback, type);
}
return true;
}
bool Utility::MkDir(const String& path, int flags)
{
#ifndef _WIN32
if (mkdir(path.CStr(), flags) < 0 && errno != EEXIST) {
#else /*_ WIN32 */
if (mkdir(path.CStr()) < 0 && errno != EEXIST) {
#endif /* _WIN32 */
//TODO handle missing dirs properly
return false;
}
return true;
}
bool Utility::MkDirP(const String& path, int flags)
{
size_t pos = 0;
bool ret = true;
while (ret && pos != String::NPos) {
pos = path.Find("/", pos + 1);
ret = MkDir(path.SubStr(0, pos), flags);
}
return ret;
}
#ifndef _WIN32
void Utility::SetNonBlocking(int fd)
{
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("fcntl")
<< boost::errinfo_errno(errno));
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("fcntl")
<< boost::errinfo_errno(errno));
}
}
void Utility::SetCloExec(int fd)
{
int flags = fcntl(fd, F_GETFD, 0);
if (flags < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("fcntl")
<< boost::errinfo_errno(errno));
}
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("fcntl")
<< boost::errinfo_errno(errno));
}
}
#endif /* _WIN32 */
void Utility::SetNonBlockingSocket(SOCKET s)
{
#ifndef _WIN32
SetNonBlocking(s);
#else /* _WIN32 */
unsigned long lTrue = 1;
ioctlsocket(s, FIONBIO, &lTrue);
#endif /* _WIN32 */
}
void Utility::QueueAsyncCallback(const boost::function<void (void)>& callback)
{
Application::GetTP().Post(callback);
}
String Utility::NaturalJoin(const std::vector<String>& tokens)
{
String result;
for (std::vector<String>::size_type i = 0; i < tokens.size(); i++) {
result += tokens[i];
if (tokens.size() > i + 1) {
if (i < tokens.size() - 2)
result += ", ";
else if (i == tokens.size() - 2)
result += " and ";
}
}
return result;
}
String Utility::FormatDuration(int duration)
{
std::vector<String> tokens;
String result;
if (duration >= 86400) {
int days = duration / 86400;
tokens.push_back(Convert::ToString(days) + (days != 1 ? " days" : " day"));
duration %= 86400;
}
if (duration >= 3600) {
int hours = duration / 3600;
tokens.push_back(Convert::ToString(hours) + (hours != 1 ? " hours" : " hour"));
duration %= 3600;
}
if (duration >= 60) {
int minutes = duration / 60;
tokens.push_back(Convert::ToString(minutes) + (minutes != 1 ? " minutes" : " minute"));
duration %= 60;
}
if (duration >= 1) {
int seconds = duration;
tokens.push_back(Convert::ToString(seconds) + (seconds != 1 ? " seconds" : " second"));
}
if (tokens.size() == 0) {
int milliseconds = floor(duration * 1000);
if (milliseconds >= 1)
tokens.push_back(Convert::ToString(milliseconds) + (milliseconds != 1 ? " milliseconds" : " millisecond"));
else
tokens.push_back("less than 1 millisecond");
}
return NaturalJoin(tokens);
}
String Utility::FormatDateTime(const char *format, double ts)
{
char timestamp[128];
time_t tempts = (time_t)ts; /* We don't handle sub-second timestamps here just yet. */
tm tmthen;
#ifdef _MSC_VER
tm *temp = localtime(&tempts);
if (temp == NULL) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("localtime")
<< boost::errinfo_errno(errno));
}
tmthen = *temp;
#else /* _MSC_VER */
if (localtime_r(&tempts, &tmthen) == NULL) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("localtime_r")
<< boost::errinfo_errno(errno));
}
#endif /* _MSC_VER */
strftime(timestamp, sizeof(timestamp), format, &tmthen);
return timestamp;
}
String Utility::FormatErrorNumber(int code) {
std::ostringstream msgbuf;
#ifdef _WIN32
char *message;
String result = "Unknown error.";
DWORD rc = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, (char *)&message,
0, NULL);
if (rc != 0) {
result = String(message);
LocalFree(message);
/* remove trailing new-line characters */
boost::algorithm::trim_right(result);
}
msgbuf << code << ", \"" << result << "\"";
return tmp.str();
#else
msgbuf << strerror(code);
#endif
return msgbuf.str();
}
String Utility::EscapeShellCmd(const String& s)
{
String result;
size_t prev_quote = String::NPos;
int index = -1;
BOOST_FOREACH(char ch, s) {
bool escape = false;
index++;
#ifdef _WIN32
if (ch == '%' || ch == '"' || ch == '\'')
escape = true;
#else /* _WIN32 */
if (ch == '"' || ch == '\'') {
/* Find a matching closing quotation character. */
if (prev_quote == String::NPos && (prev_quote = s.FindFirstOf(ch, index + 1)) != String::NPos)
; /* Empty statement. */
else if (prev_quote != String::NPos && s[prev_quote] == ch)
prev_quote = String::NPos;
else
escape = true;
}
#endif /* _WIN32 */
if (ch == '#' || ch == '&' || ch == ';' || ch == '`' || ch == '|' ||
ch == '*' || ch == '?' || ch == '~' || ch == '<' || ch == '>' ||
ch == '^' || ch == '(' || ch == ')' || ch == '[' || ch == ']' ||
ch == '{' || ch == '}' || ch == '$' || ch == '\\' || ch == '\x0A' ||
ch == '\xFF')
escape = true;
if (escape)
#ifdef _WIN32
result += '^';
#else /* _WIN32 */
result += '\\';
#endif /* _WIN32 */
result += ch;
}
return result;
}
String Utility::EscapeShellArg(const String& s)
{
String result;
#ifdef _WIN32
result = "\"";
#else /* _WIN32 */
result = "'";
#endif /* _WIN32 */
BOOST_FOREACH(char ch, s) {
#ifdef _WIN32
if (ch == '"' || ch == '%') {
result += ' ';
}
#else /* _WIN32 */
if (ch == '\'')
result += "'\\'";
#endif
result += ch;
}
#ifdef _WIN32
result += '"';
#else /* _WIN32 */
result += '\'';
#endif /* _WIN32 */
return result;
}
#ifdef _WIN32
static void WindowsSetThreadName(const char *name)
{
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = name;
info.dwThreadID = -1;
info.dwFlags = 0;
__try {
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info);
} __except(EXCEPTION_EXECUTE_HANDLER) {
/* Nothing to do here. */
}
}
#endif /* _WIN32 */
void Utility::SetThreadName(const String& name, bool os)
{
m_ThreadName.reset(new String(name));
if (!os)
return;
#ifdef _WIN32
WindowsSetThreadName(name.CStr());
#endif /* _WIN32 */
#ifdef HAVE_PTHREAD_SET_NAME_NP
pthread_set_name_np(pthread_self(), name.CStr());
#endif /* HAVE_PTHREAD_SET_NAME_NP */
#ifdef HAVE_PTHREAD_SETNAME_NP
# ifdef __APPLE__
pthread_setname_np(name.CStr());
# else /* __APPLE__ */
String tname = name.SubStr(0, 15);
pthread_setname_np(pthread_self(), tname.CStr());
# endif /* __APPLE__ */
#endif /* HAVE_PTHREAD_SETNAME_NP */
}
String Utility::GetThreadName(void)
{
String *name = m_ThreadName.get();
if (!name) {
std::ostringstream idbuf;
idbuf << boost::this_thread::get_id();
return idbuf.str();
}
return *name;
}
unsigned long Utility::SDBM(const String& str, size_t len)
{
unsigned long hash = 0;
size_t current = 0;
BOOST_FOREACH(char c, str) {
if (current >= len)
break;
hash = c + (hash << 6) + (hash << 16) - hash;
current++;
}
return hash;
}
int Utility::CompareVersion(const String& v1, const String& v2)
{
std::vector<String> tokensv1, tokensv2;
boost::algorithm::split(tokensv1, v1, boost::is_any_of("."));
boost::algorithm::split(tokensv2, v2, boost::is_any_of("."));
for (std::vector<String>::size_type i = 0; i < tokensv2.size() - tokensv1.size(); i++)
tokensv1.push_back("0");
for (std::vector<String>::size_type i = 0; i < tokensv1.size() - tokensv2.size(); i++)
tokensv2.push_back("0");
for (std::vector<String>::size_type i = 0; i < tokensv1.size(); i++) {
if (Convert::ToLong(tokensv2[i]) > Convert::ToLong(tokensv1[i]))
return 1;
else if (Convert::ToLong(tokensv2[i]) < Convert::ToLong(tokensv1[i]))
return -1;
}
return 0;
}
String Utility::GetHostName(void)
{
char name[255];
if (gethostname(name, sizeof(name)) < 0)
return "localhost";
return name;
}
/**
* Returns the fully-qualified domain name for the host
* we're running on.
*
* @returns The FQDN.
*/
String Utility::GetFQDN(void)
{
String hostname = GetHostName();
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_CANONNAME;
addrinfo *result;
int rc = getaddrinfo(hostname.CStr(), NULL, &hints, &result);
if (rc < 0)
result = NULL;
String canonicalName;
if (result) {
if (strcmp(result->ai_canonname, "localhost") != 0)
canonicalName = result->ai_canonname;
freeaddrinfo(result);
} else {
canonicalName = hostname;
}
return canonicalName;
}
int Utility::Random(void)
{
#ifdef _WIN32
return rand();
#else /* _WIN32 */
unsigned int *seed = m_RandSeed.get();
if (!seed) {
seed = new unsigned int(Utility::GetTime());
m_RandSeed.reset(seed);
}
return rand_r(seed);
#endif /* _WIN32 */
}
tm Utility::LocalTime(time_t ts)
{
#ifdef _MSC_VER
tm *result = localtime(&ts);
if (result == NULL) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("localtime")
<< boost::errinfo_errno(errno));
}
return *result;
#else /* _MSC_VER */
tm result;
if (localtime_r(&ts, &result) == NULL) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("localtime_r")
<< boost::errinfo_errno(errno));
}
return result;
#endif /* _MSC_VER */
}
bool Utility::PathExists(const String& path)
{
#ifndef _WIN32
struct stat statbuf;
return (lstat(path.CStr(), &statbuf) >= 0);
#else /* _WIN32 */
struct _stat statbuf;
return (_stat(path.CStr(), &statbuf) >= 0);
#endif /* _WIN32 */
}