svn commit: r211304 - head/lib/libutil
Dag-Erling Smorgrav
des at FreeBSD.org
Sat Aug 14 14:34:36 UTC 2010
Author: des
Date: Sat Aug 14 14:34:36 2010
New Revision: 211304
URL: http://svn.freebsd.org/changeset/base/211304
Log:
Simplify expand_number() by combining the (unrolled) loop with the
switch. Since expand_number() does not accept negative numbers, switch
from int64_t to uint64_t; this makes it easier to check for overflow.
MFC after: 3 weeks
Modified:
head/lib/libutil/expand_number.c
head/lib/libutil/libutil.h
Modified: head/lib/libutil/expand_number.c
==============================================================================
--- head/lib/libutil/expand_number.c Sat Aug 14 14:18:02 2010 (r211303)
+++ head/lib/libutil/expand_number.c Sat Aug 14 14:34:36 2010 (r211304)
@@ -37,7 +37,7 @@ __FBSDID("$FreeBSD$");
/*
* Convert an expression of the following forms to a int64_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).
* 3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10).
* 4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20).
@@ -47,14 +47,12 @@ __FBSDID("$FreeBSD$");
* 8) A positive decimal number followed by a 'e' or 'E' (mult by 1 << 60).
*/
int
-expand_number(const char *buf, int64_t *num)
+expand_number(const char *buf, uint64_t *num)
{
- static const char unit[] = "bkmgtpe";
- char *endptr, s;
- int64_t number;
- int i;
+ uint64_t number;
+ char *endptr;
- number = strtoimax(buf, &endptr, 0);
+ number = strtoumax(buf, &endptr, 0);
if (endptr == buf) {
/* No valid digits. */
@@ -68,15 +66,23 @@ expand_number(const char *buf, int64_t *
return (0);
}
- s = tolower(*endptr);
- switch (s) {
- case 'b':
- case 'k':
- case 'm':
- case 'g':
- case 't':
- case 'p':
+#define SHIFT(n, b) \
+ do { if ((n << b) < n) goto overflow; n <<= b; } while (0)
+
+ switch (tolower((unsigned char)*endptr)) {
case 'e':
+ SHIFT(number, 10);
+ 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;
default:
/* Unrecognized unit. */
@@ -84,17 +90,11 @@ expand_number(const char *buf, int64_t *
return (-1);
}
- for (i = 0; unit[i] != '\0'; i++) {
- if (s == unit[i])
- break;
- if ((number < 0 && (number << 10) > number) ||
- (number >= 0 && (number << 10) < number)) {
- errno = ERANGE;
- return (-1);
- }
- number <<= 10;
- }
-
*num = number;
return (0);
+
+overflow:
+ /* Overflow */
+ errno = ERANGE;
+ return (-1);
}
Modified: head/lib/libutil/libutil.h
==============================================================================
--- head/lib/libutil/libutil.h Sat Aug 14 14:18:02 2010 (r211303)
+++ head/lib/libutil/libutil.h Sat Aug 14 14:34:36 2010 (r211304)
@@ -109,7 +109,7 @@ int forkpty(int *_amaster, char *_name,
struct termios *_termp, struct winsize *_winp);
int humanize_number(char *_buf, size_t _len, int64_t _number,
const char *_suffix, int _scale, int _flags);
-int expand_number(const char *_buf, int64_t *_num);
+int expand_number(const char *_buf, uint64_t *_num);
const char *uu_lockerr(int _uu_lockresult);
int uu_lock(const char *_ttyname);
int uu_unlock(const char *_ttyname);
More information about the svn-src-all
mailing list