1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

libdevmapper: add dm_units_to_factor for size unit parsing

Actually moving the existing code from LVM to libdm for reuse.
This commit is contained in:
Peter Rajnoha 2014-04-28 10:25:43 +02:00
parent 75d399800a
commit 4360fdf89c
7 changed files with 155 additions and 105 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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
**************************/

View File

@ -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);
}

View File

@ -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;
}