From patchwork Thu Sep 14 19:03:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joseph Myers X-Patchwork-Id: 1834421 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Rmmv15Hh4z1yhn for ; Fri, 15 Sep 2023 05:03:41 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id AED353858032 for ; Thu, 14 Sep 2023 19:03:39 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from esa2.mentor.iphmx.com (esa2.mentor.iphmx.com [68.232.141.98]) by sourceware.org (Postfix) with ESMTPS id 2FD7C3858CDA for ; Thu, 14 Sep 2023 19:03:27 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2FD7C3858CDA Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com X-CSE-ConnectionGUID: vFrLFtFKSnGt+F0pDDSXaQ== X-CSE-MsgGUID: AIVP5DVoTiqkcUnGQXPlLA== X-IronPort-AV: E=Sophos;i="6.02,146,1688457600"; d="scan'208";a="18943886" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa2.mentor.iphmx.com with ESMTP; 14 Sep 2023 11:03:25 -0800 IronPort-SDR: xNWK4bGXT19CIc9TwIsziD991AjkHxfNupkq1o5JxGqWKYSubu/dQNKfioDsdluILs8U2BDGCs KXdH1KXxZru7FeFAyXWzU1W9Mj+Z52dFFbcyTjdD2CIRvGLYr/Y8TMC+5KTGn8h/3u6cpBozjM YUI2EljvGb61Iz6fvnCtkljgzs9oqLGQQhX/HjGYJMrq27lAnC8XW9WHxT43/N/Ff4nJGq3zda dvOEizKJ9hG17HuGhRTHaaugPr1hs1saoi8NgEaeKvc3oTlYJazHphEPzrn4hURa3D/QcuVCdi X2c= Date: Thu, 14 Sep 2023 19:03:20 +0000 From: Joseph Myers To: Subject: C2x scanf %wN, %wfN support Message-ID: <611ae3f4-969-441e-8a51-68dbdf45f62a@codesourcery.com> MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-11.mgc.mentorg.com (139.181.222.11) To svr-ies-mbx-10.mgc.mentorg.com (139.181.222.10) X-Spam-Status: No, score=-3110.3 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, KAM_LOTSOFHASH, KAM_SHORT, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org 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 --git a/NEWS b/NEWS index a48c32e76f..d2ae239895 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..cf94af4f54 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,51 @@ __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"