diff options
| author | Federico Angelilli <code@fedang.net> | 2024-11-19 11:17:50 +0100 |
|---|---|---|
| committer | Federico Angelilli <code@fedang.net> | 2024-11-19 11:17:50 +0100 |
| commit | afcbe44a7cf454f3588a60180d93f65df9e5fcc7 (patch) | |
| tree | 7a3b94a9c9f7ef8cbd3062b26e31ef25b9d9a742 /src | |
| parent | 79a32360e76cb0739312e15299fc22941e51b64b (diff) | |
Add byte human readable formatting
Diffstat (limited to 'src')
| -rw-r--r-- | src/blocks/fs.c | 45 | ||||
| -rw-r--r-- | src/format.c | 4 | ||||
| -rw-r--r-- | src/format.h | 4 | ||||
| -rw-r--r-- | src/util.c | 108 | ||||
| -rw-r--r-- | src/util.h | 15 |
5 files changed, 106 insertions, 70 deletions
diff --git a/src/blocks/fs.c b/src/blocks/fs.c index 7163cc5..a0e1133 100644 --- a/src/blocks/fs.c +++ b/src/blocks/fs.c @@ -25,10 +25,26 @@ typedef enum { FS_USED_PERC, } block_fs_mark_t; +#define FS_SHIFT 12 + +static const format_pair_t block_fs_units[] = { + { "-si", UNIT_SI << FS_SHIFT }, + { "-b", UNIT_B << FS_SHIFT }, + { "-kib", UNIT_KB << FS_SHIFT }, + { "-mib", UNIT_MB << FS_SHIFT }, + { "-gib", UNIT_GB << FS_SHIFT }, + { "-tib", UNIT_TB << FS_SHIFT }, + { "-kb", (UNIT_KB | UNIT_SI) << FS_SHIFT }, + { "-mb", (UNIT_MB | UNIT_SI) << FS_SHIFT }, + { "-gb", (UNIT_GB | UNIT_SI) << FS_SHIFT }, + { "-tb", (UNIT_TB | UNIT_SI) << FS_SHIFT }, + { NULL }, +}; + static const format_option_t block_fs_options[] = { - { { "total", FS_TOTAL } }, - { { "free", FS_FREE } }, - { { "used", FS_USED } }, + { { "total", FS_TOTAL }, .suffixes = block_fs_units }, + { { "free", FS_FREE }, .suffixes = block_fs_units }, + { { "used", FS_USED }, .suffixes = block_fs_units }, { { "free-percentage", FS_FREE_PERC } }, { { "used-percentage", FS_USED_PERC } }, { { NULL } }, @@ -45,13 +61,19 @@ static void block_fs_update(block_t *block) struct statvfs sbuf; if (statvfs(fs->path, &sbuf) < 0) { - log_value_debug("Failed to read filesystem", + log_value_debug("Failed to read filesystem info", "s:label", block->label, "s:path", fs->path, "i:errno", errno); return; } + uint64_t total = sbuf.f_bsize * sbuf.f_blocks; + uint64_t available = sbuf.f_bsize * sbuf.f_bavail; + uint64_t used = sbuf.f_bsize * (sbuf.f_blocks - sbuf.f_bavail); + uint64_t free_perc = (100 * sbuf.f_bavail) / sbuf.f_blocks; + uint64_t used_perc = (100 * (sbuf.f_blocks - sbuf.f_bavail)) / sbuf.f_blocks; + char buffer[256] = { 0 }; size_t start = 0, size = sizeof(buffer); @@ -59,28 +81,31 @@ static void block_fs_update(block_t *block) size_t rest = start >= size ? 0 : size - start; if (rest == 0) break; - switch (fs->format.parts[i].mark) { + unit_t mask = UNIT_MASK << FS_SHIFT; + unit_t unit = (fs->format.parts[i].mark & mask) >> FS_SHIFT; + + switch (fs->format.parts[i].mark & ~mask) { case FS_STRING: start += snprintf(buffer + start, rest, "%s", fs->format.parts[i].string); break; case FS_TOTAL: - start += snprintf(buffer + start, rest, "%ld", sbuf.f_bsize * (uint64_t)sbuf.f_blocks); + start += snprintf_units(buffer + start, rest, total, unit); break; case FS_FREE: - start += snprintf(buffer + start, rest, "%ld", sbuf.f_bsize * (uint64_t)sbuf.f_bavail); + start += snprintf_units(buffer + start, rest, available, unit); break; case FS_USED: - start += snprintf(buffer + start, rest, "%ld", sbuf.f_bsize * (sbuf.f_blocks - sbuf.f_bavail)); + start += snprintf_units(buffer + start, rest, used, unit); break; case FS_FREE_PERC: - start += snprintf(buffer + start, rest, "%ld", (100 * sbuf.f_bavail) / sbuf.f_blocks); + start += snprintf(buffer + start, rest, "%ld", free_perc); break; case FS_USED_PERC: - start += snprintf(buffer + start, rest, "%ld", (100 * (sbuf.f_blocks - sbuf.f_bavail)) / sbuf.f_blocks); + start += snprintf(buffer + start, rest, "%ld", used_perc); break; default: diff --git a/src/format.c b/src/format.c index 0f25084..73d645e 100644 --- a/src/format.c +++ b/src/format.c @@ -94,7 +94,7 @@ static bool format_option_match(format_pair_t *part, const format_option_t *opti format_mark_t mark = 0; size_t off = 0, tmp = 0; - for (format_pair_t *ps = option->prefixes; ps != NULL && ps->string != NULL; ps++) { + for (const format_pair_t *ps = option->prefixes; ps != NULL && ps->string != NULL; ps++) { tmp = format_option_cmp(part->string, ps->string); if (tmp != 0) { off += tmp; @@ -108,7 +108,7 @@ static bool format_option_match(format_pair_t *part, const format_option_t *opti off += tmp; mark |= option->option.mark; - for (format_pair_t *ss = option->suffixes; ss != NULL && ss->string != NULL; ss++) { + for (const format_pair_t *ss = option->suffixes; ss != NULL && ss->string != NULL; ss++) { tmp = format_option_cmp(part->string + off, ss->string); if (tmp != 0) { off += tmp; diff --git a/src/format.h b/src/format.h index e5173de..d7f8976 100644 --- a/src/format.h +++ b/src/format.h @@ -18,8 +18,8 @@ typedef struct { typedef struct { format_pair_t option; - format_pair_t *prefixes; - format_pair_t *suffixes; + const format_pair_t *prefixes; + const format_pair_t *suffixes; } format_option_t; bool format_init(format_t *format, const char *string, char delim); @@ -2,6 +2,7 @@ #include <stdlib.h> #include <string.h> #include <stdio.h> +#include <math.h> #include "util.h" #include "any_log.h" @@ -152,60 +153,6 @@ size_t strprefix(const char *string, const char *prefix) return i; } -// FIXME: Slow and inefficient -char *strformat(const char *string, char delim, const char **keys, const char **values) -{ - size_t length = strlen(string); - size_t size = length; - size_t n = 0; - char *buffer = malloc(size); - - for (size_t i = 0; i < length; i++) { - if (string[i] == delim && i + 2 < length && string[i + 1] == '{') { - bool found = false; - size_t j = i + 2; - for ( ; j < length; j++) { - if (string[j] == '}') { - found = true; - break; - } - } - - if (found) { - for (int k = 0; keys[k] != NULL; k++) { - if (!strncmp(string + i + 2, keys[k], j - i - 2)) { - - size_t vl = strlen(values[k]); - while (n + vl >= size) { - size *= 1.5; - buffer = realloc(buffer, size); - if (buffer == NULL) - return NULL; - } - - memcpy(buffer + n, values[k], vl); - n += vl; - i = j; - goto next; - } - } - } - } - - if (n + 1 >= size) { - size *= 1.5; - buffer = realloc(buffer, size); - if (buffer == NULL) - return NULL; - } - buffer[n++] = string[i]; -next: - } - - buffer[n] = '\0'; - return buffer; -} - void strfree(char **list) { if (list == NULL) @@ -225,3 +172,56 @@ bool iszero(const void *ptr, size_t size) } return true; } + +int snprintf_units(char *buffer, size_t max, uint64_t bytes, unit_t unit) +{ + int base = unit & UNIT_SI ? 1000 : 1024; + double value = bytes; + const char *label = ""; + + switch (unit & ~UNIT_SI) { + case UNIT_B: + break; + + case UNIT_TB: + value /= base; + // fallthrough + + case UNIT_GB: + value /= base; + // fallthrough + + case UNIT_MB: + value /= base; + // fallthrough + + case UNIT_KB: + value /= base; + break; + + default: { + int i = -1; + do { + value /= base; + i++; + } while (round(value * 10) / 10 >= base && i < 4); + + const char *units[2][5] = { + { " B", " kB", " MB", " GB", " TB" }, + { " B", " KiB", " MiB", " GiB", " TiB" }, + }; + label = units[!(unit & UNIT_SI)][i]; + break; + } + } + + int prec = 1; + if (floor(value) >= 100.0) { + value = ceil(value); + prec = 0; + } + + int ret = snprintf(buffer, max, "%.*lf%s", prec, value, label); + assert(ret > 0); + return ret; +} @@ -5,6 +5,7 @@ #include <stddef.h> #include <stdbool.h> #include <stdio.h> +#include <stdint.h> #define unreachable() log_panic("The impossible happened"); @@ -67,10 +68,20 @@ bool strfind(const char *string, const char *cases[]); size_t strprefix(const char *string, const char *prefix); -char *strformat(const char *string, char delim, const char *keys[], const char *values[]); - void strfree(char **list); bool iszero(const void *ptr, size_t size); +typedef enum { + UNIT_B = 1 << 0, + UNIT_KB = 1 << 1, + UNIT_MB = 1 << 2, + UNIT_GB = 1 << 3, + UNIT_TB = 1 << 4, + UNIT_SI = 1 << 5, + UNIT_MASK = UNIT_B | UNIT_KB | UNIT_MB | UNIT_GB | UNIT_TB | UNIT_SI, +} unit_t; + +int snprintf_units(char *buffer, size_t max, uint64_t bytes, unit_t unit); + #endif |
