summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarel Zak2010-03-30 13:47:33 +0200
committerKarel Zak2010-03-30 13:51:58 +0200
commitcf8de26afe0db5c330f4c913d736dc1f840add88 (patch)
treef84ed27c9f14a7bdf3e98b0fdc79a35b6bb91ec4
parenthwclock: add --predict for predicting RTC reading at a given time (diff)
downloadkernel-qcow2-util-linux-cf8de26afe0db5c330f4c913d736dc1f840add88.tar.gz
kernel-qcow2-util-linux-cf8de26afe0db5c330f4c913d736dc1f840add88.tar.xz
kernel-qcow2-util-linux-cf8de26afe0db5c330f4c913d736dc1f840add88.zip
lib: add strtosize() function
This function int strtosize(const char *str, uintmax_t *res) supports {K,M,G,T,E,P}iB and {K,M,G,T,E,P}B suffixes. Signed-off-by: Karel Zak <kzak@redhat.com>
-rw-r--r--include/Makefile.am1
-rw-r--r--include/strtosize.h8
-rw-r--r--lib/Makefile.am4
-rw-r--r--lib/strtosize.c148
-rw-r--r--tests/commands.sh.in1
-rw-r--r--tests/expected/misc/strtosize23
-rwxr-xr-xtests/ts/misc/strtosize51
7 files changed, 235 insertions, 1 deletions
diff --git a/include/Makefile.am b/include/Makefile.am
index ccae85d7c..65e447d51 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -22,4 +22,5 @@ dist_noinst_HEADERS = \
widechar.h \
crc32.h \
mangle.h \
+ strtosize.h \
xstrncpy.h
diff --git a/include/strtosize.h b/include/strtosize.h
new file mode 100644
index 000000000..c789df93d
--- /dev/null
+++ b/include/strtosize.h
@@ -0,0 +1,8 @@
+#ifndef UTIL_LINUX_STRTOSIZE
+#define UTIL_LINUX_STRTOSIZE
+
+#include <inttypes.h>
+
+extern int strtosize(const char *str, uintmax_t *res);
+
+#endif /* UTIL_LINUX_STRING_TO_NUMBE */
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 0fddfb5ed..0f008b302 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -2,12 +2,14 @@ include $(top_srcdir)/config/include-Makefile.am
AM_CPPFLAGS += -DTEST_PROGRAM
-noinst_PROGRAMS = test_blkdev test_ismounted test_wholedisk test_mangle
+noinst_PROGRAMS = test_blkdev test_ismounted test_wholedisk test_mangle \
+ test_strtosize
test_blkdev_SOURCES = blkdev.c
test_ismounted_SOURCES = ismounted.c
test_wholedisk_SOURCES = wholedisk.c
test_mangle_SOURCES = mangle.c
+test_strtosize_SOURCES = strtosize.c
if LINUX
test_blkdev_SOURCES += linux_version.c
diff --git a/lib/strtosize.c b/lib/strtosize.c
new file mode 100644
index 000000000..068c5429a
--- /dev/null
+++ b/lib/strtosize.c
@@ -0,0 +1,148 @@
+/*
+ * strtosize() - convert string to size (uintmax_t).
+ *
+ * Supported suffixes:
+ *
+ * XiB or X for 2^N
+ * where X = {K,M,G,T,P,E,Y,Z}
+ * or X = {k,m,g,t,p,e} (undocumented for backward compatibility only)
+ * for example:
+ * 10KiB = 10240
+ * 10K = 10240
+ *
+ * XB for 10^N
+ * where X = {K,M,G,T,P,E,Y,Z}
+ * for example:
+ * 10KB = 10000
+ *
+ * Note that the function does not accept numbers with '-' (negative sign)
+ * prefix.
+ *
+ * Returns 0 on success, -1 in case of error, -2 in case of overflow.
+ *
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ */
+#include <stdio.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <errno.h>
+
+static int do_scale_by_power (uintmax_t *x, int base, int power)
+{
+ while (power--) {
+ if (UINTMAX_MAX / base < *x)
+ return -2;
+ *x *= base;
+ }
+ return 0;
+}
+
+int strtosize(const char *str, uintmax_t *res)
+{
+ char *p;
+ uintmax_t x;
+ int base = 1024, rc = 0;
+
+ *res = 0;
+
+ if (!str || !*str)
+ goto err;
+
+ /* Only positive numbers are acceptable
+ *
+ * Note that this check is not perfect, it would be better to
+ * use lconv->negative_sign. But coreutils use the same solution,
+ * so it's probably good enough...
+ */
+ p = (char *) str;
+ while (isspace((unsigned char) *p))
+ p++;
+ if (*p == '-')
+ goto err;
+ p = NULL;
+
+ errno = 0;
+ x = strtoumax(str, &p, 0);
+
+ if (p == str ||
+ (errno != 0 && (x == UINTMAX_MAX || x == 0)))
+ goto err;
+
+ if (!p || !*p)
+ goto done; /* without suffix */
+
+ /*
+ * Check size suffixes
+ */
+ if (*(p + 1) == 'i' && *(p + 2) == 'B' && !*(p + 3))
+ base = 1024; /* XiB, 2^N */
+ else if (*(p + 1) == 'B' && !*(p + 2))
+ base = 1000; /* XB, 10^N */
+ else if (*(p + 1))
+ goto err; /* unexpected suffix */
+
+ switch(*p) {
+ case 'K':
+ case 'k':
+ rc = do_scale_by_power(&x, base, 1);
+ break;
+ case 'M':
+ case 'm':
+ rc = do_scale_by_power(&x, base, 2);
+ break;
+ case 'G':
+ case 'g':
+ rc = do_scale_by_power(&x, base, 3);
+ break;
+ case 'T':
+ case 't':
+ rc = do_scale_by_power(&x, base, 4);
+ break;
+ case 'P':
+ case 'p':
+ rc = do_scale_by_power(&x, base, 5);
+ break;
+ case 'E':
+ case 'e':
+ rc = do_scale_by_power(&x, base, 6);
+ break;
+ case 'Z':
+ rc = do_scale_by_power(&x, base, 7);
+ break;
+ case 'Y':
+ rc = do_scale_by_power(&x, base, 8);
+ break;
+ default:
+ goto err;
+ }
+
+done:
+ *res = x;
+ return rc;
+err:
+ return -1;
+}
+
+#ifdef TEST_PROGRAM
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <err.h>
+
+int main(int argc, char *argv[])
+{
+ uintmax_t size = 0;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s <number>[suffix]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (strtosize(argv[1], &size))
+ errx(EXIT_FAILURE, "invalid size '%s' value", argv[1]);
+
+ printf("%25s : %20ju\n", argv[1], size);
+ return EXIT_FAILURE;
+}
+#endif /* TEST_PROGRAM */
+
diff --git a/tests/commands.sh.in b/tests/commands.sh.in
index 8399738c8..f52a68687 100644
--- a/tests/commands.sh.in
+++ b/tests/commands.sh.in
@@ -10,6 +10,7 @@ TS_HELPER_BYTESWAP="$TS_TOPDIR/helpers/test_byteswap"
TS_HELPER_MD5="$TS_TOPDIR/helpers/test_md5"
TS_HELPER_ISMOUNTED="$TOPDIR/lib/test_ismounted"
+TS_HELPER_STRTOSIZE="$TOPDIR/lib/test_strtosize"
# TODO: use partx
TS_HELPER_PARTITIONS="$TOPDIR/shlibs/blkid/samples/partitions"
diff --git a/tests/expected/misc/strtosize b/tests/expected/misc/strtosize
new file mode 100644
index 000000000..b7cb24617
--- /dev/null
+++ b/tests/expected/misc/strtosize
@@ -0,0 +1,23 @@
+test_strtosize: invalid size '-1' value
+ 0 : 0
+ 1 : 1
+ 123 : 123
+ 18446744073709551615 : 18446744073709551615
+ 1K : 1024
+ 1KiB : 1024
+ 1M : 1048576
+ 1MiB : 1048576
+ 1G : 1073741824
+ 1GiB : 1073741824
+ 1T : 1099511627776
+ 1TiB : 1099511627776
+ 1P : 1125899906842624
+ 1PiB : 1125899906842624
+ 1E : 1152921504606846976
+ 1EiB : 1152921504606846976
+ 1KB : 1000
+ 1MB : 1000000
+ 1GB : 1000000000
+ 1TB : 1000000000000
+ 1PB : 1000000000000000
+ 1EB : 1000000000000000000
diff --git a/tests/ts/misc/strtosize b/tests/ts/misc/strtosize
new file mode 100755
index 000000000..4668823c6
--- /dev/null
+++ b/tests/ts/misc/strtosize
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+#
+# Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+#
+# This file is part of util-linux-ng.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="$(dirname $0)/../.."
+TS_DESC="strtosize"
+
+. $TS_TOPDIR/functions.sh
+ts_init "$*"
+
+$TS_HELPER_STRTOSIZE -1 >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 0 >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1 >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 123 >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 18446744073709551615 >> $TS_OUTPUT 2>&1
+
+$TS_HELPER_STRTOSIZE 1K >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1KiB >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1M >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1MiB >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1G >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1GiB >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1T >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1TiB >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1P >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1PiB >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1E >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1EiB >> $TS_OUTPUT 2>&1
+
+$TS_HELPER_STRTOSIZE 1KB >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1MB >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1GB >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1TB >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1PB >> $TS_OUTPUT 2>&1
+$TS_HELPER_STRTOSIZE 1EB >> $TS_OUTPUT 2>&1
+
+ts_finalize
+