@@ -2566,7 +2566,7 @@ static noinline_for_stack
2566
2566
struct fmt format_decode (struct fmt fmt , struct printf_spec * spec )
2567
2567
{
2568
2568
const char * start = fmt .str ;
2569
- char flag , qualifier ;
2569
+ char flag ;
2570
2570
2571
2571
/* we finished early by reading the field width */
2572
2572
if (fmt .state == FORMAT_STATE_WIDTH ) {
@@ -2637,96 +2637,71 @@ struct fmt format_decode(struct fmt fmt, struct printf_spec *spec)
2637
2637
}
2638
2638
2639
2639
qualifier :
2640
- /* get the conversion qualifier */
2641
- qualifier = 0 ;
2642
- if (* fmt .str == 'h' || _tolower (* fmt .str ) == 'l' ||
2643
- * fmt .str == 'z' || * fmt .str == 't' ) {
2644
- qualifier = * fmt .str ++ ;
2645
- if (unlikely (qualifier == * fmt .str )) {
2646
- if (qualifier == 'l' ) {
2647
- qualifier = 'L' ;
2648
- fmt .str ++ ;
2649
- } else if (qualifier == 'h' ) {
2650
- qualifier = 'H' ;
2651
- fmt .str ++ ;
2652
- }
2653
- }
2654
- }
2655
-
2656
- /* default base */
2640
+ /* Set up default numeric format */
2657
2641
spec -> base = 10 ;
2658
- switch (* fmt .str ) {
2659
- case 'c' :
2660
- fmt .state = FORMAT_STATE_CHAR ;
2661
- fmt .str ++ ;
2662
- return fmt ;
2663
-
2664
- case 's' :
2665
- fmt .state = FORMAT_STATE_STR ;
2666
- fmt .str ++ ;
2667
- return fmt ;
2668
-
2669
- case 'p' :
2670
- fmt .state = FORMAT_STATE_PTR ;
2671
- fmt .str ++ ;
2672
- return fmt ;
2673
-
2674
- case '%' :
2675
- fmt .state = FORMAT_STATE_PERCENT_CHAR ;
2676
- fmt .str ++ ;
2677
- return fmt ;
2678
-
2679
- /* integer number formats - set up the flags and "break" */
2680
- case 'o' :
2681
- spec -> base = 8 ;
2682
- break ;
2683
-
2684
- case 'x' :
2685
- spec -> flags |= SMALL ;
2686
- fallthrough ;
2687
-
2688
- case 'X' :
2689
- spec -> base = 16 ;
2690
- break ;
2642
+ fmt .state = FORMAT_STATE_SIZE (int );
2643
+ static const struct format_state {
2644
+ unsigned char state ;
2645
+ unsigned char flags_or_double_state ;
2646
+ unsigned char modifier ;
2647
+ unsigned char base ;
2648
+ } lookup_state [256 ] = {
2649
+ // Qualifiers
2650
+ ['l' ] = { FORMAT_STATE_SIZE (long ), FORMAT_STATE_SIZE (long long ), 1 },
2651
+ ['L' ] = { FORMAT_STATE_SIZE (long long ), 0 , 1 },
2652
+ ['h' ] = { FORMAT_STATE_SIZE (short ), FORMAT_STATE_SIZE (char ), 1 },
2653
+ ['H' ] = { FORMAT_STATE_SIZE (char ), 0 , 1 }, // Questionable, historic
2654
+ ['z' ] = { FORMAT_STATE_SIZE (size_t ), 0 , 1 },
2655
+ ['t' ] = { FORMAT_STATE_SIZE (ptrdiff_t ), 0 , 1 },
2656
+
2657
+ // Non-numeric formats
2658
+ ['c' ] = { FORMAT_STATE_CHAR },
2659
+ ['s' ] = { FORMAT_STATE_STR },
2660
+ ['p' ] = { FORMAT_STATE_PTR },
2661
+ ['%' ] = { FORMAT_STATE_PERCENT_CHAR },
2662
+
2663
+ // Numerics
2664
+ ['o' ] = { 0 , 0 , 0 , 8 },
2665
+ ['x' ] = { 0 , SMALL , 0 , 16 },
2666
+ ['X' ] = { 0 , 0 , 0 , 16 },
2667
+ ['d' ] = { 0 , SIGN , 0 , 10 },
2668
+ ['i' ] = { 0 , SIGN , 0 , 10 },
2669
+ ['u' ] = { 0 , 0 , 0 , 10 , },
2691
2670
2692
- case 'd' :
2693
- case 'i' :
2694
- spec -> flags |= SIGN ;
2695
- break ;
2696
- case 'u' :
2697
- break ;
2698
-
2699
- case 'n' :
2700
2671
/*
2701
2672
* Since %n poses a greater security risk than
2702
2673
* utility, treat it as any other invalid or
2703
2674
* unsupported format specifier.
2704
2675
*/
2705
- fallthrough ;
2676
+ } ;
2706
2677
2707
- default :
2708
- WARN_ONCE (1 , "Please remove unsupported %%%c in format string\n" , * fmt .str );
2709
- fmt .state = FORMAT_STATE_INVALID ;
2678
+ const struct format_state * p = lookup_state + (u8 )* fmt .str ;
2679
+ if (p -> modifier ) {
2680
+ fmt .state = p -> state ;
2681
+ if (p -> flags_or_double_state && fmt .str [0 ] == fmt .str [1 ]) {
2682
+ fmt .state = p -> flags_or_double_state ;
2683
+ fmt .str ++ ;
2684
+ }
2685
+ fmt .str ++ ;
2686
+ p = lookup_state + * fmt .str ;
2687
+ if (unlikely (p -> modifier ))
2688
+ goto invalid ;
2689
+ }
2690
+ if (p -> base ) {
2691
+ spec -> base = p -> base ;
2692
+ spec -> flags |= p -> flags_or_double_state ;
2693
+ fmt .str ++ ;
2710
2694
return fmt ;
2711
2695
}
2712
-
2713
- if (qualifier == 'L' )
2714
- fmt .state = FORMAT_STATE_SIZE (long long );
2715
- else if (qualifier == 'l' ) {
2716
- fmt .state = FORMAT_STATE_SIZE (long );
2717
- } else if (qualifier == 'z' ) {
2718
- fmt .state = FORMAT_STATE_SIZE (size_t );
2719
- } else if (qualifier == 't' ) {
2720
- fmt .state = FORMAT_STATE_SIZE (ptrdiff_t );
2721
- } else if (qualifier == 'H' ) {
2722
- fmt .state = FORMAT_STATE_SIZE (char );
2723
- } else if (qualifier == 'h' ) {
2724
- fmt .state = FORMAT_STATE_SIZE (short );
2725
- } else {
2726
- fmt .state = FORMAT_STATE_SIZE (int );
2696
+ if (p -> state ) {
2697
+ fmt .state = p -> state ;
2698
+ fmt .str ++ ;
2699
+ return fmt ;
2727
2700
}
2728
2701
2729
- fmt .str ++ ;
2702
+ invalid :
2703
+ WARN_ONCE (1 , "Please remove unsupported %%%c in format string\n" , * fmt .str );
2704
+ fmt .state = FORMAT_STATE_INVALID ;
2730
2705
return fmt ;
2731
2706
}
2732
2707
0 commit comments