summaryrefslogtreecommitdiff
path: root/src/shared/util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2014-02-23 03:13:54 +0100
committerLennart Poettering <lennart@poettering.net>2014-02-23 03:19:04 +0100
commit5556b5fe41173107a67dbe875fbd916a46e52a02 (patch)
treea9ca468b7c030c5c95a87bb35b4f986dedb1bba8 /src/shared/util.c
parente342365c27ecae32a7f20ada0b2c623ce22e5ea8 (diff)
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.
Diffstat (limited to 'src/shared/util.c')
-rw-r--r--src/shared/util.c53
1 files changed, 46 insertions, 7 deletions
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;
}