2015-04-13 04:09:02 -05:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
2015-03-17 18:56:15 -05:00
|
|
|
/*
|
|
|
|
* This file is part of the LibreOffice project.
|
|
|
|
*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef INCLUDED_UTIL_HPP
|
|
|
|
#define INCLUDED_UTIL_HPP
|
|
|
|
|
loolwsd: include cleanup and organization
A source file (.cpp) must include its own header first.
This insures that the header is self-contained and
doesn't depend on arbitrary (and accidental) includes
before it to compile.
Furthermore, system headers should go next, followed by
C then C++ headers, then libraries (Poco, etc) and, finally,
project headers come last.
This makes sure that headers and included in the same dependency
order to avoid side-effects. For example, Poco should never rely on
anything from our project in the same way that a C header should
never rely on anything in C++, Poco, or project headers.
Also, includes ought to be sorted where possible, to improve
readability and avoid accidental duplicates (of which there
were a few).
Change-Id: I62cc1343e4a091d69195e37ed659dba20cfcb1ef
Reviewed-on: https://gerrit.libreoffice.org/25262
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-21 09:23:07 -05:00
|
|
|
#include <cassert>
|
2018-07-11 04:54:23 -05:00
|
|
|
#include <cerrno>
|
2019-09-16 06:45:38 -05:00
|
|
|
#include <cinttypes>
|
2018-02-17 16:32:41 -06:00
|
|
|
#include <cstddef>
|
2018-06-10 13:02:02 -05:00
|
|
|
#include <cstring>
|
2018-02-17 16:32:41 -06:00
|
|
|
#include <atomic>
|
2015-12-28 15:34:21 -06:00
|
|
|
#include <functional>
|
2016-01-21 08:28:05 -06:00
|
|
|
#include <memory>
|
2016-10-05 21:04:25 -05:00
|
|
|
#include <mutex>
|
2016-04-18 17:52:10 -05:00
|
|
|
#include <set>
|
loolwsd: include cleanup and organization
A source file (.cpp) must include its own header first.
This insures that the header is self-contained and
doesn't depend on arbitrary (and accidental) includes
before it to compile.
Furthermore, system headers should go next, followed by
C then C++ headers, then libraries (Poco, etc) and, finally,
project headers come last.
This makes sure that headers and included in the same dependency
order to avoid side-effects. For example, Poco should never rely on
anything from our project in the same way that a C header should
never rely on anything in C++, Poco, or project headers.
Also, includes ought to be sorted where possible, to improve
readability and avoid accidental duplicates (of which there
were a few).
Change-Id: I62cc1343e4a091d69195e37ed659dba20cfcb1ef
Reviewed-on: https://gerrit.libreoffice.org/25262
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-21 09:23:07 -05:00
|
|
|
#include <sstream>
|
|
|
|
#include <string>
|
2019-06-20 14:20:26 -05:00
|
|
|
#include <inttypes.h>
|
2017-11-29 15:56:25 -06:00
|
|
|
|
2017-11-28 21:23:45 -06:00
|
|
|
#include <memory.h>
|
2015-04-24 04:49:19 -05:00
|
|
|
|
2018-08-29 10:48:00 -05:00
|
|
|
#ifndef __linux
|
|
|
|
#include <thread>
|
|
|
|
#endif
|
|
|
|
|
2015-12-25 19:11:47 -06:00
|
|
|
#include <Poco/File.h>
|
|
|
|
#include <Poco/Path.h>
|
2016-02-16 15:25:51 -06:00
|
|
|
#include <Poco/Process.h>
|
2016-09-27 10:07:52 -05:00
|
|
|
#include <Poco/RegularExpression.h>
|
2015-04-22 03:14:11 -05:00
|
|
|
|
2015-11-24 02:19:17 -06:00
|
|
|
#define LOK_USE_UNSTABLE_API
|
|
|
|
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
|
|
|
|
|
2015-03-26 10:07:52 -05:00
|
|
|
namespace Util
|
2015-03-17 18:56:15 -05:00
|
|
|
{
|
2015-12-19 08:16:44 -06:00
|
|
|
namespace rng
|
|
|
|
{
|
2016-03-12 09:15:45 -06:00
|
|
|
void reseed();
|
|
|
|
unsigned getNext();
|
2016-11-12 15:38:13 -06:00
|
|
|
|
2017-02-17 00:15:42 -06:00
|
|
|
/// Generate an array of random characters.
|
|
|
|
std::vector<char> getBytes(const size_t length);
|
|
|
|
|
2019-05-16 15:12:20 -05:00
|
|
|
/// Generate a string of random characters.
|
|
|
|
std::string getHexString(const size_t length);
|
|
|
|
|
2019-06-21 06:34:53 -05:00
|
|
|
/// Generate a hard random string of characters.
|
|
|
|
std::string getHardRandomHexString(const size_t length);
|
|
|
|
|
2016-11-12 15:38:13 -06:00
|
|
|
/// Generates a random string suitable for
|
|
|
|
/// file/directory names.
|
|
|
|
std::string getFilename(const size_t length);
|
2015-12-19 08:16:44 -06:00
|
|
|
}
|
|
|
|
|
2018-03-14 10:46:52 -05:00
|
|
|
/// Create randomized temporary directory
|
|
|
|
std::string createRandomTmpDir();
|
|
|
|
|
2019-02-12 05:16:40 -06:00
|
|
|
#if !MOBILEAPP
|
2018-04-16 14:03:01 -05:00
|
|
|
/// Get number of threads in this process or -1 on error
|
|
|
|
int getProcessThreadCount();
|
|
|
|
|
2018-01-29 09:13:54 -06:00
|
|
|
/// Spawn a process if stdInput is non-NULL it contains a writable descriptor
|
|
|
|
/// to send data to the child.
|
|
|
|
int spawnProcess(const std::string &cmd, const std::vector<std::string> &args,
|
2019-11-12 03:50:33 -06:00
|
|
|
const std::vector<int>* fdsToKeep = nullptr, int *stdInput = nullptr);
|
|
|
|
|
2018-09-11 01:30:55 -05:00
|
|
|
#endif
|
2018-01-29 09:13:54 -06:00
|
|
|
|
2017-05-24 14:37:20 -05:00
|
|
|
/// Hex to unsigned char
|
|
|
|
bool dataFromHexString(const std::string& hexString, std::vector<unsigned char>& data);
|
2015-12-27 21:47:39 -06:00
|
|
|
/// Encode an integral ID into a string, with padding support.
|
2019-04-14 11:21:19 -05:00
|
|
|
std::string encodeId(const std::uint64_t number, const int padding = 5);
|
2016-01-09 14:46:08 -06:00
|
|
|
/// Decode an integral ID from a string.
|
2019-04-14 11:21:19 -05:00
|
|
|
std::uint64_t decodeId(const std::string& str);
|
2015-12-27 21:47:39 -06:00
|
|
|
|
2015-03-28 06:53:44 -05:00
|
|
|
bool windowingAvailable();
|
2015-04-24 04:49:47 -05:00
|
|
|
|
2019-02-12 05:16:40 -06:00
|
|
|
#if !defined(BUILDING_TESTS) && !defined(KIT_IN_PROCESS) && !MOBILEAPP
|
2016-11-17 08:00:05 -06:00
|
|
|
|
|
|
|
/// Send a message to all clients.
|
|
|
|
void alertAllUsers(const std::string& msg);
|
|
|
|
|
|
|
|
/// Send a 'error:' message with the specified cmd and kind parameters to all connected
|
|
|
|
/// clients. This function can be called either in loolwsd or loolkit processes, even if only
|
|
|
|
/// loolwsd obviously has contact with the actual clients; in loolkit it will be forwarded to
|
|
|
|
/// loolwsd for redistribution. (This function must be implemented separately in each program
|
|
|
|
/// that uses it, it is not in Util.cpp.)
|
2016-09-28 14:07:07 -05:00
|
|
|
void alertAllUsers(const std::string& cmd, const std::string& kind);
|
|
|
|
#else
|
2016-11-17 08:00:05 -06:00
|
|
|
|
|
|
|
/// No-op implementation in the test programs
|
|
|
|
inline void alertAllUsers(const std::string&)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/// No-op implementation in the test programs
|
2016-09-28 14:07:07 -05:00
|
|
|
inline void alertAllUsers(const std::string&, const std::string&)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif
|
2016-09-27 07:48:32 -05:00
|
|
|
|
2016-05-02 18:17:46 -05:00
|
|
|
/// Assert that a lock is already taken.
|
|
|
|
template <typename T>
|
2016-10-05 21:04:25 -05:00
|
|
|
void assertIsLocked(const T& lock)
|
2016-05-02 18:17:46 -05:00
|
|
|
{
|
2017-04-05 04:57:28 -05:00
|
|
|
#ifdef NDEBUG
|
|
|
|
(void) lock;
|
|
|
|
#else
|
2016-10-05 21:04:25 -05:00
|
|
|
assert(lock.owns_lock());
|
2017-04-05 04:57:28 -05:00
|
|
|
#endif
|
2016-10-05 21:04:25 -05:00
|
|
|
}
|
|
|
|
|
2016-10-29 20:15:00 -05:00
|
|
|
inline void assertIsLocked(std::mutex& mtx)
|
2016-10-05 21:04:25 -05:00
|
|
|
{
|
2017-04-05 04:57:28 -05:00
|
|
|
#ifdef NDEBUG
|
|
|
|
(void) mtx;
|
|
|
|
#else
|
2016-10-05 21:04:25 -05:00
|
|
|
assert(!mtx.try_lock());
|
2017-04-05 04:57:28 -05:00
|
|
|
#endif
|
2016-05-02 18:17:46 -05:00
|
|
|
}
|
|
|
|
|
2019-02-12 05:16:40 -06:00
|
|
|
#if !MOBILEAPP
|
2018-01-26 08:32:09 -06:00
|
|
|
/// Print given number of bytes in human-understandable form (KB,MB, etc.)
|
|
|
|
std::string getHumanizedBytes(unsigned long nBytes);
|
|
|
|
|
2017-07-07 06:42:19 -05:00
|
|
|
/// Returns the total physical memory (in kB) available in the system
|
2018-01-10 22:53:47 -06:00
|
|
|
size_t getTotalSystemMemoryKb();
|
2017-07-07 06:42:19 -05:00
|
|
|
|
2017-02-03 00:29:53 -06:00
|
|
|
/// Returns the process PSS in KB (works only when we have perms for /proc/pid/smaps).
|
|
|
|
size_t getMemoryUsagePSS(const Poco::Process::PID pid);
|
|
|
|
|
|
|
|
/// Returns the process RSS in KB.
|
|
|
|
size_t getMemoryUsageRSS(const Poco::Process::PID pid);
|
|
|
|
|
|
|
|
/// Returns the RSS and PSS of the current process in KB.
|
|
|
|
/// Example: "procmemstats: pid=123 rss=12400 pss=566"
|
|
|
|
std::string getMemoryStats(FILE* file);
|
2016-03-31 03:01:21 -05:00
|
|
|
|
2017-06-05 20:17:42 -05:00
|
|
|
size_t getCpuUsage(const Poco::Process::PID pid);
|
|
|
|
|
|
|
|
size_t getStatFromPid(const Poco::Process::PID pid, int ind);
|
2018-09-11 01:30:55 -05:00
|
|
|
#endif
|
2017-06-05 20:17:42 -05:00
|
|
|
|
2017-05-14 20:44:16 -05:00
|
|
|
std::string replace(std::string s, const std::string& a, const std::string& b);
|
2016-03-31 03:01:21 -05:00
|
|
|
|
|
|
|
std::string formatLinesForLog(const std::string& s);
|
2016-04-07 02:55:57 -05:00
|
|
|
|
|
|
|
void setThreadName(const std::string& s);
|
2016-04-12 04:00:33 -05:00
|
|
|
|
2017-03-30 12:14:40 -05:00
|
|
|
const char *getThreadName();
|
|
|
|
|
2018-08-29 10:48:00 -05:00
|
|
|
#ifdef __linux
|
2017-03-30 12:14:40 -05:00
|
|
|
pid_t getThreadId();
|
2018-08-29 10:48:00 -05:00
|
|
|
#else
|
|
|
|
std::thread::id getThreadId();
|
|
|
|
#endif
|
2017-03-30 12:14:40 -05:00
|
|
|
|
2016-06-20 04:51:35 -05:00
|
|
|
/// Get version information
|
|
|
|
void getVersionInfo(std::string& version, std::string& hash);
|
2016-04-18 17:52:10 -05:00
|
|
|
|
2016-04-20 08:43:00 -05:00
|
|
|
/// Return a string that is unique across processes and calls.
|
|
|
|
std::string UniqueId();
|
|
|
|
|
2017-05-28 11:20:49 -05:00
|
|
|
// Extract all json entries into a map.
|
|
|
|
std::map<std::string, std::string> JsonToMap(const std::string& jsonString);
|
|
|
|
|
2019-05-21 21:21:50 -05:00
|
|
|
inline int hexDigitFromChar(char c)
|
|
|
|
{
|
|
|
|
if (c >= '0' && c <= '9')
|
|
|
|
return c - '0';
|
|
|
|
else if (c >= 'a' && c <= 'f')
|
|
|
|
return c - 'a' + 10;
|
|
|
|
else if (c >= 'A' && c <= 'F')
|
|
|
|
return c - 'A' + 10;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-12-15 12:18:23 -06:00
|
|
|
/// Dump a lineof data as hex
|
|
|
|
inline std::string stringifyHexLine(
|
|
|
|
const std::vector<char> &buffer,
|
|
|
|
unsigned int offset,
|
|
|
|
const unsigned int width = 32)
|
|
|
|
{
|
|
|
|
char scratch[64];
|
|
|
|
std::stringstream os;
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < width; i++)
|
|
|
|
{
|
|
|
|
if (i && (i % 8) == 0)
|
|
|
|
os << " ";
|
|
|
|
if ((offset + i) < buffer.size())
|
|
|
|
sprintf (scratch, "%.2x ", (unsigned char)buffer[offset+i]);
|
|
|
|
else
|
|
|
|
sprintf (scratch, " ");
|
|
|
|
os << scratch;
|
|
|
|
}
|
|
|
|
os << " | ";
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < width; i++)
|
|
|
|
{
|
|
|
|
if ((offset + i) < buffer.size() && ::isprint(buffer[offset+i]))
|
|
|
|
sprintf (scratch, "%c", buffer[offset+i]);
|
|
|
|
else
|
|
|
|
sprintf (scratch, ".");
|
|
|
|
os << scratch;
|
|
|
|
}
|
|
|
|
|
|
|
|
return os.str();
|
|
|
|
}
|
|
|
|
|
2017-11-28 21:23:45 -06:00
|
|
|
/// Dump data as hex and chars to stream
|
|
|
|
inline void dumpHex (std::ostream &os, const char *legend, const char *prefix,
|
2017-11-29 15:56:25 -06:00
|
|
|
const std::vector<char> &buffer, bool skipDup = true,
|
|
|
|
const unsigned int width = 32)
|
2017-11-28 21:23:45 -06:00
|
|
|
{
|
2017-12-15 12:18:23 -06:00
|
|
|
unsigned int j;
|
2017-11-28 21:23:45 -06:00
|
|
|
char scratch[64];
|
2017-12-15 12:18:23 -06:00
|
|
|
int skip = 0;
|
|
|
|
std::string lastLine;
|
2017-11-28 21:23:45 -06:00
|
|
|
|
|
|
|
os << legend;
|
|
|
|
for (j = 0; j < buffer.size() + width - 1; j += width)
|
|
|
|
{
|
|
|
|
sprintf (scratch, "%s0x%.4x ", prefix, j);
|
|
|
|
os << scratch;
|
|
|
|
|
2017-12-15 12:18:23 -06:00
|
|
|
std::string line = stringifyHexLine(buffer, j, width);
|
|
|
|
if (skipDup && lastLine == line)
|
|
|
|
skip++;
|
|
|
|
else {
|
|
|
|
if (skip > 0)
|
|
|
|
{
|
|
|
|
os << "... dup " << skip - 1 << "...";
|
|
|
|
skip = 0;
|
|
|
|
}
|
2017-11-28 21:23:45 -06:00
|
|
|
else
|
2017-12-15 12:18:23 -06:00
|
|
|
os << line;
|
2017-11-28 21:23:45 -06:00
|
|
|
}
|
2017-12-15 12:18:23 -06:00
|
|
|
lastLine.swap(line);
|
|
|
|
|
2017-11-28 21:23:45 -06:00
|
|
|
os << "\n";
|
|
|
|
}
|
|
|
|
os.flush();
|
|
|
|
}
|
|
|
|
|
2019-06-22 06:46:50 -05:00
|
|
|
inline void dumpHex (std::ostream &os, const char *legend, const char *prefix,
|
|
|
|
const std::string &str, bool skipDup = true,
|
|
|
|
const unsigned int width = 32)
|
|
|
|
{
|
|
|
|
std::vector<char> buffer(str.begin(), str.end());
|
|
|
|
dumpHex(os, legend, prefix, buffer, skipDup, width);
|
|
|
|
}
|
|
|
|
|
2019-05-21 21:21:50 -05:00
|
|
|
inline std::string dumpHex (const char *legend, const char *prefix,
|
|
|
|
const std::vector<char>::iterator &startIt,
|
|
|
|
const std::vector<char>::iterator &endIt,
|
|
|
|
bool skipDup = true, const unsigned int width = 32)
|
|
|
|
{
|
|
|
|
std::ostringstream oss;
|
|
|
|
std::vector<char> data(startIt, endIt);
|
|
|
|
dumpHex(oss, legend, prefix, data, skipDup, width);
|
|
|
|
return oss.str();
|
|
|
|
}
|
|
|
|
|
2019-05-29 10:26:16 -05:00
|
|
|
size_t findInVector(const std::vector<char>& tokens, const char *cstring);
|
|
|
|
|
2016-10-09 10:27:01 -05:00
|
|
|
/// Trim spaces from the left. Just spaces.
|
2016-10-29 20:15:00 -05:00
|
|
|
inline std::string& ltrim(std::string& s)
|
2016-10-09 10:27:01 -05:00
|
|
|
{
|
2018-02-07 03:17:19 -06:00
|
|
|
const size_t pos = s.find_first_not_of(' ');
|
2016-10-09 10:27:01 -05:00
|
|
|
if (pos != std::string::npos)
|
|
|
|
{
|
|
|
|
s = s.substr(pos);
|
|
|
|
}
|
2016-10-21 12:01:13 -05:00
|
|
|
|
|
|
|
return s;
|
2016-10-09 10:27:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Trim spaces from the left and copy. Just spaces.
|
2016-10-29 20:15:00 -05:00
|
|
|
inline std::string ltrimmed(const std::string& s)
|
2016-10-09 10:27:01 -05:00
|
|
|
{
|
2018-02-07 03:17:19 -06:00
|
|
|
const size_t pos = s.find_first_not_of(' ');
|
2016-10-09 10:27:01 -05:00
|
|
|
if (pos != std::string::npos)
|
|
|
|
{
|
|
|
|
return s.substr(pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2016-12-17 08:55:28 -06:00
|
|
|
/// Trim spaces from both left and right. Just spaces.
|
|
|
|
inline std::string& trim(std::string& s)
|
|
|
|
{
|
2018-02-07 03:17:19 -06:00
|
|
|
const size_t first = s.find_first_not_of(' ');
|
|
|
|
const size_t last = s.find_last_not_of(' ');
|
2016-12-17 08:55:28 -06:00
|
|
|
if (first != std::string::npos)
|
|
|
|
{
|
|
|
|
if (last != std::string::npos)
|
|
|
|
{
|
|
|
|
s = s.substr(first, last + 1 - first);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
s = s.substr(first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (last != std::string::npos)
|
|
|
|
{
|
|
|
|
s = s.substr(0, last + 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
s.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Trim spaces from both left and right and copy. Just spaces.
|
|
|
|
inline std::string trimmed(const std::string& s)
|
|
|
|
{
|
2018-02-07 03:17:19 -06:00
|
|
|
const size_t first = s.find_first_not_of(' ');
|
|
|
|
const size_t last = s.find_last_not_of(' ');
|
2016-12-17 08:55:28 -06:00
|
|
|
if (first != std::string::npos)
|
|
|
|
{
|
|
|
|
if (last != std::string::npos)
|
|
|
|
{
|
|
|
|
return s.substr(first, last + 1 - first);
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.substr(first);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (last != std::string::npos)
|
|
|
|
{
|
|
|
|
return s.substr(0, last + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Trim spaces from left and right. Just spaces.
|
|
|
|
inline std::string trimmed(const char* s)
|
|
|
|
{
|
|
|
|
return trimmed(std::string(s));
|
|
|
|
}
|
|
|
|
|
2018-06-10 13:02:02 -05:00
|
|
|
/// Return true iff s starts with t.
|
2018-01-15 05:37:40 -06:00
|
|
|
inline bool startsWith(const std::string& s, const std::string& t)
|
|
|
|
{
|
|
|
|
return s.length() >= t.length() && memcmp(s.c_str(), t.c_str(), t.length()) == 0;
|
|
|
|
}
|
|
|
|
|
2018-06-10 13:02:02 -05:00
|
|
|
/// Return true iff s starts with t.
|
|
|
|
inline bool startsWith(const std::string& s, const char* t)
|
|
|
|
{
|
|
|
|
if (t != nullptr && !s.empty())
|
|
|
|
{
|
|
|
|
const size_t len = std::strlen(t);
|
|
|
|
return s.length() >= len && memcmp(s.c_str(), t, len) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-10-17 03:22:03 -05:00
|
|
|
#ifdef IOS
|
|
|
|
|
2018-10-17 04:34:49 -05:00
|
|
|
inline void *memrchr(const void *s, int c, size_t n)
|
2018-10-17 03:22:03 -05:00
|
|
|
{
|
|
|
|
char *p = (char*)s + n - 1;
|
|
|
|
while (p >= (char*)s)
|
|
|
|
{
|
|
|
|
if (*p == c)
|
|
|
|
return p;
|
|
|
|
p--;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
// Unit test for the above memrchr()
|
|
|
|
|
|
|
|
int main(int argc, char**argv)
|
|
|
|
{
|
|
|
|
int success = 1;
|
|
|
|
char *s;
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
#define TEST(s_,c,n,e) \
|
|
|
|
s = s_; \
|
|
|
|
printf("memrchr(\"%s\",'%c',%d)=",s,c,n); \
|
|
|
|
p = memrchr(s, c, n); \
|
|
|
|
if (p) \
|
|
|
|
printf("\"%s\"", p); \
|
|
|
|
else \
|
|
|
|
printf("NULL"); \
|
|
|
|
if (p == e) \
|
|
|
|
printf(" OK\n"); \
|
|
|
|
else \
|
|
|
|
{ \
|
|
|
|
printf(" FAIL\n"); \
|
|
|
|
success = 0; \
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST("abc", 'x', 0, NULL);
|
|
|
|
TEST("abc", 'x', 1, NULL);
|
|
|
|
TEST("abc", 'x', 3, NULL);
|
|
|
|
TEST("abc", 'a', 0, NULL);
|
|
|
|
TEST("abc", 'a', 1, s);
|
|
|
|
TEST("abc", 'a', 3, s);
|
|
|
|
TEST("abc", 'b', 0, NULL);
|
|
|
|
TEST("abc", 'b', 1, NULL);
|
|
|
|
TEST("abc", 'b', 2, s+1);
|
|
|
|
TEST("abc", 'b', 3, s+1);
|
2018-10-17 03:55:19 -05:00
|
|
|
TEST("abc", 'c', 0, NULL);
|
|
|
|
TEST("abc", 'c', 1, NULL);
|
|
|
|
TEST("abc", 'c', 2, NULL);
|
|
|
|
TEST("abc", 'c', 3, s+2);
|
2018-10-17 03:22:03 -05:00
|
|
|
|
|
|
|
if (success)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2018-07-17 01:01:05 -05:00
|
|
|
inline size_t getLastDelimiterPosition(const char* message, const int length, const char delim)
|
|
|
|
{
|
|
|
|
if (message && length > 0)
|
|
|
|
{
|
|
|
|
const char *founddelim = static_cast<const char *>(memrchr(message, delim, length));
|
|
|
|
const auto size = (founddelim == nullptr ? length : founddelim - message);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-07-11 04:54:23 -05:00
|
|
|
/// Return the symbolic name for an errno value, or in decimal if not handled here.
|
|
|
|
inline std::string symbolicErrno(int e)
|
|
|
|
{
|
|
|
|
// Errnos from <asm-generic/errno-base.h> and <asm-generic/errno.h> on Linux.
|
|
|
|
switch (e)
|
|
|
|
{
|
|
|
|
case EPERM: return "EPERM";
|
|
|
|
case ENOENT: return "ENOENT";
|
|
|
|
case ESRCH: return "ESRCH";
|
|
|
|
case EINTR: return "EINTR";
|
|
|
|
case EIO: return "EIO";
|
|
|
|
case ENXIO: return "ENXIO";
|
|
|
|
case E2BIG: return "E2BIG";
|
|
|
|
case ENOEXEC: return "ENOEXEC";
|
|
|
|
case EBADF: return "EBADF";
|
|
|
|
case ECHILD: return "ECHILD";
|
|
|
|
case EAGAIN: return "EAGAIN";
|
|
|
|
case ENOMEM: return "ENOMEM";
|
|
|
|
case EACCES: return "EACCES";
|
|
|
|
case EFAULT: return "EFAULT";
|
|
|
|
case ENOTBLK: return "ENOTBLK";
|
|
|
|
case EBUSY: return "EBUSY";
|
|
|
|
case EEXIST: return "EEXIST";
|
|
|
|
case EXDEV: return "EXDEV";
|
|
|
|
case ENODEV: return "ENODEV";
|
|
|
|
case ENOTDIR: return "ENOTDIR";
|
|
|
|
case EISDIR: return "EISDIR";
|
|
|
|
case EINVAL: return "EINVAL";
|
|
|
|
case ENFILE: return "ENFILE";
|
|
|
|
case EMFILE: return "EMFILE";
|
|
|
|
case ENOTTY: return "ENOTTY";
|
|
|
|
case ETXTBSY: return "ETXTBSY";
|
|
|
|
case EFBIG: return "EFBIG";
|
|
|
|
case ENOSPC: return "ENOSPC";
|
|
|
|
case ESPIPE: return "ESPIPE";
|
|
|
|
case EROFS: return "EROFS";
|
|
|
|
case EMLINK: return "EMLINK";
|
|
|
|
case EPIPE: return "EPIPE";
|
|
|
|
case EDOM: return "EDOM";
|
|
|
|
case ERANGE: return "ERANGE";
|
|
|
|
case EDEADLK: return "EDEADLK";
|
|
|
|
case ENAMETOOLONG: return "ENAMETOOLONG";
|
|
|
|
case ENOLCK: return "ENOLCK";
|
|
|
|
case ENOSYS: return "ENOSYS";
|
|
|
|
case ENOTEMPTY: return "ENOTEMPTY";
|
|
|
|
case ELOOP: return "ELOOP";
|
|
|
|
case ENOMSG: return "ENOMSG";
|
|
|
|
case EIDRM: return "EIDRM";
|
2018-08-29 10:48:00 -05:00
|
|
|
#ifdef ECHRNG
|
2018-07-11 04:54:23 -05:00
|
|
|
case ECHRNG: return "ECHRNG";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EL2NSYNC
|
2018-07-11 04:54:23 -05:00
|
|
|
case EL2NSYNC: return "EL2NSYNC";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EL3HLT
|
2018-07-11 04:54:23 -05:00
|
|
|
case EL3HLT: return "EL3HLT";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EL3RST
|
2018-07-11 04:54:23 -05:00
|
|
|
case EL3RST: return "EL3RST";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef ELNRNG
|
2018-07-11 04:54:23 -05:00
|
|
|
case ELNRNG: return "ELNRNG";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EUNATCH
|
2018-07-11 04:54:23 -05:00
|
|
|
case EUNATCH: return "EUNATCH";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef ENOCSI
|
2018-07-11 04:54:23 -05:00
|
|
|
case ENOCSI: return "ENOCSI";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EL2HLT
|
2018-07-11 04:54:23 -05:00
|
|
|
case EL2HLT: return "EL2HLT";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EBADE
|
2018-07-11 04:54:23 -05:00
|
|
|
case EBADE: return "EBADE";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EBADR
|
2018-07-11 04:54:23 -05:00
|
|
|
case EBADR: return "EBADR";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EXFULL
|
2018-07-11 04:54:23 -05:00
|
|
|
case EXFULL: return "EXFULL";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef ENOANO
|
2018-07-11 04:54:23 -05:00
|
|
|
case ENOANO: return "ENOANO";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EBADRQC
|
2018-07-11 04:54:23 -05:00
|
|
|
case EBADRQC: return "EBADRQC";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EBADSLT
|
2018-07-11 04:54:23 -05:00
|
|
|
case EBADSLT: return "EBADSLT";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EBFONT
|
2018-07-11 04:54:23 -05:00
|
|
|
case EBFONT: return "EBFONT";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
2018-07-11 04:54:23 -05:00
|
|
|
case ENOSTR: return "ENOSTR";
|
|
|
|
case ENODATA: return "ENODATA";
|
|
|
|
case ETIME: return "ETIME";
|
|
|
|
case ENOSR: return "ENOSR";
|
2018-08-29 10:48:00 -05:00
|
|
|
#ifdef ENONET
|
2018-07-11 04:54:23 -05:00
|
|
|
case ENONET: return "ENONET";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef ENOPKG
|
2018-07-11 04:54:23 -05:00
|
|
|
case ENOPKG: return "ENOPKG";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
2018-07-11 04:54:23 -05:00
|
|
|
case EREMOTE: return "EREMOTE";
|
|
|
|
case ENOLINK: return "ENOLINK";
|
2018-08-29 10:48:00 -05:00
|
|
|
#ifdef EADV
|
2018-07-11 04:54:23 -05:00
|
|
|
case EADV: return "EADV";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef ESRMNT
|
2018-07-11 04:54:23 -05:00
|
|
|
case ESRMNT: return "ESRMNT";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef ECOMM
|
2018-07-11 04:54:23 -05:00
|
|
|
case ECOMM: return "ECOMM";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
2018-07-11 04:54:23 -05:00
|
|
|
case EPROTO: return "EPROTO";
|
|
|
|
case EMULTIHOP: return "EMULTIHOP";
|
2018-08-29 10:48:00 -05:00
|
|
|
#ifdef EDOTDOT
|
2018-07-11 04:54:23 -05:00
|
|
|
case EDOTDOT: return "EDOTDOT";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
2018-07-11 04:54:23 -05:00
|
|
|
case EBADMSG: return "EBADMSG";
|
|
|
|
case EOVERFLOW: return "EOVERFLOW";
|
2018-08-29 10:48:00 -05:00
|
|
|
#ifdef ENOTUNIQ
|
2018-07-11 04:54:23 -05:00
|
|
|
case ENOTUNIQ: return "ENOTUNIQ";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EBADFD
|
2018-07-11 04:54:23 -05:00
|
|
|
case EBADFD: return "EBADFD";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EREMCHG
|
2018-07-11 04:54:23 -05:00
|
|
|
case EREMCHG: return "EREMCHG";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef ELIBACC
|
2018-07-11 04:54:23 -05:00
|
|
|
case ELIBACC: return "ELIBACC";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef ELIBBAD
|
2018-07-11 04:54:23 -05:00
|
|
|
case ELIBBAD: return "ELIBBAD";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef ELIBSCN
|
2018-07-11 04:54:23 -05:00
|
|
|
case ELIBSCN: return "ELIBSCN";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef ELIBMAX
|
2018-07-11 04:54:23 -05:00
|
|
|
case ELIBMAX: return "ELIBMAX";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef ELIBEXEC
|
2018-07-11 04:54:23 -05:00
|
|
|
case ELIBEXEC: return "ELIBEXEC";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
2018-07-11 04:54:23 -05:00
|
|
|
case EILSEQ: return "EILSEQ";
|
2018-08-29 10:48:00 -05:00
|
|
|
#ifdef ERESTART
|
2018-07-11 04:54:23 -05:00
|
|
|
case ERESTART: return "ERESTART";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef ESTRPIPE
|
2018-07-11 04:54:23 -05:00
|
|
|
case ESTRPIPE: return "ESTRPIPE";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
2018-07-11 04:54:23 -05:00
|
|
|
case EUSERS: return "EUSERS";
|
|
|
|
case ENOTSOCK: return "ENOTSOCK";
|
|
|
|
case EDESTADDRREQ: return "EDESTADDRREQ";
|
|
|
|
case EMSGSIZE: return "EMSGSIZE";
|
|
|
|
case EPROTOTYPE: return "EPROTOTYPE";
|
|
|
|
case ENOPROTOOPT: return "ENOPROTOOPT";
|
|
|
|
case EPROTONOSUPPORT: return "EPROTONOSUPPORT";
|
|
|
|
case ESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT";
|
|
|
|
case EOPNOTSUPP: return "EOPNOTSUPP";
|
|
|
|
case EPFNOSUPPORT: return "EPFNOSUPPORT";
|
|
|
|
case EAFNOSUPPORT: return "EAFNOSUPPORT";
|
|
|
|
case EADDRINUSE: return "EADDRINUSE";
|
|
|
|
case EADDRNOTAVAIL: return "EADDRNOTAVAIL";
|
|
|
|
case ENETDOWN: return "ENETDOWN";
|
|
|
|
case ENETUNREACH: return "ENETUNREACH";
|
|
|
|
case ENETRESET: return "ENETRESET";
|
|
|
|
case ECONNABORTED: return "ECONNABORTED";
|
|
|
|
case ECONNRESET: return "ECONNRESET";
|
|
|
|
case ENOBUFS: return "ENOBUFS";
|
|
|
|
case EISCONN: return "EISCONN";
|
|
|
|
case ENOTCONN: return "ENOTCONN";
|
|
|
|
case ESHUTDOWN: return "ESHUTDOWN";
|
|
|
|
case ETOOMANYREFS: return "ETOOMANYREFS";
|
|
|
|
case ETIMEDOUT: return "ETIMEDOUT";
|
|
|
|
case ECONNREFUSED: return "ECONNREFUSED";
|
|
|
|
case EHOSTDOWN: return "EHOSTDOWN";
|
|
|
|
case EHOSTUNREACH: return "EHOSTUNREACH";
|
|
|
|
case EALREADY: return "EALREADY";
|
|
|
|
case EINPROGRESS: return "EINPROGRESS";
|
|
|
|
case ESTALE: return "ESTALE";
|
2018-08-29 10:48:00 -05:00
|
|
|
#ifdef EUCLEAN
|
2018-07-11 04:54:23 -05:00
|
|
|
case EUCLEAN: return "EUCLEAN";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef ENOTNAM
|
2018-07-11 04:54:23 -05:00
|
|
|
case ENOTNAM: return "ENOTNAM";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef ENAVAIL
|
2018-07-11 04:54:23 -05:00
|
|
|
case ENAVAIL: return "ENAVAIL";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EISNAM
|
2018-07-11 04:54:23 -05:00
|
|
|
case EISNAM: return "EISNAM";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EREMOTEIO
|
2018-07-11 04:54:23 -05:00
|
|
|
case EREMOTEIO: return "EREMOTEIO";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
2018-07-11 04:54:23 -05:00
|
|
|
case EDQUOT: return "EDQUOT";
|
2018-08-29 10:48:00 -05:00
|
|
|
#ifdef ENOMEDIUM
|
2018-07-11 04:54:23 -05:00
|
|
|
case ENOMEDIUM: return "ENOMEDIUM";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EMEDIUMTYPE
|
2018-07-11 04:54:23 -05:00
|
|
|
case EMEDIUMTYPE: return "EMEDIUMTYPE";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
2018-07-11 04:54:23 -05:00
|
|
|
case ECANCELED: return "ECANCELED";
|
2018-08-29 10:48:00 -05:00
|
|
|
#ifdef ENOKEY
|
2018-07-11 04:54:23 -05:00
|
|
|
case ENOKEY: return "ENOKEY";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EKEYEXPIRED
|
2018-07-11 04:54:23 -05:00
|
|
|
case EKEYEXPIRED: return "EKEYEXPIRED";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EKEYREVOKED
|
2018-07-11 04:54:23 -05:00
|
|
|
case EKEYREVOKED: return "EKEYREVOKED";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EKEYREJECTED
|
2018-07-11 04:54:23 -05:00
|
|
|
case EKEYREJECTED: return "EKEYREJECTED";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
2018-07-11 04:54:23 -05:00
|
|
|
case EOWNERDEAD: return "EOWNERDEAD";
|
|
|
|
case ENOTRECOVERABLE: return "ENOTRECOVERABLE";
|
2018-08-29 10:48:00 -05:00
|
|
|
#ifdef ERFKILL
|
2018-07-11 04:54:23 -05:00
|
|
|
case ERFKILL: return "ERFKILL";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
|
|
|
#ifdef EHWPOISON
|
2018-07-11 04:54:23 -05:00
|
|
|
case EHWPOISON: return "EHWPOISON";
|
2018-08-29 10:48:00 -05:00
|
|
|
#endif
|
2018-07-11 04:54:23 -05:00
|
|
|
default: return std::to_string(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-12 23:18:30 -05:00
|
|
|
inline size_t getDelimiterPosition(const char* message, const int length, const char delim)
|
|
|
|
{
|
|
|
|
if (message && length > 0)
|
|
|
|
{
|
|
|
|
const char *founddelim = static_cast<const char *>(std::memchr(message, delim, length));
|
|
|
|
const size_t size = (founddelim == nullptr ? length : founddelim - message);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline
|
|
|
|
std::string getDelimitedInitialSubstring(const char *message, const int length, const char delim)
|
|
|
|
{
|
|
|
|
const size_t size = getDelimiterPosition(message, length, delim);
|
|
|
|
return std::string(message, size);
|
|
|
|
}
|
|
|
|
|
2019-10-08 04:23:29 -05:00
|
|
|
/// Split a string in two at the delimiter, removing it.
|
2018-07-12 23:18:30 -05:00
|
|
|
inline
|
2019-10-08 04:23:29 -05:00
|
|
|
std::pair<std::string, std::string> split(const char* s, const int length, const char delimiter = ' ', bool removeDelim = true)
|
2018-07-12 23:18:30 -05:00
|
|
|
{
|
2019-10-08 04:23:29 -05:00
|
|
|
const size_t size = getDelimiterPosition(s, length, delimiter);
|
2018-07-18 09:18:03 -05:00
|
|
|
|
|
|
|
std::string after;
|
|
|
|
int after_pos = size + (removeDelim? 1: 0);
|
|
|
|
if (after_pos < length)
|
|
|
|
after = std::string(s + after_pos, length - after_pos);
|
|
|
|
|
|
|
|
return std::make_pair(std::string(s, size), after);
|
2018-07-12 23:18:30 -05:00
|
|
|
}
|
|
|
|
|
2019-10-08 04:23:29 -05:00
|
|
|
/// Split a string in two at the delimiter, removing it.
|
2018-07-12 23:18:30 -05:00
|
|
|
inline
|
2019-10-08 04:23:29 -05:00
|
|
|
std::pair<std::string, std::string> split(const std::string& s, const char delimiter = ' ', bool removeDelim = true)
|
2018-07-12 23:18:30 -05:00
|
|
|
{
|
2019-10-08 04:23:29 -05:00
|
|
|
return split(s.c_str(), s.size(), delimiter, removeDelim);
|
2018-07-12 23:18:30 -05:00
|
|
|
}
|
|
|
|
|
2019-10-08 04:23:29 -05:00
|
|
|
/// Split a string in two at the delimiter.
|
2018-07-17 01:01:05 -05:00
|
|
|
inline
|
2019-10-08 04:23:29 -05:00
|
|
|
std::pair<std::string, std::string> splitLast(const char* s, const int length, const char delimiter = ' ', bool removeDelim = true)
|
2018-07-17 01:01:05 -05:00
|
|
|
{
|
2019-10-08 04:23:29 -05:00
|
|
|
const size_t size = getLastDelimiterPosition(s, length, delimiter);
|
2018-07-18 09:18:03 -05:00
|
|
|
|
|
|
|
std::string after;
|
|
|
|
int after_pos = size + (removeDelim? 1: 0);
|
|
|
|
if (after_pos < length)
|
|
|
|
after = std::string(s + after_pos, length - after_pos);
|
|
|
|
|
|
|
|
return std::make_pair(std::string(s, size), after);
|
2018-07-17 01:01:05 -05:00
|
|
|
}
|
|
|
|
|
2019-10-08 04:23:29 -05:00
|
|
|
/// Split a string in two at the delimiter, removing it.
|
2018-07-17 01:01:05 -05:00
|
|
|
inline
|
2019-10-08 04:23:29 -05:00
|
|
|
std::pair<std::string, std::string> splitLast(const std::string& s, const char delimiter = ' ', bool removeDelim = true)
|
2018-07-17 01:01:05 -05:00
|
|
|
{
|
2019-10-08 04:23:29 -05:00
|
|
|
return splitLast(s.c_str(), s.size(), delimiter, removeDelim);
|
2018-07-17 01:01:05 -05:00
|
|
|
}
|
|
|
|
|
2019-06-20 14:20:26 -05:00
|
|
|
/// Append a length bytes to a vector, or strlen of data as a C string if not provided
|
|
|
|
/// returns count of bytes appended.
|
|
|
|
inline void vectorAppend(std::vector<char> &vector, const char *data, ssize_t length = -1)
|
|
|
|
{
|
|
|
|
size_t vlen = vector.size();
|
2019-08-15 01:37:46 -05:00
|
|
|
|
|
|
|
if (!data)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-20 14:20:26 -05:00
|
|
|
size_t dataLen = length;
|
|
|
|
if (length < 0)
|
|
|
|
dataLen = strlen(data);
|
|
|
|
vector.resize(vlen+dataLen);
|
|
|
|
std::memcpy(vector.data() + vlen, data, dataLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Append a number as hexadecimal to a vector
|
|
|
|
inline void vectorAppendHex(std::vector<char> &vector, uint64_t number)
|
|
|
|
{
|
|
|
|
char output[32];
|
2019-09-16 06:45:38 -05:00
|
|
|
sprintf(output, "%" PRIx64, number);
|
2019-06-20 14:20:26 -05:00
|
|
|
vectorAppend(vector, output);
|
|
|
|
}
|
|
|
|
|
2018-07-17 01:01:05 -05:00
|
|
|
/// Splits a URL into path (with protocol), filename, extension, parameters.
|
|
|
|
/// All components are optional, depending on what the URL represents (can be a unix path).
|
|
|
|
std::tuple<std::string, std::string, std::string, std::string> splitUrl(const std::string& url);
|
|
|
|
|
2018-04-04 05:36:11 -05:00
|
|
|
/// Check for the URI scheme validity.
|
|
|
|
/// For now just a basic sanity check, can be extended if necessary.
|
|
|
|
bool isValidURIScheme(const std::string& scheme);
|
|
|
|
|
|
|
|
/// Check for the URI host validity.
|
|
|
|
/// For now just a basic sanity check, can be extended if necessary.
|
|
|
|
bool isValidURIHost(const std::string& host);
|
|
|
|
|
2018-06-10 10:35:59 -05:00
|
|
|
/// Anonymize a sensitive string to avoid leaking it.
|
|
|
|
/// Called on strings to be logged or exposed.
|
2019-04-14 11:21:19 -05:00
|
|
|
std::string anonymize(const std::string& text, const std::uint64_t nAnonymizationSalt);
|
2018-06-10 10:35:59 -05:00
|
|
|
|
2018-07-10 22:09:27 -05:00
|
|
|
/// Sets the anonymized version of a given plain-text string.
|
|
|
|
/// After this, 'anonymize(plain)' will return 'anonymized'.
|
|
|
|
void mapAnonymized(const std::string& plain, const std::string& anonymized);
|
|
|
|
|
2018-06-10 10:35:59 -05:00
|
|
|
/// Anonymize the basename of filenames only, preserving the path and extension.
|
2019-04-14 11:21:19 -05:00
|
|
|
std::string anonymizeUrl(const std::string& url, const std::uint64_t nAnonymizationSalt);
|
2018-06-10 10:35:59 -05:00
|
|
|
|
2018-07-17 01:01:05 -05:00
|
|
|
/// Extract and return the filename given a url or path.
|
|
|
|
std::string getFilenameFromURL(const std::string& url);
|
2018-07-10 22:09:27 -05:00
|
|
|
|
2016-04-18 17:52:10 -05:00
|
|
|
/// Given one or more patterns to allow, and one or more to deny,
|
|
|
|
/// the match member will return true if, and only if, the subject
|
|
|
|
/// matches the allowed list, but not the deny.
|
|
|
|
/// By default, everything is denied.
|
|
|
|
class RegexListMatcher
|
|
|
|
{
|
|
|
|
public:
|
2016-08-04 17:44:24 -05:00
|
|
|
RegexListMatcher() :
|
|
|
|
_allowByDefault(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
RegexListMatcher(const bool allowByDefault) :
|
|
|
|
_allowByDefault(allowByDefault)
|
2016-04-18 20:11:33 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-04-19 02:35:36 -05:00
|
|
|
RegexListMatcher(std::initializer_list<std::string> allowed) :
|
2016-08-04 17:44:24 -05:00
|
|
|
_allowByDefault(false),
|
2016-04-19 02:35:36 -05:00
|
|
|
_allowed(allowed)
|
2016-04-18 20:11:33 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-04-19 02:35:36 -05:00
|
|
|
RegexListMatcher(std::initializer_list<std::string> allowed,
|
|
|
|
std::initializer_list<std::string> denied) :
|
2016-08-04 17:44:24 -05:00
|
|
|
_allowByDefault(false),
|
2016-04-19 02:35:36 -05:00
|
|
|
_allowed(allowed),
|
|
|
|
_denied(denied)
|
2016-04-18 20:11:33 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-08-04 17:44:24 -05:00
|
|
|
RegexListMatcher(const bool allowByDefault,
|
|
|
|
std::initializer_list<std::string> denied) :
|
|
|
|
_allowByDefault(allowByDefault),
|
|
|
|
_denied(denied)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-04-18 17:52:10 -05:00
|
|
|
void allow(const std::string& pattern) { _allowed.insert(pattern); }
|
|
|
|
void deny(const std::string& pattern)
|
|
|
|
{
|
|
|
|
_allowed.erase(pattern);
|
|
|
|
_denied.insert(pattern);
|
|
|
|
}
|
|
|
|
|
2016-04-18 20:11:33 -05:00
|
|
|
void clear()
|
|
|
|
{
|
|
|
|
_allowed.clear();
|
|
|
|
_denied.clear();
|
|
|
|
}
|
|
|
|
|
2016-04-18 17:52:10 -05:00
|
|
|
bool match(const std::string& subject) const
|
|
|
|
{
|
2016-10-29 20:15:00 -05:00
|
|
|
return (_allowByDefault || match(_allowed, subject)) && !match(_denied, subject);
|
2016-04-18 17:52:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2016-12-23 00:42:35 -06:00
|
|
|
static bool match(const std::set<std::string>& set, const std::string& subject)
|
2016-04-18 17:52:10 -05:00
|
|
|
{
|
|
|
|
if (set.find(subject) != set.end())
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not a perfect match, try regex.
|
|
|
|
for (const auto& value : set)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Not performance critical to warrant caching.
|
2016-09-27 09:59:29 -05:00
|
|
|
Poco::RegularExpression re(value, Poco::RegularExpression::RE_CASELESS);
|
2016-09-27 10:07:52 -05:00
|
|
|
Poco::RegularExpression::Match reMatch;
|
2016-04-18 17:52:10 -05:00
|
|
|
|
|
|
|
// Must be a full match.
|
2016-09-27 09:59:29 -05:00
|
|
|
if (re.match(subject, reMatch) && reMatch.offset == 0 && reMatch.length == subject.size())
|
2016-04-18 17:52:10 -05:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (const std::exception& exc)
|
|
|
|
{
|
|
|
|
// Nothing to do; skip.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2016-08-04 17:44:24 -05:00
|
|
|
const bool _allowByDefault;
|
2016-04-18 17:52:10 -05:00
|
|
|
std::set<std::string> _allowed;
|
|
|
|
std::set<std::string> _denied;
|
|
|
|
};
|
|
|
|
|
2016-08-13 23:01:45 -05:00
|
|
|
/// A logical constant that is allowed to initialize
|
|
|
|
/// exactly once and checks usage before initialization.
|
2016-10-29 20:15:00 -05:00
|
|
|
template <typename T>
|
2016-07-19 04:07:07 -05:00
|
|
|
class RuntimeConstant
|
2016-07-18 06:45:36 -05:00
|
|
|
{
|
2016-07-28 01:39:03 -05:00
|
|
|
T _value;
|
2016-08-13 23:01:45 -05:00
|
|
|
std::atomic<bool> _initialized;
|
2016-07-18 06:45:36 -05:00
|
|
|
|
|
|
|
public:
|
2016-07-19 04:07:07 -05:00
|
|
|
RuntimeConstant()
|
2016-07-28 01:39:03 -05:00
|
|
|
: _value()
|
|
|
|
, _initialized(false)
|
2016-08-13 23:01:45 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Use a compile-time const instead.
|
|
|
|
RuntimeConstant(const T& value) = delete;
|
2016-07-18 06:45:36 -05:00
|
|
|
|
|
|
|
const T& get()
|
|
|
|
{
|
2016-08-13 23:01:45 -05:00
|
|
|
if (_initialized)
|
2016-07-18 06:45:36 -05:00
|
|
|
{
|
2016-07-28 01:39:03 -05:00
|
|
|
return _value;
|
2016-07-18 06:45:36 -05:00
|
|
|
}
|
2016-08-13 23:01:45 -05:00
|
|
|
|
|
|
|
throw std::runtime_error("RuntimeConstant instance read before being initialized.");
|
2016-07-18 06:45:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void set(const T& value)
|
|
|
|
{
|
2016-07-28 01:39:03 -05:00
|
|
|
assert(!_initialized);
|
2016-07-19 04:07:07 -05:00
|
|
|
|
2016-07-28 01:39:03 -05:00
|
|
|
_initialized = true;
|
|
|
|
_value = value;
|
2016-07-18 06:45:36 -05:00
|
|
|
}
|
|
|
|
};
|
2019-05-20 00:40:12 -05:00
|
|
|
|
|
|
|
//// Return current time in HTTP format.
|
|
|
|
std::string getHttpTimeNow();
|
2019-08-30 12:37:55 -05:00
|
|
|
|
2019-09-27 11:56:16 -05:00
|
|
|
//// Return time in HTTP format.
|
|
|
|
std::string getHttpTime(std::chrono::system_clock::time_point time);
|
|
|
|
|
2019-08-30 12:37:55 -05:00
|
|
|
//// Return timestamp of file
|
|
|
|
std::chrono::system_clock::time_point getFileTimestamp(std::string str_path);
|
|
|
|
|
|
|
|
//// Return time in ISO8061 fraction format
|
|
|
|
std::string getIso8601FracformatTime(std::chrono::system_clock::time_point time);
|
|
|
|
|
2019-10-25 19:48:05 -05:00
|
|
|
/// Convert a time_point to iso8601 formatted string.
|
|
|
|
std::string time_point_to_iso8601(std::chrono::system_clock::time_point tp);
|
|
|
|
|
2019-11-27 03:12:59 -06:00
|
|
|
/// Convert time from ISO8061 fraction format
|
2019-08-30 12:37:55 -05:00
|
|
|
std::chrono::system_clock::time_point iso8601ToTimestamp(const std::string& iso8601Time, const std::string& logName);
|
|
|
|
|
2019-11-27 03:12:59 -06:00
|
|
|
/// conversion from steady_clock for debugging / tracing
|
|
|
|
std::string getSteadyClockAsString(const std::chrono::steady_clock::time_point &time);
|
|
|
|
|
2019-05-27 21:57:53 -05:00
|
|
|
/// Automatically execute code at end of current scope.
|
|
|
|
/// Used for exception-safe code.
|
|
|
|
class ScopeGuard
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
template <typename T>
|
|
|
|
explicit ScopeGuard(T const &func) : m_func(func) {}
|
|
|
|
|
|
|
|
~ScopeGuard()
|
|
|
|
{
|
|
|
|
if (m_func)
|
|
|
|
m_func();
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
ScopeGuard(const ScopeGuard &) = delete;
|
|
|
|
ScopeGuard &operator=(const ScopeGuard &) = delete;
|
|
|
|
|
|
|
|
std::function<void()> m_func;
|
|
|
|
};
|
2016-07-18 06:45:36 -05:00
|
|
|
} // end namespace Util
|
2015-03-17 18:56:15 -05:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|