diff main.cpp @ 1:841975e638f2

add stuff
author Yasuri <yasuri@charliesmp.net>
date Sun, 04 Oct 2026 14:33:34 -0500
parents bb144f2c5a3b
children f7c837561bfa
line wrap: on
line diff
--- 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 <iostream>
+// topfetch++ - live system monitor + fetch tool
+// ISC licensed, see LICENSE.
+// Logos adapted from pfetch (MIT), see THIRD-PARTY-NOTICES._
+#include <algorithm>
+#include <chrono>
 #include <fstream>
-#include <sstream>
 #include <iomanip>
-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 <iostream>
+#include <map>
+#include <sstream>
+#include <string>
+#include <thread>
+#include <vector>
+
+// ---------- 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<long>(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<std::string> 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<std::string, Logo> 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<std::string> 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();
 }