URI: 
       more concise memory calculation on Linux - slstatus - status monitor
  HTML git clone git://git.suckless.org/slstatus
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 8723e8b8c69c08bae8abe02ea1f4a49758b8bdfc
   DIR parent 6eb7887853537ac0cf91517019328e038382bdd8
  HTML Author: drkhsh <me@drkhsh.at>
       Date:   Thu, 24 Jul 2025 22:41:25 +0200
       
       more concise memory calculation on Linux
       
       more flexible parsing for /proc/meminfo to take shared and reclaimable
       memory into account. this matches the output with free(1).
       
       additionally this could fix some corner cases, as the order of fields in
       /proc/meminfo is not strictly defined.
       
       slstatus:
       percent 81% free 2.5 Gi total 23.4 Gi used 19.0 Gi
       
       free(1):
                      total        used        free      shared  buff/cache   available
       Mem:            23Gi        19Gi       2.5Gi       1.3Gi       3.2Gi       3.6Gi
       
       Diffstat:
         M components/ram.c                    |      61 +++++++++++++++++++------------
         M util.c                              |      17 +++++++++++++++++
         M util.h                              |       2 ++
       
       3 files changed, 57 insertions(+), 23 deletions(-)
       ---
   DIR diff --git a/components/ram.c b/components/ram.c
       @@ -11,36 +11,45 @@
                ram_free(const char *unused)
                {
                        uintmax_t free;
       +                FILE *fp;
        
       -                if (pscanf("/proc/meminfo",
       -                           "MemTotal: %ju kB\n"
       -                           "MemFree: %ju kB\n"
       -                           "MemAvailable: %ju kB\n",
       -                           &free, &free, &free) != 3)
       +                if (!(fp = fopen("/proc/meminfo", "r")))
                                return NULL;
        
       +                if (lscanf(fp, "MemFree:", "%ju kB", &free) != 1) {
       +                        fclose(fp);
       +                        return NULL;
       +                }
       +
       +                fclose(fp);
                        return fmt_human(free * 1024, 1024);
                }
        
                const char *
                ram_perc(const char *unused)
                {
       -                uintmax_t total, free, buffers, cached;
       +                uintmax_t total, free, buffers, cached, shmem, sreclaimable;
                        int percent;
       +                FILE *fp;
       +
       +                if (!(fp = fopen("/proc/meminfo", "r")))
       +                        return NULL;
        
       -                if (pscanf("/proc/meminfo",
       -                           "MemTotal: %ju kB\n"
       -                           "MemFree: %ju kB\n"
       -                           "MemAvailable: %ju kB\n"
       -                           "Buffers: %ju kB\n"
       -                           "Cached: %ju kB\n",
       -                           &total, &free, &buffers, &buffers, &cached) != 5)
       +                if (lscanf(fp, "MemTotal:", "%ju kB", &total)  != 1 ||
       +                    lscanf(fp, "MemFree:", "%ju kB", &free)    != 1 ||
       +                    lscanf(fp, "Buffers:", "%ju kB", &buffers) != 1 ||
       +                    lscanf(fp, "Cached:", "%ju kB", &cached)   != 1 ||
       +                    lscanf(fp, "Shmem:", "%ju kB", &shmem)     != 1 ||
       +                    lscanf(fp, "SReclaimable:", "%ju kB", &sreclaimable) != 1) {
       +                        fclose(fp);
                                return NULL;
       +                }
       +                fclose(fp);
        
                        if (total == 0)
                                return NULL;
        
       -                percent = 100 * ((total - free) - (buffers + cached)) / total;
       +                percent = 100 * (total - free - buffers - cached - sreclaimable + shmem) / total;
                        return bprintf("%d", percent);
                }
        
       @@ -59,18 +68,24 @@
                const char *
                ram_used(const char *unused)
                {
       -                uintmax_t total, free, buffers, cached, used;
       +                uintmax_t total, free, buffers, cached, used, shmem, sreclaimable;
       +                FILE *fp;
       +
       +                if (!(fp = fopen("/proc/meminfo", "r")))
       +                        return NULL;
        
       -                if (pscanf("/proc/meminfo",
       -                           "MemTotal: %ju kB\n"
       -                           "MemFree: %ju kB\n"
       -                           "MemAvailable: %ju kB\n"
       -                           "Buffers: %ju kB\n"
       -                           "Cached: %ju kB\n",
       -                           &total, &free, &buffers, &buffers, &cached) != 5)
       +                if (lscanf(fp, "MemTotal:", "%ju kB", &total)  != 1 ||
       +                    lscanf(fp, "MemFree:", "%ju kB", &free)    != 1 ||
       +                    lscanf(fp, "Buffers:", "%ju kB", &buffers) != 1 ||
       +                    lscanf(fp, "Cached:", "%ju kB", &cached)   != 1 ||
       +                    lscanf(fp, "Shmem:", "%ju kB", &shmem)     != 1 ||
       +                    lscanf(fp, "SReclaimable:", "%ju kB", &sreclaimable) != 1) {
       +                        fclose(fp);
                                return NULL;
       +                }
       +                fclose(fp);
        
       -                used = (total - free - buffers - cached);
       +                used = total - free - buffers - cached - sreclaimable + shmem;
                        return fmt_human(used * 1024, 1024);
                }
        #elif defined(__OpenBSD__)
   DIR diff --git a/util.c b/util.c
       @@ -139,3 +139,20 @@ pscanf(const char *path, const char *fmt, ...)
        
                return (n == EOF) ? -1 : n;
        }
       +
       +int
       +lscanf(FILE *fp, const char *key, const char *fmt, void *res)
       +{
       +                int n;
       +                char line[256];
       +
       +                n = -1;
       +                while (fgets(line, sizeof(line), fp))
       +                        if (strncmp(line, key, strlen(key)) == 0) {
       +                                n = sscanf(line + strlen(key), fmt, res);
       +                                break;
       +                        }
       +
       +                rewind(fp);
       +                return (n == 1) ? 1 : -1;
       +}
   DIR diff --git a/util.h b/util.h
       @@ -1,5 +1,6 @@
        /* See LICENSE file for copyright and license details. */
        #include <stdint.h>
       +#include <stdio.h>
        
        extern char buf[1024];
        
       @@ -14,3 +15,4 @@ int esnprintf(char *str, size_t size, const char *fmt, ...);
        const char *bprintf(const char *fmt, ...);
        const char *fmt_human(uintmax_t num, int base);
        int pscanf(const char *path, const char *fmt, ...);
       +int lscanf(FILE *fp, const char *key, const char *fmt, void *res);