952 lines
27 KiB
C++
952 lines
27 KiB
C++
/*
|
||
Copyright 2025 Yağız Zengin
|
||
|
||
Licensed under the Apache License, Version 2.0 (the "License");
|
||
you may not use this file except in compliance with the License.
|
||
You may obtain a copy of the License at
|
||
|
||
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
||
Unless required by applicable law or agreed to in writing, software
|
||
distributed under the License is distributed on an "AS IS" BASIS,
|
||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
See the License for the specific language governing permissions and
|
||
limitations under the License.
|
||
*/
|
||
|
||
#ifndef LIBHELPER_LIB_HPP
|
||
#define LIBHELPER_LIB_HPP
|
||
|
||
#include <cstdint>
|
||
#include <dirent.h>
|
||
#include <exception>
|
||
#include <functional>
|
||
#include <optional>
|
||
#include <random>
|
||
#include <set>
|
||
#include <sstream>
|
||
#include <string>
|
||
#include <string_view>
|
||
#include <vector>
|
||
|
||
#define KB(x) (static_cast<uint64_t>(x) * 1024) // KB(8) = 8192 (8 * 1024)
|
||
#define MB(x) (KB(x) * 1024) // MB(4) = 4194304 (KB(4) * 1024)
|
||
#define GB(x) (MB(x) * 1024) // GB(1) = 1073741824 (MB(1) * 1024)
|
||
|
||
#define TO_KB(x) (x / 1024) // TO_KB(1024) = 1
|
||
#define TO_MB(x) (TO_KB(x) / 1024) // TO_MB(2048) (2048 / 1024)
|
||
#define TO_GB(x) (TO_MB(x) / 1024) // TO_GB(1048576) (TO_MB(1048576) / 1024)
|
||
|
||
#ifndef ONLY_HELPER_MACROS
|
||
|
||
enum LogLevels {
|
||
INFO = static_cast<int>('I'),
|
||
WARNING = static_cast<int>('W'),
|
||
ERROR = static_cast<int>('E'),
|
||
ABORT = static_cast<int>('A')
|
||
};
|
||
|
||
enum sizeCastTypes {
|
||
B = static_cast<int>('B'),
|
||
KB = static_cast<int>('K'),
|
||
MB = static_cast<int>('M'),
|
||
GB = static_cast<int>('G')
|
||
};
|
||
|
||
constexpr mode_t DEFAULT_FILE_PERMS = 0644;
|
||
constexpr mode_t DEFAULT_EXTENDED_FILE_PERMS = 0755;
|
||
constexpr mode_t DEFAULT_DIR_PERMS = 0755;
|
||
constexpr int YES = 1;
|
||
constexpr int NO = 0;
|
||
|
||
namespace Helper {
|
||
// Throwable error class
|
||
class Error final : public std::exception {
|
||
private:
|
||
std::string _message;
|
||
std::ostringstream _oss;
|
||
|
||
public:
|
||
__attribute__((format(printf, 2, 3))) explicit Error(const char *format, ...);
|
||
|
||
[[nodiscard]] const char *what() const noexcept override;
|
||
};
|
||
|
||
// Logging
|
||
class Logger final {
|
||
private:
|
||
LogLevels _level;
|
||
std::ostringstream _oss;
|
||
const char *_function_name, *_logFile, *_program_name, *_file;
|
||
int _line;
|
||
|
||
public:
|
||
Logger(LogLevels level, const char *func, const char *file, const char *name,
|
||
const char *source_file, int line);
|
||
|
||
~Logger();
|
||
|
||
template <typename T> Logger &operator<<(const T &msg) {
|
||
_oss << msg;
|
||
return *this;
|
||
}
|
||
|
||
Logger &operator<<(std::ostream &(*msg)(std::ostream &));
|
||
};
|
||
|
||
// Close file descriptors and delete allocated array memory
|
||
class garbageCollector {
|
||
private:
|
||
std::vector<std::function<void()>> _cleaners;
|
||
std::vector<FILE *> _fps;
|
||
std::vector<DIR *> _dps;
|
||
std::vector<int> _fds;
|
||
std::vector<std::string> _files;
|
||
|
||
public:
|
||
~garbageCollector();
|
||
|
||
template <typename T> void delAfterProgress(T *_ptr) {
|
||
_cleaners.push_back([_ptr] { delete[] _ptr; });
|
||
}
|
||
|
||
void delFileAfterProgress(const std::string &_path);
|
||
void closeAfterProgress(FILE *_fp);
|
||
void closeAfterProgress(DIR *_dp);
|
||
void closeAfterProgress(int _fd);
|
||
};
|
||
|
||
template <int max = 100, int start = 0, int count = 10, int d = 0>
|
||
class Random {
|
||
static_assert(max > start, "max is larger than start");
|
||
static_assert(count > 1, "count is larger than 1");
|
||
static_assert(count <= max - start, "count is greater than max-start");
|
||
|
||
public:
|
||
static std::set<int> get() {
|
||
std::set<int> set;
|
||
std::random_device rd;
|
||
std::mt19937 gen(rd());
|
||
|
||
if constexpr (d > 0) {
|
||
std::uniform_int_distribution<> dist(0, (max - start - 1) / d);
|
||
while (set.size() < count)
|
||
set.insert(start + dist(gen) * d);
|
||
} else {
|
||
std::uniform_int_distribution<> dist(start, max - 1);
|
||
while (set.size() < count)
|
||
set.insert(dist(gen));
|
||
}
|
||
|
||
return set;
|
||
}
|
||
|
||
static int getNumber() {
|
||
std::random_device rd;
|
||
std::mt19937 gen(rd());
|
||
int ret;
|
||
|
||
if constexpr (d > 0) {
|
||
std::uniform_int_distribution<> dist(0, (max - start - 1) / d);
|
||
ret = start + dist(gen) * d;
|
||
} else {
|
||
std::uniform_int_distribution<> dist(start, max - 1); // max exclusive
|
||
ret = dist(gen);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
};
|
||
|
||
template <typename _Type1, typename _Type2, typename _Type3> class PureTuple {
|
||
private:
|
||
void expand_if_needed() {
|
||
if (count == capacity) {
|
||
capacity *= 2;
|
||
Data *data = new Data[capacity];
|
||
|
||
for (size_t i = 0; i < count; i++)
|
||
data[i] = tuple_data[i];
|
||
|
||
delete[] tuple_data;
|
||
tuple_data = data;
|
||
}
|
||
}
|
||
|
||
public:
|
||
struct Data {
|
||
_Type1 first;
|
||
_Type2 second;
|
||
_Type3 third;
|
||
|
||
bool
|
||
operator==(const std::tuple<_Type1, _Type2, _Type3> &t) const noexcept {
|
||
return first == std::get<0>(t) && second == std::get<1>(t) &&
|
||
third == std::get<2>(t);
|
||
}
|
||
|
||
bool operator==(const Data &other) const noexcept {
|
||
return first == other.first && second == other.second &&
|
||
third == other.third;
|
||
}
|
||
|
||
bool operator!=(const Data &other) const noexcept {
|
||
return !(*this == other);
|
||
}
|
||
|
||
explicit operator bool() const noexcept {
|
||
return first != _Type1{} || second != _Type2{} || third != _Type3{};
|
||
}
|
||
|
||
bool operator!() const noexcept { return !bool{*this}; }
|
||
|
||
void operator()(const std::tuple<_Type1, _Type2, _Type3> &t) {
|
||
first = std::get<0>(t);
|
||
second = std::get<1>(t);
|
||
third = std::get<2>(t);
|
||
}
|
||
|
||
Data &operator=(const std::tuple<_Type1, _Type2, _Type3> &t) {
|
||
first = std::get<0>(t);
|
||
second = std::get<1>(t);
|
||
third = std::get<2>(t);
|
||
return *this;
|
||
}
|
||
};
|
||
|
||
Data *tuple_data = nullptr;
|
||
Data tuple_data_type = {_Type1{}, _Type2{}, _Type3{}};
|
||
size_t capacity{}, count{};
|
||
|
||
PureTuple() : tuple_data(new Data[20]), capacity(20), count(0) {}
|
||
~PureTuple() { delete[] tuple_data; }
|
||
|
||
PureTuple(std::initializer_list<Data> val)
|
||
: tuple_data(new Data[20]), capacity(20), count(0) {
|
||
for (const auto &v : val)
|
||
insert(v);
|
||
}
|
||
PureTuple(PureTuple &other)
|
||
: tuple_data(new Data[other.capacity]), capacity(other.capacity),
|
||
count(other.count) {
|
||
std::copy(other.tuple_data, other.tuple_data + count, tuple_data);
|
||
}
|
||
PureTuple(PureTuple &&other) noexcept
|
||
: tuple_data(new Data[other.capacity]), capacity(other.capacity),
|
||
count(other.count) {
|
||
std::copy(other.tuple_data, other.tuple_data + count, tuple_data);
|
||
other.clear();
|
||
}
|
||
|
||
class iterator {
|
||
private:
|
||
Data *it;
|
||
|
||
public:
|
||
using iterator_category = std::random_access_iterator_tag;
|
||
using value_type = Data;
|
||
using difference_type = std::ptrdiff_t;
|
||
using pointer = Data *;
|
||
using reference = Data &;
|
||
|
||
explicit iterator(Data *ptr) : it(ptr) {}
|
||
|
||
pointer operator->() const { return it; }
|
||
reference operator*() { return *it; }
|
||
|
||
iterator &operator++() {
|
||
++it;
|
||
return *this;
|
||
}
|
||
iterator operator++(int) {
|
||
iterator tmp = *this;
|
||
++(*this);
|
||
return tmp;
|
||
}
|
||
iterator &operator--() {
|
||
--it;
|
||
return *this;
|
||
}
|
||
iterator operator--(int) {
|
||
iterator tmp = *this;
|
||
--(*this);
|
||
return tmp;
|
||
}
|
||
|
||
iterator &operator+=(difference_type n) {
|
||
it += n;
|
||
return *this;
|
||
}
|
||
iterator operator+(difference_type n) const { return iterator(it + n); }
|
||
iterator &operator-=(difference_type n) {
|
||
it -= n;
|
||
return *this;
|
||
}
|
||
iterator operator-(difference_type n) const { return iterator(it - n); }
|
||
difference_type operator-(const iterator &other) const {
|
||
return it - other.it;
|
||
}
|
||
|
||
reference operator[](difference_type n) const { return it[n]; }
|
||
|
||
bool operator<(const iterator &other) const { return it < other.it; }
|
||
bool operator>(const iterator &other) const { return it > other.it; }
|
||
bool operator<=(const iterator &other) const { return it <= other.it; }
|
||
bool operator>=(const iterator &other) const { return it >= other.it; }
|
||
|
||
bool operator!=(const iterator &other) const { return it != other.it; }
|
||
bool operator==(const iterator &other) const { return it == other.it; }
|
||
};
|
||
|
||
bool find(const Data &data) const noexcept {
|
||
for (size_t i = 0; i < count; i++)
|
||
if (data == tuple_data[i]) return true;
|
||
|
||
return false;
|
||
}
|
||
|
||
template <typename T = std::tuple<_Type1, _Type2, _Type3>>
|
||
std::enable_if_t<std::is_same_v<T, std::tuple<_Type1, _Type2, _Type3>>, bool>
|
||
find(const std::tuple<_Type1, _Type2, _Type3> &t) const noexcept {
|
||
for (size_t i = 0; i < count; i++)
|
||
if (tuple_data[i] == t) return true;
|
||
|
||
return false;
|
||
}
|
||
|
||
bool find(const _Type1 &val, const _Type2 &val2,
|
||
const _Type3 &val3) const noexcept {
|
||
for (size_t i = 0; i < count; i++)
|
||
if (tuple_data[i] == std::make_tuple(val, val2, val3)) return true;
|
||
|
||
return false;
|
||
}
|
||
|
||
void insert(const Data &val) noexcept {
|
||
expand_if_needed();
|
||
if (!find(val)) tuple_data[count++] = val;
|
||
}
|
||
|
||
template <typename T = std::tuple<_Type1, _Type2, _Type3>>
|
||
std::enable_if_t<std::is_same_v<T, std::tuple<_Type1, _Type2, _Type3>>, void>
|
||
insert(const std::tuple<_Type1, _Type2, _Type3> &t) noexcept {
|
||
expand_if_needed();
|
||
if (!find(t))
|
||
tuple_data[count++] =
|
||
Data{std::get<0>(t), std::get<1>(t), std::get<2>(t)};
|
||
}
|
||
|
||
void insert(const _Type1 &val, const _Type2 &val2,
|
||
const _Type3 &val3) noexcept {
|
||
expand_if_needed();
|
||
if (!find(val, val2, val3)) tuple_data[count++] = Data{val, val2, val3};
|
||
}
|
||
|
||
void merge(const PureTuple &other) noexcept {
|
||
for (const auto &v : other)
|
||
insert(v);
|
||
}
|
||
|
||
void pop_back() noexcept {
|
||
if (count > 0) --count;
|
||
}
|
||
|
||
void pop(const Data &data) noexcept {
|
||
for (size_t i = 0; i < count; i++) {
|
||
if (tuple_data[i] == data) {
|
||
for (size_t j = i; j < count - 1; j++)
|
||
tuple_data[j] = tuple_data[j + 1];
|
||
--count;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void pop(const size_t i) noexcept {
|
||
if (i >= count) return;
|
||
for (size_t x = 0; x < count; x++) {
|
||
if (i == x) {
|
||
for (size_t j = i; j < count - 1; j++)
|
||
tuple_data[j] = tuple_data[j + 1];
|
||
--count;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void pop(const _Type1 &val, const _Type2 &val2, const _Type3 &val3) noexcept {
|
||
for (size_t i = 0; i < count; i++) {
|
||
if (tuple_data[i] == std::make_tuple(val, val2, val3)) {
|
||
for (size_t j = i; j < count - 1; j++)
|
||
tuple_data[j] = tuple_data[j + 1];
|
||
--count;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
template <typename T = std::tuple<_Type1, _Type2, _Type3>>
|
||
std::enable_if_t<std::is_same_v<T, std::tuple<_Type1, _Type2, _Type3>>, void>
|
||
pop(const std::tuple<_Type1, _Type2, _Type3> &t) noexcept {
|
||
for (size_t i = 0; i < count; i++) {
|
||
if (tuple_data[i] == t) {
|
||
for (size_t j = i; j < count - 1; j++)
|
||
tuple_data[j] = tuple_data[j + 1];
|
||
--count;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void clear() noexcept {
|
||
delete[] tuple_data;
|
||
count = 0;
|
||
capacity = 20;
|
||
tuple_data = new Data[capacity];
|
||
}
|
||
|
||
Data back() const noexcept {
|
||
return (count > 0) ? tuple_data[count - 1] : Data{};
|
||
}
|
||
Data top() const noexcept { return (count > 0) ? tuple_data[0] : Data{}; }
|
||
|
||
Data at(size_t i) const noexcept {
|
||
if (i >= count) return Data{};
|
||
return tuple_data[i];
|
||
}
|
||
|
||
void foreach (std::function<void(_Type1, _Type2, _Type3)> func) {
|
||
for (size_t i = 0; i < count; i++)
|
||
func(tuple_data[i].first, tuple_data[i].second, tuple_data[i].third);
|
||
}
|
||
|
||
void foreach (std::function<void(std::tuple<_Type1, _Type2, _Type3>)> func) {
|
||
for (size_t i = 0; i < count; i++)
|
||
func(std::make_tuple(tuple_data[i].first, tuple_data[i].second,
|
||
tuple_data[i].third));
|
||
}
|
||
|
||
[[nodiscard]] size_t size() const noexcept { return count; }
|
||
[[nodiscard]] bool empty() const noexcept { return count == 0; }
|
||
|
||
iterator begin() const noexcept { return iterator(tuple_data); }
|
||
iterator end() const noexcept { return iterator(tuple_data + count); }
|
||
|
||
explicit operator bool() const noexcept { return count > 0; }
|
||
bool operator!() const noexcept { return count == 0; }
|
||
|
||
bool operator==(const PureTuple &other) const noexcept {
|
||
if (this->count != other.count || this->capacity != other.capacity)
|
||
return false;
|
||
|
||
for (size_t i = 0; i < this->count; i++)
|
||
if (tuple_data[i] != other.tuple_data[i]) return false;
|
||
|
||
return true;
|
||
}
|
||
bool operator!=(const PureTuple &other) const noexcept {
|
||
return !(*this == other);
|
||
}
|
||
|
||
Data operator[](size_t i) const noexcept {
|
||
if (i >= count) return Data{};
|
||
return tuple_data[i];
|
||
}
|
||
explicit operator int() const noexcept { return count; }
|
||
|
||
PureTuple &operator=(const PureTuple &other) {
|
||
if (this != &other) {
|
||
delete[] tuple_data;
|
||
|
||
capacity = other.capacity;
|
||
count = other.count;
|
||
tuple_data = new Data[capacity];
|
||
|
||
std::copy(other.tuple_data, other.tuple_data + count, tuple_data);
|
||
}
|
||
|
||
return *this;
|
||
}
|
||
|
||
PureTuple &operator<<(const std::tuple<_Type1, _Type2, _Type3> &t) noexcept {
|
||
insert(t);
|
||
return *this;
|
||
}
|
||
|
||
friend PureTuple &operator>>(const std::tuple<_Type1, _Type2, _Type3> &t,
|
||
PureTuple &tuple) noexcept {
|
||
tuple.insert(t);
|
||
return tuple;
|
||
}
|
||
};
|
||
|
||
// Provides a capsule structure to store variable references and values.
|
||
template <typename _Type> class Capsule : public garbageCollector {
|
||
public:
|
||
_Type &value;
|
||
|
||
// The value to be stored is taken as a reference as an argument
|
||
explicit Capsule(_Type &value) noexcept : value(value) {}
|
||
|
||
// Set the value.
|
||
void set(const _Type &_value) noexcept { this->value = _value; }
|
||
void set(_Type &_value) noexcept { this->value = _value; }
|
||
|
||
// Get reference of the value.
|
||
_Type &get() noexcept { return this->value; }
|
||
const _Type &get() const noexcept { return this->value; }
|
||
|
||
// You can get the reference of the stored value in the input type (casting is
|
||
// required).
|
||
operator _Type &() noexcept { return this->value; }
|
||
operator const _Type &() const noexcept { return this->value; }
|
||
explicit operator _Type *() noexcept { return &this->value; }
|
||
|
||
// The value of another capsule is taken.
|
||
Capsule &operator=(const Capsule &other) noexcept {
|
||
this->value = other.value;
|
||
return *this;
|
||
}
|
||
|
||
// Assign another value.
|
||
Capsule &operator=(const _Type &_value) noexcept {
|
||
this->value = _value;
|
||
return *this;
|
||
}
|
||
|
||
// Check if this capsule and another capsule hold the same data.
|
||
bool operator==(const Capsule &other) const noexcept {
|
||
return this->value == other.value;
|
||
}
|
||
|
||
// Check if this capsule value and another capsule value hold the same data.
|
||
bool operator==(const _Type &_value) const noexcept {
|
||
return this->value == _value;
|
||
}
|
||
|
||
// Check that this capsule and another capsule do not hold the same data.
|
||
bool operator!=(const Capsule &other) const noexcept {
|
||
return !(*this == other);
|
||
}
|
||
|
||
// Check that this capsule value and another capsule value do not hold the
|
||
// same data.
|
||
bool operator!=(const _Type &_value) const noexcept {
|
||
return !(*this == _value);
|
||
}
|
||
|
||
// Check if the current held value is actually empty.
|
||
explicit operator bool() const noexcept { return this->value != _Type{}; }
|
||
|
||
// Check that the current held value is actually empty.
|
||
bool operator!() const noexcept { return this->value == _Type{}; }
|
||
|
||
// Change the value with the input operator.
|
||
friend Capsule &operator>>(const _Type &_value, Capsule &_capsule) noexcept {
|
||
_capsule.value = _value;
|
||
return _capsule;
|
||
}
|
||
|
||
// Get the reference of the value held.
|
||
_Type &operator()() noexcept { return value; }
|
||
const _Type &operator()() const noexcept { return value; }
|
||
|
||
// Set the value.
|
||
void operator()(const _Type &_value) noexcept { this->value = _value; }
|
||
};
|
||
|
||
namespace LoggingProperties {
|
||
extern std::string_view FILE, NAME;
|
||
extern bool PRINT, DISABLE;
|
||
|
||
void set(std::string_view name, std::string_view file);
|
||
void setProgramName(std::string_view name);
|
||
void setLogFile(std::string_view file);
|
||
|
||
template <int state> void setPrinting() {
|
||
if (state == 1 || state == 0) PRINT = state;
|
||
else PRINT = NO;
|
||
}
|
||
template <int state> void setLoggingState() {
|
||
if (state == 1 || state == 0) DISABLE = state;
|
||
else DISABLE = NO;
|
||
}
|
||
|
||
void reset();
|
||
} // namespace LoggingProperties
|
||
|
||
// -------------------------------
|
||
// Checkers - not throws Helper::Error
|
||
// -------------------------------
|
||
|
||
/**
|
||
* It is checked whether the user ID used is equivalent to AID_ROOT.
|
||
* See include/private/android_filesystem_config.h
|
||
*/
|
||
bool hasSuperUser();
|
||
|
||
/**
|
||
* It is checked whether the user ID used is equivalent to AID_SHELL.
|
||
* See include/private/android_filesystem_config.h
|
||
*/
|
||
bool hasAdbPermissions();
|
||
|
||
/**
|
||
* Checks whether the file/directory exists.
|
||
*/
|
||
bool isExists(std::string_view entry);
|
||
|
||
/**
|
||
* Checks whether the file exists.
|
||
*/
|
||
bool fileIsExists(std::string_view file);
|
||
|
||
/**
|
||
* Checks whether the directory exists.
|
||
*/
|
||
bool directoryIsExists(std::string_view directory);
|
||
|
||
/**
|
||
* Checks whether the link (symbolic or hard) exists.
|
||
*/
|
||
bool linkIsExists(std::string_view entry);
|
||
|
||
/**
|
||
* Checks if the entry is a symbolic link.
|
||
*/
|
||
bool isLink(std::string_view entry);
|
||
|
||
/**
|
||
* Checks if the entry is a symbolic link.
|
||
*/
|
||
bool isSymbolicLink(std::string_view entry);
|
||
|
||
/**
|
||
* Checks if the entry is a hard link.
|
||
*/
|
||
bool isHardLink(std::string_view entry);
|
||
|
||
/**
|
||
* Checks whether entry1 is linked to entry2.
|
||
*/
|
||
bool areLinked(std::string_view entry1, std::string_view entry2);
|
||
|
||
// -------------------------------
|
||
// File I/O - not throws Helper::Error
|
||
// -------------------------------
|
||
|
||
/**
|
||
* Writes given text into file.
|
||
* If file does not exist, it is automatically created.
|
||
* Returns true on success.
|
||
*/
|
||
bool writeFile(std::string_view file, std::string_view text);
|
||
|
||
/**
|
||
* Reads file content into string.
|
||
* On success returns file content.
|
||
* On error returns std::nullopt.
|
||
*/
|
||
std::optional<std::string> readFile(std::string_view file);
|
||
|
||
// -------------------------------
|
||
// Creators
|
||
// -------------------------------
|
||
|
||
/**
|
||
* Create directory.
|
||
*/
|
||
bool makeDirectory(std::string_view path);
|
||
|
||
/**
|
||
* Create recursive directory.
|
||
*/
|
||
bool makeRecursiveDirectory(std::string_view paths);
|
||
|
||
/**
|
||
* Create file.
|
||
*/
|
||
bool createFile(std::string_view path);
|
||
|
||
/**
|
||
* Symlink entry1 to entry2.
|
||
*/
|
||
bool createSymlink(std::string_view entry1, std::string_view entry2);
|
||
|
||
// -------------------------------
|
||
// Removers - not throws Helper::Error
|
||
// -------------------------------
|
||
|
||
/**
|
||
* Remove file or empty directory.
|
||
*/
|
||
bool eraseEntry(std::string_view entry);
|
||
|
||
/**
|
||
* Remove directory and all directory contents recursively.
|
||
*/
|
||
bool eraseDirectoryRecursive(std::string_view directory);
|
||
|
||
// -------------------------------
|
||
// Getters - not throws Helper::Error
|
||
// -------------------------------
|
||
|
||
/**
|
||
* Get file size.
|
||
*/
|
||
int64_t fileSize(std::string_view file);
|
||
|
||
/**
|
||
* Read symlinks.
|
||
*/
|
||
std::string readSymlink(std::string_view entry);
|
||
|
||
// -------------------------------
|
||
// SHA-256
|
||
// -------------------------------
|
||
|
||
/**
|
||
* Compare SHA-256 values SHA-256 of files.
|
||
* Throws Helper::Error on error occurred.
|
||
*/
|
||
bool sha256Compare(std::string_view file1, std::string_view file2);
|
||
|
||
/**
|
||
* Get SHA-256 of file.
|
||
* Throws Helper::Error on error occurred.
|
||
*/
|
||
std::optional<std::string> sha256Of(std::string_view path);
|
||
|
||
// -------------------------------
|
||
// Utilities - not throws Helper::Error
|
||
// -------------------------------
|
||
|
||
/**
|
||
* Copy file to dest.
|
||
*/
|
||
bool copyFile(std::string_view file, std::string_view dest);
|
||
|
||
/**
|
||
* Run shell command.
|
||
*/
|
||
bool runCommand(std::string_view cmd);
|
||
|
||
/**
|
||
* Shows message and asks for y/N from user.
|
||
*/
|
||
bool confirmPropt(std::string_view message);
|
||
|
||
/**
|
||
* Change file permissions.
|
||
*/
|
||
bool changeMode(std::string_view file, mode_t mode);
|
||
|
||
/**
|
||
* Change file owner (user ID and group ID).
|
||
*/
|
||
bool changeOwner(std::string_view file, uid_t uid, gid_t gid);
|
||
|
||
/**
|
||
* Get current working directory as string.
|
||
* Returns empty string on error.
|
||
*/
|
||
std::string currentWorkingDirectory();
|
||
|
||
/**
|
||
* Get current date as string (format: YYYY-MM-DD).
|
||
* Returns empty string on error.
|
||
*/
|
||
std::string currentDate();
|
||
|
||
/**
|
||
* Get current time as string (format: HH:MM:SS).
|
||
* Returns empty string on error.
|
||
*/
|
||
std::string currentTime();
|
||
|
||
/**
|
||
* Run shell command return output as string.
|
||
* Returns std::pair<std::string, int>.
|
||
*/
|
||
std::pair<std::string, int> runCommandWithOutput(std::string_view cmd);
|
||
|
||
/**
|
||
* Joins base path with relative path and returns result.
|
||
*/
|
||
std::string pathJoin(std::string base, std::string relative);
|
||
|
||
/**
|
||
* Get the filename part of given path.
|
||
*/
|
||
std::string pathBasename(std::string_view entry);
|
||
|
||
/**
|
||
* Get the directory part of given path.
|
||
*/
|
||
std::string pathDirname(std::string_view entry);
|
||
|
||
/**
|
||
* Get random offset depending on size and bufferSize.
|
||
*/
|
||
uint64_t getRandomOffset(uint64_t size, uint64_t bufferSize);
|
||
|
||
/**
|
||
* Convert input size to input multiple.
|
||
*/
|
||
int convertTo(uint64_t size, sizeCastTypes type);
|
||
|
||
/**
|
||
* Convert input multiple variable to string.
|
||
*/
|
||
std::string multipleToString(sizeCastTypes type);
|
||
|
||
/**
|
||
* Format it input and return as std::string.
|
||
*/
|
||
__attribute__((format(printf, 1, 2))) std::string format(const char *format,
|
||
...);
|
||
|
||
/**
|
||
* Convert input size to input multiple
|
||
*/
|
||
template <uint64_t size> int convertTo(const sizeCastTypes type) {
|
||
if (type == KB) return TO_KB(size);
|
||
if (type == MB) return TO_MB(size);
|
||
if (type == GB) return TO_GB(size);
|
||
return static_cast<int>(size);
|
||
}
|
||
|
||
// -------------------------------
|
||
// Android - not throws Helper::Error
|
||
// -------------------------------
|
||
#ifdef __ANDROID__
|
||
/**
|
||
* Get input property as string (for Android).
|
||
*/
|
||
std::string getProperty(std::string_view prop);
|
||
|
||
/**
|
||
* Reboot device to input mode (for Android).
|
||
*/
|
||
bool androidReboot(std::string_view arg);
|
||
#endif
|
||
|
||
/**
|
||
* Get libhelper library version string.
|
||
*/
|
||
std::string getLibVersion();
|
||
|
||
/**
|
||
* Open input path with flags and add to integrity list.
|
||
* And returns file descriptor.
|
||
*/
|
||
[[nodiscard]] int openAndAddToCloseList(const std::string_view &path,
|
||
garbageCollector &collector, int flags,
|
||
mode_t mode = 0000);
|
||
/**
|
||
* Open input path with flags and add to integrity list.
|
||
* And returns file pointer.
|
||
*/
|
||
[[nodiscard]] FILE *openAndAddToCloseList(const std::string_view &path,
|
||
garbageCollector &collector,
|
||
const char *mode);
|
||
/**
|
||
* Open input directory and add to integrity list.
|
||
* And returns directory pointer.
|
||
*/
|
||
[[nodiscard]] DIR *openAndAddToCloseList(const std::string_view &path,
|
||
garbageCollector &collector);
|
||
|
||
} // namespace Helper
|
||
|
||
#endif // #ifndef ONLY_HELPER_MACROS
|
||
|
||
#define HELPER "libhelper"
|
||
|
||
#define STYLE_RESET "\033[0m"
|
||
#define BOLD "\033[1m"
|
||
#define FAINT "\033[2m"
|
||
#define ITALIC "\033[3m"
|
||
#define UNDERLINE "\033[4m"
|
||
#define BLINC "\033[5m"
|
||
#define FAST_BLINC "\033[6m"
|
||
#define STRIKE_THROUGHT "\033[9m"
|
||
#define NO_UNDERLINE "\033[24m"
|
||
#define NO_BLINC "\033[25m"
|
||
#define RED "\033[31m"
|
||
#define GREEN "\033[32m"
|
||
#define YELLOW "\033[33m"
|
||
|
||
#ifndef NO_C_TYPE_HANDLERS
|
||
// ABORT(message), ex: ABORT("memory error!\n")
|
||
#define ABORT(msg) \
|
||
do { \
|
||
fprintf(stderr, "%s%sCRITICAL ERROR%s: %s\nAborting...\n", BOLD, RED, \
|
||
STYLE_RESET, msg); \
|
||
abort(); \
|
||
} while (0)
|
||
|
||
// ERROR(message, exit), ex: ERROR("an error occured.\n", 1)
|
||
#define ERROR(msg, code) \
|
||
do { \
|
||
fprintf(stderr, "%s%sERROR%s: %s", BOLD, RED, STYLE_RESET, msg); \
|
||
exit(code); \
|
||
} while (0)
|
||
|
||
// WARNING(message), ex: WARNING("using default setting.\n")
|
||
#define WARNING(msg) \
|
||
fprintf(stderr, "%s%sWARNING%s: %s", BOLD, YELLOW, STYLE_RESET, msg);
|
||
|
||
// INFO(message), ex: INFO("operation ended.\n")
|
||
#define INFO(msg) \
|
||
fprintf(stdout, "%s%sINFO%s: %s", BOLD, GREEN, STYLE_RESET, msg);
|
||
#endif // #ifndef NO_C_TYPE_HANDLERS
|
||
|
||
#define LOG(level) \
|
||
Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \
|
||
Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
|
||
#define LOGF(file, level) \
|
||
Helper::Logger(level, __func__, file, \
|
||
Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
|
||
#define LOGN(name, level) \
|
||
Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \
|
||
name, __FILE__, __LINE__)
|
||
#define LOGNF(name, file, level) \
|
||
Helper::Logger(level, file, name, __FILE__, __LINE__)
|
||
|
||
#define LOG_IF(level, condition) \
|
||
if (condition) \
|
||
Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \
|
||
Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
|
||
#define LOGF_IF(file, level, condition) \
|
||
if (condition) \
|
||
Helper::Logger(level, __func__, file, \
|
||
Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
|
||
#define LOGN_IF(name, level, condition) \
|
||
if (condition) \
|
||
Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \
|
||
name, __FILE__, __LINE__)
|
||
#define LOGNF_IF(name, file, level, condition) \
|
||
if (condition) Helper::Logger(level, __func__, file, name, __FILE__, __LINE__)
|
||
|
||
#ifdef ANDROID_BUILD
|
||
#define MKVERSION(name) \
|
||
char vinfo[512]; \
|
||
sprintf(vinfo, \
|
||
"%s 1.3.0\nCompiler: clang\n" \
|
||
"BuildFlags: -Wall;-Werror;-Wno-deprecated-declarations;-Os", \
|
||
name); \
|
||
return std::string(vinfo)
|
||
#else
|
||
#define MKVERSION(name) \
|
||
char vinfo[512]; \
|
||
sprintf(vinfo, \
|
||
"%s %s [%s %s]\nBuildType: %s\nCMakeVersion: %s\nCompilerVersion: " \
|
||
"%s\nBuildFlags: %s", \
|
||
name, BUILD_VERSION, BUILD_DATE, BUILD_TIME, BUILD_TYPE, \
|
||
BUILD_CMAKE_VERSION, BUILD_COMPILER_VERSION, BUILD_FLAGS); \
|
||
return std::string(vinfo)
|
||
#endif
|
||
|
||
#endif // #ifndef LIBHELPER_LIB_HPP
|