summaryrefslogtreecommitdiffstats
path: root/lib/libutil
diff options
context:
space:
mode:
authordes <des@FreeBSD.org>2010-08-14 14:34:36 +0000
committerdes <des@FreeBSD.org>2010-08-14 14:34:36 +0000
commitb1567fc88a793d2451dccca6af424040a30ca275 (patch)
tree8aa22a76cb1718df0d484eefe5706aa137dc3d00 /lib/libutil
parent03b390ec5396151ffe7d1d9d293066f626c262d1 (diff)
downloadFreeBSD-src-b1567fc88a793d2451dccca6af424040a30ca275.zip
FreeBSD-src-b1567fc88a793d2451dccca6af424040a30ca275.tar.gz
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
Diffstat (limited to 'lib/libutil')
-rw-r--r--lib/libutil/expand_number.c52
-rw-r--r--lib/libutil/libutil.h2
2 files changed, 27 insertions, 27 deletions
diff --git a/lib/libutil/expand_number.c b/lib/libutil/expand_number.c
index 4c8d6f5..d1882bd4 100644
--- a/lib/libutil/expand_number.c
+++ b/lib/libutil/expand_number.c
@@ -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 *num)
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 *num)
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);
}
diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h
index 5b7ffad..3d8f59e 100644
--- a/lib/libutil/libutil.h
+++ b/lib/libutil/libutil.h
@@ -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);
OpenPOWER on IntegriCloud