]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
vsprintf: deal with format flags with a simple lookup table
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 19 Dec 2024 18:02:45 +0000 (10:02 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 23 Dec 2024 19:18:35 +0000 (11:18 -0800)
Rather than a case statement, just look up the printf format flags
(justification, zero-padding etc) using a small table.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
lib/vsprintf.c

index e6bd223b0184a4d44ca42838e175bf476bc9a27d..123e58724262a1c4ff1154bdc85f46d0325bae3a 100644 (file)
@@ -2527,6 +2527,20 @@ struct fmt {
        enum format_state state;
 };
 
+#define SPEC_CHAR(x, flag) [(x)-32] = flag
+static unsigned char spec_flag(unsigned char c)
+{
+       static const unsigned char spec_flag_array[] = {
+               SPEC_CHAR(' ', SPACE),
+               SPEC_CHAR('#', SPECIAL),
+               SPEC_CHAR('+', PLUS),
+               SPEC_CHAR('-', LEFT),
+               SPEC_CHAR('0', ZEROPAD),
+       };
+       c -= 32;
+       return (c < sizeof(spec_flag_array)) ? spec_flag_array[c] : 0;
+}
+
 /*
  * Helper function to decode printf style format.
  * Each call decode a token from the format and return the
@@ -2552,7 +2566,7 @@ static noinline_for_stack
 struct fmt format_decode(struct fmt fmt, struct printf_spec *spec)
 {
        const char *start = fmt.str;
-       char qualifier;
+       char flag, qualifier;
 
        /* we finished early by reading the field width */
        if (fmt.state == FORMAT_STATE_WIDTH) {
@@ -2585,26 +2599,13 @@ struct fmt format_decode(struct fmt fmt, struct printf_spec *spec)
        if (fmt.str != start || !*fmt.str)
                return fmt;
 
-       /* Process flags */
+       /* Process flags. This also skips the first '%' */
        spec->flags = 0;
-
-       while (1) { /* this also skips first '%' */
-               bool found = true;
-
-               fmt.str++;
-
-               switch (*fmt.str) {
-               case '-': spec->flags |= LEFT;    break;
-               case '+': spec->flags |= PLUS;    break;
-               case ' ': spec->flags |= SPACE;   break;
-               case '#': spec->flags |= SPECIAL; break;
-               case '0': spec->flags |= ZEROPAD; break;
-               default:  found = false;
-               }
-
-               if (!found)
-                       break;
-       }
+       do {
+               /* this also skips first '%' */
+               flag = spec_flag(*++fmt.str);
+               spec->flags |= flag;
+       } while (flag);
 
        /* get field width */
        spec->field_width = -1;