From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1105) id 605F33858C52; Thu, 28 Sep 2023 17:28:38 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 605F33858C52 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1695922118; bh=XL6YrViUDodKJcNUvB2NZQsn5LFDazzJYWcH9XC+zbE=; h=From:To:Subject:Date:From; b=cbL78ETwFP3gymwWW5TRAP9bWIZIV+sN3Lb1sPNfet2skQ7EhwUAjud82wXtDCFS4 mfhOUbtlL1mzsIjwvEc4SQxlqgkD0u+KFgSCnlBJgfT3u00oUSxJnf9J83qyalKj7E sGW2YYjY+bh9TRhOUZWJZ8foP2k+Cy5NmHUdRSv0= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Joseph Myers To: glibc-cvs@sourceware.org Subject: [glibc] C2x scanf %wN, %wfN support X-Act-Checkin: glibc X-Git-Author: Joseph Myers X-Git-Refname: refs/heads/master X-Git-Oldrev: aea4ddb87168d0475777e605f3bb576b0f62b3a2 X-Git-Newrev: cdbf8229bb1438998b211e4760a97d94a13674d4 Message-Id: <20230928172838.605F33858C52@sourceware.org> Date: Thu, 28 Sep 2023 17:28:38 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=cdbf8229bb1438998b211e4760a97d94a13674d4 commit cdbf8229bb1438998b211e4760a97d94a13674d4 Author: Joseph Myers Date: Thu Sep 28 17:27:58 2023 +0000 C2x scanf %wN, %wfN support ISO C2x defines scanf length modifiers wN (for intN_t / int_leastN_t / uintN_t / uint_leastN_t) and wfN (for int_fastN_t / uint_fastN_t). Add support for those length modifiers, similar to the printf support previously added. Tested for x86_64 and x86. Diff: --- NEWS | 7 + manual/stdio.texi | 14 ++ stdio-common/Makefile | 1 + stdio-common/tst-scanf-intn-main.c | 479 +++++++++++++++++++++++++++++++++++++ stdio-common/tst-scanf-intn.c | 24 ++ stdio-common/vfscanf-internal.c | 48 ++++ wcsmbs/Makefile | 1 + wcsmbs/tst-wscanf-intn.c | 24 ++ 8 files changed, 598 insertions(+) diff --git a/NEWS b/NEWS index 5b7b327b29..a94650da64 100644 --- a/NEWS +++ b/NEWS @@ -31,6 +31,13 @@ Major new features: the process ID associated with the process file descriptor created by pid_spawn, fork_np, or pidfd_open. +* scanf-family functions now support the wN format length modifiers for + arguments pointing to types intN_t, int_leastN_t, uintN_t or + uint_leastN_t (for example, %w32d to read int32_t or int_least32_t in + decimal, or %w32x to read uint32_t or uint_least32_t in hexadecimal) + and the wfN format length modifiers for arguments pointing to types + int_fastN_t or uint_fastN_t, as specified in draft ISO C2X. + Deprecated and removed features, and other changes affecting compatibility: [Add deprecations, removals and changes affecting compatibility here] diff --git a/manual/stdio.texi b/manual/stdio.texi index 9cf622403f..002fce7a10 100644 --- a/manual/stdio.texi +++ b/manual/stdio.texi @@ -3714,6 +3714,20 @@ Specifies that the argument is a @code{ptrdiff_t *}. This modifier was introduced in @w{ISO C99}. +@item w@var{n} +Specifies that the argument is an @code{int@var{n}_t *} or +@code{int_least@var{n}_t *} (which are the same type), or +@code{uint@var{n}_t *} or @code{uint_least@var{n}_t *} (which are the +same type). + +This modifier was introduced in @w{ISO C2X}. + +@item wf@var{n} +Specifies that the argument is an @code{int_fast@var{n}_t *} or +@code{uint_fast@var{n}_t *}. + +This modifier was introduced in @w{ISO C2X}. + @item z Specifies that the argument is a @code{size_t *}. diff --git a/stdio-common/Makefile b/stdio-common/Makefile index 3866362bae..bacb795fed 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -243,6 +243,7 @@ tests := \ tst-scanf-binary-c2x \ tst-scanf-binary-gnu11 \ tst-scanf-binary-gnu89 \ + tst-scanf-intn \ tst-scanf-round \ tst-scanf-to_inpunct \ tst-setvbuf1 \ diff --git a/stdio-common/tst-scanf-intn-main.c b/stdio-common/tst-scanf-intn-main.c new file mode 100644 index 0000000000..fa0462a8de --- /dev/null +++ b/stdio-common/tst-scanf-intn-main.c @@ -0,0 +1,479 @@ +/* Test scanf formats for intN_t, int_leastN_t and int_fastN_t types. + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include + +#include +#include + +/* GCC does not know the %wN or %wfN length modifiers before GCC 13. */ +DIAG_PUSH_NEEDS_COMMENT; +#if !__GNUC_PREREQ (13, 0) +DIAG_IGNORE_NEEDS_COMMENT (12, "-Wformat"); +DIAG_IGNORE_NEEDS_COMMENT (12, "-Wformat-extra-args"); +#endif + +#define CHECK_SCANF1(EXPECTED, STR, FMT) \ + do \ + { \ + var = ((typeof (var)) 0xabababab); \ + int ret = SSCANF (L_(STR), L_(FMT), &var); \ + TEST_COMPARE (var, (EXPECTED)); \ + TEST_COMPARE (ret, 1); \ + } \ + while (0) + +#define CHECK_SCANF1N(EXPECTED, STR, FMT) \ + do \ + { \ + var = ((typeof (var)) 0xabababab); \ + n = 123; \ + int ret = SSCANF (L_(STR), L_(FMT), &var, &n); \ + TEST_COMPARE (var, (EXPECTED)); \ + TEST_COMPARE (n, STRLEN (L_(STR))); \ + TEST_COMPARE (ret, 1); \ + } \ + while (0) + +#define CHECK_SCANF_ERR(OK, STR, FMT, ...) \ + do \ + { \ + int ret = SSCANF (L_(STR), L_(FMT), __VA_ARGS__); \ + TEST_VERIFY (ret == (OK)); \ + TEST_COMPARE (errno, EINVAL); \ + } \ + while (0) + +static void +test_w8 (void) +{ + { + int8_t var, n; + CHECK_SCANF1 (42, "42", "%w8d"); + CHECK_SCANF1N (42, "42", "%w8d%w8n"); + CHECK_SCANF1 (-43, "-43", "%w8d"); + CHECK_SCANF1 (42, "42", "%w8i"); + CHECK_SCANF1 (-43, "-43", "%w8i"); + CHECK_SCANF1 (123, "0b1111011", "%w8i"); + CHECK_SCANF1 (127, "0x7f", "%w8i"); + CHECK_SCANF1 (-19, "-023", "%w8i"); + } + { + uint8_t var; + int8_t n; + CHECK_SCANF1 (123, "1111011", "%w8b"); + CHECK_SCANF1 (19, "023", "%w8o"); + CHECK_SCANF1 (50, "50", "%w8u"); + CHECK_SCANF1 (65, "41", "%w8x"); + CHECK_SCANF1N (65, "41", "%w8x%w8n"); + CHECK_SCANF1 (66, "42", "%w8X"); + } + { + int_least8_t var, n; + CHECK_SCANF1 (42, "42", "%w8d"); + CHECK_SCANF1N (42, "42", "%w8d%w8n"); + CHECK_SCANF1 (-43, "-43", "%w8d"); + CHECK_SCANF1 (42, "42", "%w8i"); + CHECK_SCANF1 (-43, "-43", "%w8i"); + CHECK_SCANF1 (123, "0b1111011", "%w8i"); + CHECK_SCANF1 (127, "0x7f", "%w8i"); + CHECK_SCANF1 (-19, "-023", "%w8i"); + } + { + uint_least8_t var; + int_least8_t n; + CHECK_SCANF1 (123, "1111011", "%w8b"); + CHECK_SCANF1 (19, "023", "%w8o"); + CHECK_SCANF1 (50, "50", "%w8u"); + CHECK_SCANF1 (65, "41", "%w8x"); + CHECK_SCANF1N (65, "41", "%w8x%w8n"); + CHECK_SCANF1 (66, "42", "%w8X"); + } +} + +static void +test_wf8 (void) +{ + { + int_fast8_t var, n; + CHECK_SCANF1 (42, "42", "%wf8d"); + CHECK_SCANF1N (42, "42", "%wf8d%wf8n"); + CHECK_SCANF1 (-43, "-43", "%wf8d"); + CHECK_SCANF1 (42, "42", "%wf8i"); + CHECK_SCANF1 (-43, "-43", "%wf8i"); + CHECK_SCANF1 (123, "0b1111011", "%wf8i"); + CHECK_SCANF1 (127, "0x7f", "%wf8i"); + CHECK_SCANF1 (-19, "-023", "%wf8i"); + } + { + uint_fast8_t var; + int_fast8_t n; + CHECK_SCANF1 (123, "1111011", "%wf8b"); + CHECK_SCANF1 (19, "023", "%wf8o"); + CHECK_SCANF1 (50, "50", "%wf8u"); + CHECK_SCANF1 (65, "41", "%wf8x"); + CHECK_SCANF1N (65, "41", "%wf8x%wf8n"); + CHECK_SCANF1 (66, "42", "%wf8X"); + } +} + +static void +test_w16 (void) +{ + { + int16_t var, n; + CHECK_SCANF1 (12345, "12345", "%w16d"); + CHECK_SCANF1N (23456, "23456", "%w16d%w16n"); + CHECK_SCANF1 (-10101, "-10101", "%w16d"); + CHECK_SCANF1 (30000, "30000", "%w16i"); + CHECK_SCANF1 (-19876, "-19876", "%w16i"); + CHECK_SCANF1 (16384, "0b100000000000000", "%w16i"); + CHECK_SCANF1 (32767, "0x7fff", "%w16i"); + CHECK_SCANF1 (-16383, "-037777", "%w16i"); + } + { + uint16_t var; + int16_t n; + CHECK_SCANF1 (32767, "111111111111111", "%w16b"); + CHECK_SCANF1 (4095, "07777", "%w16o"); + CHECK_SCANF1 (9999, "9999", "%w16u"); + CHECK_SCANF1 (23456, "5ba0", "%w16x"); + CHECK_SCANF1N (23456, "5ba0", "%w16x%w16n"); + CHECK_SCANF1 (23457, "5ba1", "%w16X"); + } + { + int_least16_t var, n; + CHECK_SCANF1 (12345, "12345", "%w16d"); + CHECK_SCANF1N (23456, "23456", "%w16d%w16n"); + CHECK_SCANF1 (-10101, "-10101", "%w16d"); + CHECK_SCANF1 (30000, "30000", "%w16i"); + CHECK_SCANF1 (-19876, "-19876", "%w16i"); + CHECK_SCANF1 (16384, "0b100000000000000", "%w16i"); + CHECK_SCANF1 (32767, "0x7fff", "%w16i"); + CHECK_SCANF1 (-16383, "-037777", "%w16i"); + } + { + uint_least16_t var; + int_least16_t n; + CHECK_SCANF1 (32767, "111111111111111", "%w16b"); + CHECK_SCANF1 (4095, "07777", "%w16o"); + CHECK_SCANF1 (9999, "9999", "%w16u"); + CHECK_SCANF1 (23456, "5ba0", "%w16x"); + CHECK_SCANF1N (23456, "5ba0", "%w16x%w16n"); + CHECK_SCANF1 (23457, "5ba1", "%w16X"); + } +} + +static void +test_wf16 (void) +{ + { + int_fast16_t var, n; + CHECK_SCANF1 (12345, "12345", "%wf16d"); + CHECK_SCANF1N (23456, "23456", "%wf16d%wf16n"); + CHECK_SCANF1 (-10101, "-10101", "%wf16d"); + CHECK_SCANF1 (30000, "30000", "%wf16i"); + CHECK_SCANF1 (-19876, "-19876", "%wf16i"); + CHECK_SCANF1 (16384, "0b100000000000000", "%wf16i"); + CHECK_SCANF1 (32767, "0x7fff", "%wf16i"); + CHECK_SCANF1 (-16383, "-037777", "%wf16i"); + } + { + uint_fast16_t var; + int_fast16_t n; + CHECK_SCANF1 (32767, "111111111111111", "%wf16b"); + CHECK_SCANF1 (4095, "07777", "%wf16o"); + CHECK_SCANF1 (9999, "9999", "%wf16u"); + CHECK_SCANF1 (23456, "5ba0", "%wf16x"); + CHECK_SCANF1N (23456, "5ba0", "%wf16x%wf16n"); + CHECK_SCANF1 (23457, "5ba1", "%wf16X"); + } +#if INT_FAST16_MAX >= INT32_MAX + { + int_fast16_t var, n; + CHECK_SCANF1 (1234567, "1234567", "%wf16d"); + CHECK_SCANF1N (2345678, "2345678", "%wf16d%wf16n"); + CHECK_SCANF1 (-1010101, "-1010101", "%wf16d"); + CHECK_SCANF1 (3000000, "3000000", "%wf16i"); + CHECK_SCANF1 (-98765432, "-98765432", "%wf16i"); + CHECK_SCANF1 (1048576, "0b100000000000000000000", "%wf16i"); + CHECK_SCANF1 (1048575, "0xfffff", "%wf16i"); + CHECK_SCANF1 (-1048575, "-03777777", "%wf16i"); + } + { + uint_fast16_t var; + int_fast16_t n; + CHECK_SCANF1 (1234567, "100101101011010000111", "%wf16b"); + CHECK_SCANF1 (1048575, "03777777", "%wf16o"); + CHECK_SCANF1 (999999, "999999", "%wf16u"); + CHECK_SCANF1 (987654, "f1206", "%wf16x"); + CHECK_SCANF1N (987654, "f1206", "%wf16x%wf16n"); + CHECK_SCANF1 (987655, "f1207", "%wf16X"); + } +#endif +#if INT_FAST16_MAX >= INT64_MAX + { + int_fast16_t var, n; + CHECK_SCANF1 (123456789012LL, "123456789012", "%wf16d"); + CHECK_SCANF1N (234567890123LL, "234567890123", "%wf16d%wf16n"); + CHECK_SCANF1 (-10101010101LL, "-10101010101", "%wf16d"); + CHECK_SCANF1 (3000000000000000LL, "3000000000000000", "%wf16i"); + CHECK_SCANF1 (-9876543210LL, "-9876543210", "%wf16i"); + CHECK_SCANF1 (1LL << 40, "0b10000000000000000000000000000000000000000", + "%wf16i"); + CHECK_SCANF1 (1LL << 41, "0x20000000000", "%wf16i"); + CHECK_SCANF1 (-(1LL << 42), "-0100000000000000", "%wf16i"); + } + { + uint_fast16_t var; + int_fast16_t n; + CHECK_SCANF1 (123456789012ULL, "1110010111110100110010001101000010100", + "%wf16b"); + CHECK_SCANF1 (1ULL << 40, "20000000000000", "%wf16o"); + CHECK_SCANF1 (999999999999ULL, "999999999999", "%wf16u"); + CHECK_SCANF1 (9876543210ULL, "24cb016ea", "%wf16x"); + CHECK_SCANF1N (9876543210ULL, "24cb016ea", "%wf16x%wf16n"); + CHECK_SCANF1 (9876543211ULL, "24cb016eb", "%wf16X"); + } +#endif +} + +static void +test_w32 (void) +{ + { + int32_t var, n; + CHECK_SCANF1 (1234567, "1234567", "%w32d"); + CHECK_SCANF1N (2345678, "2345678", "%w32d%w32n"); + CHECK_SCANF1 (-1010101, "-1010101", "%w32d"); + CHECK_SCANF1 (3000000, "3000000", "%w32i"); + CHECK_SCANF1 (-98765432, "-98765432", "%w32i"); + CHECK_SCANF1 (1048576, "0b100000000000000000000", "%w32i"); + CHECK_SCANF1 (1048575, "0xfffff", "%w32i"); + CHECK_SCANF1 (-1048575, "-03777777", "%w32i"); + } + { + uint32_t var; + int32_t n; + CHECK_SCANF1 (1234567, "100101101011010000111", "%w32b"); + CHECK_SCANF1 (1048575, "03777777", "%w32o"); + CHECK_SCANF1 (999999, "999999", "%w32u"); + CHECK_SCANF1 (987654, "f1206", "%w32x"); + CHECK_SCANF1N (987654, "f1206", "%w32x%w32n"); + CHECK_SCANF1 (987655, "f1207", "%w32X"); + } + { + int_least32_t var, n; + CHECK_SCANF1 (1234567, "1234567", "%w32d"); + CHECK_SCANF1N (2345678, "2345678", "%w32d%w32n"); + CHECK_SCANF1 (-1010101, "-1010101", "%w32d"); + CHECK_SCANF1 (3000000, "3000000", "%w32i"); + CHECK_SCANF1 (-98765432, "-98765432", "%w32i"); + CHECK_SCANF1 (1048576, "0b100000000000000000000", "%w32i"); + CHECK_SCANF1 (1048575, "0xfffff", "%w32i"); + CHECK_SCANF1 (-1048575, "-03777777", "%w32i"); + } + { + uint_least32_t var; + int_least32_t n; + CHECK_SCANF1 (1234567, "100101101011010000111", "%w32b"); + CHECK_SCANF1 (1048575, "03777777", "%w32o"); + CHECK_SCANF1 (999999, "999999", "%w32u"); + CHECK_SCANF1 (987654, "f1206", "%w32x"); + CHECK_SCANF1N (987654, "f1206", "%w32x%w32n"); + CHECK_SCANF1 (987655, "f1207", "%w32X"); + } +} + +static void +test_wf32 (void) +{ + { + int_fast32_t var, n; + CHECK_SCANF1 (1234567, "1234567", "%wf32d"); + CHECK_SCANF1N (2345678, "2345678", "%wf32d%wf32n"); + CHECK_SCANF1 (-1010101, "-1010101", "%wf32d"); + CHECK_SCANF1 (3000000, "3000000", "%wf32i"); + CHECK_SCANF1 (-98765432, "-98765432", "%wf32i"); + CHECK_SCANF1 (1048576, "0b100000000000000000000", "%wf32i"); + CHECK_SCANF1 (1048575, "0xfffff", "%wf32i"); + CHECK_SCANF1 (-1048575, "-03777777", "%wf32i"); + } + { + uint_fast32_t var; + int_fast32_t n; + CHECK_SCANF1 (1234567, "100101101011010000111", "%wf32b"); + CHECK_SCANF1 (1048575, "03777777", "%wf32o"); + CHECK_SCANF1 (999999, "999999", "%wf32u"); + CHECK_SCANF1 (987654, "f1206", "%wf32x"); + CHECK_SCANF1N (987654, "f1206", "%wf32x%wf32n"); + CHECK_SCANF1 (987655, "f1207", "%wf32X"); + } +#if INT_FAST32_MAX >= INT64_MAX + { + int_fast32_t var, n; + CHECK_SCANF1 (123456789012LL, "123456789012", "%wf32d"); + CHECK_SCANF1N (234567890123LL, "234567890123", "%wf32d%wf32n"); + CHECK_SCANF1 (-10101010101LL, "-10101010101", "%wf32d"); + CHECK_SCANF1 (3000000000000000LL, "3000000000000000", "%wf32i"); + CHECK_SCANF1 (-9876543210LL, "-9876543210", "%wf32i"); + CHECK_SCANF1 (1LL << 40, "0b10000000000000000000000000000000000000000", + "%wf32i"); + CHECK_SCANF1 (1LL << 41, "0x20000000000", "%wf32i"); + CHECK_SCANF1 (-(1LL << 42), "-0100000000000000", "%wf32i"); + } + { + uint_fast32_t var; + int_fast32_t n; + CHECK_SCANF1 (123456789012ULL, "1110010111110100110010001101000010100", + "%wf32b"); + CHECK_SCANF1 (1ULL << 40, "20000000000000", "%wf32o"); + CHECK_SCANF1 (999999999999ULL, "999999999999", "%wf32u"); + CHECK_SCANF1 (9876543210ULL, "24cb016ea", "%wf32x"); + CHECK_SCANF1N (9876543210ULL, "24cb016ea", "%wf32x%wf32n"); + CHECK_SCANF1 (9876543211ULL, "24cb016eb", "%wf32X"); + } +#endif +} + +static void +test_w64 (void) +{ + { + int64_t var, n; + CHECK_SCANF1 (123456789012LL, "123456789012", "%w64d"); + CHECK_SCANF1N (234567890123LL, "234567890123", "%w64d%w64n"); + CHECK_SCANF1 (-10101010101LL, "-10101010101", "%w64d"); + CHECK_SCANF1 (3000000000000000LL, "3000000000000000", "%w64i"); + CHECK_SCANF1 (-9876543210LL, "-9876543210", "%w64i"); + CHECK_SCANF1 (1LL << 40, "0b10000000000000000000000000000000000000000", + "%w64i"); + CHECK_SCANF1 (1LL << 41, "0x20000000000", "%w64i"); + CHECK_SCANF1 (-(1LL << 42), "-0100000000000000", "%w64i"); + } + { + uint64_t var; + int64_t n; + CHECK_SCANF1 (123456789012ULL, "1110010111110100110010001101000010100", + "%w64b"); + CHECK_SCANF1 (1ULL << 40, "20000000000000", "%w64o"); + CHECK_SCANF1 (999999999999ULL, "999999999999", "%w64u"); + CHECK_SCANF1 (9876543210ULL, "24cb016ea", "%w64x"); + CHECK_SCANF1N (9876543210ULL, "24cb016ea", "%w64x%w64n"); + CHECK_SCANF1 (9876543211ULL, "24cb016eb", "%w64X"); + } + { + int_least64_t var, n; + CHECK_SCANF1 (123456789012LL, "123456789012", "%w64d"); + CHECK_SCANF1N (234567890123LL, "234567890123", "%w64d%w64n"); + CHECK_SCANF1 (-10101010101LL, "-10101010101", "%w64d"); + CHECK_SCANF1 (3000000000000000LL, "3000000000000000", "%w64i"); + CHECK_SCANF1 (-9876543210LL, "-9876543210", "%w64i"); + CHECK_SCANF1 (1LL << 40, "0b10000000000000000000000000000000000000000", + "%w64i"); + CHECK_SCANF1 (1LL << 41, "0x20000000000", "%w64i"); + CHECK_SCANF1 (-(1LL << 42), "-0100000000000000", "%w64i"); + } + { + uint_least64_t var; + int_least64_t n; + CHECK_SCANF1 (123456789012ULL, "1110010111110100110010001101000010100", + "%w64b"); + CHECK_SCANF1 (1ULL << 40, "20000000000000", "%w64o"); + CHECK_SCANF1 (999999999999ULL, "999999999999", "%w64u"); + CHECK_SCANF1 (9876543210ULL, "24cb016ea", "%w64x"); + CHECK_SCANF1N (9876543210ULL, "24cb016ea", "%w64x%w64n"); + CHECK_SCANF1 (9876543211ULL, "24cb016eb", "%w64X"); + } +} + +static void +test_wf64 (void) +{ + { + int_fast64_t var, n; + CHECK_SCANF1 (123456789012LL, "123456789012", "%wf64d"); + CHECK_SCANF1N (234567890123LL, "234567890123", "%wf64d%wf64n"); + CHECK_SCANF1 (-10101010101LL, "-10101010101", "%wf64d"); + CHECK_SCANF1 (3000000000000000LL, "3000000000000000", "%wf64i"); + CHECK_SCANF1 (-9876543210LL, "-9876543210", "%wf64i"); + CHECK_SCANF1 (1LL << 40, "0b10000000000000000000000000000000000000000", + "%wf64i"); + CHECK_SCANF1 (1LL << 41, "0x20000000000", "%wf64i"); + CHECK_SCANF1 (-(1LL << 42), "-0100000000000000", "%wf64i"); + } + { + uint_fast64_t var; + int_fast64_t n; + CHECK_SCANF1 (123456789012ULL, "1110010111110100110010001101000010100", + "%wf64b"); + CHECK_SCANF1 (1ULL << 40, "20000000000000", "%wf64o"); + CHECK_SCANF1 (999999999999ULL, "999999999999", "%wf64u"); + CHECK_SCANF1 (9876543210ULL, "24cb016ea", "%wf64x"); + CHECK_SCANF1N (9876543210ULL, "24cb016ea", "%wf64x%wf64n"); + CHECK_SCANF1 (9876543211ULL, "24cb016eb", "%wf64X"); + } +} + +static int +do_test (void) +{ + int a, b; + test_w8 (); + test_wf8 (); + test_w16 (); + test_wf16 (); + test_w32 (); + test_wf32 (); + test_w64 (); + test_wf64 (); + /* Bad N in %wN and %wfN are required to produce an error return (of + the number of input items assigned) from scanf functions (and can + also be seen to be invalid at compile time). */ + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT (13, "-Wformat"); + DIAG_IGNORE_NEEDS_COMMENT (13, "-Wformat-extra-args"); + CHECK_SCANF_ERR (0, "1", "%w1d", &a); + CHECK_SCANF_ERR (0, "1", "%w123d", &a); + CHECK_SCANF_ERR (0, "1", "%w99999999999999999999d", &a); + CHECK_SCANF_ERR (0, "1", "%wf1d", &a); + CHECK_SCANF_ERR (0, "1", "%wf123d", &a); + CHECK_SCANF_ERR (0, "1", "%wf99999999999999999999d", &a); + CHECK_SCANF_ERR (1, "1 1", "%d %w1d", &a, &b); + CHECK_SCANF_ERR (1, "1 1", "%d %w123d", &a, &b); + CHECK_SCANF_ERR (1, "1 1", "%d %w99999999999999999999d", &a, &b); + CHECK_SCANF_ERR (1, "1 1", "%d %wf1d", &a, &b); + CHECK_SCANF_ERR (1, "1 1", "%d %wf123d", &a, &b); + CHECK_SCANF_ERR (1, "1 1", "%d %wf99999999999999999999d", &a, &b); + CHECK_SCANF_ERR (0, "1", "%1$w1d", &a); + CHECK_SCANF_ERR (0, "1", "%1$w123d", &a); + CHECK_SCANF_ERR (0, "1", "%1$w99999999999999999999d", &a); + CHECK_SCANF_ERR (0, "1", "%1$wf1d", &a); + CHECK_SCANF_ERR (0, "1", "%1$wf123d", &a); + CHECK_SCANF_ERR (0, "1", "%1$wf99999999999999999999d", &a); + DIAG_POP_NEEDS_COMMENT; + return 0; +} + +DIAG_POP_NEEDS_COMMENT; + +#include diff --git a/stdio-common/tst-scanf-intn.c b/stdio-common/tst-scanf-intn.c new file mode 100644 index 0000000000..876eda30ee --- /dev/null +++ b/stdio-common/tst-scanf-intn.c @@ -0,0 +1,24 @@ +/* Test scanf formats for intN_t, int_leastN_t and int_fastN_t types. + Narrow string version. + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#define SSCANF sscanf +#define STRLEN strlen +#define L_(C) C + +#include diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c index 9b1197d751..cacb9668ba 100644 --- a/stdio-common/vfscanf-internal.c +++ b/stdio-common/vfscanf-internal.c @@ -381,6 +381,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr, while (*f != '\0') { unsigned int argpos; + bool is_fast; /* Extract the next argument, which is of type TYPE. For a %N$... spec, this is the Nth argument from the beginning; otherwise it is the next argument after the state now in ARG. */ @@ -602,6 +603,53 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr, else if (sizeof (ptrdiff_t) > sizeof (int)) flags |= LONG; break; + case L_('w'): + { + is_fast = false; + if (*f == L_('f')) + { + ++f; + is_fast = true; + } + int bitwidth = 0; + if (ISDIGIT (*f)) + bitwidth = read_int (&f); + if (is_fast) + switch (bitwidth) + { + case 8: + bitwidth = INT_FAST8_WIDTH; + break; + case 16: + bitwidth = INT_FAST16_WIDTH; + break; + case 32: + bitwidth = INT_FAST32_WIDTH; + break; + case 64: + bitwidth = INT_FAST64_WIDTH; + break; + } + switch (bitwidth) + { + case 8: + flags |= CHAR; + break; + case 16: + flags |= SHORT; + break; + case 32: + break; + case 64: + flags |= LONGDBL | LONG; + break; + default: + /* ISO C requires this error to be detected. */ + __set_errno (EINVAL); + goto errout; + } + } + break; default: /* Not a recognized modifier. Backup. */ --f; diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile index 431136b9c9..cde9a3221e 100644 --- a/wcsmbs/Makefile +++ b/wcsmbs/Makefile @@ -196,6 +196,7 @@ tests := \ tst-wscanf-binary-c2x \ tst-wscanf-binary-gnu11 \ tst-wscanf-binary-gnu89 \ + tst-wscanf-intn \ tst-wscanf-to_inpunct \ wcsatcliff \ wcsmbs-tst1 \ diff --git a/wcsmbs/tst-wscanf-intn.c b/wcsmbs/tst-wscanf-intn.c new file mode 100644 index 0000000000..8b6e6d3c0e --- /dev/null +++ b/wcsmbs/tst-wscanf-intn.c @@ -0,0 +1,24 @@ +/* Test scanf formats for intN_t, int_leastN_t and int_fastN_t types. + Wide string version. + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#define SSCANF swscanf +#define STRLEN wcslen +#define L_(C) L ## C + +#include "../stdio-common/tst-scanf-intn-main.c"