diff --git a/btop.cpp b/btop.cpp index 19f2fe4..66e3192 100644 --- a/btop.cpp +++ b/btop.cpp @@ -78,6 +78,12 @@ namespace Global { string banner; const uint banner_width = 49; + + fs::path conf_dir; + fs::path conf_file; + fs::path logfile; + fs::path theme_folder; + fs::path user_theme_folder; } @@ -145,22 +151,50 @@ string my_worker(int x){ //? --------------------------------------------- Main starts here! --------------------------------------------------- int main(int argc, char **argv){ - // using namespace std; - //? Init cout.setf(std::ios::boolalpha); if (argc > 1) argumentParser(argc, argv); + if (!string(getenv("LANG")).ends_with("UTF-8") && !string(getenv("LANG")).ends_with("utf-8")) { + cout << "WARNING: No UTF-8 locale was detected! Symbols might not look as intended." << endl; + } + #if defined(LINUX) //? Linux init - Global::proc_path = (fs::is_directory(fs::path("/proc")) && access("/proc", R_OK) != -1) ? fs::path("/proc") : Global::proc_path; + Global::proc_path = (fs::is_directory(fs::path("/proc")) && access("/proc", R_OK) != -1) ? "/proc" : ""; if (Global::proc_path.empty()) { - cout << "ERROR: Proc filesystem not found/readable!" << endl; + cout << "ERROR: Proc filesystem not found or no permission to read from it!" << endl; exit(1); } #endif + //? Setup paths for config, log and themes + for (auto env : {"XDG_CONFIG_HOME", "HOME"}) { + if (getenv(env) != NULL && access(getenv(env), W_OK) != -1) { + Global::conf_dir = fs::path(getenv(env)) / (((string)env == "HOME") ? ".config/btop" : "btop"); + break; + } + } + if (!Global::conf_dir.empty()) { + if (!fs::is_directory(Global::conf_dir) && !fs::create_directories(Global::conf_dir)) { + cout << "WARNING: Could not create or access btop config directory. Logging and config saving disabled." << endl; + } + else { + Global::conf_file = Global::conf_dir / "btop.conf"; + Global::logfile = Global::conf_dir / "btop.log"; + Global::user_theme_folder = Global::conf_dir / "themes"; + if (!fs::exists(Global::user_theme_folder) && !fs::create_directory(Global::user_theme_folder)) Global::user_theme_folder.clear(); + } + } + for (auto theme_path : {"/usr/local/share/btop/themes", "/usr/share/btop/themes"}) { + if (access(theme_path, R_OK) != -1) { + Global::theme_folder = theme_path; + break; + } + } + + //? Initialize terminal and set options if (!Term::init()) { cout << "ERROR: No tty detected!" << endl; @@ -320,7 +354,7 @@ int main(int argc, char **argv){ if (avgtimes.size() > 100) avgtimes.pop_back(); cout << pbox << ostring << Fx::reset << "\n" << endl; cout << Mv::to(Term::height - 4, 1) << "Processes call took: " << rjust(to_string(timestamp), 4) << "ms. Average: " << rjust(to_string(accumulate(avgtimes.begin(), avgtimes.end(), 0) / avgtimes.size()), 3) << - "ms of " << avgtimes.size() << " samples. Drawing took: " << time_ms() - timestamp2 << "ms. Number of processes: " << Proc::numpids << ". Run count: " << ++rcount << " " << endl; + "ms of " << avgtimes.size() << " samples. Drawing took: " << time_ms() - timestamp2 << "ms. Number of processes: " << Proc::numpids << ". Run count: " << ++rcount << ". Time: " << strf_time("%X ") << endl; while (time_ms() < tsl) { if (Input::poll(tsl - time_ms())) key = Input::get(); diff --git a/src/btop_linux.h b/src/btop_linux.h index a4a5f96..5cf64d2 100644 --- a/src/btop_linux.h +++ b/src/btop_linux.h @@ -73,8 +73,8 @@ namespace Proc { fs::path passwd_path; fs::file_time_type passwd_time; uint counter = 0; - auto page_size = sysconf(_SC_PAGE_SIZE); - auto clk_tck = sysconf(_SC_CLK_TCK); + long page_size; + long clk_tck; } @@ -93,7 +93,7 @@ namespace Proc { }; unordered_map sort_map; - //* proc_info: pid, name, cmd, threads, user, mem, cpu_p, cpu_c, state, tty, cpu_n, p_nice, ppid + //* proc_info: pid, name, cmd, threads, user, mem, cpu_p, cpu_c, state, cpu_n, p_nice, ppid struct proc_info { uint pid; string name, cmd; @@ -125,8 +125,6 @@ namespace Proc { auto sortint = (sort_map.contains(sorting)) ? sort_map[sorting] : 7; vector procs; procs.reserve((numpids + 10)); - vector c_pids; - c_pids.reserve((numpids + 10)); numpids = 0; //* Update uid_user map if /etc/passwd changed since last run @@ -164,7 +162,6 @@ namespace Proc { if (d.is_directory() && isdigit(pid_str[0])) { numpids++; pid = stoul(pid_str); - c_pids.push_back(pid); //* Cache program name, command and username if (!cache.contains(pid)) { @@ -215,14 +212,14 @@ namespace Proc { continue; } - //* Get cpu usage, cpu cumulative and threads from /proc/[pid]/stat + //* Parse /proc/[pid]/stat pread.open(d.path() / "stat"); if (pread.good()) { instr.clear(); s_pos = 0; c_pos = 0; s_count = 0; getline(pread, instr); pread.close(); - //? Skip pid and comm field and find comm fields closing ')' to avoid names with whitespace or parenthesis + //? Skip pid and comm field and find comm fields closing ')' s_pos = instr.find_last_of(')') + 2; do { @@ -329,8 +326,11 @@ namespace Proc { if (++counter >= 10000 || (filter.empty() && cache.size() > procs.size() + 100)) { unordered_map r_cache; counter = 0; - for (auto& p : c_pids) r_cache[p] = cache[p]; - cache = move(r_cache); + if (filter.empty()) { + for (auto& p : procs) r_cache[p.pid] = cache[p.pid]; + cache = move(r_cache); + } + else cache.clear(); } tstamp = time_ms(); @@ -341,7 +341,14 @@ namespace Proc { //* Initialize needed variables for collect void init(){ tstamp = time_ms(); - passwd_path = (access("/etc/passwd", R_OK) != -1) ? fs::path("/etc/passwd") : passwd_path; + passwd_path = (access("/etc/passwd", R_OK) != -1) ? fs::path("/etc/passwd") : passwd_path; //! add logger error + + page_size = sysconf(_SC_PAGE_SIZE); //! add logger error + if (page_size <= 0) page_size = 4096; + + clk_tck = sysconf(_SC_CLK_TCK); //! add logger error + if (clk_tck <= 0) clk_tck = 100; + uint i = 0; for (auto& item : sort_array) sort_map[item] = i++; } diff --git a/src/btop_tools.h b/src/btop_tools.h index 8a402fe..a127acf 100644 --- a/src/btop_tools.h +++ b/src/btop_tools.h @@ -24,6 +24,9 @@ tab-size = 4 #include #include #include +#include +#include +#include #include #include @@ -361,9 +364,9 @@ namespace Tools { m = sec / 60; sec %= 60; if (d>0) out = to_string(d) + "d "; - out += (h<10) ? "0" + to_string(h) + ":" : to_string(h) + ":"; - out += (m<10) ? "0" + to_string(m) + ":" : to_string(m) + ":"; - out += (sec<10) ? "0" + to_string(sec) : to_string(sec); + out += ((h<10) ? "0" : "") + to_string(h) + ":"; + out += ((m<10) ? "0" : "") + to_string(m) + ":"; + out += ((sec<10) ? "0" : "") + to_string(sec); return out; } @@ -433,6 +436,20 @@ namespace Tools { return repeat(std::move(str), n); } + //* Return current time in format + std::string strf_time(std::string strf){ + auto now = std::chrono::system_clock::now(); + auto in_time_t = std::chrono::system_clock::to_time_t(now); + std::tm bt {}; + std::stringstream ss; + ss << std::put_time(localtime_r(&in_time_t, &bt), strf.c_str()); + return ss.str(); + } + +} + +namespace Logger { + string cur_date = Tools::strf_time("%Y-%m-%d"); }