mirror of
https://github.com/aristocratos/btop.git
synced 2024-06-17 09:54:57 +12:00
Added config file loader
This commit is contained in:
parent
63a286d6a1
commit
c4b55c7dfd
35
btop.cpp
35
btop.cpp
|
@ -256,8 +256,19 @@ int main(int argc, char **argv){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Global::debug = true;
|
//? Read config file if present
|
||||||
if (Global::debug) { Logger::loglevel = 4; Logger::debug("Starting in debug mode");}
|
{ vector<string> load_errors;
|
||||||
|
Config::load(Config::conf_file, load_errors);
|
||||||
|
|
||||||
|
if (Global::debug) Logger::loglevel = 4;
|
||||||
|
else Logger::loglevel = v_index(Logger::log_levels, Config::getS("log_level"));
|
||||||
|
|
||||||
|
if (Logger::loglevel == 4) Logger::debug("Starting with logger set to debug.");
|
||||||
|
|
||||||
|
if (!load_errors.empty()) {
|
||||||
|
for (auto& err_str : load_errors) Logger::error(err_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!string(getenv("LANG")).ends_with("UTF-8") && !string(getenv("LANG")).ends_with("utf-8")) {
|
if (!string(getenv("LANG")).ends_with("UTF-8") && !string(getenv("LANG")).ends_with("utf-8")) {
|
||||||
string err_msg = "No UTF-8 locale was detected! Symbols might not look as intended.\n"
|
string err_msg = "No UTF-8 locale was detected! Symbols might not look as intended.\n"
|
||||||
|
@ -279,8 +290,7 @@ int main(int argc, char **argv){
|
||||||
Proc::init();
|
Proc::init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//? Read config file if present
|
|
||||||
Config::load();
|
|
||||||
// Config::set("truecolor", false);
|
// Config::set("truecolor", false);
|
||||||
|
|
||||||
auto thts = time_ms();
|
auto thts = time_ms();
|
||||||
|
@ -433,6 +443,23 @@ int main(int argc, char **argv){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (false) {
|
||||||
|
cout << Config::getS("log_level") << endl;
|
||||||
|
|
||||||
|
vector<string> vv = {"hej", "vad", "du"};
|
||||||
|
vector<int> vy;
|
||||||
|
|
||||||
|
cout << v_contains(vv, "vad"s) << endl;
|
||||||
|
cout << v_index(vv, "hej"s) << endl;
|
||||||
|
cout << v_index(vv, "du"s) << endl;
|
||||||
|
cout << v_index(vv, "kodkod"s) << endl;
|
||||||
|
cout << v_index(vy, 4) << endl;
|
||||||
|
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// if (thread_test){
|
// if (thread_test){
|
||||||
|
|
||||||
// unordered_flat_map<int, future<string>> runners;
|
// unordered_flat_map<int, future<string>> runners;
|
||||||
|
|
|
@ -41,7 +41,7 @@ namespace Config {
|
||||||
|
|
||||||
atomic<bool> locked (false);
|
atomic<bool> locked (false);
|
||||||
atomic<bool> writelock (false);
|
atomic<bool> writelock (false);
|
||||||
bool changed;
|
bool write_new;
|
||||||
|
|
||||||
vector<array<string, 2>> descriptions = {
|
vector<array<string, 2>> descriptions = {
|
||||||
{"color_theme", "#* Color theme, looks for a .theme file in \"/usr/[local/]share/bpytop/themes\" and \"~/.config/bpytop/themes\", \"Default\" for builtin default theme.\n"
|
{"color_theme", "#* Color theme, looks for a .theme file in \"/usr/[local/]share/bpytop/themes\" and \"~/.config/bpytop/themes\", \"Default\" for builtin default theme.\n"
|
||||||
|
@ -160,7 +160,7 @@ namespace Config {
|
||||||
|
|
||||||
bool _locked(){
|
bool _locked(){
|
||||||
atomic_wait(writelock);
|
atomic_wait(writelock);
|
||||||
if (!changed) changed = true;
|
if (!write_new) write_new = true;
|
||||||
return locked.load();
|
return locked.load();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,14 +238,71 @@ namespace Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Load the config file from disk
|
//* Load the config file from disk
|
||||||
void load(){
|
void load(fs::path conf_file, vector<string>& load_errors){
|
||||||
if (conf_file.empty()) return;
|
if (conf_file.empty())
|
||||||
else if (!fs::exists(conf_file)) { changed = true; return; }
|
return;
|
||||||
|
else if (!fs::exists(conf_file)) {
|
||||||
|
write_new = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::ifstream cread(conf_file);
|
||||||
|
if (cread.good()) {
|
||||||
|
unordered_flat_map<string, int> valid_names;
|
||||||
|
for (auto &n : descriptions)
|
||||||
|
valid_names[n[0]] = 0;
|
||||||
|
string v_string;
|
||||||
|
getline(cread, v_string, '\n');
|
||||||
|
if (!v_string.ends_with(Global::Version))
|
||||||
|
write_new = true;
|
||||||
|
while (!cread.eof()) {
|
||||||
|
cread >> std::ws;
|
||||||
|
if (cread.peek() == '#') {
|
||||||
|
cread.ignore(SSmax, '\n');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
string name, value;
|
||||||
|
getline(cread, name, '=');
|
||||||
|
if (!valid_names.contains(name)) {
|
||||||
|
cread.ignore(SSmax, '\n');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bools.contains(name)) {
|
||||||
|
cread >> value;
|
||||||
|
if (!isbool(value))
|
||||||
|
load_errors.push_back("Got an invalid bool value for config name: " + name);
|
||||||
|
else
|
||||||
|
bools.at(name) = stobool(value);
|
||||||
|
}
|
||||||
|
else if (ints.contains(name)) {
|
||||||
|
cread >> value;
|
||||||
|
if (!isint(value))
|
||||||
|
load_errors.push_back("Got an invalid integer value for config name: " + name);
|
||||||
|
else
|
||||||
|
ints.at(name) = stoi(value);
|
||||||
|
}
|
||||||
|
else if (strings.contains(name)) {
|
||||||
|
cread >> std::ws;
|
||||||
|
if (cread.peek() == '"') {
|
||||||
|
cread.ignore(1);
|
||||||
|
getline(cread, value, '"');
|
||||||
|
}
|
||||||
|
else cread >> value;
|
||||||
|
|
||||||
|
if (name == "log_level" && !v_contains(Logger::log_levels, value)) load_errors.push_back("Invalid log_level: " + value);
|
||||||
|
else strings.at(name) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
cread.ignore(SSmax, '\n');
|
||||||
|
}
|
||||||
|
cread.close();
|
||||||
|
if (!load_errors.empty()) write_new = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Write the config file to disk
|
//* Write the config file to disk
|
||||||
void write(){
|
void write(){
|
||||||
if (conf_file.empty() || !changed) return;
|
if (conf_file.empty() || !write_new) return;
|
||||||
Logger::debug("Writing new config file");
|
Logger::debug("Writing new config file");
|
||||||
std::ofstream cwrite(conf_file, std::ios::trunc);
|
std::ofstream cwrite(conf_file, std::ios::trunc);
|
||||||
if (cwrite.good()) {
|
if (cwrite.good()) {
|
||||||
|
|
|
@ -193,14 +193,13 @@ namespace Draw {
|
||||||
int ai = 0;
|
int ai = 0;
|
||||||
for (auto value : {last, data_value}) {
|
for (auto value : {last, data_value}) {
|
||||||
if (value >= cur_high)
|
if (value >= cur_high)
|
||||||
result[ai] = 4;
|
result[ai++] = 4;
|
||||||
else if (value <= cur_low)
|
else if (value <= cur_low)
|
||||||
result[ai] = 0;
|
result[ai++] = 0;
|
||||||
else {
|
else {
|
||||||
result[ai] = round((float)(value - cur_low) * 4 / (cur_high - cur_low) + mod);
|
result[ai++] = round((float)(value - cur_low) * 4 / (cur_high - cur_low) + mod);
|
||||||
if (no_zero && horizon == height - 1 && i != -1 && result[ai] == 0) result[ai] = 1;
|
if (no_zero && horizon == height - 1 && i != -1 && result[ai] == 0) result[ai] = 1;
|
||||||
}
|
}
|
||||||
ai++;
|
|
||||||
}
|
}
|
||||||
//? Generate braille symbol from 5x5 2D vector
|
//? Generate braille symbol from 5x5 2D vector
|
||||||
graphs[current][horizon] += (height == 1 && result[0] + result[1] == 0) ? Mv::r(1) : graph_symbol[(result[0] * 5 + result[1])];
|
graphs[current][horizon] += (height == 1 && result[0] + result[1] == 0) ? Mv::r(1) : graph_symbol[(result[0] * 5 + result[1])];
|
||||||
|
@ -228,8 +227,10 @@ namespace Draw {
|
||||||
graphs[true].clear(); graphs[false].clear();
|
graphs[true].clear(); graphs[false].clear();
|
||||||
this->width = width; this->height = height;
|
this->width = width; this->height = height;
|
||||||
this->invert = invert; this->offset = offset;
|
this->invert = invert; this->offset = offset;
|
||||||
this->no_zero = no_zero; this->max_value = max_value;
|
this->no_zero = no_zero;
|
||||||
this->color_gradient = color_gradient;
|
this->color_gradient = color_gradient;
|
||||||
|
if (max_value == 0 && offset > 0) max_value = 100;
|
||||||
|
this->max_value = max_value;
|
||||||
int value_width = ceil((float)data.size() / 2);
|
int value_width = ceil((float)data.size() / 2);
|
||||||
int data_offset = 0;
|
int data_offset = 0;
|
||||||
if (value_width > width) data_offset = data.size() - width * 2;
|
if (value_width > width) data_offset = data.size() - width * 2;
|
||||||
|
@ -268,6 +269,7 @@ namespace Box {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Proc {
|
namespace Proc {
|
||||||
|
|
|
@ -90,10 +90,10 @@ namespace Input {
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Get a key or mouse action from input
|
//* Get a key or mouse action from input
|
||||||
string get(){
|
string get(bool clear = false){
|
||||||
string key;
|
string key;
|
||||||
while (cin.rdbuf()->in_avail() > 0 && key.size() < 100) key += cin.get();
|
while (cin.rdbuf()->in_avail() > 0 && key.size() < 100) key += cin.get();
|
||||||
if (!key.empty()){
|
if (!clear && !key.empty()){
|
||||||
if (key.substr(0,2) == Fx::e) key.erase(0, 1);
|
if (key.substr(0,2) == Fx::e) key.erase(0, 1);
|
||||||
if (Key_escapes.contains(key)) key = Key_escapes.at(key);
|
if (Key_escapes.contains(key)) key = Key_escapes.at(key);
|
||||||
else if (ulen(key) > 1) key = "";
|
else if (ulen(key) > 1) key = "";
|
||||||
|
@ -105,9 +105,10 @@ namespace Input {
|
||||||
//* Wait until input is available
|
//* Wait until input is available
|
||||||
void wait(bool clear=false){
|
void wait(bool clear=false){
|
||||||
while (cin.rdbuf()->in_avail() < 1) sleep_ms(10);
|
while (cin.rdbuf()->in_avail() < 1) sleep_ms(10);
|
||||||
if (clear) get();
|
if (clear) get(clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//* Clears last entered key
|
||||||
void clear(){
|
void clear(){
|
||||||
last.clear();
|
last.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,6 @@ using std::string, std::vector, std::array, std::ifstream, std::atomic, std::num
|
||||||
using std::cout, std::flush, std::endl;
|
using std::cout, std::flush, std::endl;
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
using namespace Tools;
|
using namespace Tools;
|
||||||
const auto SSmax = std::numeric_limits<streamsize>::max();
|
|
||||||
|
|
||||||
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
|
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
|
||||||
|
|
||||||
|
@ -63,6 +62,9 @@ namespace Proc {
|
||||||
struct p_cache {
|
struct p_cache {
|
||||||
string name, cmd, user;
|
string name, cmd, user;
|
||||||
uint64_t cpu_t = 0, cpu_s = 0;
|
uint64_t cpu_t = 0, cpu_s = 0;
|
||||||
|
string prefix = "";
|
||||||
|
size_t depth = 0;
|
||||||
|
bool collapsed = false;
|
||||||
};
|
};
|
||||||
unordered_flat_map<uint, p_cache> cache;
|
unordered_flat_map<uint, p_cache> cache;
|
||||||
unordered_flat_map<string, string> uid_user;
|
unordered_flat_map<string, string> uid_user;
|
||||||
|
@ -92,7 +94,7 @@ namespace Proc {
|
||||||
};
|
};
|
||||||
unordered_flat_map<string, int> sort_map;
|
unordered_flat_map<string, int> sort_map;
|
||||||
|
|
||||||
//* proc_info: pid, name, cmd, threads, user, mem, cpu_p, cpu_c, state, cpu_n, p_nice, ppid
|
//* Container for process information
|
||||||
struct proc_info {
|
struct proc_info {
|
||||||
uint pid;
|
uint pid;
|
||||||
string name = "", cmd = "";
|
string name = "", cmd = "";
|
||||||
|
@ -102,21 +104,25 @@ namespace Proc {
|
||||||
double cpu_p = 0.0, cpu_c = 0.0;
|
double cpu_p = 0.0, cpu_c = 0.0;
|
||||||
char state = '0';
|
char state = '0';
|
||||||
int cpu_n = 0, p_nice = 0;
|
int cpu_n = 0, p_nice = 0;
|
||||||
uint ppid = 0;
|
int ppid = -1;
|
||||||
|
string prefix = "";
|
||||||
};
|
};
|
||||||
|
|
||||||
vector<proc_info> current_procs;
|
vector<proc_info> current_procs;
|
||||||
|
|
||||||
|
|
||||||
//* Collects process information from /proc, saves to and returns reference to Proc::current_procs;
|
//* Collects and sorts process information from /proc, saves to and returns reference to Proc::current_procs;
|
||||||
auto& collect(string sorting="pid", bool reverse=false, string filter="", bool per_core=true){
|
auto& collect(string sorting="pid", bool reverse=false, string filter="", bool per_core=true, bool tree=false){
|
||||||
atomic_wait_set(collecting);
|
atomic_wait_set(collecting);
|
||||||
ifstream pread;
|
ifstream pread;
|
||||||
auto uptime = system_uptime();
|
auto uptime = system_uptime();
|
||||||
vector<proc_info> procs;
|
vector<proc_info> procs;
|
||||||
|
vector<uint> pid_list;
|
||||||
procs.reserve((numpids + 10));
|
procs.reserve((numpids + 10));
|
||||||
|
pid_list.reserve(numpids + 10);
|
||||||
int npids = 0;
|
int npids = 0;
|
||||||
int cmult = (per_core) ? Global::coreCount : 1;
|
int cmult = (per_core) ? Global::coreCount : 1;
|
||||||
|
(void)tree;
|
||||||
|
|
||||||
//* Update uid_user map if /etc/passwd changed since last run
|
//* Update uid_user map if /etc/passwd changed since last run
|
||||||
if (!passwd_path.empty() && fs::last_write_time(passwd_path) != passwd_time) {
|
if (!passwd_path.empty() && fs::last_write_time(passwd_path) != passwd_time) {
|
||||||
|
@ -160,6 +166,7 @@ namespace Proc {
|
||||||
if (d.is_directory() && isdigit(pid_str[0])) {
|
if (d.is_directory() && isdigit(pid_str[0])) {
|
||||||
npids++;
|
npids++;
|
||||||
proc_info new_proc (stoul(pid_str));
|
proc_info new_proc (stoul(pid_str));
|
||||||
|
pid_list.push_back(new_proc.pid);
|
||||||
|
|
||||||
//* Cache program name, command and username
|
//* Cache program name, command and username
|
||||||
if (!cache.contains(new_proc.pid)) {
|
if (!cache.contains(new_proc.pid)) {
|
||||||
|
@ -238,7 +245,7 @@ namespace Proc {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1: { //? Process parent pid
|
case 1: { //? Process parent pid
|
||||||
new_proc.ppid = stoul(instr.substr(s_pos, c_pos - s_pos));
|
new_proc.ppid = stoi(instr.substr(s_pos, c_pos - s_pos));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 11: { //? Process utime
|
case 11: { //? Process utime
|
||||||
|
@ -297,7 +304,7 @@ namespace Proc {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//* Sort processes vector
|
//* Sort processes
|
||||||
std::ranges::sort(procs, [sortint = sort_map.at(sorting), &reverse](proc_info& a, proc_info& b) {
|
std::ranges::sort(procs, [sortint = sort_map.at(sorting), &reverse](proc_info& a, proc_info& b) {
|
||||||
switch (sortint) {
|
switch (sortint) {
|
||||||
case 0: return (reverse) ? a.pid < b.pid : a.pid > b.pid;
|
case 0: return (reverse) ? a.pid < b.pid : a.pid > b.pid;
|
||||||
|
@ -326,14 +333,13 @@ namespace Proc {
|
||||||
|
|
||||||
//* Clear dead processes from cache at a regular interval
|
//* Clear dead processes from cache at a regular interval
|
||||||
if (++counter >= 10000 || ((int)cache.size() > npids + 100)) {
|
if (++counter >= 10000 || ((int)cache.size() > npids + 100)) {
|
||||||
unordered_flat_map<uint, p_cache> r_cache;
|
|
||||||
r_cache.reserve(procs.size());
|
|
||||||
counter = 0;
|
counter = 0;
|
||||||
if (filter.empty()) {
|
unordered_flat_map<uint, p_cache> r_cache;
|
||||||
for (auto& p : procs) r_cache[p.pid] = cache[p.pid];
|
r_cache.reserve(pid_list.size());
|
||||||
cache.swap(r_cache);
|
for (auto& p : pid_list) {
|
||||||
|
if (cache.contains(p)) r_cache[p] = cache.at(p);
|
||||||
}
|
}
|
||||||
else cache.clear();
|
cache.swap(r_cache);
|
||||||
}
|
}
|
||||||
old_cputimes = cputimes;
|
old_cputimes = cputimes;
|
||||||
atomic_wait(drawing);
|
atomic_wait(drawing);
|
||||||
|
|
|
@ -38,7 +38,7 @@ tab-size = 4
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
using std::string, std::vector, std::array, std::regex, std::max, std::to_string, std::cin, std::atomic, robin_hood::unordered_flat_map;
|
using std::string, std::string_view, std::vector, std::array, std::regex, std::max, std::to_string, std::cin, std::atomic, robin_hood::unordered_flat_map;
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
//? ------------------------------------------------- NAMESPACES ------------------------------------------------------
|
//? ------------------------------------------------- NAMESPACES ------------------------------------------------------
|
||||||
|
@ -225,8 +225,10 @@ namespace Term {
|
||||||
|
|
||||||
namespace Tools {
|
namespace Tools {
|
||||||
|
|
||||||
|
const auto SSmax = std::numeric_limits<std::streamsize>::max();
|
||||||
|
|
||||||
//* Return number of UTF8 characters in a string with option to disregard escape sequences
|
//* Return number of UTF8 characters in a string with option to disregard escape sequences
|
||||||
size_t ulen(string str, bool escape=false){
|
size_t ulen(string str, const bool escape=false){
|
||||||
if (escape) str = std::regex_replace(str, Fx::escape_regex, "");
|
if (escape) str = std::regex_replace(str, Fx::escape_regex, "");
|
||||||
return std::count_if(str.begin(), str.end(),
|
return std::count_if(str.begin(), str.end(),
|
||||||
[](char c) { return (static_cast<unsigned char>(c) & 0xC0) != 0x80; } );
|
[](char c) { return (static_cast<unsigned char>(c) & 0xC0) != 0x80; } );
|
||||||
|
@ -247,6 +249,18 @@ namespace Tools {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//* Check if vector <vec> contains value <find_val>
|
||||||
|
template <typename T>
|
||||||
|
bool v_contains(vector<T>& vec, T find_val) {
|
||||||
|
return std::ranges::find(vec, find_val) != vec.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
//* Return index of <find_val> from vector <vec>, returns size of <vec> if <find_val> is not present
|
||||||
|
template <typename T>
|
||||||
|
size_t v_index(vector<T>& vec, T find_val) {
|
||||||
|
return std::ranges::distance(vec.begin(), std::ranges::find(vec, find_val));
|
||||||
|
}
|
||||||
|
|
||||||
//* Return current time since epoch in seconds
|
//* Return current time since epoch in seconds
|
||||||
uint64_t time_s(){
|
uint64_t time_s(){
|
||||||
return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||||
|
@ -267,49 +281,57 @@ namespace Tools {
|
||||||
return (str == "true") || (str == "false") || (str == "True") || (str == "False");
|
return (str == "true") || (str == "false") || (str == "True") || (str == "False");
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Check if a string is a valid positive integer value
|
//* Convert string to bool, returning any value not equal to "true" or "True" as false
|
||||||
bool isuint(string& str){
|
bool stobool(string& str){
|
||||||
return all_of(str.begin(), str.end(), ::isdigit);
|
return (str == "true" || str == "True") ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Left-trim <t_str> from <str> and return string
|
//* Check if a string is a valid integer value
|
||||||
string ltrim(string str, string t_str = " "){
|
bool isint(string& str){
|
||||||
while (str.starts_with(t_str)) str.erase(0, t_str.size());
|
if (str.empty()) return false;
|
||||||
return str;
|
size_t offset = (str[0] == '-' ? 1 : 0);
|
||||||
|
return all_of(str.begin() + offset, str.end(), ::isdigit);
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Right-trim <t_str> from <str> and return string
|
//* Left-trim <t_str> from <str> and return new string
|
||||||
string rtrim(string str, string t_str = " "){
|
string ltrim(const string& str, const string t_str = " "){
|
||||||
while (str.ends_with(t_str)) str.resize(str.size() - t_str.size());
|
string_view str_v = str;
|
||||||
return str;
|
while (str_v.starts_with(t_str)) str_v.remove_prefix(t_str.size());
|
||||||
|
return (string)str_v;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Left-right-trim <t_str> from <str> and return string
|
//* Right-trim <t_str> from <str> and return new string
|
||||||
string trim(string str, string t_str = " "){
|
string rtrim(const string& str, const string t_str = " "){
|
||||||
|
string_view str_v = str;
|
||||||
|
while (str_v.ends_with(t_str)) str_v.remove_suffix(t_str.size());
|
||||||
|
return (string)str_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
//* Left-right-trim <t_str> from <str> and return new string
|
||||||
|
string trim(const string& str, const string t_str = " "){
|
||||||
return ltrim(rtrim(str, t_str), t_str);
|
return ltrim(rtrim(str, t_str), t_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Split <string> at <delim> <time> number of times (0 for unlimited) and return vector
|
//* Split <string> at <delim> <time> number of times (0 for unlimited) and return vector
|
||||||
vector<string> ssplit(string str, string delim = " ", int times = 0, bool ignore_remainder=false){
|
vector<string> ssplit(const string& str, const string delim = " ", const int times = 0, const bool ignore_remainder=false){
|
||||||
vector<string> out;
|
vector<string> out;
|
||||||
|
string_view str_v = str;
|
||||||
if (times > 0) out.reserve(times);
|
if (times > 0) out.reserve(times);
|
||||||
if (!str.empty() && !delim.empty()){
|
if (!str_v.empty() && !delim.empty()){
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
int x = 0;
|
int x = 0;
|
||||||
string tmp;
|
while ((pos = str_v.find(delim)) != string::npos){
|
||||||
while ((pos = str.find(delim)) != string::npos){
|
if (str_v.substr(0, pos) != delim) out.emplace_back(str_v.substr(0, pos));
|
||||||
tmp = str.substr(0, pos);
|
str_v.remove_prefix(pos + delim.size());
|
||||||
if (tmp != delim && !tmp.empty()) out.push_back(tmp);
|
|
||||||
str.erase(0, pos + delim.size());
|
|
||||||
if (times > 0 && ++x >= times) break;
|
if (times > 0 && ++x >= times) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!ignore_remainder) out.push_back(str);
|
if (!ignore_remainder) out.emplace_back(str_v);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Put current thread to sleep for <ms> milliseconds
|
//* Put current thread to sleep for <ms> milliseconds
|
||||||
void sleep_ms(uint ms) {
|
void sleep_ms(const uint& ms) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,12 +477,12 @@ namespace Logger {
|
||||||
std::atomic<bool> busy (false);
|
std::atomic<bool> busy (false);
|
||||||
bool first = true;
|
bool first = true;
|
||||||
string tdf = "%Y/%m/%d (%T) | ";
|
string tdf = "%Y/%m/%d (%T) | ";
|
||||||
unordered_flat_map<uint, string> log_levels = {
|
vector<string> log_levels = {
|
||||||
{ 0, "DISABLED" },
|
"DISABLED",
|
||||||
{ 1, "ERROR" },
|
"ERROR",
|
||||||
{ 2, "WARNING" },
|
"WARNING",
|
||||||
{ 3, "INFO" },
|
"INFO",
|
||||||
{ 4, "DEBUG" }
|
"DEBUG"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,7 +502,7 @@ namespace Logger {
|
||||||
if (!ec) {
|
if (!ec) {
|
||||||
std::ofstream lwrite(logfile, std::ios::app);
|
std::ofstream lwrite(logfile, std::ios::app);
|
||||||
if (first) { first = false; lwrite << "\n" << strf_time(tdf) << "===> btop++ v." << Global::Version << "\n";}
|
if (first) { first = false; lwrite << "\n" << strf_time(tdf) << "===> btop++ v." << Global::Version << "\n";}
|
||||||
lwrite << strf_time(tdf) << log_levels[level] << ": " << msg << "\n";
|
lwrite << strf_time(tdf) << log_levels.at(level) << ": " << msg << "\n";
|
||||||
lwrite.close();
|
lwrite.close();
|
||||||
}
|
}
|
||||||
else logfile.clear();
|
else logfile.clear();
|
||||||
|
|
Loading…
Reference in a new issue