Implement C23 scanf 'w' length modifiers
wN: Specifies that a following b, d, i, o, u, x, or X conversion specifier applies to an integer argument with a specific width where N is a positive decimal integer with no leading zeros (the argument will have been promoted according to the integer promotions, but its value shall be converted to the unpromoted type); or that a following n conversion specifier applies to a pointer to an integer type argument with a width of N bits. All minimum-width integer types (7.22.1.2) and exact-width integer types (7.22.1.1) defined in the header <stdint.h> shall be supported. Other supported values of N are implementation-defined.
Bug: b/271903607
Test: adb shell
Change-Id: I595fd2ac7bc40d9fb7f1935b39933a6cc068eeff
diff --git a/libc/stdio/vfscanf.cpp b/libc/stdio/vfscanf.cpp
index dfd001d..65f54a5 100644
--- a/libc/stdio/vfscanf.cpp
+++ b/libc/stdio/vfscanf.cpp
@@ -31,53 +31,7 @@
* SUCH DAMAGE.
*/
-#include <ctype.h>
-#include <inttypes.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/param.h>
-#include <wctype.h>
-#include "local.h"
-
-#include <private/bionic_fortify.h>
-#include <platform/bionic/macros.h>
-#include <private/bionic_mbstate.h>
-
-#define BUF 513 /* Maximum length of numeric string. */
-
-// Flags used during conversion.
-// Size/type:
-#define LONG 0x00001 // l: long or double
-#define LONGDBL 0x00002 // L: long double
-#define SHORT 0x00004 // h: short
-#define SHORTSHORT 0x00008 // hh: 8 bit integer
-#define LLONG 0x00010 // ll: long long (+ deprecated q: quad)
-#define POINTER 0x00020 // p: void* (as hex)
-#define SIZEINT 0x00040 // z: (signed) size_t
-#define MAXINT 0x00080 // j: intmax_t
-#define PTRINT 0x00100 // t: ptrdiff_t
-#define NOSKIP 0x00200 // [ or c: do not skip blanks
-// Modifiers:
-#define SUPPRESS 0x00400 // *: suppress assignment
-#define UNSIGNED 0x00800 // %[oupxX] conversions
-#define ALLOCATE 0x01000 // m: allocate a char*
-// Internal use during integer parsing:
-#define SIGNOK 0x02000 // +/- is (still) legal
-#define HAVESIGN 0x04000 // Sign detected
-#define NDIGITS 0x08000 // No digits detected
-#define PFXOK 0x10000 // "0x" prefix is (still) legal
-#define PFBOK 0x20000 // "0b" prefix is (still) legal
-#define NZDIGITS 0x40000 // No zero digits detected
-
-// Conversion types.
-#define CT_CHAR 0 // %c conversion
-#define CT_CCL 1 // %[...] conversion
-#define CT_STRING 2 // %s conversion
-#define CT_INT 3 // Integer: strtoimax/strtoumax
-#define CT_FLOAT 4 // Float: strtod
+#include "scanf_common.h"
static const unsigned char* __sccl(char*, const unsigned char*);
@@ -122,6 +76,7 @@
*/
again:
c = *fmt++;
+reswitch:
switch (c) {
case '%':
literal:
@@ -220,6 +175,18 @@
base = 10;
break;
+ case 'w': {
+ int size = 0;
+ bool fast = false;
+ c = *fmt++;
+ while (is_digit(c)) {
+ APPEND_DIGIT(size, c);
+ c = *fmt++;
+ }
+ flags |= w_to_flag(size, fast);
+ goto reswitch;
+ }
+
case 'X':
case 'x':
flags |= PFXOK; /* enable 0x prefixing */