Further simplify the code, and update the manpage.

Submitted by:	Christoph Mallon <christoph.mallon@gmx.de>
This commit is contained in:
Dag-Erling Smørgrav 2010-08-15 18:32:06 +00:00
parent fb26ece72c
commit a2e0c5ae31
2 changed files with 32 additions and 31 deletions

@ -25,7 +25,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd April 16, 2007 .Dd August 15, 2010
.Dt EXPAND_NUMBER 3 .Dt EXPAND_NUMBER 3
.Os .Os
.Sh NAME .Sh NAME
@ -37,14 +37,14 @@
.In libutil.h .In libutil.h
.Ft int .Ft int
.Fo expand_number .Fo expand_number
.Fa "const char *buf" "int64_t *num" .Fa "const char *buf" "uint64_t *num"
.Fc .Fc
.Sh DESCRIPTION .Sh DESCRIPTION
The The
.Fn expand_number .Fn expand_number
function unformats the function unformats the
.Fa buf .Fa buf
string and stores a signed 64-bit quantity at address pointed out by the string and stores a unsigned 64-bit quantity at address pointed out by the
.Fa num .Fa num
argument. argument.
.Pp .Pp

@ -36,7 +36,7 @@ __FBSDID("$FreeBSD$");
#include <stdint.h> #include <stdint.h>
/* /*
* Convert an expression of the following forms to a int64_t. * Convert an expression of the following forms to a uint64_t.
* 1) A positive decimal number. * 1) A positive decimal number.
* 2) A positive decimal number followed by a 'b' or 'B' (mult by 1). * 2) A positive decimal number followed by a 'b' or 'B' (mult by 1).
* 3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10). * 3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10).
@ -50,6 +50,7 @@ int
expand_number(const char *buf, uint64_t *num) expand_number(const char *buf, uint64_t *num)
{ {
uint64_t number; uint64_t number;
unsigned shift;
char *endptr; char *endptr;
number = strtoumax(buf, &endptr, 0); number = strtoumax(buf, &endptr, 0);
@ -60,41 +61,41 @@ expand_number(const char *buf, uint64_t *num)
return (-1); return (-1);
} }
if (*endptr == '\0') {
/* No unit. */
*num = number;
return (0);
}
#define SHIFT(n, b) \
do { if (((n << b) >> b) != n) goto overflow; n <<= b; } while (0)
switch (tolower((unsigned char)*endptr)) { switch (tolower((unsigned char)*endptr)) {
case 'e': case 'e':
SHIFT(number, 10); shift = 60;
case 'p':
SHIFT(number, 10);
case 't':
SHIFT(number, 10);
case 'g':
SHIFT(number, 10);
case 'm':
SHIFT(number, 10);
case 'k':
SHIFT(number, 10);
case 'b':
break; break;
case 'p':
shift = 50;
break;
case 't':
shift = 40;
break;
case 'g':
shift = 30;
break;
case 'm':
shift = 20;
break;
case 'k':
shift = 10;
break;
case 'b':
case '\0': /* No unit. */
*num = number;
return (0);
default: default:
/* Unrecognized unit. */ /* Unrecognized unit. */
errno = EINVAL; errno = EINVAL;
return (-1); return (-1);
} }
*num = number; if ((number << shift) >> shift != number) {
return (0); /* Overflow */
errno = ERANGE;
return (-1);
}
overflow: *num = number << shift;
/* Overflow */ return (0);
errno = ERANGE;
return (-1);
} }