[lvm-devel] master - libdevmapper: add dm_units_to_factor for size unit parsing

Peter Rajnoha prajnoha at fedoraproject.org
Mon Apr 28 08:27:15 UTC 2014


Gitweb:        http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=4360fdf89c7f38c5de0d3e6d612f67ee915cba15
Commit:        4360fdf89c7f38c5de0d3e6d612f67ee915cba15
Parent:        75d399800ab60264d1201ad3fa1f9283542459f6
Author:        Peter Rajnoha <prajnoha at redhat.com>
AuthorDate:    Mon Apr 28 10:25:43 2014 +0200
Committer:     Peter Rajnoha <prajnoha at redhat.com>
CommitterDate: Mon Apr 28 10:25:43 2014 +0200

libdevmapper: add dm_units_to_factor for size unit parsing

Actually moving the existing code from LVM to libdm for reuse.
---
 WHATS_NEW_DM               |    1 +
 lib/commands/toolcontext.c |    4 +-
 lib/display/display.c      |   99 -----------------------------------------
 lib/display/display.h      |    2 -
 libdm/libdevmapper.h       |   44 ++++++++++++++++++
 libdm/libdm-string.c       |  106 ++++++++++++++++++++++++++++++++++++++++++++
 tools/lvmcmdline.c         |    4 +-
 7 files changed, 155 insertions(+), 105 deletions(-)

diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 6a983a7..c81d354 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,6 @@
 Version 1.02.88 - 
 =================================
+  Add dm_units_to_factor for size unit parsing.
   Increase bitset size for minors for thin dmeventd plugin.
 
 Version 1.02.85 - 10th April 2014
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index d62fb8a..b2f8293 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -282,8 +282,8 @@ static int _check_config(struct cmd_context *cmd)
 
 int process_profilable_config(struct cmd_context *cmd) {
 	if (!(cmd->default_settings.unit_factor =
-	      units_to_bytes(find_config_tree_str(cmd, global_units_CFG, NULL),
-			     &cmd->default_settings.unit_type))) {
+	      dm_units_to_factor(find_config_tree_str(cmd, global_units_CFG, NULL),
+				 &cmd->default_settings.unit_type, 1, NULL))) {
 		log_error("Invalid units specification");
 		return 0;
 	}
diff --git a/lib/display/display.c b/lib/display/display.c
index b7fbf1a..c93b2b3 100644
--- a/lib/display/display.c
+++ b/lib/display/display.c
@@ -20,8 +20,6 @@
 #include "toolcontext.h"
 #include "segtype.h"
 #include "defaults.h"
-#include <math.h>  /* fabs() */
-#include <float.h> /* DBL_EPSILON */
 #include <stdarg.h>
 
 #define SIZE_BUF 128
