Revert "ACPI: Ignore _BQC object when registering backlight device"
[sfrench/cifs-2.6.git] / lib / vsprintf.c
index 0172902412613025213c07e7758af9492e2bd761..6021757a449663074cded737138d31acd83da325 100644 (file)
@@ -26,6 +26,9 @@
 #include <asm/page.h>          /* for PAGE_SIZE */
 #include <asm/div64.h>
 
+/* Works only for digits and letters, but small and fast */
+#define TOLOWER(x) ((x) | 0x20)
+
 /**
  * simple_strtoul - convert a string to an unsigned long
  * @cp: The start of the string
@@ -41,17 +44,17 @@ unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
                if (*cp == '0') {
                        base = 8;
                        cp++;
-                       if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+                       if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) {
                                cp++;
                                base = 16;
                        }
                }
        } else if (base == 16) {
-               if (cp[0] == '0' && toupper(cp[1]) == 'X')
+               if (cp[0] == '0' && TOLOWER(cp[1]) == 'x')
                        cp += 2;
        }
        while (isxdigit(*cp) &&
-              (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
+              (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) {
                result = result*base + value;
                cp++;
        }
@@ -92,17 +95,17 @@ unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
                if (*cp == '0') {
                        base = 8;
                        cp++;
-                       if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+                       if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) {
                                cp++;
                                base = 16;
                        }
                }
        } else if (base == 16) {
-               if (cp[0] == '0' && toupper(cp[1]) == 'X')
+               if (cp[0] == '0' && TOLOWER(cp[1]) == 'x')
                        cp += 2;
        }
-       while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
-           ? toupper(*cp) : *cp)-'A'+10) < base) {
+       while (isxdigit(*cp)
+        && (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) {
                result = result*base + value;
                cp++;
        }
@@ -126,6 +129,129 @@ long long simple_strtoll(const char *cp,char **endp,unsigned int base)
        return simple_strtoull(cp,endp,base);
 }
 
+
+/**
+ * strict_strtoul - convert a string to an unsigned long strictly
+ * @cp: The string to be converted
+ * @base: The number base to use
+ * @res: The converted result value
+ *
+ * strict_strtoul converts a string to an unsigned long only if the
+ * string is really an unsigned long string, any string containing
+ * any invalid char at the tail will be rejected and -EINVAL is returned,
+ * only a newline char at the tail is acceptible because people generally
+ * change a module parameter in the following way:
+ *
+ *     echo 1024 > /sys/module/e1000/parameters/copybreak
+ *
+ * echo will append a newline to the tail.
+ *
+ * It returns 0 if conversion is successful and *res is set to the converted
+ * value, otherwise it returns -EINVAL and *res is set to 0.
+ *
+ * simple_strtoul just ignores the successive invalid characters and
+ * return the converted value of prefix part of the string.
+ */
+int strict_strtoul(const char *cp, unsigned int base, unsigned long *res);
+
+/**
+ * strict_strtol - convert a string to a long strictly
+ * @cp: The string to be converted
+ * @base: The number base to use
+ * @res: The converted result value
+ *
+ * strict_strtol is similiar to strict_strtoul, but it allows the first
+ * character of a string is '-'.
+ *
+ * It returns 0 if conversion is successful and *res is set to the converted
+ * value, otherwise it returns -EINVAL and *res is set to 0.
+ */
+int strict_strtol(const char *cp, unsigned int base, long *res);
+
+/**
+ * strict_strtoull - convert a string to an unsigned long long strictly
+ * @cp: The string to be converted
+ * @base: The number base to use
+ * @res: The converted result value
+ *
+ * strict_strtoull converts a string to an unsigned long long only if the
+ * string is really an unsigned long long string, any string containing
+ * any invalid char at the tail will be rejected and -EINVAL is returned,
+ * only a newline char at the tail is acceptible because people generally
+ * change a module parameter in the following way:
+ *
+ *     echo 1024 > /sys/module/e1000/parameters/copybreak
+ *
+ * echo will append a newline to the tail of the string.
+ *
+ * It returns 0 if conversion is successful and *res is set to the converted
+ * value, otherwise it returns -EINVAL and *res is set to 0.
+ *
+ * simple_strtoull just ignores the successive invalid characters and
+ * return the converted value of prefix part of the string.
+ */
+int strict_strtoull(const char *cp, unsigned int base, unsigned long long *res);
+
+/**
+ * strict_strtoll - convert a string to a long long strictly
+ * @cp: The string to be converted
+ * @base: The number base to use
+ * @res: The converted result value
+ *
+ * strict_strtoll is similiar to strict_strtoull, but it allows the first
+ * character of a string is '-'.
+ *
+ * It returns 0 if conversion is successful and *res is set to the converted
+ * value, otherwise it returns -EINVAL and *res is set to 0.
+ */
+int strict_strtoll(const char *cp, unsigned int base, long long *res);
+
+#define define_strict_strtoux(type, valtype)                           \
+int strict_strtou##type(const char *cp, unsigned int base, valtype *res)\
+{                                                                      \
+       char *tail;                                                     \
+       valtype val;                                                    \
+       size_t len;                                                     \
+                                                                       \
+       *res = 0;                                                       \
+       len = strlen(cp);                                               \
+       if (len == 0)                                                   \
+               return -EINVAL;                                         \
+                                                                       \
+       val = simple_strtoul(cp, &tail, base);                          \
+       if ((*tail == '\0') ||                                          \
+               ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {\
+               *res = val;                                             \
+               return 0;                                               \
+       }                                                               \
+                                                                       \
+       return -EINVAL;                                                 \
+}                                                                      \
+
+#define define_strict_strtox(type, valtype)                            \
+int strict_strto##type(const char *cp, unsigned int base, valtype *res)        \
+{                                                                      \
+       int ret;                                                        \
+       if (*cp == '-') {                                               \
+               ret = strict_strtou##type(cp+1, base, res);             \
+               if (!ret)                                               \
+                       *res = -(*res);                                 \
+       } else                                                          \
+               ret = strict_strtou##type(cp, base, res);               \
+                                                                       \
+       return ret;                                                     \
+}                                                                      \
+
+define_strict_strtoux(l, unsigned long)
+define_strict_strtox(l, long)
+define_strict_strtoux(ll, unsigned long long)
+define_strict_strtox(ll, long long)
+
+EXPORT_SYMBOL(strict_strtoul);
+EXPORT_SYMBOL(strict_strtol);
+EXPORT_SYMBOL(strict_strtoll);
+EXPORT_SYMBOL(strict_strtoull);
+
 static int skip_atoi(const char **s)
 {
        int i=0;
@@ -135,28 +261,127 @@ static int skip_atoi(const char **s)
        return i;
 }
 
+/* Decimal conversion is by far the most typical, and is used
+ * for /proc and /sys data. This directly impacts e.g. top performance
+ * with many processes running. We optimize it for speed
+ * using code from
+ * http://www.cs.uiowa.edu/~jones/bcd/decimal.html
+ * (with permission from the author, Douglas W. Jones). */
+
+/* Formats correctly any integer in [0,99999].
+ * Outputs from one to five digits depending on input.
+ * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */
+static char* put_dec_trunc(char *buf, unsigned q)
+{
+       unsigned d3, d2, d1, d0;
+       d1 = (q>>4) & 0xf;
+       d2 = (q>>8) & 0xf;
+       d3 = (q>>12);
+
+       d0 = 6*(d3 + d2 + d1) + (q & 0xf);
+       q = (d0 * 0xcd) >> 11;
+       d0 = d0 - 10*q;
+       *buf++ = d0 + '0'; /* least significant digit */
+       d1 = q + 9*d3 + 5*d2 + d1;
+       if (d1 != 0) {
+               q = (d1 * 0xcd) >> 11;
+               d1 = d1 - 10*q;
+               *buf++ = d1 + '0'; /* next digit */
+
+               d2 = q + 2*d2;
+               if ((d2 != 0) || (d3 != 0)) {
+                       q = (d2 * 0xd) >> 7;
+                       d2 = d2 - 10*q;
+                       *buf++ = d2 + '0'; /* next digit */
+
+                       d3 = q + 4*d3;
+                       if (d3 != 0) {
+                               q = (d3 * 0xcd) >> 11;
+                               d3 = d3 - 10*q;
+                               *buf++ = d3 + '0';  /* next digit */
+                               if (q != 0)
+                                       *buf++ = q + '0';  /* most sign. digit */
+                       }
+               }
+       }
+       return buf;
+}
+/* Same with if's removed. Always emits five digits */
+static char* put_dec_full(char *buf, unsigned q)
+{
+       /* BTW, if q is in [0,9999], 8-bit ints will be enough, */
+       /* but anyway, gcc produces better code with full-sized ints */
+       unsigned d3, d2, d1, d0;
+       d1 = (q>>4) & 0xf;
+       d2 = (q>>8) & 0xf;
+       d3 = (q>>12);
+
+       /* Possible ways to approx. divide by 10 */
+       /* gcc -O2 replaces multiply with shifts and adds */
+       // (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386)
+       // (x * 0x67) >> 10:  1100111
+       // (x * 0x34) >> 9:    110100 - same
+       // (x * 0x1a) >> 8:     11010 - same
+       // (x * 0x0d) >> 7:      1101 - same, shortest code (on i386)
+
+       d0 = 6*(d3 + d2 + d1) + (q & 0xf);
+       q = (d0 * 0xcd) >> 11;
+       d0 = d0 - 10*q;
+       *buf++ = d0 + '0';
+       d1 = q + 9*d3 + 5*d2 + d1;
+               q = (d1 * 0xcd) >> 11;
+               d1 = d1 - 10*q;
+               *buf++ = d1 + '0';
+
+               d2 = q + 2*d2;
+                       q = (d2 * 0xd) >> 7;
+                       d2 = d2 - 10*q;
+                       *buf++ = d2 + '0';
+
+                       d3 = q + 4*d3;
+                               q = (d3 * 0xcd) >> 11; /* - shorter code */
+                               /* q = (d3 * 0x67) >> 10; - would also work */
+                               d3 = d3 - 10*q;
+                               *buf++ = d3 + '0';
+                                       *buf++ = q + '0';
+       return buf;
+}
+/* No inlining helps gcc to use registers better */
+static noinline char* put_dec(char *buf, unsigned long long num)
+{
+       while (1) {
+               unsigned rem;
+               if (num < 100000)
+                       return put_dec_trunc(buf, num);
+               rem = do_div(num, 100000);
+               buf = put_dec_full(buf, rem);
+       }
+}
+
 #define ZEROPAD        1               /* pad with zero */
 #define SIGN   2               /* unsigned/signed long */
 #define PLUS   4               /* show plus */
 #define SPACE  8               /* space if plus */
 #define LEFT   16              /* left justified */
-#define SPECIAL        32              /* 0x */
-#define LARGE  64              /* use 'ABCDEF' instead of 'abcdef' */
+#define SMALL  32              /* Must be 32 == 0x20 */
+#define SPECIAL        64              /* 0x */
 
-static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type)
+static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type)
 {
-       char c,sign,tmp[66];
-       const char *digits;
-       static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
-       static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       /* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
+       static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
+
+       char tmp[66];
+       char sign;
+       char locase;
+       int need_pfx = ((type & SPECIAL) && base != 10);
        int i;
 
-       digits = (type & LARGE) ? large_digits : small_digits;
+       /* locase = 0 or 0x20. ORing digits or letters with 'locase'
+        * produces same digits or (maybe lowercased) letters */
+       locase = (type & SMALL);
        if (type & LEFT)
                type &= ~ZEROPAD;
-       if (base < 2 || base > 36)
-               return NULL;
-       c = (type & ZEROPAD) ? '0' : ' ';
        sign = 0;
        if (type & SIGN) {
                if ((signed long long) num < 0) {
@@ -171,64 +396,85 @@ static char * number(char * buf, char * end, unsigned long long num, int base, i
                        size--;
                }
        }
-       if (type & SPECIAL) {
+       if (need_pfx) {
+               size--;
                if (base == 16)
-                       size -= 2;
-               else if (base == 8)
                        size--;
        }
+
+       /* generate full string in tmp[], in reverse order */
        i = 0;
        if (num == 0)
-               tmp[i++]='0';
-       else while (num != 0)
-               tmp[i++] = digits[do_div(num,base)];
+               tmp[i++] = '0';
+       /* Generic code, for any base:
+       else do {
+               tmp[i++] = (digits[do_div(num,base)] | locase);
+       } while (num != 0);
+       */
+       else if (base != 10) { /* 8 or 16 */
+               int mask = base - 1;
+               int shift = 3;
+               if (base == 16) shift = 4;
+               do {
+                       tmp[i++] = (digits[((unsigned char)num) & mask] | locase);
+                       num >>= shift;
+               } while (num);
+       } else { /* base 10 */
+               i = put_dec(tmp, num) - tmp;
+       }
+
+       /* printing 100 using %2d gives "100", not "00" */
        if (i > precision)
                precision = i;
+       /* leading space padding */
        size -= precision;
-       if (!(type&(ZEROPAD+LEFT))) {
-               while(size-->0) {
+       if (!(type & (ZEROPAD+LEFT))) {
+               while(--size >= 0) {
                        if (buf < end)
                                *buf = ' ';
                        ++buf;
                }
        }
+       /* sign */
        if (sign) {
                if (buf < end)
                        *buf = sign;
                ++buf;
        }
-       if (type & SPECIAL) {
-               if (base==8) {
-                       if (buf < end)
-                               *buf = '0';
-                       ++buf;
-               } else if (base==16) {
-                       if (buf < end)
-                               *buf = '0';
-                       ++buf;
+       /* "0x" / "0" prefix */
+       if (need_pfx) {
+               if (buf < end)
+                       *buf = '0';
+               ++buf;
+               if (base == 16) {
                        if (buf < end)
-                               *buf = digits[33];
+                               *buf = ('X' | locase);
                        ++buf;
                }
        }
+       /* zero or space padding */
        if (!(type & LEFT)) {
-               while (size-- > 0) {
+               char c = (type & ZEROPAD) ? '0' : ' ';
+               while (--size >= 0) {
                        if (buf < end)
                                *buf = c;
                        ++buf;
                }
        }
-       while (i < precision--) {
+       /* hmm even more zero padding? */
+       while (i <= --precision) {
                if (buf < end)
                        *buf = '0';
                ++buf;
        }
-       while (i-- > 0) {
+       /* actual digits of result */
+       while (--i >= 0) {
                if (buf < end)
                        *buf = tmp[i];
                ++buf;
        }
-       while (size-- > 0) {
+       /* trailing space padding */
+       while (--size >= 0) {
                if (buf < end)
                        *buf = ' ';
                ++buf;
@@ -276,7 +522,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
           used for unknown buffer sizes. */
        if (unlikely((int) size < 0)) {
                /* There can be only one.. */
-               static int warn = 1;
+               static char warn = 1;
                WARN_ON(warn);
                warn = 0;
                return 0;
@@ -402,6 +648,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
                                continue;
 
                        case 'p':
+                               flags |= SMALL;
                                if (field_width == -1) {
                                        field_width = 2*sizeof(void *);
                                        flags |= ZEROPAD;
@@ -438,9 +685,9 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
                                base = 8;
                                break;
 
-                       case 'X':
-                               flags |= LARGE;
                        case 'x':
+                               flags |= SMALL;
+                       case 'X':
                                base = 16;
                                break;
 
@@ -859,38 +1106,3 @@ int sscanf(const char * buf, const char * fmt, ...)
 }
 
 EXPORT_SYMBOL(sscanf);
-
-
-/* Simplified asprintf. */
-char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
-{
-       unsigned int len;
-       char *p;
-       va_list aq;
-
-       va_copy(aq, ap);
-       len = vsnprintf(NULL, 0, fmt, aq);
-       va_end(aq);
-
-       p = kmalloc(len+1, gfp);
-       if (!p)
-               return NULL;
-
-       vsnprintf(p, len+1, fmt, ap);
-
-       return p;
-}
-EXPORT_SYMBOL(kvasprintf);
-
-char *kasprintf(gfp_t gfp, const char *fmt, ...)
-{
-       va_list ap;
-       char *p;
-
-       va_start(ap, fmt);
-       p = kvasprintf(gfp, fmt, ap);
-       va_end(ap);
-
-       return p;
-}
-EXPORT_SYMBOL(kasprintf);