From 5556b5fe41173107a67dbe875fbd916a46e52a02 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Feb 2014 03:13:54 +0100 Subject: core: clean up some confusing regarding SI decimal and IEC binary suffixes for sizes According to Wikipedia it is customary to specify hardware metrics and transfer speeds to the basis 1000 (SI decimal), while software metrics and physical volatile memory (RAM) sizes to the basis 1024 (IEC binary). So far we specified everything in IEC, let's fix that and be more true to what's otherwise customary. Since we don't want to parse "Mi" instead of "M" we document each time what the context used is. --- src/shared/util.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 7 deletions(-) (limited to 'src/shared/util.c') diff --git a/src/shared/util.c b/src/shared/util.c index b33f1203e6..5cb598c4c5 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -2135,11 +2135,28 @@ ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { return n; } -int parse_bytes(const char *t, off_t *bytes) { - static const struct { +int parse_size(const char *t, off_t base, off_t *size) { + + /* Soo, sometimes we want to parse IEC binary suffxies, and + * sometimes SI decimal suffixes. This function can parse + * both. Which one is the right way depends on the + * context. Wikipedia suggests that SI is customary for + * hardrware metrics and network speeds, while IEC is + * customary for most data sizes used by software and volatile + * (RAM) memory. Hence be careful which one you pick! + * + * In either case we use just K, M, G as suffix, and not Ki, + * Mi, Gi or so (as IEC would suggest). That's because that's + * frickin' ugly. But this means you really need to make sure + * to document which base you are parsing when you use this + * call. */ + + struct table { const char *suffix; unsigned long long factor; - } table[] = { + }; + + static const struct table iec[] = { { "B", 1 }, { "K", 1024ULL }, { "M", 1024ULL*1024ULL }, @@ -2150,11 +2167,33 @@ int parse_bytes(const char *t, off_t *bytes) { { "", 1 }, }; + static const struct table si[] = { + { "B", 1 }, + { "K", 1000ULL }, + { "M", 1000ULL*1000ULL }, + { "G", 1000ULL*1000ULL*1000ULL }, + { "T", 1000ULL*1000ULL*1000ULL*1000ULL }, + { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, + { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, + { "", 1 }, + }; + + const struct table *table; const char *p; unsigned long long r = 0; + unsigned n_entries; assert(t); - assert(bytes); + assert(base == 1000 || base == 1024); + assert(size); + + if (base == 1000) { + table = si; + n_entries = ELEMENTSOF(si); + } else { + table = iec; + n_entries = ELEMENTSOF(iec); + } p = t; do { @@ -2176,7 +2215,7 @@ int parse_bytes(const char *t, off_t *bytes) { e += strspn(e, WHITESPACE); - for (i = 0; i < ELEMENTSOF(table); i++) + for (i = 0; i < n_entries; i++) if (startswith(e, table[i].suffix)) { unsigned long long tmp; if ((unsigned long long) l > ULLONG_MAX / table[i].factor) @@ -2193,12 +2232,12 @@ int parse_bytes(const char *t, off_t *bytes) { break; } - if (i >= ELEMENTSOF(table)) + if (i >= n_entries) return -EINVAL; } while (*p); - *bytes = r; + *size = r; return 0; } -- cgit v1.2.3-54-g00ecf