@@ -44,103 +42,6 @@ static const struct {
 
 static const int _num_policies = DM_ARRAY_SIZE(_policies);
 
-/* Test if the doubles are close enough to be considered equal */
-static int _close_enough(double d1, double d2)
-{
-	return fabs(d1 - d2) < DBL_EPSILON;
-}
-
-uint64_t units_to_bytes(const char *units, char *unit_type)
-{
-	char *ptr = NULL;
-	uint64_t v;
-	double custom_value = 0;
-	uint64_t multiplier;
-
-	if (isdigit(*units)) {
-		custom_value = strtod(units, &ptr);
-		if (ptr == units)
-			return 0;
-		v = (uint64_t) strtoull(units, NULL, 10);
-		if (_close_enough((double) v, custom_value))
-			custom_value = 0;	/* Use integer arithmetic */
-		units = ptr;
-	} else
-		v = 1;
-
-	/* Only one units char permitted. */
-	if (units[0] && units[1])
-		return 0;
-
-	if (v == 1)
-		*unit_type = *units;
-	else
-		*unit_type = 'U';
-
-	switch (*units) {
-	case 'h':
-	case 'H':
-		multiplier = v = UINT64_C(1);
-		*unit_type = *units;
-		break;
-	case 'b':
-	case 'B':
-		multiplier = UINT64_C(1);
-		break;
-#define KILO UINT64_C(1024)
-	case 's':
-	case 'S':
-		multiplier = (KILO/2);
-		break;
-	case 'k':
-		multiplier = KILO;
-		break;
-	case 'm':
-		multiplier = KILO * KILO;
-		break;
-	case 'g':
-		multiplier = KILO * KILO * KILO;
-		break;
-	case 't':
-		multiplier = KILO * KILO * KILO * KILO;
-		break;
-	case 'p':
-		multiplier = KILO * KILO * KILO * KILO * KILO;
-		break;
-	case 'e':
-		multiplier = KILO * KILO * KILO * KILO * KILO * KILO;
-		break;
-#undef KILO
-#define KILO UINT64_C(1000)
-	case 'K':
-		multiplier = KILO;
-		break;
-	case 'M':
-		multiplier = KILO * KILO;
-		break;
-	case 'G':
-		multiplier = KILO * KILO * KILO;
-		break;
-	case 'T':
-		multiplier = KILO * KILO * KILO * KILO;
-		break;
-	case 'P':
-		multiplier = KILO * KILO * KILO * KILO * KILO;
-		break;
-	case 'E':
-		multiplier = KILO * KILO * KILO * KILO * KILO * KILO;
-		break;
-#undef KILO
-	default:
-		return 0;
-	}
-
-	if (_close_enough(custom_value, 0.))
-		return v * multiplier; /* Use integer arithmetic */
-	else
-		return (uint64_t) (custom_value * multiplier);
-}
-
 char alloc_policy_char(alloc_policy_t alloc)
 {
 	int i;
diff --git a/lib/display/display.h b/lib/display/display.h
index 41fba03..d5c0efa 100644
--- a/lib/display/display.h
+++ b/lib/display/display.h
@@ -22,8 +22,6 @@
 
 #include <stdint.h>
 
-uint64_t units_to_bytes(const char *units, char *unit_type);
-
 /* Specify size in KB */
 const char *display_size(const struct cmd_context *cmd, uint64_t size);
 const char *display_size_long(const struct cmd_context *cmd, uint64_t size);
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 5f7b14c..8ffa145 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -1454,6 +1454,50 @@ void dm_unescape_colons_and_at_signs(char *src,
  */
 int dm_strncpy(char *dest, const char *src, size_t n);
 
+/*
+ * Recognize unit specifier in the 'units' arg and return a factor
+ * representing that unit. If the 'units' contains a prefix with digits,
+ * the 'units' is considered to be a custom unit.
+ *
+ * Also, set 'unit_type' output arg to the character that represents
+ * the unit specified. The 'unit_type' character equals to the unit
+ * character itself recognized in the 'units' arg for canonical units.
+ * Otherwise, the 'unit_type' character is set to 'U' for custom unit.
+ *
+ * An example for k/K canonical units and 8k/8K custom units:
+ *
+ *   units  unit_type  return value (factor)
+ *   k      k          1024
+ *   K      K          1000
+ *   8k     U          1024*8
+ *   8K     U          1000*8
+ *   etc...
+ *
+ * Recognized units:
+ *
+ *   h/H - human readable (returns 1 for both)
+ *   b/B - byte (returns 1 for both)
+ *   s/S - sector (returns 512 for both)
+ *   k/K - kilo (returns 1024/1000 respectively)
+ *   m/M - mega (returns 1024^2/1000^2 respectively)
+ *   g/G - giga (returns 1024^3/1000^3 respectively)
+ *   t/T - tera (returns 1024^4/1000^4 respectively)
+ *   p/P - peta (returns 1024^5/1000^5 respectively)
+ *   e/E - exa (returns 1024^6/1000^6 respectively)
+ *
+ * Only one units character is allowed in the 'units' arg
+ * if strict mode is enabled by 'strict' arg.
+ *
+ * The 'endptr' output arg, if not NULL, saves the pointer
+ * in the 'units' string which follows the unit specifier
+ * recognized (IOW the position where the parsing of the
+ * unit specifier stopped).
+ *
+ * Returns the unit factor or 0 if no unit is recognized.
+ */
+uint64_t dm_units_to_factor(const char *units, char *unit_type,
+			    int strict, char **endptr);
+
 /**************************
  * file/stream manipulation
  **************************/
diff --git a/libdm/libdm-string.c b/libdm/libdm-string.c
index 64a9792..7336e6b 100644
--- a/libdm/libdm-string.c
+++ b/libdm/libdm-string.c
@@ -16,6 +16,8 @@
 
 #include <ctype.h>
 #include <stdarg.h>
+#include <math.h>  /* fabs() */
+#include <float.h> /* DBL_EPSILON */
 
 /*
  * consume characters while they match the predicate function.
@@ -434,3 +436,107 @@ int dm_strncpy(char *dest, const char *src, size_t n)
 
 	return 0;
 }
+
+/* Test if the doubles are close enough to be considered equal */
+static int _close_enough(double d1, double d2)
+{
+	return fabs(d1 - d2) < DBL_EPSILON;
+}
+
+uint64_t dm_units_to_factor(const char *units, char *unit_type,
+			    int strict, char **endptr)
+{
+	char *ptr = NULL;
+	uint64_t v;
+	double custom_value = 0;
+	uint64_t multiplier;
+
+	if (endptr)
+		*endptr = (char *) units;
+
+	if (isdigit(*units)) {
+		custom_value = strtod(units, &ptr);
+		if (ptr == units)
+			return 0;
+		v = (uint64_t) strtoull(units, NULL, 10);
+		if (_close_enough((double) v, custom_value))
+			custom_value = 0;	/* Use integer arithmetic */
+		units = ptr;
+	} else
+		v = 1;
+
+	/* Only one units char permitted in strict mode. */
+	if (strict && units[0] && units[1])
+		return 0;
+
+	if (v == 1)
+		*unit_type = *units;
+	else
+		*unit_type = 'U';
+
+	switch (*units) {
+	case 'h':
+	case 'H':
+		multiplier = v = UINT64_C(1);
+		*unit_type = *units;
+		break;
+	case 'b':
+	case 'B':
+		multiplier = UINT64_C(1);
+		break;
+#define KILO UINT64_C(1024)
+	case 's':
+	case 'S':
+		multiplier = (KILO/2);
+		break;
+	case 'k':
+		multiplier = KILO;
+		break;
+	case 'm':
+		multiplier = KILO * KILO;
+		break;
+	case 'g':
+		multiplier = KILO * KILO * KILO;
+		break;
+	case 't':
+		multiplier = KILO * KILO * KILO * KILO;
+		break;
+	case 'p':
+		multiplier = KILO * KILO * KILO * KILO * KILO;
+		break;
+	case 'e':
+		multiplier = KILO * KILO * KILO * KILO * KILO * KILO;
+		break;
+#undef KILO
+#define KILO UINT64_C(1000)
+	case 'K':
+		multiplier = KILO;
+		break;
+	case 'M':
+		multiplier = KILO * KILO;
+		break;
+	case 'G':
+		multiplier = KILO * KILO * KILO;
+		break;
+	case 'T':
+		multiplier = KILO * KILO * KILO * KILO;
+		break;
+	case 'P':
+		multiplier = KILO * KILO * KILO * KILO * KILO;
+		break;
+	case 'E':
+		multiplier = KILO * KILO * KILO * KILO * KILO * KILO;
+		break;
+#undef KILO
+	default:
+		return 0;
+	}
+
+	if (endptr)
+		*endptr = (char *) units + 1;
+
+	if (_close_enough(custom_value, 0.))
+		return v * multiplier; /* Use integer arithmetic */
+	else
+		return (uint64_t) (custom_value * multiplier);
+}
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 758c429..7e4d9a6 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -923,8 +923,8 @@ static int _get_settings(struct cmd_context *cmd)
 
 	if (arg_count(cmd, units_ARG))
 		if (!(cmd->current_settings.unit_factor =
-		      units_to_bytes(arg_str_value(cmd, units_ARG, ""),
-				     &cmd->current_settings.unit_type))) {
+		      dm_units_to_factor(arg_str_value(cmd, units_ARG, ""),
+					 &cmd->current_settings.unit_type, 1, NULL))) {
 			log_error("Invalid units specification");
 			return EINVALID_CMD_LINE;
 		}




More information about the lvm-devel mailing list