My C++ Lib
PS is completly in progress currently, so plese dont forget that and feel free to propose changes here!
The Libary can be found here.Source Code
#pragma once
// INFO if you find bugs in this libary, please send them
// to shadowdara74@gmail.com
// This Shadowdara Personal Library is a collection of utility
// functions and classes for various purposes, including
// configuration management, file loading, rendering, and string
// manipulation. It is designed to be used in conjunction with SDL2,
// OpenGL, and ImGui for creating graphical applications.
// for C++ 20
// LICENSE MIT for the libary
// and when using the libary in project which will be published,
// it would be cool if you could send an email to email down below,
// i want to see what you have created with it!
//
// shadowdara74@gmail.com
//
// CREDIT WHEN USING THIS LIB (COPY THE LINE DOWN BELOW)
/*
used shadowdara's C++ Lib by Shadowdara which is licensed under MIT
LICENSE
https://shadowdara.github.io/blog/my-cpp-lib-for-stuff/
*/
// PS SOME CREDITS WHICH I USED TO CREATE THE LIBARY
//
// https://stackoverflow.com/questions/13172158/c-split-string-by-line
#pragma region includes
// CPP Libs
#include <vector>
#include <string>
#include <algorithm>
#include <sstream>
#include <stdexcept>
#include <numeric>
#include <sstream>
#include <stdexcept>
#include <fstream>
#include <unordered_map>
#include <system_error>
// C Libs
#include <cstdint>
#include <cctype>
#include <cstdint>
#pragma endregion
#pragma region Macros
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#pragma endregion
#pragma region colors
// Header File with all ANSI Colors as Macros
// by Shadowdara
//
// licensed under Appache 2.0
//
// by
// https://github.com/ShadowDara/samengine
//
//
// More Infos
// https://shadowdara.github.io/docs#/cpplibs/ansicolors
#if USE_COLORS_AS_MACRO == 0
#if RM_ANSI_FROM_COLORNAME == 0
// Use as Raylib Macros
#define ANSI_END "\x1b[0m"
#define ANSI_BOLD "\x1b[1m"
#define ANSI_ITALIC "\x1b[3m"
#define ANSI_UNDERLINED "\x1b[4m"
#define ANSI_REVERSE_TEXT "\x1b[7m"
#define ANSI_NOT_UNDERLINED "\x1b[24m"
#define ANSI_POSITIVE_TEXT "\x1b[27m"
#define ANSI_BLACK "\x1b[30m"
#define ANSI_RED "\x1b[31m"
#define ANSI_GREEN "\x1b[32m"
#define ANSI_YELLOW "\x1b[33m"
#define ANSI_BLUE "\x1b[34m"
#define ANSI_PURPLE "\x1b[35m"
#define ANSI_CYAN "\x1b[36m"
#define ANSI_WHITE "\x1b[37m"
#define ANSI_BG_BLACK "\x1b[40m"
#define ANSI_BG_RED "\x1b[41m"
#define ANSI_BG_GREEN "\x1b[42m"
#define ANSI_BG_YELLOW "\x1b[43m"
#define ANSI_BG_BLUE "\x1b[44m"
#define ANSI_BG_PURPLE "\x1b[45m"
#define ANSI_BG_CYAN "\x1b[46m"
#define ANSI_BG_WHITE "\x1b[47m"
#define ANSI_BRIGHT_BLACK "\x1b[90m"
#define ANSI_BRIGHT_RED "\x1b[91m"
#define ANSI_BRIGHT_GREEM "\x1b[92m"
#define ANSI_BRIGHT_YELLOW "\x1b[93m"
#define ANSI_BRIGHT_BLUE "\x1b[94m"
#define ANSI_BRIGHT_PURPLE "\x1b[95m"
#define ANSI_BRIGHT_CYAN "\x1b[96m"
#define ANSI_BRIGHT_WHITE "\x1b[97m"
#define ANSI_BG_BRIGHT_BLACK "\x1b[100m"
#define ANSI_BG_BRIGHT_RED "\x1b[101m"
#define ANSI_BG_BRIGHT_GREEM "\x1b[102m"
#define ANSI_BG_BRIGHT_YELLOW "\x1b[103m"
#define ANSI_BG_BRIGHT_BLUE "\x1b[104m"
#define ANSI_BG_BRIGHT_PURPLE "\x1b[105m"
#define ANSI_BG_BRIGHT_CYAN "\x1b[106m"
#define ANSI_BG_BRIGHT_WHITE "\x1b[107m"
#else
// Use as Normal Macros
#define END "\x1b[0m"
#define BOLD "\x1b[1m"
#define ITALIC "\x1b[3m"
#define UNDERLINED "\x1b[4m"
#define REVERSE_TEXT "\x1b[7m"
#define NOT_UNDERLINED "\x1b[24m"
#define POSITIVE_TEXT "\x1b[27m"
#define BLACK "\x1b[30m"
#define RED "\x1b[31m"
#define GREEN "\x1b[32m"
#define YELLOW "\x1b[33m"
#define BLUE "\x1b[34m"
#define PURPLE "\x1b[35m"
#define CYAN "\x1b[36m"
#define WHITE "\x1b[37m"
#define BG_BLACK "\x1b[40m"
#define BG_RED "\x1b[41m"
#define BG_GREEN "\x1b[42m"
#define BG_YELLOW "\x1b[43m"
#define BG_BLUE "\x1b[44m"
#define BG_PURPLE "\x1b[45m"
#define BG_CYAN "\x1b[46m"
#define BG_WHITE "\x1b[47m"
#define BRIGHT_BLACK "\x1b[90m"
#define BRIGHT_RED "\x1b[91m"
#define BRIGHT_GREEM "\x1b[92m"
#define BRIGHT_YELLOW "\x1b[93m"
#define BRIGHT_BLUE "\x1b[94m"
#define BRIGHT_PURPLE "\x1b[95m"
#define BRIGHT_CYAN "\x1b[96m"
#define BRIGHT_WHITE "\x1b[97m"
#define BG_BRIGHT_BLACK "\x1b[100m"
#define BG_BRIGHT_RED "\x1b[101m"
#define BG_BRIGHT_GREEM "\x1b[102m"
#define BG_BRIGHT_YELLOW "\x1b[103m"
#define BG_BRIGHT_BLUE "\x1b[104m"
#define BG_BRIGHT_PURPLE "\x1b[105m"
#define BG_BRIGHT_CYAN "\x1b[106m"
#define BG_BRIGHT_WHITE "\x1b[107m"
#endif
// Use as const
#else
// Use as Const
#if RM_ANSI_FROM_COLORNAME == 1
// Use as Raylib Name Const
inline constexpr const char* ANSI_END = "\x1b[0m";
inline constexpr const char* ANSI_BOLD = "\x1b[1m";
inline constexpr const char* ANSI_ITALIC = "\x1b[3m";
inline constexpr const char* ANSI_UNDERLINED = "\x1b[4m";
inline constexpr const char* ANSI_REVERSE_TEXT = "\x1b[7m";
inline constexpr const char* ANSI_NOT_UNDERLINED = "\x1b[24m";
inline constexpr const char* ANSI_POSITIVE_TEXT = "\x1b[27m";
inline constexpr const char* ANSI_BLACK = "\x1b[30m";
inline constexpr const char* ANSI_RED = "\x1b[31m";
inline constexpr const char* ANSI_GREEN = "\x1b[32m";
inline constexpr const char* ANSI_YELLOW = "\x1b[33m";
inline constexpr const char* ANSI_BLUE = "\x1b[34m";
inline constexpr const char* ANSI_PURPLE = "\x1b[35m";
inline constexpr const char* ANSI_CYAN = "\x1b[36m";
inline constexpr const char* ANSI_WHITE = "\x1b[37m";
inline constexpr const char* ANSI_BG_BLACK = "\x1b[40m";
inline constexpr const char* ANSI_BG_RED = "\x1b[41m";
inline constexpr const char* ANSI_BG_GREEN = "\x1b[42m";
inline constexpr const char* ANSI_BG_YELLOW = "\x1b[43m";
inline constexpr const char* ANSI_BG_BLUE = "\x1b[44m";
inline constexpr const char* ANSI_BG_PURPLE = "\x1b[45m";
inline constexpr const char* ANSI_BG_CYAN = "\x1b[46m";
inline constexpr const char* ANSI_BG_WHITE = "\x1b[47m";
inline constexpr const char* ANSI_BRIGHT_BLACK = "\x1b[90m";
inline constexpr const char* ANSI_BRIGHT_RED = "\x1b[91m";
inline constexpr const char* ANSI_BRIGHT_GREEN = "\x1b[92m";
inline constexpr const char* ANSI_BRIGHT_YELLOW = "\x1b[93m";
inline constexpr const char* ANSI_BRIGHT_BLUE = "\x1b[94m";
inline constexpr const char* ANSI_BRIGHT_PURPLE = "\x1b[95m";
inline constexpr const char* ANSI_BRIGHT_CYAN = "\x1b[96m";
inline constexpr const char* ANSI_BRIGHT_WHITE = "\x1b[97m";
inline constexpr const char* ANSI_BG_BRIGHT_BLACK = "\x1b[100m";
inline constexpr const char* ANSI_BG_BRIGHT_RED = "\x1b[101m";
inline constexpr const char* ANSI_BG_BRIGHT_GREEN = "\x1b[102m";
inline constexpr const char* ANSI_BG_BRIGHT_YELLOW = "\x1b[103m";
inline constexpr const char* ANSI_BG_BRIGHT_BLUE = "\x1b[104m";
inline constexpr const char* ANSI_BG_BRIGHT_PURPLE = "\x1b[105m";
inline constexpr const char* ANSI_BG_BRIGHT_CYAN = "\x1b[106m";
inline constexpr const char* ANSI_BG_BRIGHT_WHITE = "\x1b[107m";
#else
// Use as Normal name Const
inline constexpr const char* END = "\x1b[0m";
inline constexpr const char* OLD = "\x1b[1m";
inline constexpr const char* ITALIC = "\x1b[3m";
inline constexpr const char* UNDERLINED = "\x1b[4m";
inline constexpr const char* REVERSE_TEXT = "\x1b[7m";
inline constexpr const char* NOT_UNDERLINED = "\x1b[24m";
inline constexpr const char* POSITIVE_TEXT = "\x1b[27m";
inline constexpr const char* BLACK = "\x1b[30m";
inline constexpr const char* RED = "\x1b[31m";
inline constexpr const char* GREEN = "\x1b[32m";
inline constexpr const char* YELLOW = "\x1b[33m";
inline constexpr const char* BLUE = "\x1b[34m";
inline constexpr const char* PURPLE = "\x1b[35m";
inline constexpr const char* CYAN = "\x1b[36m";
inline constexpr const char* WHITE = "\x1b[37m";
inline constexpr const char* BG_BLACK = "\x1b[40m";
inline constexpr const char* BG_RED = "\x1b[41m";
inline constexpr const char* BG_GREEN = "\x1b[42m";
inline constexpr const char* BG_YELLOW = "\x1b[43m";
inline constexpr const char* BG_BLUE = "\x1b[44m";
inline constexpr const char* BG_PURPLE = "\x1b[45m";
inline constexpr const char* BG_CYAN = "\x1b[46m";
inline constexpr const char* BG_WHITE = "\x1b[47m";
inline constexpr const char* BRIGHT_BLACK = "\x1b[90m";
inline constexpr const char* BRIGHT_RED = "\x1b[91m";
inline constexpr const char* BRIGHT_GREEN = "\x1b[92m";
inline constexpr const char* BRIGHT_YELLOW = "\x1b[93m";
inline constexpr const char* BRIGHT_BLUE = "\x1b[94m";
inline constexpr const char* BRIGHT_PURPLE = "\x1b[95m";
inline constexpr const char* BRIGHT_CYAN = "\x1b[96m";
inline constexpr const char* BRIGHT_WHITE = "\x1b[97m";
inline constexpr const char* BG_BRIGHT_BLACK = "\x1b[100m";
inline constexpr const char* BG_BRIGHT_RED = "\x1b[101m";
inline constexpr const char* BG_BRIGHT_GREEN = "\x1b[102m";
inline constexpr const char* BG_BRIGHT_YELLOW = "\x1b[103m";
inline constexpr const char* BG_BRIGHT_BLUE = "\x1b[104m";
inline constexpr const char* BG_BRIGHT_PURPLE = "\x1b[105m";
inline constexpr const char* BG_BRIGHT_CYAN = "\x1b[106m";
inline constexpr const char* BG_BRIGHT_WHITE = "\x1b[107m";
#endif
#endif
#pragma endregion
#pragma region sorting
// bublsort algorithm, which is a simple sorting algorithm that
// repeatedly steps through the list, compares adjacent elements
// and swaps them if they are in the wrong order. The pass through
// the list is repeated until no swaps are needed, which means the
// list is sorted.
/*
// Example usage:
std::vector<int> values = { 5, 2, 8, 1, 3 };
bubblesort(values, [](int a, int b)
{
return a < b;
});
*/
template <typename T, typename Compare>
inline void bubblesort(std::vector<T>& values, Compare comp)
{
bool swapped;
do
{
swapped = false;
for (size_t i = 0; i + 1 < values.size(); ++i)
{
if (comp(values[i + 1], values[i]))
{
std::swap(values[i], values[i + 1]);
swapped = true;
}
}
} while (swapped);
}
#pragma endregion
#pragma region strings
// string_utils.hpp
// Header-only C++ Bibliothek mit String-Manipulationsfunktionen,
// wie man sie aus Python, JavaScript, Java etc. kennt.
//
// Einfach includieren:
// #include "string_utils.hpp"
// using namespace strutil;
//
// Alle Funktionen sind als `inline` markiert -> keine ODR-Probleme
// beim Einbinden in mehrere �bersetzungseinheiten.
namespace strutil {
// ---------------------------------------------------------------------
// Trimming / Whitespace (Python: strip, lstrip, rstrip)
// ---------------------------------------------------------------------
inline std::string lstrip(const std::string& s) {
size_t start = 0;
while (start < s.size() && std::isspace(static_cast<unsigned char>(s[start])))
++start;
return s.substr(start);
}
inline std::string rstrip(const std::string& s) {
size_t end = s.size();
while (end > 0 && std::isspace(static_cast<unsigned char>(s[end - 1])))
--end;
return s.substr(0, end);
}
inline std::string strip(const std::string& s) {
return lstrip(rstrip(s));
}
// Variante mit eigenem Zeichensatz, der entfernt werden soll (wie Python's strip(chars))
inline std::string strip(const std::string& s, const std::string& chars) {
size_t start = s.find_first_not_of(chars);
if (start == std::string::npos) return "";
size_t end = s.find_last_not_of(chars);
return s.substr(start, end - start + 1);
}
// ---------------------------------------------------------------------
// Gro�-/Kleinschreibung (Python: upper, lower, title, capitalize, swapcase)
// ---------------------------------------------------------------------
inline std::string to_upper(std::string s) {
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c) { return std::toupper(c); });
return s;
}
inline std::string to_lower(std::string s) {
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c) { return std::tolower(c); });
return s;
}
inline std::string capitalize(std::string s) {
if (!s.empty()) {
s[0] = static_cast<char>(std::toupper(static_cast<unsigned char>(s[0])));
for (size_t i = 1; i < s.size(); ++i)
s[i] = static_cast<char>(std::tolower(static_cast<unsigned char>(s[i])));
}
return s;
}
inline std::string title(const std::string& s) {
std::string result = s;
bool new_word = true;
for (auto& c : result) {
if (std::isalpha(static_cast<unsigned char>(c))) {
c = new_word ? std::toupper(static_cast<unsigned char>(c))
: std::tolower(static_cast<unsigned char>(c));
new_word = false;
}
else {
new_word = true;
}
}
return result;
}
inline std::string swapcase(std::string s) {
for (auto& c : s) {
if (std::isupper(static_cast<unsigned char>(c)))
c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
else if (std::islower(static_cast<unsigned char>(c)))
c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
}
return s;
}
// ---------------------------------------------------------------------
// Pr�fen / Suchen (Python: startswith, endswith, contains/in, count, find)
// ---------------------------------------------------------------------
inline bool starts_with(const std::string& s, const std::string& prefix) {
return s.size() >= prefix.size() &&
s.compare(0, prefix.size(), prefix) == 0;
}
inline bool ends_with(const std::string& s, const std::string& suffix) {
return s.size() >= suffix.size() &&
s.compare(s.size() - suffix.size(), suffix.size(), suffix) == 0;
}
inline bool contains(const std::string& s, const std::string& needle) {
return s.find(needle) != std::string::npos;
}
inline size_t count(const std::string& s, const std::string& sub) {
if (sub.empty()) return 0;
size_t cnt = 0, pos = 0;
while ((pos = s.find(sub, pos)) != std::string::npos) {
++cnt;
pos += sub.size();
}
return cnt;
}
// ---------------------------------------------------------------------
// is*-Pr�fungen (Python: isdigit, isalpha, isalnum, isspace, isupper, islower)
// ---------------------------------------------------------------------
inline bool is_digit(const std::string& s) {
if (s.empty()) return false;
return std::all_of(s.begin(), s.end(),
[](unsigned char c) { return std::isdigit(c); });
}
inline bool is_alpha(const std::string& s) {
if (s.empty()) return false;
return std::all_of(s.begin(), s.end(),
[](unsigned char c) { return std::isalpha(c); });
}
inline bool is_alnum(const std::string& s) {
if (s.empty()) return false;
return std::all_of(s.begin(), s.end(),
[](unsigned char c) { return std::isalnum(c); });
}
inline bool is_space(const std::string& s) {
if (s.empty()) return false;
return std::all_of(s.begin(), s.end(),
[](unsigned char c) { return std::isspace(c); });
}
inline bool is_upper(const std::string& s) {
bool has_alpha = false;
for (unsigned char c : s) {
if (std::isalpha(c)) {
has_alpha = true;
if (!std::isupper(c)) return false;
}
}
return has_alpha;
}
inline bool is_lower(const std::string& s) {
bool has_alpha = false;
for (unsigned char c : s) {
if (std::isalpha(c)) {
has_alpha = true;
if (!std::islower(c)) return false;
}
}
return has_alpha;
}
// ---------------------------------------------------------------------
// Split / Join (Python: split, rsplit, splitlines, join)
// ---------------------------------------------------------------------
// Split an jedem beliebigen Zeichen aus `delims` (Standard: Whitespace),
// analog zu Python's str.split() ohne Argument (mehrfache Trenner werden zusammengefasst)
inline std::vector<std::string> split(const std::string& s, const std::string& delims = " \t\n\r\f\v") {
std::vector<std::string> tokens;
size_t start = s.find_first_not_of(delims);
while (start != std::string::npos) {
size_t end = s.find_first_of(delims, start);
tokens.push_back(s.substr(start, end - start));
start = (end == std::string::npos) ? std::string::npos : s.find_first_not_of(delims, end);
}
return tokens;
}
// Split an einem festen String-Trenner (wie Python's str.split(sep))
inline std::vector<std::string> split_by(const std::string& s, const std::string& sep) {
if (sep.empty()) throw std::invalid_argument("split_by: separator darf nicht leer sein");
std::vector<std::string> tokens;
size_t start = 0, pos;
while ((pos = s.find(sep, start)) != std::string::npos) {
tokens.push_back(s.substr(start, pos - start));
start = pos + sep.size();
}
tokens.push_back(s.substr(start));
return tokens;
}
inline std::vector<std::string> splitlines(const std::string& s) {
std::vector<std::string> lines;
std::istringstream iss(s);
std::string line;
while (std::getline(iss, line)) {
if (!line.empty() && line.back() == '\r') line.pop_back();
lines.push_back(line);
}
return lines;
}
inline std::string join(const std::vector<std::string>& parts, const std::string& sep) {
std::string result;
for (size_t i = 0; i < parts.size(); ++i) {
if (i) result += sep;
result += parts[i];
}
return result;
}
// ---------------------------------------------------------------------
// Ersetzen (Python: replace)
// ---------------------------------------------------------------------
inline std::string replace(const std::string& s, const std::string& from,
const std::string& to, int max_count = -1) {
if (from.empty()) return s;
std::string result;
size_t start = 0, pos;
int replaced = 0;
while ((pos = s.find(from, start)) != std::string::npos) {
if (max_count >= 0 && replaced >= max_count) break;
result.append(s, start, pos - start);
result += to;
start = pos + from.size();
++replaced;
}
result.append(s, start, std::string::npos);
return result;
}
// ---------------------------------------------------------------------
// Padding / Ausrichtung (Python: ljust, rjust, center, zfill)
// ---------------------------------------------------------------------
inline std::string ljust(const std::string& s, size_t width, char fill = ' ') {
if (s.size() >= width) return s;
return s + std::string(width - s.size(), fill);
}
inline std::string rjust(const std::string& s, size_t width, char fill = ' ') {
if (s.size() >= width) return s;
return std::string(width - s.size(), fill) + s;
}
inline std::string center(const std::string& s, size_t width, char fill = ' ') {
if (s.size() >= width) return s;
size_t total_pad = width - s.size();
size_t left = total_pad / 2;
size_t right = total_pad - left;
return std::string(left, fill) + s + std::string(right, fill);
}
inline std::string zfill(const std::string& s, size_t width) {
if (s.size() >= width) return s;
bool has_sign = !s.empty() && (s[0] == '+' || s[0] == '-');
std::string sign = has_sign ? std::string(1, s[0]) : "";
std::string rest = has_sign ? s.substr(1) : s;
size_t pad = width - s.size();
return sign + std::string(pad, '0') + rest;
}
// ---------------------------------------------------------------------
// Sonstiges (Python: str * n, reversed(str), removeprefix, removesuffix)
// ---------------------------------------------------------------------
inline std::string repeat(const std::string& s, size_t n) {
std::string result;
result.reserve(s.size() * n);
for (size_t i = 0; i < n; ++i) result += s;
return result;
}
inline std::string reverse(std::string s) {
std::reverse(s.begin(), s.end());
return s;
}
// Python 3.9+: removeprefix / removesuffix
inline std::string remove_prefix(const std::string& s, const std::string& prefix) {
return starts_with(s, prefix) ? s.substr(prefix.size()) : s;
}
inline std::string remove_suffix(const std::string& s, const std::string& suffix) {
return ends_with(s, suffix) ? s.substr(0, s.size() - suffix.size()) : s;
}
// Wie Java/JS Array.prototype.slice bzw. Python's s[start:end]
inline std::string slice(const std::string& s, int start, int end) {
int len = static_cast<int>(s.size());
if (start < 0) start += len;
if (end < 0) end += len;
start = std::max(0, std::min(start, static_cast<int>(len)));
end = std::max(0, std::min(end, static_cast<int>(len)));
if (start >= end) return "";
return s.substr(start, end - start);
}
} // namespace strutil
#pragma endregion
#pragma region Version
struct Version
{
int major = 0;
int minor = 0;
int patch = 0;
// to compare the versions
auto operator<=>(const Version&) const = default;
};
inline Version parseVersion(const std::string& versionStr)
{
Version version;
std::stringstream ss(versionStr);
std::string part;
std::vector<int> numbers;
while (std::getline(ss, part, '.'))
{
numbers.push_back(std::stoi(part));
}
if (numbers.size() != 3)
throw std::invalid_argument("Invalid version format. Expected MAJOR.MINOR.PATCH");
version.major = numbers[0];
version.minor = numbers[1];
version.patch = numbers[2];
return version;
}
#pragma endregion
#pragma region Nana UI
// Enable with the Macros
// #define SHADOWDARA_LIB_NANA_UI
#ifdef SHADOWDARA_LIB_NANA_UI
#include <nana/gui.hpp>
#include <nana/gui/widgets/label.hpp>
#include <nana/gui/widgets/button.hpp>
#include <nana/gui/widgets/slider.hpp>
#include <nana/gui/widgets/combox.hpp>
#include <nana/gui/widgets/checkbox.hpp>
#include <nana/gui/widgets/textbox.hpp>
#include <nana/gui/widgets/progress.hpp>
#include <nana/gui/widgets/panel.hpp>
namespace shadowdara::nana_ui {
inline void create_nana_button(
nana::button& button,
const std::string& name,
int desX,
int desY,
unsigned sizeX,
unsigned sizeY)
{
button.caption(name);
button.move({ desX, desY });
button.size({ sizeX, sizeY });
}
#define NANA_ON_CLICK(button, code) \
(button).events().click([&]() code );
// Easy Size, MOve
#define NANA_SIMO(object, movX, movY, sizeX, sizeY) \
object.move( { movX, movY }); \
object.size({ sizeX, sizeY });;
} // shadowdara::nana_ui
#endif
#pragma endregion
#pragma region Process
#ifdef _WIN32
#define NOMINMAX
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
inline int runProcess(
const std::string& executable,
const std::vector<std::string>& args)
{
#ifdef _WIN32
// ------------------------------------------------------------
// Windows - Unicode / UTF-16
// ------------------------------------------------------------
// UTF-8 -> UTF-16
auto utf8ToWide = [](const std::string& str) -> std::wstring
{
if (str.empty())
return {};
int size = MultiByteToWideChar(
CP_UTF8,
0,
str.data(),
static_cast<int>(str.size()),
nullptr,
0
);
if (size <= 0)
return {};
std::wstring result(size, L'\0');
MultiByteToWideChar(
CP_UTF8,
0,
str.data(),
static_cast<int>(str.size()),
result.data(),
size
);
return result;
};
std::wstring wideExecutable = utf8ToWide(executable);
std::wstring commandLine = L"\"" + wideExecutable + L"\"";
for (const auto& arg : args)
{
std::wstring wideArg = utf8ToWide(arg);
commandLine += L" \"";
// Minimal escaping für Windows command line arguments.
for (wchar_t c : wideArg)
{
if (c == L'"')
commandLine += L"\\\"";
else
commandLine += c;
}
commandLine += L"\"";
}
STARTUPINFOW startupInfo{};
startupInfo.cb = sizeof(startupInfo);
PROCESS_INFORMATION processInfo{};
std::vector<wchar_t> commandLineBuffer(
commandLine.begin(),
commandLine.end()
);
commandLineBuffer.push_back(L'\0');
BOOL success = CreateProcessW(
nullptr,
commandLineBuffer.data(),
nullptr,
nullptr,
FALSE,
0,
nullptr,
nullptr,
&startupInfo,
&processInfo
);
if (!success)
return -1;
WaitForSingleObject(
processInfo.hProcess,
INFINITE
);
DWORD exitCode = 0;
GetExitCodeProcess(
processInfo.hProcess,
&exitCode
);
CloseHandle(processInfo.hThread);
CloseHandle(processInfo.hProcess);
return static_cast<int>(exitCode);
#else
// ------------------------------------------------------------
// Linux / macOS
// ------------------------------------------------------------
pid_t pid = fork();
if (pid < 0)
return -1;
if (pid == 0)
{
std::vector<char*> argv;
argv.push_back(
const_cast<char*>(executable.c_str())
);
for (const auto& arg : args)
{
argv.push_back(
const_cast<char*>(arg.c_str())
);
}
argv.push_back(nullptr);
execvp(
executable.c_str(),
argv.data()
);
_exit(127);
}
int status = 0;
if (waitpid(pid, &status, 0) < 0)
return -1;
if (WIFEXITED(status))
return WEXITSTATUS(status);
if (WIFSIGNALED(status))
return 128 + WTERMSIG(status);
return -1;
#endif
}
// WIndows only function
inline void enable_utf8() {
#if _WIN32
// that ansi codes work
SetConsoleOutputCP(CP_UTF8);
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode = 0;
if (GetConsoleMode(hOut, &mode))
{
SetConsoleMode(hOut, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
}
#endif
}
// open a file
inline void openFile(const std::string& path)
{
#ifdef _WIN32
ShellExecuteA(NULL, "open", path.c_str(), NULL, NULL, SW_SHOW);
#elif __APPLE__
std::string command = "open \"" + path + "\"";
system(command.c_str());
#elif __linux__
std::string command = "xdg-open \"" + path + "\"";
system(command.c_str());
#endif
}
inline std::string loadFile(const std::string& pfad)
{
std::ifstream datei(pfad);
if (!datei)
return "";
std::stringstream buffer;
buffer << datei.rdbuf();
return buffer.str();
}
#pragma endregion
#pragma region ArgParser
class ArgParser {
private:
std::unordered_map<std::string, std::string> options;
std::vector<std::string> args;
public:
inline ArgParser(int argc, char* argv[])
{
for (int i = 1; i < argc; i++) {
std::string arg = argv[i];
// Option mit Wert: --name Bob
if (arg.rfind("--", 0) == 0 || arg.rfind("-", 0) == 0) {
if (i + 1 < argc && argv[i + 1][0] != '-') {
options[arg] = argv[++i];
}
else {
// Flag ohne Wert
options[arg] = "true";
}
}
else {
args.push_back(arg);
}
}
}
inline bool has(const std::string& option)
{
return options.find(option) != options.end();
}
inline std::string get(const std::string& option,
const std::string& defaultValue = "")
{
if (has(option))
return options[option];
return defaultValue;
}
inline bool getBool(const std::string& option)
{
return get(option) == "true";
}
inline std::vector<std::string> positional()
{
return args;
}
};
#pragma endregion
#pragma region splitter
// Get the section of a file with a start and an end point
// the function returns an empty string when the endpoint
// is missing
inline std::string getSection(std::string content, std::string start, std::string end)
{
std::stringstream ss(content);
std::string to;
std::string result;
bool collect = false;
while(std::getline(ss, to, '\n'))
{
// Collect the string
if (collect)
{
result += to;
}
if (to == start)
{
collect = true;
}
if (to == end)
{
return result;
}
}
return "";
}
#pragma endregion
#pragma region base64
inline static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
inline std::string base64_encode(const std::string& input) {
std::string output;
int val = 0;
int bits = -6;
for (unsigned char c : input) {
val = (val << 8) + c;
bits += 8;
while (bits >= 0) {
output += base64_chars[(val >> bits) & 0x3F];
bits -= 6;
}
}
if (bits > -6)
output += base64_chars[((val << 8) >> (bits + 8)) & 0x3F];
while (output.size() % 4)
output += '=';
return output;
}
inline std::string base64_decode(const std::string& input) {
std::vector<int> lookup(256, -1);
for (int i = 0; i < 64; ++i)
lookup[static_cast<unsigned char>(base64_chars[i])] = i;
std::string output;
int val = 0;
int bits = -8;
for (unsigned char c : input) {
if (lookup[c] == -1)
break;
val = (val << 6) + lookup[c];
bits += 6;
if (bits >= 0) {
output += static_cast<char>((val >> bits) & 0xFF);
bits -= 8;
}
}
return output;
}
#pragma endregion
#pragma region Char Count
inline std::unordered_map<char, int> counter(std::string input)
{
std::unordered_map<char, int> map;
for (char c : input)
{
map[c] += 1;
}
return map;
}
inline void printresult(std::unordered_map<char, int> map)
{
for (const auto& pair : map)
{
std::cout << pair.first << " -> " << pair.second << "\n";
}
}
#pragma endregion
#pragma region Bitpacking
#define BIT_SET(v, b) ((v) |= (uint8_t(1u) << (b)))
#define BIT_CLEAR(v, b) ((v) &= ~(uint8_t(1u) << (b)))
#define BIT_READ(v, b) (((v) >> (b)) & 1u)
#define BIT_SWAP(v, b) ((v) ^= (uint8_t(1u) << (b)))
#pragma endregion
#pragma region Terminal Markdown
// Terminal Markdown is Libary to make a syntax style similiar to markdown
// but with the ansi colors codes too.
//
// for example the text will be printed in the terminal default color,
// except red, which will be printed in red!
/*
hello, this text is [red]red[/red]
*/
inline std::string parseTerminalMarkdown(std::string input)
{}
inline std::string parseTerminalMarkdowntoMarkdown()
{}
#pragma endregion
inline std::string getHomeDir()
{
// -------------------------
// 1. HOME-Verzeichnis finden
// -------------------------
std::string home;
#if defined(_WIN32)
const char* env = std::getenv("USERPROFILE");
if (!env) env = std::getenv("HOMEPATH");
if (!env) env = std::getenv("HOME"); // falls unter MSYS/MinGW
if (!env) return {};
home = env;
// Backslashes → Slashes normalisieren
for (char& c : home)
if (c == '\\') c = '/';
#elif defined(__APPLE__) || defined(__linux__)
const char* env = std::getenv("HOME");
if (!env) return {};
home = env;
#else
#error Unsupported platform
#endif
// -------------------------
// 2. ".config"-Ordner anhängen
// -------------------------
// trailing slash entfernen
while (!home.empty() && (home.back() == '/' || home.back() == '\\'))
home.pop_back();
return home;
}
#pragma region Data
inline std::string escapeNewline(std::string input)
{
std::string result;
result.reserve(input.size());
for (char c : input)
{
if (c == '\n')
{
result += "\\n";
}
else
{
result += c;
}
}
return result;
}
inline std::string unescapeNewline(std::string input)
{
std::string result;
result.reserve(input.size());
for (size_t i = 0; i < input.size(); ++i)
{
if (input[i] == '\\' && i + 1 < input.size() && input[i + 1] == 'n')
{
result += '\n';
++i; // 'n' überspringen
}
else
{
result += input[i];
}
}
return result;
}
#pragma endregion
std::int64_t getEditTime(const std::filesystem::path& path)
{
std::error_code ec;
auto fileTime = std::filesystem::last_write_time(path, ec);
if (ec)
return 0;
auto systemTime =
std::chrono::time_point_cast<std::chrono::system_clock::duration>(
fileTime - std::filesystem::file_time_type::clock::now()
+ std::chrono::system_clock::now()
);
return std::chrono::duration_cast<std::chrono::seconds>(
systemTime.time_since_epoch()
).count();
}
// END of shadowdaras LIB