diff --git a/src/battery.c b/src/battery.c index ae32b0bff..c39b622aa 100644 --- a/src/battery.c +++ b/src/battery.c @@ -6,29 +6,53 @@ void ffPrintBattery(FFstate* state) FILE* fullFile = fopen("/sys/class/power_supply/BAT0/charge_full", "r"); if(fullFile == NULL) + { + if(state->showErrors) + ffPrintError(state, "Battery", "fopen(\"/sys/class/power_supply/BAT0/charge_full\", \"r\") == NULL"); return; + } uint32_t full; scanned = fscanf(fullFile, "%u", &full); if(scanned != 1) + { + if(state->showErrors) + ffPrintError(state, "Battery", "fscanf(fullFile, \"%u\", &full) != 1"); return; + } fclose(fullFile); - FILE* nowFile = fopen("/sys/class/power_supply/BAT0/charge_full", "r"); + FILE* nowFile = fopen("/sys/class/power_supply/BAT0/charge_now", "r"); if(nowFile == NULL) + { + if(state->showErrors) + ffPrintError(state, "Battery", "fopen(\"/sys/class/power_supply/BAT0/charge_now\", \"r\") == NULL"); return; + } uint32_t now; scanned = fscanf(nowFile, "%u", &now); if(scanned != 1) + { + if(state->showErrors) + ffPrintError(state, "Battery", "fscanf(nowFile, \"%u\", &now) != 1"); return; + } fclose(nowFile); FILE* statusFile = fopen("/sys/class/power_supply/BAT0/status", "r"); if(statusFile == NULL) + { + if(state->showErrors) + ffPrintError(state, "Battery", "fopen(\"/sys/class/power_supply/BAT0/status\", \"r\") == NULL"); return; + } char status[256]; scanned = fscanf(statusFile, "%s", status); if(scanned != 1) + { + if(state->showErrors) + ffPrintError(state, "Battery", "fscanf(statusFile, \"%u\", &status) != 1"); return; + } fclose(statusFile); uint32_t percentage = (now / (double) full) * 100; diff --git a/src/colors.c b/src/colors.c index 89494666e..7ac43edee 100644 --- a/src/colors.c +++ b/src/colors.c @@ -15,6 +15,4 @@ void ffPrintColors(FFstate* state) printf("\033[48;5;%dm ", i); puts("\033[0m"); - - puts(""); } \ No newline at end of file diff --git a/src/cpu.c b/src/cpu.c index fe538c902..b73b40e86 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -6,16 +6,32 @@ void ffPrintCPU(FFstate* state) { char name[256]; ffParsePropFile("/proc/cpuinfo", "model name%*s %[^\n]", name); + if(name[0] == '\0') + { + if(state->showErrors) + ffPrintError(state, "CPU", "\"model name%*s %[^\\n]\" not found in \"/proc/cpuinfo\""); + return; + } - char frequency[256]; - ffReadFile("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", frequency, 256); + FILE* frequencyFile = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", "r"); + if(frequencyFile == NULL) + { + if(state->showErrors) + ffPrintError(state, "CPU", "fopen(\"/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq\", \"r\") == NULL"); + return; + } + uint32_t frequency; + int scanned = fscanf(frequencyFile, "%u", &frequency); + if(scanned != 1) + { + if(state->showErrors) + ffPrintError(state, "CPU", "fscanf(frequencyFile, \"%s\", frequency) != 1"); + return; + } + fclose(frequencyFile); - char cores[256]; - - uint32_t hz; - sscanf(frequency, "%u", &hz); //in KHz - hz /= 1000; //to MHz - double ghz = (double) hz / 1000.0; //to GHz + frequency /= 1000; //to MHz + double ghz = (double) frequency / 1000.0; //to GHz ffPrintLogoAndKey(state, "CPU"); printf("%s (%i) @ %.9gGHz\n", name, get_nprocs(), ghz); diff --git a/src/desktopenvironment.c b/src/desktopenvironment.c index 9c90efd68..d1099f9fe 100644 --- a/src/desktopenvironment.c +++ b/src/desktopenvironment.c @@ -5,25 +5,14 @@ static void printKDE() { - char* line = NULL; char version[256]; - size_t len; - - FILE* plasma = fopen("/usr/share/xsessions/plasma.desktop", "r"); - if(plasma == NULL) + ffParsePropFile("/usr/share/xsessions/plasma.desktop", "X-KDE-PluginInfo-Version=%[^\n]", version); + if(version[0] == '\0') { - fputs("Error opening file: /usr/share/xsessions/plasma.desktop\n", stderr); - exit(35); + printf("KDE Plasma "); + return; } - while (getline(&line, &len, plasma) != -1) - { - if (sscanf(line, "X-KDE-PluginInfo-Version=%[^\n]", version) > 0) - break; - } - - fclose(plasma); - free(line); printf("KDE Plasma %s", version); } @@ -31,7 +20,11 @@ void ffPrintDesktopEnvironment(FFstate* state) { const char* currentDesktop = getenv("XDG_CURRENT_DESKTOP"); if(currentDesktop == NULL) + { + if(state->showErrors) + ffPrintError(state, "DE", "getenv(\"XDG_CURRENT_DESKTOP\") == NULL"); return; + } ffPrintLogoAndKey(state, "DE"); diff --git a/src/disk.c b/src/disk.c index 35ff9b6a6..55c33282f 100644 --- a/src/disk.c +++ b/src/disk.c @@ -8,6 +8,8 @@ void ffPrintDisk(FFstate* state) int ret = statvfs("/", &fs); if(ret != 0) { + if(state->showErrors) + ffPrintError(state, "Disk (/)", "statvfs(\"/\", &fs) != 0"); return; } diff --git a/src/fastfetch.c b/src/fastfetch.c index 98c3d0a15..02989ea49 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -32,8 +32,8 @@ uint32_t ffReadFile(const char* fileName, char* buffer, uint32_t bufferSize) FILE* file = fopen(fileName, "r"); if(file == NULL) { - fprintf(stderr, "Failed to open file: %s\n", fileName); - exit(3); + buffer[0] = '\0'; + return 0; } uint32_t read = fread(buffer, sizeof(char), bufferSize, file); @@ -46,15 +46,14 @@ uint32_t ffReadFile(const char* fileName, char* buffer, uint32_t bufferSize) void ffParsePropFile(const char* fileName, const char* regex, char* buffer) { + buffer[0] = '\0'; //If an error occures, this is the indicator + char* line = NULL; size_t len; FILE* file = fopen(fileName, "r"); if(file == NULL) - { - buffer[0] = '\0'; - return; - } + return; // handle errors in higher functions while (getline(&line, &len, file) != -1) { @@ -122,6 +121,25 @@ void ffPrintGtkPretty(const char* gtk2, const char* gtk3, const char* gtk4) } } +void ffPrintError(FFstate* state, const char* key, const char* message) +{ + ffPrintLogoAndKey(state, key); + printf(FASTFETCH_TEXT_MODIFIER_ERROR"%s\n"FASTFETCH_TEXT_MODIFIER_RESET, message); +} + +static void printHelp() +{ + puts( + "usage: fastfetch \n" + " -h, --help: shows this message and exits\n" + " -l , --logo : sets the shown logo. Also changes the main color accordingly\n" + " -c , --color : sets the color of the keys. Must be a linux console color code\n" + " --show-errors: if an error occurs, show it instead of discarding the category\n" + " --list-logos: lists the names of available logos and exits\n" + " --print-logos: prints available logos and exits\n" + ); +} + int main(int argc, char** argv) { FFstate state; @@ -132,11 +150,59 @@ int main(int argc, char** argv) state.passwd = getpwuid(getuid()); uname(&state.utsname); sysinfo(&state.sysinfo); - - - //Configuration state.logo_seperator = 4; state.titleLength = 20; // This is overwritten by ffPrintTitle + state.showErrors = false; + + for(int i = 1; i < argc; i++) + { + if(strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) + { + printHelp(); + return 0; + } + else if(strcmp(argv[i], "--list-logos") == 0) + { + ffListLogos(); + return 0; + } + else if(strcmp(argv[i], "--print-logos") == 0) + { + ffPrintLogos(); + return 0; + } + else if(strcmp(argv[i], "--show-errors") == 0) + { + state.showErrors = true; + } + else if(strcmp(argv[i], "--logo") == 0 || strcmp(argv[i], "-l") == 0) + { + if(i == argc - 1) + { + printf("Error: usage: %s \n", argv[i]); + return 40; + } + + ffLoadLogoSet(&state, argv[i + 1]); + ++i; + } + else if(strcmp(argv[i], "--color") == 0 || strcmp(argv[i], "-c") == 0) + { + if(i == argc - 1) + { + printf("Error: usage: %s \n", argv[i]); + return 41; + } + size_t len = strlen(argv[i + 1]); + if(len >= 10) + { + printf("Error: max color string length is 10, %zu given\n", len); + return 42; + } + strcpy(state.color, argv[i + 1]); + ++i; + } + } //Start the printing ffPrintTitle(&state); diff --git a/src/fastfetch.h b/src/fastfetch.h index b905929b7..894777302 100644 --- a/src/fastfetch.h +++ b/src/fastfetch.h @@ -16,6 +16,7 @@ #include #define FASTFETCH_TEXT_MODIFIER_BOLT "\033[1m" +#define FASTFETCH_TEXT_MODIFIER_ERROR "\033[1;31m" #define FASTFETCH_TEXT_MODIFIER_RESET "\033[0m" typedef struct FFstate @@ -29,6 +30,8 @@ typedef struct FFstate uint8_t logo_seperator; char color[10]; + bool showErrors; + uint8_t titleLength; struct passwd* passwd; struct utsname utsname; @@ -44,9 +47,12 @@ uint32_t ffReadFile(const char* fileName, char* buffer, uint32_t bufferSize); void ffParsePropFile(const char* file, const char* regex, char* buffer); void ffParsePropFileHome(FFstate* state, const char* relativeFile, const char* regex, char* buffer); void ffPrintGtkPretty(const char* gtk2, const char* gtk3, const char* gtk4); +void ffPrintError(FFstate* state, const char* key, const char* message); void ffLoadLogoSet(FFstate* state, const char* logo); void ffLoadLogo(FFstate* state); +void ffListLogos(); +void ffPrintLogos(); void ffPrintBreak(FFstate* state); void ffPrintTitle(FFstate* state); diff --git a/src/font.c b/src/font.c index 27deda393..9b321f010 100644 --- a/src/font.c +++ b/src/font.c @@ -1,32 +1,52 @@ #include "fastfetch.h" +#include + static void parseFont(char* font, char* buffer) { char name[64]; char size[32]; - sscanf(font, "%[^,], %[^,]", name, size); - sprintf(buffer, "%s (%spt)", name, size); + int scanned = sscanf(font, "%[^,], %[^,]", name, size); + + if(scanned == 0) + strcpy(buffer, font); + else if(scanned == 1) + strcpy(buffer, name); + else + sprintf(buffer, "%s (%spt)", name, size); } void ffPrintFont(FFstate* state) { char plasma[256]; ffParsePropFileHome(state, ".config/kdeglobals", "font=%[^\n]", plasma); - + char gtk2[256]; ffParsePropFileHome(state, ".gtkrc-2.0", "gtk-font-name=\"%[^\"]+", gtk2); + char gtk2Pretty[256]; - parseFont(gtk2, gtk2Pretty); + if(gtk2[0] == '\0') + gtk2Pretty[0] = '\0'; + else + parseFont(gtk2, gtk2Pretty); char gtk3[256]; ffParsePropFileHome(state, ".config/gtk-3.0/settings.ini", "gtk-font-name=%[^\n]", gtk3); + char gtk3Pretty[256]; - parseFont(gtk3, gtk3Pretty); + if(gtk3[0] == '\0') + gtk3Pretty[0]== '\0'; + else + parseFont(gtk3, gtk3Pretty); char gtk4[256]; ffParsePropFileHome(state, ".config/gtk-4.0/settings.ini", "gtk-font-name=%[^\n]", gtk4); + char gtk4Pretty[256]; - parseFont(gtk4, gtk4Pretty); + if(gtk4Pretty[0] == '\0') + gtk4Pretty[0] = '\0'; + else + parseFont(gtk4, gtk4Pretty); ffPrintLogoAndKey(state, "Font"); diff --git a/src/host.c b/src/host.c index 2bc5f0778..c778ca5eb 100644 --- a/src/host.c +++ b/src/host.c @@ -2,12 +2,33 @@ void ffPrintHost(FFstate* state) { + FILE* nameFile = fopen("/sys/devices/virtual/dmi/id/product_name", "r"); + if(nameFile == NULL) + { + if(state->showErrors) + ffPrintError(state, "Host", "fopen(\"/sys/devices/virtual/dmi/id/product_name\", \"r\") == NULL"); + return; + } char name[256]; - ffReadFile("/sys/devices/virtual/dmi/id/product_name", name, 256); - - char version[256]; - ffReadFile("/sys/devices/virtual/dmi/id/product_version", version, 256); + if(fscanf(nameFile, "%[^\n]", name) != 1) + { + if(state->showErrors) + ffPrintError(state, "Host", "fscanf(nameFile, \"%[^\\n]\", name) != 1"); + return; + } + fclose(nameFile); ffPrintLogoAndKey(state, "Host"); - printf("%s %s\n", name, version); + printf(name); + + FILE* versionFile = fopen("/sys/devices/virtual/dmi/id/product_version", "r"); + if(versionFile != NULL) + { + char version[256]; + if(fscanf(versionFile, "%[^\n]", version) == 1) + printf(" %s", version); + fclose(versionFile); + } + + putchar('\n'); } \ No newline at end of file diff --git a/src/icons.c b/src/icons.c index 520b66caa..d817b601b 100644 --- a/src/icons.c +++ b/src/icons.c @@ -1,5 +1,7 @@ #include "fastfetch.h" +#include + void ffPrintIcons(FFstate* state) { char plasma[256]; @@ -7,16 +9,24 @@ void ffPrintIcons(FFstate* state) char gtk2[256]; ffParsePropFileHome(state, ".gtkrc-2.0", "gtk-icon-theme-name=\"%[^\"]+", gtk2); + if(gtk2[0] == '\0') + strcpy(gtk2, "Adwaita"); char gtk3[256]; ffParsePropFileHome(state, ".config/gtk-3.0/settings.ini", "gtk-icon-theme-name=%[^\n]", gtk3); + if(gtk3[0] == '\0') + strcpy(gtk3, "Adwaita"); char gtk4[256]; ffParsePropFileHome(state, ".config/gtk-4.0/settings.ini", "gtk-icon-theme-name=%[^\n]", gtk4); + if(gtk4[0] == '\0') + strcpy(gtk4, "Adwaita"); ffPrintLogoAndKey(state, "Icons"); - if(plasma[0] != '\0') + if(plasma[0] == '\0') + printf("Breeze [Plasma], "); + else printf("%s [Plasma], ", plasma); ffPrintGtkPretty(gtk2, gtk3, gtk4); diff --git a/src/locale.c b/src/locale.c index 23eaac83f..3a5f809c1 100644 --- a/src/locale.c +++ b/src/locale.c @@ -4,6 +4,12 @@ void ffPrintLocale(FFstate* state) { char locale[256]; ffParsePropFile("/etc/locale.conf", "LANG=%[^\n]", locale); + if(locale[0] == '\0') + { + if(state->showErrors) + ffPrintError(state, "Locale", "\"LANG=%[^\\n]\" not found in \"/etc/locale.conf\""); + return; + } ffPrintLogoAndKey(state, "Locale"); puts(locale); diff --git a/src/logo.c b/src/logo.c index 7d0cf142c..087c8c7d4 100644 --- a/src/logo.c +++ b/src/logo.c @@ -96,3 +96,13 @@ void ffPrintLogoLine(FFstate* state) ++state->current_row; } + +void ffListLogos() +{ + puts("not implemented"); +} + +void ffPrintLogos() +{ + puts("not implemented"); +} \ No newline at end of file diff --git a/src/memory.c b/src/memory.c index 56804da58..db88958ba 100644 --- a/src/memory.c +++ b/src/memory.c @@ -3,11 +3,10 @@ // Impl by: https://github.com/sam-barr/paleofetch/blob/b7c58a52c0de39b53c9b5f417889a5886d324bfa/paleofetch.c#L544 void ffPrintMemory(FFstate* state) { - ffPrintLogoAndKey(state, "Memory"); - FILE* meminfo = fopen("/proc/meminfo", "r"); if(meminfo == NULL) { - printf("[Error opening /proc/meminfo\n"); + if(state->showErrors) + ffPrintError(state, "Memory", "fopen(\"/proc/meminfo\", \"r\") == NULL"); return; } @@ -32,5 +31,6 @@ void ffPrintMemory(FFstate* state) uint32_t total_mem = total / 1024; uint8_t percentage = (uint8_t) ((used_mem / (double) total_mem) * 100); + ffPrintLogoAndKey(state, "Memory"); printf("%uMiB / %uMiB (%u%%)\n", used_mem, total_mem, percentage); } \ No newline at end of file diff --git a/src/os.c b/src/os.c index 49c39fb04..9d76c7741 100644 --- a/src/os.c +++ b/src/os.c @@ -2,23 +2,15 @@ void ffPrintOS(FFstate* state) { - char* line = NULL; char name[256]; - size_t len; - - FILE* os_release = fopen("/etc/os-release", "r"); - if(os_release == NULL) - exit(2); - - while (getline(&line, &len, os_release) != -1) + ffParsePropFile("/etc/os-release", "NAME=\"%[^\"]+", name); + if(name[0] == '\0') { - if (sscanf(line, "NAME=\"%[^\"]+", name) > 0) - break; + if(state->showErrors) + ffPrintError(state, "OS", "\"NAME=\\\"%[^\\\"]+\" not found in \"/etc/os-release\""); + return; } - fclose(os_release); - free(line); - ffPrintLogoAndKey(state, "OS"); printf("%s %s\n", name, state->utsname.machine); } \ No newline at end of file diff --git a/src/packages.c b/src/packages.c index 459dc4be5..a83b5ba8c 100644 --- a/src/packages.c +++ b/src/packages.c @@ -8,9 +8,8 @@ static uint32_t get_num_dirs(const char* dirname) { struct dirent *entry; dirp = opendir(dirname); - if(dirp == NULL) { - fprintf(stderr, "Error opening directory: %s\n", dirname); - } + if(dirp == NULL) + return 0; while((entry = readdir(dirp)) != NULL) { if(entry->d_type == DT_DIR) diff --git a/src/shell.c b/src/shell.c index b3c302d94..31bd66492 100644 --- a/src/shell.c +++ b/src/shell.c @@ -5,6 +5,13 @@ void ffPrintShell(FFstate* state) { char* shellPath = getenv("SHELL"); + if(shellPath == NULL) + { + if(state->showErrors) + ffPrintError(state, "Shell", "getenv(\"SHELL\") == NULL"); + return; + } + char* shellName = strrchr(shellPath, '/'); if(shellName == NULL) @@ -13,5 +20,5 @@ void ffPrintShell(FFstate* state) ++shellName; ffPrintLogoAndKey(state, "Shell"); - printf("%s\n", shellName); + puts(shellName); } \ No newline at end of file diff --git a/src/terminal.c b/src/terminal.c index 048196071..6675ae54a 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -2,7 +2,7 @@ #include -void printTerminalName(const char* pid) +void printTerminalName(FFstate* state, const char* pid) { char file[256]; sprintf(file, "/proc/%s/stat", pid); @@ -10,15 +10,23 @@ void printTerminalName(const char* pid) FILE* stat = fopen(file, "r"); if(stat == NULL) { - printf("[Error opening %s]", file); + if(state->showErrors) + { + char error[256]; + sprintf(error, "fopen(\"%s\", \"r\") == NULL", file); + ffPrintError(state, "Terminal", error); + } return; } char name[256]; char ppid[256]; - if(fscanf(stat, "%*s (%[^)])%*s%s", name, ppid) != 2) + { + if(state->showErrors) + ffPrintError(state, "Terminal", "fscanf(stat, \"%*s (%[^)])%*s%s\", name, ppid) != 2"); return; + } fclose(stat); @@ -32,9 +40,13 @@ void printTerminalName(const char* pid) strcmp(name, "su") == 0 || strcmp(name, "doas") == 0 ) { - printTerminalName(ppid); + printTerminalName(state, ppid); + return; } - else if( + + ffPrintLogoAndKey(state, "Terminal"); + + if( strcmp(name, "systemd") == 0 || strcmp(name, "init") == 0 || strcmp(ppid, "0") == 0 ) @@ -43,7 +55,7 @@ void printTerminalName(const char* pid) } else { - printf("%s\n", name); + puts(name); } } @@ -51,7 +63,5 @@ void ffPrintTerminal(FFstate* state) { char ppid[256]; sprintf(ppid, "%i", getppid()); - - ffPrintLogoAndKey(state, "Terminal"); - printTerminalName(ppid); + printTerminalName(state, ppid); } diff --git a/src/theme.c b/src/theme.c index 1b76f3981..fd0cb097a 100644 --- a/src/theme.c +++ b/src/theme.c @@ -1,5 +1,7 @@ #include "fastfetch.h" +#include + void ffPrintTheme(FFstate* state) { char plasma[256]; @@ -7,16 +9,24 @@ void ffPrintTheme(FFstate* state) char gtk2[256]; ffParsePropFileHome(state, ".gtkrc-2.0", "gtk-theme-name=\"%[^\"]+", gtk2); + if(gtk2[0] == '\0') + strcpy(gtk2, "Raleigh"); char gtk3[256]; ffParsePropFileHome(state, ".config/gtk-3.0/settings.ini", "gtk-theme-name=%[^\n]", gtk3); + if(gtk3[0] == '\0') + strcpy(gtk3, "Adwaita"); char gtk4[256]; ffParsePropFileHome(state, ".config/gtk-4.0/settings.ini", "gtk-theme-name=%[^\n]", gtk4); + if(gtk4[0] == '\0') + strcpy(gtk4, "Adwaita"); ffPrintLogoAndKey(state, "Theme"); - if(plasma[0] != '\0') + if(plasma[0] == '\0') + printf("Breeze [Plasma], "); + else printf("%s [Plasma], ", plasma); ffPrintGtkPretty(gtk2, gtk3, gtk4); diff --git a/src/uptime.c b/src/uptime.c index 7c43ee95c..c4e62c856 100644 --- a/src/uptime.c +++ b/src/uptime.c @@ -3,6 +3,12 @@ void ffPrintUptime(FFstate* state) { + if(state->sysinfo.uptime < 60) + { + printf("%ls seconds\n", state->sysinfo.uptime); + return; + } + int days = state->sysinfo.uptime / 86400; int hours = (state->sysinfo.uptime - (days * 86400)) / 3600; int minutes = (state->sysinfo.uptime - (days * 86400) - (hours * 3600)) / 60; @@ -15,5 +21,8 @@ void ffPrintUptime(FFstate* state) if(hours > 0) printf("%d hour%s, ", hours, hours <= 1 ? "" : "s"); - printf("%d min%s\n", minutes, minutes <= 1 ? "" : "s"); + if(minutes > 0) + printf("%d min%s", minutes, minutes <= 1 ? "" : "s"); + + putchar('\n'); } \ No newline at end of file