slstatus-dyn_battery-20260102-8723e8b.diff (5558B)
1 From 6316c8cb7b2b92098907943223ffe1a748359146 Mon Sep 17 00:00:00 2001 2 From: Madison Lynch <madi@mxdi.xyz> 3 Date: Fri, 2 Jan 2026 04:33:17 -0800 4 Subject: [PATCH] Code refactor + Improved memory safety 5 6 --- 7 Makefile | 1 + 8 components/dyn_battery.c | 124 +++++++++++++++++++++++++++++++++++++++ 9 config.def.h | 1 + 10 slstatus.h | 3 + 11 4 files changed, 129 insertions(+) 12 create mode 100644 components/dyn_battery.c 13 14 diff --git a/Makefile b/Makefile 15 index 7a18274..d1b24dd 100644 16 --- a/Makefile 17 +++ b/Makefile 18 @@ -11,6 +11,7 @@ COM =\ 19 components/cpu\ 20 components/datetime\ 21 components/disk\ 22 + components/dyn_battery\ 23 components/entropy\ 24 components/hostname\ 25 components/ip\ 26 diff --git a/components/dyn_battery.c b/components/dyn_battery.c 27 new file mode 100644 28 index 0000000..cc87fc1 29 --- /dev/null 30 +++ b/components/dyn_battery.c 31 @@ -0,0 +1,124 @@ 32 +/* Written by Lukas Lynch <madi@mxdi.xyz> */ 33 +/* Only Linux is supported */ 34 +#include <stdio.h> 35 +#include <stdlib.h> 36 +#include <stdbool.h> 37 +#include <string.h> 38 +#include <dirent.h> 39 + 40 +#include "../util.h" 41 +#include "../slstatus.h" 42 + 43 +#define BAT_PREFIX "BAT" 44 +#define BAT_DIR "/sys/class/power_supply" 45 + 46 +static bool err; 47 +static const char *err_str = "err"; 48 + 49 +/** 50 +* Calculates the number of digits in a given positive integer. 51 +*/ 52 +static size_t 53 +count_digits(const unsigned int input) { 54 + size_t count = 0; 55 + unsigned int n = input; 56 + 57 + while(n/10 != 0) 58 + count++; 59 + 60 + return count+1; 61 +} 62 + 63 +/** 64 +* Counts number of batteries detected by system. 65 +* 66 +* @return Unsigned integer denoting the number of detected batteries 67 +* @author Lukas Lynch 68 +*/ 69 +static unsigned int 70 +count_batteries(void) { 71 + const size_t bat_prefix_s = strlen(BAT_PREFIX); 72 + DIR *dir = opendir(BAT_DIR); 73 + if(!dir) { 74 + fprintf(stderr, "dyn_battery: Failed to open %s\n", BAT_DIR); 75 + err = true; 76 + return 0; 77 + } 78 + 79 + unsigned int batc = 0; 80 + struct dirent *entry; 81 + while((entry = readdir(dir))) 82 + if( 83 + strlen(entry->d_name) > bat_prefix_s && 84 + strncmp(entry->d_name, BAT_PREFIX, bat_prefix_s) == 0 85 + ) batc++; 86 + 87 + (void) closedir(dir); 88 + return batc; 89 +} 90 + 91 +/** 92 +* Displays the status and capacity of a dynamic amount of batteries (i.e. 93 +* laptops may have secondary external batteries). 94 +* 95 +* @param fmt format string to use for each battery display. ordered key: 96 +* %u: battery number || %s: battery state || %s battery capacity 97 +* @return string containing the status and capacities of all detected batteries 98 +* @author Lukas Lynch 99 +*/ 100 +const char * 101 +dyn_battery(const char *fmt) { 102 + err = false; 103 + const size_t fmt_s = strlen(fmt); 104 + const unsigned int batc = count_batteries(); 105 + 106 + if(err) // err set by count_batteries() 107 + return err_str; 108 + 109 + if(batc == 0) 110 + return NULL; 111 + 112 + // We need the amount of digits in bat_c for displaying it in strings 113 + const size_t batc_digits = count_digits(batc); 114 + 115 + char buf[ 116 + (batc * (fmt_s - 2)) // bat count * (format string - "%u" format specifier) 117 + + (batc * batc_digits) // bat count * digits in bat count 118 + + 1 // NULL byte 119 + ]; 120 + 121 + // Fill buffer with 0s, otherwise displacement calculations below can fail 122 + memset(buf, 0, sizeof(buf)); 123 + 124 + /* 125 + * The displacement variable will be updated with the current string length, 126 + * which is independent from the buffer size, in order to allow us to write 127 + * to the buffer without overwriting. 128 + */ 129 + unsigned int displacement = 0; 130 + for(unsigned int i=0; i<batc; i++) { 131 + // Length of BAT_PREFIX + number of digits in bat count + 1 (NULL byte) 132 + char bat[strlen(BAT_PREFIX) + batc_digits + 1]; 133 + (void) sprintf(bat, "%s%u", BAT_PREFIX, i); 134 + 135 + // Add battery info to output buffer 136 + displacement += sprintf( 137 + buf + displacement, // Write into buffer after previous writes 138 + fmt, // Format string specified by config.h 139 + i, 140 + battery_state(bat), // See components/battery.c 141 + battery_perc(bat) // See components/battery.c 142 + ); 143 + 144 + // Add space between battery entries 145 + buf[displacement++] = ' '; 146 + } 147 + 148 + // Remove extra space after last battery entry 149 + buf[--displacement] = '\0'; 150 + 151 + return bprintf("%s", buf); 152 +} 153 + 154 +#undef BAT_DIR 155 +#undef BAT_PREFIX 156 \ No newline at end of file 157 diff --git a/config.def.h b/config.def.h 158 index 100093e..7f26909 100644 159 --- a/config.def.h 160 +++ b/config.def.h 161 @@ -26,6 +26,7 @@ static const char unknown_str[] = "n/a"; 162 * disk_perc disk usage in percent mountpoint path (/) 163 * disk_total total disk space in GB mountpoint path (/) 164 * disk_used used disk space in GB mountpoint path (/) 165 + * dyn_battery displays the name, state and format string (%u, %s, %s) 166 * entropy available entropy NULL 167 * gid GID of current user NULL 168 * hostname hostname NULL 169 diff --git a/slstatus.h b/slstatus.h 170 index 394281c..6beeaec 100644 171 --- a/slstatus.h 172 +++ b/slstatus.h 173 @@ -21,6 +21,9 @@ const char *disk_perc(const char *path); 174 const char *disk_total(const char *path); 175 const char *disk_used(const char *path); 176 177 +/* dyn_battery */ 178 +const char *dyn_battery(const char *fmt); 179 + 180 /* entropy */ 181 const char *entropy(const char *unused); 182 183 -- 184 2.52.0 185