commit 300acfb668e4b27c115be2d674bfdaa1e6faaf67 Author: Puechberty Arthur Date: Fri Jun 26 19:24:41 2026 +0200 first commit diff --git a/config.c b/config.c new file mode 100644 index 0000000..a49047d --- /dev/null +++ b/config.c @@ -0,0 +1,35 @@ +#include "optifetch.h" + +void generate_default_config(const char* path) { + FILE *f = fopen(path, "w"); + if (!f) return; + + fprintf(f, "{reset}{align:L}{bold}{user}{reset}@{bold}{host}{reset}\n"); + fprintf(f, "{align:L}-----------------------------\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}OS{reset}: {align:V}{os}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}Host{reset}: {align:V}{host_model}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}Kernel{reset}: {align:V}{kernel} {arch}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}Uptime{reset}: {align:V}{uptime}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}Packages{reset}: {align:V}{packages}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}Shell{reset}: {align:V}{shell}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}DE/WM{reset}: {align:V}{de} ({wm})\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}Display{reset}: {align:V}{display_server}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}Terminal{reset}: {align:V}{term}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}CPU{reset}: {align:V}{cpu} ({cores}) @ {cpu_max_freq}MHz\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{if:gpu}{fg:255,255,0}GPU{reset}: {align:V}{gpu}{endif}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}Memory{reset}: {align:V}{ram:gb} ({ram:%%})\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{if:swap}{fg:255,255,0}Swap{reset}: {align:V}{swap:gb} ({swap:%%}){endif}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}Disk{reset}: {align:V}{disk:gb} ({disk:%%}) - {disk_fs}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}Theme{reset}: {align:V}{theme}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}Font{reset}: {align:V}{font}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}Locale{reset}: {align:V}{locale}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{if:laptop}{fg:255,255,0}Battery{reset}: {align:V}{battery} ({bat_status}){endif}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}Date{reset}: {align:V}{date} {time}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}Local IP{reset}: {align:V}{ip_local}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{if:wifi}{fg:255,255,0}Wifi{reset}: {align:V}{wifi}{endif}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}Public IP{reset}: {align:V}{ip_public}\n"); + fprintf(f, "{fg:0,255,255} {logo} {align:L}{fg:255,255,0}DNS{reset}: {align:V}{dns}\n"); + fprintf(f, "\n"); + fprintf(f, "{align:L}{fg:0,255,0}███{fg:255,255,0}███{fg:255,0,255}███{fg:0,255,255}███{reset}\n"); + fclose(f); +} \ No newline at end of file diff --git a/logos.c b/logos.c new file mode 100644 index 0000000..473a100 --- /dev/null +++ b/logos.c @@ -0,0 +1,94 @@ +#include "optifetch.h" + +#define MAX_LOGO_LINES 100 +#define MAX_LOGO_WIDTH 512 + +typedef struct { + char id[64]; + char lines[MAX_LOGO_LINES][MAX_LOGO_WIDTH]; + int count; + int width; +} LogoCache; + +static LogoCache cache_normal[32]; +static LogoCache cache_small[32]; +static int cache_normal_count = 0; +static int cache_small_count = 0; + +static LogoCache* load_logo(const char* os_id, int small) { + LogoCache* cache_arr = small ? cache_small : cache_normal; + int* cache_cnt = small ? &cache_small_count : &cache_normal_count; + + for(int i=0; i<*cache_cnt; i++) { + if(strcmp(cache_arr[i].id, os_id) == 0) return &cache_arr[i]; + } + + if(*cache_cnt >= 32) return NULL; + + LogoCache* new_cache = &cache_arr[(*cache_cnt)++]; + snprintf(new_cache->id, sizeof(new_cache->id), "%s", os_id); + new_cache->count = 0; + new_cache->width = 0; + + char path[256]; + snprintf(path, sizeof(path), "logos/%s%s.txt", os_id, small ? "_small" : ""); + + FILE *f = fopen(path, "r"); + if (!f) return new_cache; + + char line[MAX_LOGO_WIDTH]; + while(fgets(line, sizeof(line), f) && new_cache->count < MAX_LOGO_LINES) { + line[strcspn(line, "\n")] = 0; + snprintf(new_cache->lines[new_cache->count], MAX_LOGO_WIDTH, "%s", line); + + int w = 0; + for(int j=0; j new_cache->width) new_cache->width = w; + + new_cache->count++; + } + fclose(f); + return new_cache; +} + +void get_logo_line(const char* os_id, int small, int idx, char* out, size_t size) { + LogoCache* c = load_logo(os_id, small); + + if(!c) { + out[0] = '\0'; + return; + } + + if(idx < c->count) { + snprintf(out, size, "%s", c->lines[idx]); + // CORRECTION : On pad la ligne avec des espaces pour que toutes les lignes du logo + // fassent exactement la même largeur visuelle. C'est vital pour l'alignement. + int current_w = 0; + for(int j=0; jwidth - current_w; + if(pad > 0) { + int len = strlen(out); + if (len + pad + 1 < (int)size) { + for(int i=0; iwidth > 0 && size > (size_t)c->width) { + for(int i=0; iwidth; i++) out[i] = ' '; + out[c->width] = '\0'; + } else { + out[0] = '\0'; + } + } +} + +int get_logo_height(const char* os_id, int small) { + LogoCache* c = load_logo(os_id, small); + return c ? c->count : 0; +} \ No newline at end of file diff --git a/logos/arch.txt b/logos/arch.txt new file mode 100644 index 0000000..c534ff9 --- /dev/null +++ b/logos/arch.txt @@ -0,0 +1,19 @@ + -` + .o+` + `ooo/ + `+oooo: + `+oooooo: + -+oooooo+: + `/:-:++oooo+: + `/++++/+++++++: + `/++++++++++++++: + `/+++ooooooooooooo/` + ./ooosssso++osssssso+` + .oossssso-````/ossssss+` + -osssssso. :ssssssso. + :osssssss/ osssso+++. + /ossssssss/ +ssssooo/- + `/ossssso+/:- -:/+osssso+- + `+sso+:-` `.-/+oso: +`++:. `-/+/ +.` `/ \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..38c32ff --- /dev/null +++ b/main.c @@ -0,0 +1,56 @@ +#include "optifetch.h" + +void print_help() { + printf("Optifetch - Lightweight system info tool\n\n"); + printf("Usage: optifetch [options]\n\n"); + printf("Options:\n"); + printf(" help Show this help message\n"); + printf(" (none) Run optifetch with default or custom config\n\n"); + printf("Configuration:\n"); + printf(" A file named 'optifetch.conf' is generated on first run.\n"); + printf(" You can edit it to customize the output.\n\n"); + printf("Available Variables:\n"); + printf(" {logo} {small_logo} {user} {host} {os} {kernel} {uptime} {arch}\n"); + printf(" {shell} {cpu} {cores} {cpu_max_freq} {gpu} {de} {wm} {term}\n"); + printf(" {packages} {battery} {bat_status} {date} {time}\n"); + printf(" {ip_local} {ip_public} {dns} {wifi} {host_model}\n"); + printf(" {display_server} {theme} {font} {locale} {disk_fs}\n\n"); + printf("Variables with Units:\n"); + printf(" {ram:gb} {ram:mb} {ram:%%}\n"); + printf(" {swap:gb} {swap:mb} {swap:%%}\n"); + printf(" {disk:gb} {disk:mb} {disk:%%}\n\n"); + printf("Formatting:\n"); + printf(" {align:id} Align text to the max width of all 'id' tags\n"); + printf(" {fg:R,G,B} Set foreground color (e.g. {fg:255,0,0})\n"); + printf(" {bg:R,G,B} Set background color\n"); + printf(" {fg:red} Named colors (red, green, blue, yellow, cyan, magenta, white, black)\n"); + printf(" {bold} Bold text\n"); + printf(" {reset} Reset formatting\n\n"); + printf("Conditionals:\n"); + printf(" {if:laptop} ... {endif} Show only if battery exists\n"); + printf(" {if:gpu} ... {endif} Show only if GPU exists\n"); + printf(" {if:swap} ... {endif} Show only if swap is active\n"); + printf(" {if:wifi} ... {endif} Show only if connected to wifi\n"); +} + +int main(int argc, char *argv[]) { + if (argc > 1 && (strcmp(argv[1], "help") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0)) { + print_help(); + return 0; + } + + SysInfo info; + get_info(&info); + + const char *config_path = "optifetch.conf"; + + if (access(config_path, F_OK) != 0) { + generate_default_config(config_path); + printf("Fichier de configuration '%s' créé. Modifiez-le pour personnaliser l'affichage.\n\n", config_path); + } + + render_config(config_path, &info); + + printf("\033[0m"); + return 0; +} \ No newline at end of file diff --git a/optifetch b/optifetch new file mode 100755 index 0000000..73a3e42 Binary files /dev/null and b/optifetch differ diff --git a/optifetch.conf b/optifetch.conf new file mode 100644 index 0000000..c86a7e0 --- /dev/null +++ b/optifetch.conf @@ -0,0 +1,27 @@ +{reset}{align:L}{bold}{user}{reset}@{bold}{host}{reset} +{align:L}----------------------------- +{fg:0,255,255} {logo} {fg:255,255,0}OS{reset}: {align:V}{os} +{fg:0,255,255} {logo} {fg:255,255,0}Host{reset}: {align:V}{host_model} +{fg:0,255,255} {logo} {fg:255,255,0}Kernel{reset}: {align:V}{kernel} {arch} +{fg:0,255,255} {logo} {fg:255,255,0}Uptime{reset}: {align:V}{uptime} +{fg:0,255,255} {logo} {fg:255,255,0}Packages{reset}: {align:V}{packages} +{fg:0,255,255} {logo} {fg:255,255,0}Shell{reset}: {align:V}{shell} +{fg:0,255,255} {logo} {fg:255,255,0}DE/WM{reset}: {align:V}{de} ({wm}) +{fg:0,255,255} {logo} {fg:255,255,0}Display{reset}: {align:V}{display_server} +{fg:0,255,255} {logo} {fg:255,255,0}Terminal{reset}: {align:V}{term} +{fg:0,255,255} {logo} {fg:255,255,0}CPU{reset}: {align:V}{cpu} ({cores}) @ {cpu_max_freq}MHz +{fg:0,255,255} {logo} {if:gpu}{fg:255,255,0}GPU{reset}: {align:V}{gpu}{endif} +{fg:0,255,255} {logo} {fg:255,255,0}Memory{reset}: {align:V}{ram:gb} ({ram:%}) +{fg:0,255,255} {logo} {if:swap}{fg:255,255,0}Swap{reset}: {align:V}{swap:gb} ({swap:%}){endif} +{fg:0,255,255} {logo} {fg:255,255,0}Disk{reset}: {align:V}{disk:gb} ({disk:%}) - {disk_fs} +{fg:0,255,255} {logo} {fg:255,255,0}Theme{reset}: {align:V}{theme} +{fg:0,255,255} {logo} {fg:255,255,0}Font{reset}: {align:V}{font} +{fg:0,255,255} {logo} {fg:255,255,0}Locale{reset}: {align:V}{locale} +{fg:0,255,255} {logo} {if:laptop}{fg:255,255,0}Battery{reset}: {align:V}{battery} ({bat_status}){endif} +{fg:0,255,255} {logo} {fg:255,255,0}Date{reset}: {align:V}{date} {time} +{fg:0,255,255} {logo} {fg:255,255,0}Local IP{reset}: {align:V}{ip_local} +{fg:0,255,255} {logo} {if:wifi}{fg:255,255,0}Wifi{reset}: {align:V}{wifi}{endif} +{fg:0,255,255} {logo} {fg:255,255,0}Public IP{reset}: {align:V}{ip_public} +{fg:0,255,255} {logo} {align:L}{fg:255,255,0}DNS{reset}: {align:V}{dns} + +{fg:0,255,0}███{fg:255,255,0}███{fg:255,0,255}███{fg:0,255,255}███{reset} diff --git a/optifetch.h b/optifetch.h new file mode 100644 index 0000000..dd18f70 --- /dev/null +++ b/optifetch.h @@ -0,0 +1,68 @@ +#ifndef OPTIFETCH_H +#define OPTIFETCH_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUF_SIZE 4096 + +typedef struct { + char user[128]; + char hostname[256]; + char os[256]; + char os_id[64]; + char kernel[128]; + char uptime[128]; + char arch[128]; + char shell[128]; + char cpu[256]; + char gpu[256]; + char de[128]; + char wm[128]; + char term[128]; + char packages[128]; + long cores; + long cpu_max_freq; + + char host_model[128]; + char display_server[32]; + char theme[128]; + char font[128]; + char locale[64]; + char dns[64]; + char wifi[128]; + char ip_public[64]; + char disk_fs[32]; + + unsigned long ram_total_mb; + unsigned long ram_used_mb; + unsigned long swap_total_mb; + unsigned long swap_used_mb; + unsigned long disk_total_mb; + unsigned long disk_used_mb; + char battery[64]; + char battery_status[64]; + char date[64]; + char time_str[64]; + char ip_local[128]; +} SysInfo; + +void get_info(SysInfo *info); +void get_logo_line(const char* os_id, int small, int idx, char* out, size_t size); +int get_logo_height(const char* os_id, int small); // NOUVEAU +void generate_default_config(const char* path); +void render_config(const char* path, SysInfo *info); +void print_help(); + +#endif \ No newline at end of file diff --git a/renderer.c b/renderer.c new file mode 100644 index 0000000..9e44a2c --- /dev/null +++ b/renderer.c @@ -0,0 +1,253 @@ +#include "optifetch.h" + +#define MAX_ALIGN_IDS 32 + +typedef struct { + char id[32]; + int max_width; +} AlignID; + +static AlignID align_ids[MAX_ALIGN_IDS]; +static int align_count = 0; + +static int current_col = 0; +static int skip_output = 0; +static int current_line_num = 0; +static int current_pass = 1; + +// NOUVEAU : Variables pour gérer l'index du logo indépendamment des lignes du fichier +static int logo_line_idx = 0; +static int prev_line_had_logo = 0; + +static int get_align_width(const char* id) { + for(int i=0; i align_ids[i].max_width) align_ids[i].max_width = width; + return; + } + } + if(align_count < MAX_ALIGN_IDS) { + snprintf(align_ids[align_count].id, sizeof(align_ids[align_count].id), "%.31s", id); + align_ids[align_count].max_width = width; + align_count++; + } +} + +static void my_putchar(char c) { + if (skip_output) return; + if (current_pass == 2) { + putchar(c); + } + if ((c & 0xC0) != 0x80) { + current_col++; + } +} + +static void my_putstr(const char* s) { + for (int i = 0; s[i]; i++) my_putchar(s[i]); +} + +static void print_color(const char* params, int is_bg) { + if (skip_output || current_pass == 1) return; + int r, g, b; + if (sscanf(params, "%d,%d,%d", &r, &g, &b) == 3) { + printf("\033[%d;2;%d;%d;%dm", is_bg ? 48 : 38, r, g, b); + return; + } + if (strcmp(params, "red") == 0) r=255, g=0, b=0; + else if (strcmp(params, "green") == 0) r=0, g=255, b=0; + else if (strcmp(params, "blue") == 0) r=0, g=0, b=255; + else if (strcmp(params, "yellow") == 0) r=255, g=255, b=0; + else if (strcmp(params, "cyan") == 0) r=0, g=255, b=255; + else if (strcmp(params, "magenta") == 0) r=255, g=0, b=255; + else if (strcmp(params, "white") == 0) r=255, g=255, b=255; + else if (strcmp(params, "black") == 0) r=0, g=0, b=0; + else r=200, g=200, b=200; + printf("\033[%d;2;%d;%d;%dm", is_bg ? 48 : 38, r, g, b); +} + +static void print_variable(const char* name, SysInfo *info) { + if (skip_output) return; + + char buf[1024]; + buf[0] = '\0'; + + if (strcmp(name, "logo") == 0 || strcmp(name, "small_logo") == 0) { + // NOUVEAU : On utilise logo_line_idx au lieu de current_line_num + get_logo_line(info->os_id, name[0] == 's', logo_line_idx, buf, sizeof(buf)); + } + else if (strcmp(name, "user") == 0) snprintf(buf, sizeof(buf), "%s", info->user); + else if (strcmp(name, "host") == 0) snprintf(buf, sizeof(buf), "%s", info->hostname); + else if (strcmp(name, "os") == 0) snprintf(buf, sizeof(buf), "%s", info->os); + else if (strcmp(name, "kernel") == 0) snprintf(buf, sizeof(buf), "%s", info->kernel); + else if (strcmp(name, "uptime") == 0) snprintf(buf, sizeof(buf), "%s", info->uptime); + else if (strcmp(name, "arch") == 0) snprintf(buf, sizeof(buf), "%s", info->arch); + else if (strcmp(name, "shell") == 0) snprintf(buf, sizeof(buf), "%s", info->shell); + else if (strcmp(name, "cpu") == 0) snprintf(buf, sizeof(buf), "%s", info->cpu); + else if (strcmp(name, "cores") == 0) snprintf(buf, sizeof(buf), "%ld", info->cores); + else if (strcmp(name, "cpu_max_freq") == 0) snprintf(buf, sizeof(buf), "%ld", info->cpu_max_freq); + else if (strcmp(name, "gpu") == 0) snprintf(buf, sizeof(buf), "%s", info->gpu); + else if (strcmp(name, "de") == 0) snprintf(buf, sizeof(buf), "%s", info->de); + else if (strcmp(name, "wm") == 0) snprintf(buf, sizeof(buf), "%s", info->wm); + else if (strcmp(name, "term") == 0) snprintf(buf, sizeof(buf), "%s", info->term); + else if (strcmp(name, "packages") == 0) snprintf(buf, sizeof(buf), "%s", info->packages); + else if (strcmp(name, "battery") == 0) snprintf(buf, sizeof(buf), "%s", info->battery); + else if (strcmp(name, "bat_status") == 0) snprintf(buf, sizeof(buf), "%s", info->battery_status); + else if (strcmp(name, "date") == 0) snprintf(buf, sizeof(buf), "%s", info->date); + else if (strcmp(name, "time") == 0) snprintf(buf, sizeof(buf), "%s", info->time_str); + else if (strcmp(name, "ip_local") == 0) snprintf(buf, sizeof(buf), "%s", info->ip_local); + else if (strcmp(name, "ip_public") == 0) snprintf(buf, sizeof(buf), "%s", info->ip_public); + else if (strcmp(name, "dns") == 0) snprintf(buf, sizeof(buf), "%s", info->dns); + else if (strcmp(name, "wifi") == 0) snprintf(buf, sizeof(buf), "%s", info->wifi[0] ? info->wifi : "N/A"); + else if (strcmp(name, "host_model") == 0) snprintf(buf, sizeof(buf), "%s", info->host_model); + else if (strcmp(name, "display_server") == 0) snprintf(buf, sizeof(buf), "%s", info->display_server); + else if (strcmp(name, "theme") == 0) snprintf(buf, sizeof(buf), "%s", info->theme); + else if (strcmp(name, "font") == 0) snprintf(buf, sizeof(buf), "%s", info->font); + else if (strcmp(name, "locale") == 0) snprintf(buf, sizeof(buf), "%s", info->locale); + else if (strcmp(name, "disk_fs") == 0) snprintf(buf, sizeof(buf), "%s", info->disk_fs); + else if (strncmp(name, "ram", 3) == 0) { + char unit[128] = "mb"; + if (strlen(name) > 4 && name[3] == ':') snprintf(unit, sizeof(unit), "%s", name + 4); + if (strcmp(unit, "gb") == 0) snprintf(buf, sizeof(buf), "%.1fGB / %.1fGB", (double)info->ram_used_mb / 1024.0, (double)info->ram_total_mb / 1024.0); + else if (strcmp(unit, "%") == 0) snprintf(buf, sizeof(buf), "%.1f%%", info->ram_total_mb ? (double)info->ram_used_mb / (double)info->ram_total_mb * 100.0 : 0); + else snprintf(buf, sizeof(buf), "%luMB / %luMB", info->ram_used_mb, info->ram_total_mb); + } + else if (strncmp(name, "swap", 4) == 0) { + char unit[128] = "mb"; + if (strlen(name) > 5 && name[4] == ':') snprintf(unit, sizeof(unit), "%s", name + 5); + if (strcmp(unit, "gb") == 0) snprintf(buf, sizeof(buf), "%.1fGB / %.1fGB", (double)info->swap_used_mb / 1024.0, (double)info->swap_total_mb / 1024.0); + else if (strcmp(unit, "%") == 0) snprintf(buf, sizeof(buf), "%.1f%%", info->swap_total_mb ? (double)info->swap_used_mb / (double)info->swap_total_mb * 100.0 : 0); + else snprintf(buf, sizeof(buf), "%luMB / %luMB", info->swap_used_mb, info->swap_total_mb); + } + else if (strncmp(name, "disk", 4) == 0) { + char unit[128] = "mb"; + if (strlen(name) > 5 && name[4] == ':') snprintf(unit, sizeof(unit), "%s", name + 5); + if (strcmp(unit, "gb") == 0) snprintf(buf, sizeof(buf), "%.1fGB / %.1fGB", (double)info->disk_used_mb / 1024.0, (double)info->disk_total_mb / 1024.0); + else if (strcmp(unit, "%") == 0) snprintf(buf, sizeof(buf), "%.1f%%", info->disk_total_mb ? (double)info->disk_used_mb / (double)info->disk_total_mb * 100.0 : 0); + else snprintf(buf, sizeof(buf), "%luMB / %luMB", info->disk_used_mb, info->disk_total_mb); + } + else { + snprintf(buf, sizeof(buf), "{%s}", name); + } + + my_putstr(buf); +} + +static void process_line(const char* line, SysInfo *info) { + int i = 0; + current_col = 0; + skip_output = 0; + + // NOUVEAU : Détection de la présence du logo sur la ligne courante + int has_logo = (strstr(line, "{logo}") != NULL || strstr(line, "{small_logo}") != NULL); + if (has_logo && !prev_line_had_logo) { + logo_line_idx = 0; // On réinitialise l'index du logo à 0 si c'est le début du logo + } + + while (line[i] != '\0' && line[i] != '\n') { + if (line[i] == '{') { + int j = i + 1; + char token[128]; + int k = 0; + while (line[j] != '}' && line[j] != '\0' && line[j] != '\n' && k < 127) { + token[k++] = line[j++]; + } + token[k] = '\0'; + if (line[j] == '}') { + i = j + 1; + + if (strcmp(token, "if:laptop") == 0) skip_output = (strcmp(info->battery, "N/A") == 0); + else if (strcmp(token, "if:gpu") == 0) skip_output = (strlen(info->gpu) == 0); + else if (strcmp(token, "if:swap") == 0) skip_output = (info->swap_total_mb == 0); + else if (strcmp(token, "if:wifi") == 0) skip_output = (strlen(info->wifi) == 0); + else if (strcmp(token, "endif") == 0) skip_output = 0; + + else if (strncmp(token, "align:", 6) == 0) { + if (!skip_output) { + if (current_pass == 1) { + set_align_width(token + 6, current_col); + } + int target = get_align_width(token + 6); + while (current_col < target) my_putchar(' '); + } + } + else if (strncmp(token, "fg:", 3) == 0) print_color(token + 3, 0); + else if (strncmp(token, "bg:", 3) == 0) print_color(token + 3, 1); + else if (strcmp(token, "reset") == 0) { if(!skip_output && current_pass == 2) printf("\033[0m"); } + else if (strcmp(token, "bold") == 0) { if(!skip_output && current_pass == 2) printf("\033[1m"); } + else print_variable(token, info); + + } else { + my_putchar(line[i++]); + } + } else { + my_putchar(line[i++]); + } + } + if (current_pass == 2 && !skip_output) putchar('\n'); + current_line_num++; + + // NOUVEAU : Mise à jour des variables pour la gestion du logo + prev_line_had_logo = has_logo; + if (has_logo) logo_line_idx++; +} + +void render_config(const char* path, SysInfo *info) { + FILE *f = fopen(path, "r"); + if (!f) return; + + static char lines[200][1024]; + int line_count = 0; + while (fgets(lines[line_count], sizeof(lines[line_count]), f) && line_count < 200) { + line_count++; + } + fclose(f); + + int logo_h = 0; + char logo_token[20] = ""; + + for (int i = 0; i < line_count; i++) { + if (strstr(lines[i], "{logo}")) { + snprintf(logo_token, sizeof(logo_token), "{logo}"); + logo_h = get_logo_height(info->os_id, 0); + } + if (strstr(lines[i], "{small_logo}")) { + snprintf(logo_token, sizeof(logo_token), "{small_logo}"); + int sh = get_logo_height(info->os_id, 1); + if (sh > logo_h) logo_h = sh; + } + } + + if (strlen(logo_token) > 0) { + while (line_count < logo_h && line_count < 200) { + snprintf(lines[line_count++], 1024, "%s{align:L} \n", logo_token); + } + } + + align_count = 0; + + // Pass 1 + current_pass = 1; + current_line_num = 0; + logo_line_idx = 0; + prev_line_had_logo = 0; + for (int i = 0; i < line_count; i++) { + process_line(lines[i], info); + } + + // Pass 2 + current_pass = 2; + current_line_num = 0; + logo_line_idx = 0; + prev_line_had_logo = 0; + for (int i = 0; i < line_count; i++) { + process_line(lines[i], info); + } +} \ No newline at end of file diff --git a/sysinfo.c b/sysinfo.c new file mode 100644 index 0000000..ced5107 --- /dev/null +++ b/sysinfo.c @@ -0,0 +1,168 @@ +#include "optifetch.h" + +static void read_file(const char *path, char *buf, size_t size) { + FILE *f = fopen(path, "r"); + if (!f) { if(size>0) buf[0] = '\0'; return; } + size_t n = fread(buf, 1, size - 1, f); + buf[n] = '\0'; + fclose(f); +} + +static void extract_value(const char *buf, const char *key, char *out, size_t size) { + out[0] = '\0'; + const char *p = strstr(buf, key); + if (p) { + p += strlen(key); + while (*p == ' ' || *p == '\t' || *p == ':' || *p == '=' || *p == '"') p++; + size_t i = 0; + while (p[i] && p[i] != '\n' && p[i] != '"' && i < size - 1) { + out[i] = p[i]; + i++; + } + out[i] = '\0'; + } +} + +static void clean_newline(char *str) { + str[strcspn(str, "\n")] = 0; +} + +void get_info(SysInfo *info) { + struct passwd *pw = getpwuid(getuid()); + snprintf(info->user, sizeof(info->user), "%s", pw ? pw->pw_name : "unknown"); + gethostname(info->hostname, sizeof(info->hostname)); + + char buf[BUF_SIZE]; + + read_file("/etc/os-release", buf, sizeof(buf)); + extract_value(buf, "PRETTY_NAME", info->os, sizeof(info->os)); + extract_value(buf, "ID", info->os_id, sizeof(info->os_id)); + + struct utsname uts; + uname(&uts); + snprintf(info->kernel, sizeof(info->kernel), "%s", uts.release); + snprintf(info->arch, sizeof(info->arch), "%s", uts.machine); + + struct sysinfo s_info; + sysinfo(&s_info); + int days = s_info.uptime / 86400; + int hours = (s_info.uptime % 86400) / 3600; + int mins = (s_info.uptime % 3600) / 60; + snprintf(info->uptime, sizeof(info->uptime), "%dd %dh %dm", days, hours, mins); + + const char *sh = getenv("SHELL"); + snprintf(info->shell, sizeof(info->shell), "%s", sh ? sh : "unknown"); + const char *ds = getenv("XDG_SESSION_TYPE"); + snprintf(info->display_server, sizeof(info->display_server), "%s", ds ? ds : "Unknown"); + const char *loc = getenv("LANG"); + snprintf(info->locale, sizeof(info->locale), "%s", loc ? loc : "Unknown"); + + read_file("/proc/cpuinfo", buf, sizeof(buf)); + extract_value(buf, "model name", info->cpu, sizeof(info->cpu)); + info->cores = sysconf(_SC_NPROCESSORS_ONLN); + read_file("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", buf, sizeof(buf)); + info->cpu_max_freq = atol(buf) / 1000; + + read_file("/sys/class/dmi/id/product_name", info->host_model, sizeof(info->host_model)); + clean_newline(info->host_model); + if (strlen(info->host_model) == 0) snprintf(info->host_model, sizeof(info->host_model), "Unknown"); + + info->ram_total_mb = s_info.totalram * s_info.mem_unit / (1024 * 1024); + info->ram_used_mb = (s_info.totalram - s_info.freeram) * s_info.mem_unit / (1024 * 1024); + info->swap_total_mb = s_info.totalswap * s_info.mem_unit / (1024 * 1024); + info->swap_used_mb = (s_info.totalswap - s_info.freeswap) * s_info.mem_unit / (1024 * 1024); + + struct statvfs vfs; + if (statvfs("/", &vfs) == 0) { + info->disk_total_mb = (vfs.f_blocks * vfs.f_frsize) / (1024 * 1024); + info->disk_used_mb = info->disk_total_mb - ((vfs.f_bfree * vfs.f_frsize) / (1024 * 1024)); + } else { + info->disk_total_mb = 0; info->disk_used_mb = 0; + } + FILE *fp_fs = popen("findmnt -no FSTYPE / 2>/dev/null", "r"); + if (fp_fs) { if (fgets(info->disk_fs, sizeof(info->disk_fs), fp_fs)) clean_newline(info->disk_fs); pclose(fp_fs); } + + const char *de = getenv("XDG_CURRENT_DESKTOP"); + const char *wm = getenv("DESKTOP_SESSION"); + snprintf(info->de, sizeof(info->de), "%s", de ? de : "Unknown"); + snprintf(info->wm, sizeof(info->wm), "%s", wm ? wm : info->de); + + const char *term = getenv("TERM"); + snprintf(info->term, sizeof(info->term), "%s", term ? term : "Unknown"); + + info->gpu[0] = '\0'; + FILE *fdrm = popen("cat /sys/class/drm/card*/device/uevent 2>/dev/null | grep DRIVER | head -n 1", "r"); + if (fdrm) { + char drmbuf[256]; + if (fgets(drmbuf, sizeof(drmbuf), fdrm)) { + extract_value(drmbuf, "DRIVER", info->gpu, sizeof(info->gpu)); + if(info->gpu[0] >= 'a' && info->gpu[0] <= 'z') info->gpu[0] -= 32; + } + pclose(fdrm); + } + + FILE *fp_th = popen("gsettings get org.gnome.desktop.interface gtk-theme 2>/dev/null | tr -d \"'\"", "r"); + if (fp_th) { if (fgets(info->theme, sizeof(info->theme), fp_th)) clean_newline(info->theme); pclose(fp_th); } + FILE *fp_fn = popen("gsettings get org.gnome.desktop.interface font-name 2>/dev/null | tr -d \"'\"", "r"); + if (fp_fn) { if (fgets(info->font, sizeof(info->font), fp_fn)) clean_newline(info->font); pclose(fp_fn); } + + int pkg_count = 0; + DIR *d; struct dirent *dir; + d = opendir("/var/lib/pacman/local"); + if (d) { while ((dir = readdir(d)) != NULL) if (dir->d_type == DT_DIR && dir->d_name[0] != '.') pkg_count++; closedir(d); } + else { + FILE *fp = popen("ls /var/lib/dpkg/info 2>/dev/null | grep -c '.list$' ; rpm -qa 2>/dev/null | wc -l", "r"); + if(fp) { char out[32]; if(fgets(out, sizeof(out), fp)) pkg_count = atoi(out); pclose(fp); } + } + snprintf(info->packages, sizeof(info->packages), "%d", pkg_count); + + char bat_path[256] = ""; + if (access("/sys/class/power_supply/BAT0/capacity", F_OK) == 0) snprintf(bat_path, sizeof(bat_path), "/sys/class/power_supply/BAT0"); + else if (access("/sys/class/power_supply/BAT1/capacity", F_OK) == 0) snprintf(bat_path, sizeof(bat_path), "/sys/class/power_supply/BAT1"); + if (strlen(bat_path) > 0) { + char cap_path[512], stat_path[512]; + snprintf(cap_path, sizeof(cap_path), "%s/capacity", bat_path); + snprintf(stat_path, sizeof(stat_path), "%s/status", bat_path); + read_file(cap_path, buf, sizeof(buf)); clean_newline(buf); + snprintf(info->battery, sizeof(info->battery), "%s%%", buf); + read_file(stat_path, buf, sizeof(buf)); clean_newline(buf); + snprintf(info->battery_status, sizeof(info->battery_status), "%s", buf); + } else { + snprintf(info->battery, sizeof(info->battery), "N/A"); + snprintf(info->battery_status, sizeof(info->battery_status), "N/A"); + } + + time_t t = time(NULL); + struct tm tm = *localtime(&t); + snprintf(info->date, sizeof(info->date), "%02d/%02d/%04d", tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900); + snprintf(info->time_str, sizeof(info->time_str), "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec); + + info->ip_local[0] = '\0'; + struct ifaddrs *ifaddr, *ifa; + if (getifaddrs(&ifaddr) == 0) { + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) continue; + if (ifa->ifa_addr->sa_family == AF_INET) { + struct sockaddr_in *sa = (struct sockaddr_in *)ifa->ifa_addr; + char ip[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &sa->sin_addr, ip, INET_ADDRSTRLEN); + if (strcmp(ip, "127.0.0.1") != 0) { + snprintf(info->ip_local, sizeof(info->ip_local), "%s (%s)", ip, ifa->ifa_name); + break; + } + } + } + freeifaddrs(ifaddr); + } + + read_file("/etc/resolv.conf", buf, sizeof(buf)); + extract_value(buf, "nameserver", info->dns, sizeof(info->dns)); + + info->wifi[0] = '\0'; + FILE *fp_wf = popen("iwgetid -r 2>/dev/null", "r"); + if (fp_wf) { if (fgets(info->wifi, sizeof(info->wifi), fp_wf)) clean_newline(info->wifi); pclose(fp_wf); } + + info->ip_public[0] = '\0'; + FILE *fp_ip = popen("curl -s --max-time 2 ifconfig.me 2>/dev/null", "r"); + if (fp_ip) { if (fgets(info->ip_public, sizeof(info->ip_public), fp_ip)) clean_newline(info->ip_public); pclose(fp_ip); } +} \ No newline at end of file