Mercurial > topfetch++
comparison main.cpp @ 1:841975e638f2
add stuff
| author | Yasuri <yasuri@charliesmp.net> |
|---|---|
| date | Sun, 04 Oct 2026 14:33:34 -0500 |
| parents | bb144f2c5a3b |
| children | f7c837561bfa |
comparison
equal
deleted
inserted
replaced
| 0:bb144f2c5a3b | 1:841975e638f2 |
|---|---|
| 1 // topfetch++ - live system monitor + fetch tool | |
| 2 // ISC licensed, see LICENSE. | |
| 3 // Logos adapted from pfetch (MIT), see THIRD-PARTY-NOTICES._ | |
| 4 #include <algorithm> | |
| 5 #include <chrono> | |
| 6 #include <fstream> | |
| 7 #include <iomanip> | |
| 1 #include <iostream> | 8 #include <iostream> |
| 2 #include <fstream> | 9 #include <map> |
| 3 #include <sstream> | 10 #include <sstream> |
| 4 #include <iomanip> | 11 #include <string> |
| 5 int main() { | 12 #include <thread> |
| 6 std::string myText; | 13 #include <vector> |
| 7 std::ifstream Meminfo("/proc/meminfo"); | 14 |
| 8 std::string uptimeText; | 15 // ---------- simple readers ---------- |
| 9 std::ifstream Uptime("/proc/uptime"); | 16 |
| 10 std::string distro; | 17 std::string readHostname() { |
| 11 std::ifstream OsRelease("/etc/os-release"); | 18 std::ifstream f("/proc/sys/kernel/hostname"); |
| 19 if (!f.is_open()) return "(none)"; | |
| 20 std::string s; | |
| 21 std::getline(f, s); | |
| 22 return s.empty() ? "(none)" : s; | |
| 23 } | |
| 24 | |
| 25 std::string readVersion() { | |
| 26 std::ifstream f("/proc/version"); | |
| 27 if (!f.is_open()) return "unknown"; | |
| 28 std::string w1, w2, version; | |
| 29 f >> w1 >> w2 >> version; // "Linux version 6.x.y ..." | |
| 30 return version.empty() ? "unknown" : version; | |
| 31 } | |
| 32 | |
| 33 long readUptime() { | |
| 34 std::ifstream f("/proc/uptime"); | |
| 35 if (!f.is_open()) return -1; | |
| 36 double seconds = 0; | |
| 37 f >> seconds; | |
| 38 return static_cast<long>(seconds); | |
| 39 } | |
| 40 | |
| 41 struct Mem { | |
| 42 long total = 0; // kB | |
| 43 long available = 0; // kB | |
| 44 }; | |
| 45 | |
| 46 Mem readMeminfo() { | |
| 47 Mem m; | |
| 48 std::ifstream f("/proc/meminfo"); | |
| 49 if (!f.is_open()) return m; | |
| 50 std::string line; | |
| 51 while (std::getline(f, line)) { | |
| 52 std::istringstream ss(line); | |
| 53 std::string name; | |
| 54 long value = 0; | |
| 55 ss >> name >> value; | |
| 56 if (name == "MemTotal:") m.total = value; | |
| 57 else if (name == "MemAvailable:") m.available = value; | |
| 58 } | |
| 59 return m; | |
| 60 } | |
| 61 | |
| 62 struct CpuTimes { | |
| 63 long busy = 0; | |
| 12 long total = 0; | 64 long total = 0; |
| 13 long available = 0; | 65 }; |
| 14 while (std::getline (Meminfo, myText)) { | 66 |
| 15 std::istringstream ss(myText); | 67 CpuTimes readCpuTimes() { |
| 16 std::string name; | 68 CpuTimes t; |
| 17 long value; | 69 std::ifstream f("/proc/stat"); |
| 18 ss >> name >> value; | 70 if (!f.is_open()) return t; |
| 19 if (name == "MemTotal:") { | 71 |
| 20 total = value; | 72 std::string label; |
| 73 f >> label; // "cpu" | |
| 74 | |
| 75 long values[8] = {0}; // user nice system idle iowait irq softirq steal | |
| 76 for (int i = 0; i < 8; i++) f >> values[i]; | |
| 77 | |
| 78 long total = 0; | |
| 79 for (int i = 0; i < 8; i++) total += values[i]; | |
| 80 | |
| 81 long idle = values[3] + values[4]; | |
| 82 t.total = total; | |
| 83 t.busy = total - idle; | |
| 84 return t; | |
| 85 } | |
| 86 | |
| 87 // ---------- distro ---------- | |
| 88 | |
| 89 struct Distro { | |
| 90 std::string pretty = "Linux"; | |
| 91 std::string id; | |
| 92 std::string idLike; | |
| 93 }; | |
| 94 | |
| 95 std::string unquote(const std::string& v) { | |
| 96 if (v.size() >= 2 && (v.front() == '"' || v.front() == '\'') && | |
| 97 v.back() == v.front()) { | |
| 98 return v.substr(1, v.size() - 2); | |
| 99 } | |
| 100 return v; | |
| 101 } | |
| 102 | |
| 103 Distro readDistro() { | |
| 104 Distro d; | |
| 105 std::ifstream f("/etc/os-release"); | |
| 106 if (!f.is_open()) return d; | |
| 107 | |
| 108 std::string line; | |
| 109 while (std::getline(f, line)) { | |
| 110 size_t pos = line.find('='); | |
| 111 if (pos == std::string::npos) continue; | |
| 112 std::string key = line.substr(0, pos); | |
| 113 std::string val = unquote(line.substr(pos + 1)); | |
| 114 if (key == "PRETTY_NAME" && !val.empty()) d.pretty = val; | |
| 115 else if (key == "ID") d.id = val; | |
| 116 else if (key == "ID_LIKE") d.idLike = val; | |
| 117 } | |
| 118 return d; | |
| 119 } | |
| 120 | |
| 121 // ---------- logos ---------- | |
| 122 | |
| 123 struct Logo { | |
| 124 std::vector<std::string> lines; | |
| 125 std::string color; // ANSI escape | |
| 126 }; | |
| 127 | |
| 128 // Logos adapted from pfetch (MIT) | |
| 129 // Copyright (c) 2016-2021 Dylan Araps | |
| 130 // Copyright (c) 2024-2025 Joey Reinhart | |
| 131 Logo pickLogo(const Distro& d, const std::string& override = "") { | |
| 132 static const std::map<std::string, Logo> logos = { | |
| 133 {"nixos", {{ | |
| 134 R"art( \\ \\ //)art", | |
| 135 R"art( ==\\__\\/ //)art", | |
| 136 R"art( // \\//)art", | |
| 137 R"art(==// //==)art", | |
| 138 R"art( //\\___//)art", | |
| 139 R"art(// /\\ \\==)art", | |
| 140 R"art( // \\ \\)art", | |
| 141 }, "\033[34m"}}, | |
| 142 {"arch", {{ | |
| 143 R"art( /\)art", | |
| 144 R"art( / \)art", | |
| 145 R"art( /\ \)art", | |
| 146 R"art( / \)art", | |
| 147 R"art( / ,, \)art", | |
| 148 R"art( / | | -\)art", | |
| 149 R"art(/_-'' ''-_\)art", | |
| 150 }, "\033[36m"}}, | |
| 151 {"gentoo", {{ | |
| 152 R"art( _-----_)art", | |
| 153 R"art(( \)art", | |
| 154 R"art(\ 0 \)art", | |
| 155 R"art( \ ))art", | |
| 156 R"art( / _/)art", | |
| 157 R"art(( _-)art", | |
| 158 R"art(\____-)art", | |
| 159 }, "\033[35m"}}, | |
| 160 }; | |
| 161 | |
| 162 static const Logo fallback = {{ | |
| 163 R"art( .--.)art", | |
| 164 R"art( |o_o |)art", | |
| 165 R"art( |:_/ |)art", | |
| 166 R"art( // \ \)art", | |
| 167 R"art( (| | ))art", | |
| 168 R"art(/'\_ _/`\)art", | |
| 169 R"art(\___)=(___/)art", | |
| 170 }, "\033[33m"}; | |
| 171 | |
| 172 std::string id = override.empty() ? d.id : override; | |
| 173 auto it = logos.find(id); | |
| 174 if (it != logos.end()) return it->second; | |
| 175 | |
| 176 // ID_LIKE fallback (Manjaro -> arch, etc.) | |
| 177 std::istringstream ss(d.idLike); | |
| 178 std::string word; | |
| 179 while (ss >> word) { | |
| 180 it = logos.find(word); | |
| 181 if (it != logos.end()) return it->second; | |
| 182 } | |
| 183 return fallback; | |
| 184 } | |
| 185 | |
| 186 // ---------- main ---------- | |
| 187 | |
| 188 int main(int argc, char** argv) { | |
| 189 std::string override; | |
| 190 if (argc >= 3 && std::string(argv[1]) == "--logo") override = argv[2]; | |
| 191 | |
| 192 const Distro distro = readDistro(); | |
| 193 const Logo logo = pickLogo(distro, override); | |
| 194 const std::string hostname = readHostname(); | |
| 195 const std::string kernver = readVersion(); | |
| 196 | |
| 197 size_t logoWidth = 0; | |
| 198 for (const auto& line : logo.lines) logoWidth = std::max(logoWidth, line.size()); | |
| 199 | |
| 200 CpuTimes prev = readCpuTimes(); | |
| 201 const double kbToGb = 1024.0 * 1024.0; | |
| 202 | |
| 203 while (true) { | |
| 204 std::this_thread::sleep_for(std::chrono::seconds(1)); | |
| 205 | |
| 206 Mem m = readMeminfo(); | |
| 207 long up = readUptime(); | |
| 208 CpuTimes now = readCpuTimes(); | |
| 209 | |
| 210 long totalChange = now.total - prev.total; | |
| 211 double cpuPercent = 0.0; | |
| 212 if (totalChange > 0) cpuPercent = 100.0 * (now.busy - prev.busy) / totalChange; | |
| 213 prev = now; | |
| 214 | |
| 215 std::ostringstream uptimeLine, memLine, cpuLine; | |
| 216 uptimeLine << "Uptime: "; | |
| 217 if (up < 0) { | |
| 218 uptimeLine << "Unknown"; | |
| 219 } else { | |
| 220 uptimeLine << up / 86400 << "d " << (up % 86400) / 3600 << "h " | |
| 221 << (up % 3600) / 60 << "m"; | |
| 21 } | 222 } |
| 22 if (name == "MemAvailable:") { | 223 |
| 23 available = value; | 224 memLine << std::fixed << std::setprecision(2) << "Memory: "; |
| 225 if (m.total == 0) { | |
| 226 memLine << "Unknown"; | |
| 227 } else { | |
| 228 memLine << (m.total - m.available) / kbToGb << " GB / " | |
| 229 << m.total / kbToGb << " GB"; | |
| 24 } | 230 } |
| 25 } | 231 |
| 26 std::string osLine; | 232 cpuLine << std::fixed << std::setprecision(1) |
| 27 while (std::getline(OsRelease, osLine)) { | 233 << "CPU: " << cpuPercent << " %"; |
| 28 size_t pos = osLine.find('='); | 234 |
| 29 if (pos == std::string::npos) continue; | 235 std::vector<std::string> info = { |
| 30 std::string key = osLine.substr(0, pos); | 236 "OS: " + distro.pretty, |
| 31 std::string val = osLine.substr(pos + 1); | 237 "Hostname: " + hostname, |
| 32 if (key == "PRETTY_NAME") { | 238 "Kernel: " + kernver, |
| 33 distro = val.substr(1, val.size() - 2); | 239 uptimeLine.str(), |
| 240 memLine.str(), | |
| 241 cpuLine.str(), | |
| 242 }; | |
| 243 | |
| 244 size_t rows = std::max(logo.lines.size(), info.size()); | |
| 245 | |
| 246 std::cout << "\033[H\033[2J"; | |
| 247 for (size_t i = 0; i < rows; i++) { | |
| 248 std::string art = i < logo.lines.size() ? logo.lines[i] : ""; | |
| 249 std::string text = i < info.size() ? info[i] : ""; | |
| 250 std::cout << logo.color << std::left << std::setw(logoWidth) << art | |
| 251 << "\033[0m" << " " << text << '\n'; | |
| 34 } | 252 } |
| 35 } | 253 std::cout << std::flush; |
| 36 long timeup = 0; | 254 } |
| 37 while (std::getline (Uptime, uptimeText)) { | 255 } |
| 38 std::istringstream ss2(uptimeText); | |
| 39 double uptime; | |
| 40 ss2 >> uptime; | |
| 41 timeup = uptime; | |
| 42 } | |
| 43 std::cout << std::fixed << std::setprecision(2); | |
| 44 std::cout << "Used: " << (total - available) / (1024.0 * 1024.0) << " GB" << "/" << total / (1024.0 * 1024.0) << "GB" << std::endl; | |
| 45 std::cout << "Uptime: " << "Hours: " << timeup / 3600 << " Minutes: " << (timeup % 3600) / 60 << std::endl; | |
| 46 std::cout << "OS: " << distro << std::endl; | |
| 47 Meminfo.close(); | |
| 48 } |
