]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - lib/vsprintf.c
lib/uuid.c: introduce a few more generic helpers
[mirror_ubuntu-artful-kernel.git] / lib / vsprintf.c
index 525c8e19bda2b8a4e7398d7fc19064b2abc84b45..0967771d8f7fd725972c74097bd324a8b39b5609 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/ioport.h>
 #include <linux/dcache.h>
 #include <linux/cred.h>
+#include <linux/uuid.h>
 #include <net/addrconf.h>
 #ifdef CONFIG_BLOCK
 #include <linux/blkdev.h>
@@ -1304,19 +1305,17 @@ static noinline_for_stack
 char *uuid_string(char *buf, char *end, const u8 *addr,
                  struct printf_spec spec, const char *fmt)
 {
-       char uuid[sizeof("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")];
+       char uuid[UUID_STRING_LEN + 1];
        char *p = uuid;
        int i;
-       static const u8 be[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
-       static const u8 le[16] = {3,2,1,0,5,4,7,6,8,9,10,11,12,13,14,15};
-       const u8 *index = be;
+       const u8 *index = uuid_be_index;
        bool uc = false;
 
        switch (*(++fmt)) {
        case 'L':
                uc = true;              /* fall-through */
        case 'l':
-               index = le;
+               index = uuid_le_index;
                break;
        case 'B':
                uc = true;
@@ -1324,7 +1323,10 @@ char *uuid_string(char *buf, char *end, const u8 *addr,
        }
 
        for (i = 0; i < 16; i++) {
-               p = hex_byte_pack(p, addr[index[i]]);
+               if (uc)
+                       p = hex_byte_pack_upper(p, addr[index[i]]);
+               else
+                       p = hex_byte_pack(p, addr[index[i]]);
                switch (i) {
                case 3:
                case 5:
@@ -1337,13 +1339,6 @@ char *uuid_string(char *buf, char *end, const u8 *addr,
 
        *p = 0;
 
-       if (uc) {
-               p = uuid;
-               do {
-                       *p = toupper(*p);
-               } while (*(++p));
-       }
-
        return string(buf, end, uuid, spec);
 }
 
@@ -2640,8 +2635,12 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
                if (*fmt == '*') {
                        if (!*str)
                                break;
-                       while (!isspace(*fmt) && *fmt != '%' && *fmt)
+                       while (!isspace(*fmt) && *fmt != '%' && *fmt) {
+                               /* '%*[' not yet supported, invalid format */
+                               if (*fmt == '[')
+                                       return num;
                                fmt++;
+                       }
                        while (!isspace(*str) && *str)
                                str++;
                        continue;
@@ -2714,6 +2713,59 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
                        num++;
                }
                continue;
+               /*
+                * Warning: This implementation of the '[' conversion specifier
+                * deviates from its glibc counterpart in the following ways:
+                * (1) It does NOT support ranges i.e. '-' is NOT a special
+                *     character
+                * (2) It cannot match the closing bracket ']' itself
+                * (3) A field width is required
+                * (4) '%*[' (discard matching input) is currently not supported
+                *
+                * Example usage:
+                * ret = sscanf("00:0a:95","%2[^:]:%2[^:]:%2[^:]",
+                *              buf1, buf2, buf3);
+                * if (ret < 3)
+                *    // etc..
+                */
+               case '[':
+               {
+                       char *s = (char *)va_arg(args, char *);
+                       DECLARE_BITMAP(set, 256) = {0};
+                       unsigned int len = 0;
+                       bool negate = (*fmt == '^');
+
+                       /* field width is required */
+                       if (field_width == -1)
+                               return num;
+
+                       if (negate)
+                               ++fmt;
+
+                       for ( ; *fmt && *fmt != ']'; ++fmt, ++len)
+                               set_bit((u8)*fmt, set);
+
+                       /* no ']' or no character set found */
+                       if (!*fmt || !len)
+                               return num;
+                       ++fmt;
+
+                       if (negate) {
+                               bitmap_complement(set, set, 256);
+                               /* exclude null '\0' byte */
+                               clear_bit(0, set);
+                       }
+
+                       /* match must be non-empty */
+                       if (!test_bit((u8)*str, set))
+                               return num;
+
+                       while (test_bit((u8)*str, set) && field_width--)
+                               *s++ = *str++;
+                       *s = '\0';
+                       ++num;
+               }
+               continue;
                case 'o':
                        base = 8;
                        break;