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);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to