# HG changeset patch # User Yasuri # Date 1791142414 18000 # Node ID 841975e638f29898df030218b83f3f5b78bd82f5 # Parent bb144f2c5a3bae7e4d0006b3a951b06752a35513 add stuff diff -r bb144f2c5a3b -r 841975e638f2 main.cpp --- a/main.cpp Sun Oct 04 13:36:00 2026 -0500 +++ b/main.cpp Sun Oct 04 14:33:34 2026 -0500 @@ -1,48 +1,255 @@ -#include +// topfetch++ - live system monitor + fetch tool +// ISC licensed, see LICENSE. +// Logos adapted from pfetch (MIT), see THIRD-PARTY-NOTICES._ +#include +#include #include -#include #include -int main() { - std::string myText; - std::ifstream Meminfo("/proc/meminfo"); - std::string uptimeText; - std::ifstream Uptime("/proc/uptime"); - std::string distro; - std::ifstream OsRelease("/etc/os-release"); +#include +#include +#include +#include +#include +#include + +// ---------- simple readers ---------- + +std::string readHostname() { + std::ifstream f("/proc/sys/kernel/hostname"); + if (!f.is_open()) return "(none)"; + std::string s; + std::getline(f, s); + return s.empty() ? "(none)" : s; +} + +std::string readVersion() { + std::ifstream f("/proc/version"); + if (!f.is_open()) return "unknown"; + std::string w1, w2, version; + f >> w1 >> w2 >> version; // "Linux version 6.x.y ..." + return version.empty() ? "unknown" : version; +} + +long readUptime() { + std::ifstream f("/proc/uptime"); + if (!f.is_open()) return -1; + double seconds = 0; + f >> seconds; + return static_cast(seconds); +} + +struct Mem { + long total = 0; // kB + long available = 0; // kB +}; + +Mem readMeminfo() { + Mem m; + std::ifstream f("/proc/meminfo"); + if (!f.is_open()) return m; + std::string line; + while (std::getline(f, line)) { + std::istringstream ss(line); + std::string name; + long value = 0; + ss >> name >> value; + if (name == "MemTotal:") m.total = value; + else if (name == "MemAvailable:") m.available = value; + } + return m; +} + +struct CpuTimes { + long busy = 0; + long total = 0; +}; + +CpuTimes readCpuTimes() { + CpuTimes t; + std::ifstream f("/proc/stat"); + if (!f.is_open()) return t; + + std::string label; + f >> label; // "cpu" + + long values[8] = {0}; // user nice system idle iowait irq softirq steal + for (int i = 0; i < 8; i++) f >> values[i]; + long total = 0; - long available = 0; - while (std::getline (Meminfo, myText)) { - std::istringstream ss(myText); - std::string name; - long value; - ss >> name >> value; - if (name == "MemTotal:") { - total = value; - } - if (name == "MemAvailable:") { - available = value; + for (int i = 0; i < 8; i++) total += values[i]; + + long idle = values[3] + values[4]; + t.total = total; + t.busy = total - idle; + return t; +} + +// ---------- distro ---------- + +struct Distro { + std::string pretty = "Linux"; + std::string id; + std::string idLike; +}; + +std::string unquote(const std::string& v) { + if (v.size() >= 2 && (v.front() == '"' || v.front() == '\'') && + v.back() == v.front()) { + return v.substr(1, v.size() - 2); + } + return v; +} + +Distro readDistro() { + Distro d; + std::ifstream f("/etc/os-release"); + if (!f.is_open()) return d; + + std::string line; + while (std::getline(f, line)) { + size_t pos = line.find('='); + if (pos == std::string::npos) continue; + std::string key = line.substr(0, pos); + std::string val = unquote(line.substr(pos + 1)); + if (key == "PRETTY_NAME" && !val.empty()) d.pretty = val; + else if (key == "ID") d.id = val; + else if (key == "ID_LIKE") d.idLike = val; + } + return d; +} + +// ---------- logos ---------- + +struct Logo { + std::vector lines; + std::string color; // ANSI escape +}; + +// Logos adapted from pfetch (MIT) +// Copyright (c) 2016-2021 Dylan Araps +// Copyright (c) 2024-2025 Joey Reinhart +Logo pickLogo(const Distro& d, const std::string& override = "") { + static const std::map logos = { + {"nixos", {{ + R"art( \\ \\ //)art", + R"art( ==\\__\\/ //)art", + R"art( // \\//)art", + R"art(==// //==)art", + R"art( //\\___//)art", + R"art(// /\\ \\==)art", + R"art( // \\ \\)art", + }, "\033[34m"}}, + {"arch", {{ + R"art( /\)art", + R"art( / \)art", + R"art( /\ \)art", + R"art( / \)art", + R"art( / ,, \)art", + R"art( / | | -\)art", + R"art(/_-'' ''-_\)art", + }, "\033[36m"}}, + {"gentoo", {{ + R"art( _-----_)art", + R"art(( \)art", + R"art(\ 0 \)art", + R"art( \ ))art", + R"art( / _/)art", + R"art(( _-)art", + R"art(\____-)art", + }, "\033[35m"}}, + }; + + static const Logo fallback = {{ + R"art( .--.)art", + R"art( |o_o |)art", + R"art( |:_/ |)art", + R"art( // \ \)art", + R"art( (| | ))art", + R"art(/'\_ _/`\)art", + R"art(\___)=(___/)art", + }, "\033[33m"}; + + std::string id = override.empty() ? d.id : override; + auto it = logos.find(id); + if (it != logos.end()) return it->second; + + // ID_LIKE fallback (Manjaro -> arch, etc.) + std::istringstream ss(d.idLike); + std::string word; + while (ss >> word) { + it = logos.find(word); + if (it != logos.end()) return it->second; + } + return fallback; +} + +// ---------- main ---------- + +int main(int argc, char** argv) { + std::string override; + if (argc >= 3 && std::string(argv[1]) == "--logo") override = argv[2]; + + const Distro distro = readDistro(); + const Logo logo = pickLogo(distro, override); + const std::string hostname = readHostname(); + const std::string kernver = readVersion(); + + size_t logoWidth = 0; + for (const auto& line : logo.lines) logoWidth = std::max(logoWidth, line.size()); + + CpuTimes prev = readCpuTimes(); + const double kbToGb = 1024.0 * 1024.0; + + while (true) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + + Mem m = readMeminfo(); + long up = readUptime(); + CpuTimes now = readCpuTimes(); + + long totalChange = now.total - prev.total; + double cpuPercent = 0.0; + if (totalChange > 0) cpuPercent = 100.0 * (now.busy - prev.busy) / totalChange; + prev = now; + + std::ostringstream uptimeLine, memLine, cpuLine; + uptimeLine << "Uptime: "; + if (up < 0) { + uptimeLine << "Unknown"; + } else { + uptimeLine << up / 86400 << "d " << (up % 86400) / 3600 << "h " + << (up % 3600) / 60 << "m"; } - } - std::string osLine; - while (std::getline(OsRelease, osLine)) { - size_t pos = osLine.find('='); - if (pos == std::string::npos) continue; - std::string key = osLine.substr(0, pos); - std::string val = osLine.substr(pos + 1); - if (key == "PRETTY_NAME") { - distro = val.substr(1, val.size() - 2); + + memLine << std::fixed << std::setprecision(2) << "Memory: "; + if (m.total == 0) { + memLine << "Unknown"; + } else { + memLine << (m.total - m.available) / kbToGb << " GB / " + << m.total / kbToGb << " GB"; } + + cpuLine << std::fixed << std::setprecision(1) + << "CPU: " << cpuPercent << " %"; + + std::vector info = { + "OS: " + distro.pretty, + "Hostname: " + hostname, + "Kernel: " + kernver, + uptimeLine.str(), + memLine.str(), + cpuLine.str(), + }; + + size_t rows = std::max(logo.lines.size(), info.size()); + + std::cout << "\033[H\033[2J"; + for (size_t i = 0; i < rows; i++) { + std::string art = i < logo.lines.size() ? logo.lines[i] : ""; + std::string text = i < info.size() ? info[i] : ""; + std::cout << logo.color << std::left << std::setw(logoWidth) << art + << "\033[0m" << " " << text << '\n'; + } + std::cout << std::flush; } - long timeup = 0; - while (std::getline (Uptime, uptimeText)) { - std::istringstream ss2(uptimeText); - double uptime; - ss2 >> uptime; - timeup = uptime; - } - std::cout << std::fixed << std::setprecision(2); - std::cout << "Used: " << (total - available) / (1024.0 * 1024.0) << " GB" << "/" << total / (1024.0 * 1024.0) << "GB" << std::endl; - std::cout << "Uptime: " << "Hours: " << timeup / 3600 << " Minutes: " << (timeup % 3600) / 60 << std::endl; - std::cout << "OS: " << distro << std::endl; - Meminfo.close(); }