From 300acfb668e4b27c115be2d674bfdaa1e6faaf67 Mon Sep 17 00:00:00 2001 From: Puechberty Arthur Date: Fri, 26 Jun 2026 19:24:41 +0200 Subject: [PATCH] first commit --- config.c | 35 +++++++ logos.c | 94 ++++++++++++++++++ logos/arch.txt | 19 ++++ main.c | 56 +++++++++++ optifetch | Bin 0 -> 31160 bytes optifetch.conf | 27 ++++++ optifetch.h | 68 +++++++++++++ renderer.c | 253 +++++++++++++++++++++++++++++++++++++++++++++++++ sysinfo.c | 168 ++++++++++++++++++++++++++++++++ 9 files changed, 720 insertions(+) create mode 100644 config.c create mode 100644 logos.c create mode 100644 logos/arch.txt create mode 100644 main.c create mode 100755 optifetch create mode 100644 optifetch.conf create mode 100644 optifetch.h create mode 100644 renderer.c create mode 100644 sysinfo.c 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 0000000000000000000000000000000000000000..73a3e420f1e20151c8be767c6996a85b94edf61a GIT binary patch literal 31160 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âvUnfem3YFO6OTywnVk-kF*MoOg`$MUPfkaCYNnig- zVtAxfjExeFW0F4LP=ZObNgg^MKmi%z;4Axj^A zRpLn&y5^UehNVwxLQckK!LO4^dJOBxe`Rdr;>m|6DaDh+A0n+h zoJ@Msp$FGso=B#9XGx}|Ii_I)`(|x`F2b|NnBfbaEW~3PeRC)=<1-GQO~1lp0MI36 z=S<5UdXqe0NmiqDgC9c#WCSZOFeci@wSGAxEZ$(o&$UT@0ILUtrROYwQ@$z(E} zXw$Pd4OPvw?m@;6AKM=4*EuC7bFEu4|&Xq%Cp zWy@B=8N{~-pF`klJ&!L)eA9?;G-#jULopqNhvH#-e?eWi@0vdAGGiI*)6<&=^v}++ z4oI&uJ(yO$Pg22RhL0Pzfj<+#l?3{BHuTS)V9hSHWRC<3SRpbcJ8SxYGKl-3E7+DyK2GrmVO^Rvd+3^Ulq#GtJ-hIp z{@IEpd#Hs;+%zD4Qo0dg8NljgD|8%bPbTp|1&ix^M3t2vcn$c+sa~KWoR zz{28A?DQ}SwH3c;D~M-VXnorJaC+Kz+sgOOgP+-D;q>)s>GMr(dvBtgG#N4@p>qY= z(--{!OwZoZZ_&E6S>cS?YtqxNGqtJh>Ylr@vsB>28EewlrKR^xZ)@K(j{_?pLT}cc zjK@wd#h*|>zA;T*pT08OcgdPQvmQ*lonoKv!)rSCsIRE|((LdVEWA!0OiOEN-}B18 zN*$a>P}+1IOq;&v71-Z5OGl)yNF$B~IxNkBNe%YjdNY~4oZ@cHZZwrYn6?P@wJsBm z*w^$)^T2~vQ(Jj^`JVDu%J(9s7I5)~u|9o%+syWvduHx+o@*)4gX`#D((yOlrzKL0 zzg%JUKzNGtivPs3GPtPY&{(3we)xiSeMldo57EW?7hs@qrDxIm=TSw-=Jb)$ho<2N z44@)CYXA_$)jN&9EWyNo$ni8OSpkmYNt$)kqh#b)ge4`AhsHPZ#0n^Ud{5 z1ip#DHxc;Xh`=UVaNyE^&q5!s=r=a#8pxB>4{p%ZP1oq@Jf#_wBDfW za-O7qKZDjbbm{cJpH2D*-YM2aG=9=mCKzaJr|X2E>ubX!!asU^n=V@S&^3f7sc#`B zX{$JjkM)wYSrA0=C7K@TqWOWY7NJLHCDO$rT_e(sBIVl9u2=IM)&KOVQzt4TG24$)ipJ*`_Ea ztLG_x=!j8pS3ZD~hAu!AXgEA@kbubfJwejw#y8zIm-2B>(hZsqJ5Ps{@2tbK2iS5~ z)zv^&hu|Q?8r;K~0&b(??iu&kGR2mMo9tY5m7}4-0Sc+s^YFk?@2-Y>J{ZMUKJ$cI zU5MX6!gjyD9(OhM*!@pZ>dw@c_5QzBbTBADsxw{wNg=PN`naa6(fhX! z(^?Y`FZ*K^i~Fwl1%aOA~-2mvwo4eAQEZ zJOvB8y8B-SER9{dygpv(=^b1wwO-Zv^t1wW8Vhw;9}o3(fspU+zd*A+EfrChKO)9c zJ=MqK?(x&h?}9ARrU-@l_^zj$MST(v$#jpOA2^DMJ|D5gI$%B3=RHEvrTf7lNm_)A zQC<<_oSru71rq{-tgDw6caz^F#uYvN-Z&^cJgzY7AjeciskK1luUtQau#^_woIw}THMODwv){`+Wgw)){` zQy`} +#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