git: bce0bef3c6ab - main - libc: Implement N2680.

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Thu, 07 Sep 2023 06:41:58 UTC
The branch main has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=bce0bef3c6abab92c7ac8cc23b7cc632a382721e

commit bce0bef3c6abab92c7ac8cc23b7cc632a382721e
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2023-09-07 06:14:44 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2023-09-07 06:40:14 +0000

    libc: Implement N2680.
    
    This adds specific width length modifiers in the form of wN and wfN (where N is 8, 16, 32, or 64) which allow printing intN_t and int_fastN_t without resorting to casts or PRI macros.
    
    Reviewed by:    imp, emaste
    Differential Revision:  https://reviews.freebsd.org/D41725
---
 lib/libc/stdio/printf.3      |  4 +++-
 lib/libc/stdio/printflocal.h |  1 +
 lib/libc/stdio/scanf.3       | 30 +++++++++++++++++++++++++++++-
 lib/libc/stdio/vfprintf.c    | 44 ++++++++++++++++++++++++++++++++++++++++++++
 lib/libc/stdio/vfscanf.c     | 40 ++++++++++++++++++++++++++++++++++++++++
 lib/libc/stdio/vfwprintf.c   | 44 ++++++++++++++++++++++++++++++++++++++++++++
 lib/libc/stdio/vfwscanf.c    | 40 ++++++++++++++++++++++++++++++++++++++++
 7 files changed, 201 insertions(+), 2 deletions(-)

diff --git a/lib/libc/stdio/printf.3 b/lib/libc/stdio/printf.3
index 110851e2a421..a7b0c7399e2e 100644
--- a/lib/libc/stdio/printf.3
+++ b/lib/libc/stdio/printf.3
@@ -31,7 +31,7 @@
 .\"
 .\"     @(#)printf.3	8.1 (Berkeley) 6/4/93
 .\"
-.Dd August 21, 2023
+.Dd September 5, 2023
 .Dt PRINTF 3
 .Os
 .Sh NAME
@@ -342,6 +342,8 @@ conversion:
 .It Cm ll No (ell ell) Ta Vt "long long" Ta Vt "unsigned long long" Ta Vt "long long *"
 .It Cm j Ta Vt intmax_t Ta Vt uintmax_t Ta Vt "intmax_t *"
 .It Cm t Ta Vt ptrdiff_t Ta (see note) Ta Vt "ptrdiff_t *"
+.It Cm w Ns Ar N Ta Vt intN_t Ta Vt uintN_t Ta Vt "intN_t *"
+.It Cm wf Ns Ar N Ta Vt int_fastN_t Ta Vt uint_fastN_t Ta Vt "int_fastN_t *"
 .It Cm z Ta (see note) Ta Vt size_t Ta (see note)
 .It Cm q Em (deprecated) Ta Vt quad_t Ta Vt u_quad_t Ta Vt "quad_t *"
 .El
diff --git a/lib/libc/stdio/printflocal.h b/lib/libc/stdio/printflocal.h
index 3594f75d0050..f3d0d3e9e216 100644
--- a/lib/libc/stdio/printflocal.h
+++ b/lib/libc/stdio/printflocal.h
@@ -49,6 +49,7 @@
 #define	PTRDIFFT	0x800		/* ptrdiff_t */
 #define	INTMAXT		0x1000		/* intmax_t */
 #define	CHARINT		0x2000		/* print char using int format */
+#define	FASTINT		0x4000		/* int_fastN_t */
 
 /*
  * Macros for converting digits to letters and vice versa
diff --git a/lib/libc/stdio/scanf.3 b/lib/libc/stdio/scanf.3
index 6cefdb133983..b8d2360c5e76 100644
--- a/lib/libc/stdio/scanf.3
+++ b/lib/libc/stdio/scanf.3
@@ -31,7 +31,7 @@
 .\"
 .\"     @(#)scanf.3	8.2 (Berkeley) 12/11/93
 .\"
-.Dd August 21, 2023
+.Dd September 5, 2023
 .Dt SCANF 3
 .Os
 .Sh NAME
@@ -217,6 +217,34 @@ and the next pointer is a pointer to a
 .Vt ptrdiff_t
 (rather than
 .Vt int ) .
+.It Cm w Ns Ar N
+.Po
+where
+.Ar N
+is 8, 16, 32, or 64
+.Pc
+Indicates that the conversion will be one of
+.Cm bdioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt intN_t
+(rather than
+.Vt int ) .
+.It Cm wf Ns Ar N
+.Po
+where
+.Ar N
+is 8, 16, 32, or 64
+.Pc
+Indicates that the conversion will be one of
+.Cm bdioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt int_fastN_t
+(rather than
+.Vt int ) .
 .It Cm z
 Indicates that the conversion will be one of
 .Cm bdioux
diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c
index 5e5a9b5e31c1..8ce77626fb6f 100644
--- a/lib/libc/stdio/vfprintf.c
+++ b/lib/libc/stdio/vfprintf.c
@@ -610,6 +610,49 @@ reswitch:	switch (ch) {
 		case 't':
 			flags |= PTRDIFFT;
 			goto rflag;
+		case 'w':
+			/*
+			 * Fixed-width integer types.  On all platforms we
+			 * support, int8_t is equivalent to char, int16_t
+			 * is equivalent to short, int32_t is equivalent
+			 * to int, int64_t is equivalent to long long int.
+			 * Furthermore, int_fast8_t, int_fast16_t and
+			 * int_fast32_t are equivalent to int, and
+			 * int_fast64_t is equivalent to long long int.
+			 */
+			flags &= ~(CHARINT|SHORTINT|LONGINT|LLONGINT|INTMAXT);
+			if (fmt[0] == 'f') {
+				flags |= FASTINT;
+				fmt++;
+			} else {
+				flags &= ~FASTINT;
+			}
+			if (fmt[0] == '8') {
+				if (!(flags & FASTINT))
+					flags |= CHARINT;
+				else
+					/* no flag set = 32 */ ;
+				fmt += 1;
+			} else if (fmt[0] == '1' && fmt[1] == '6') {
+				if (!(flags & FASTINT))
+					flags |= SHORTINT;
+				else
+					/* no flag set = 32 */ ;
+				fmt += 2;
+			} else if (fmt[0] == '3' && fmt[1] == '2') {
+				/* no flag set = 32 */ ;
+				fmt += 2;
+			} else if (fmt[0] == '6' && fmt[1] == '4') {
+				flags |= LLONGINT;
+				fmt += 2;
+			} else {
+				if (flags & FASTINT) {
+					flags &= ~FASTINT;
+					fmt--;
+				}
+				goto invalid;
+			}
+			goto rflag;
 		case 'z':
 			flags |= SIZET;
 			goto rflag;
@@ -932,6 +975,7 @@ number:			if ((dprec = prec) >= 0)
 		default:	/* "%?" prints ?, unless ? is NUL */
 			if (ch == '\0')
 				goto done;
+invalid:
 			/* pretend it was %c with argument ch */
 			cp = buf;
 			*cp = ch;
diff --git a/lib/libc/stdio/vfscanf.c b/lib/libc/stdio/vfscanf.c
index 9727c9e70c34..fa2e865f33f9 100644
--- a/lib/libc/stdio/vfscanf.c
+++ b/lib/libc/stdio/vfscanf.c
@@ -75,6 +75,7 @@ static char sccsid[] = "@(#)vfscanf.c	8.1 (Berkeley) 6/4/93";
 #define	SUPPRESS	0x08	/* *: suppress assignment */
 #define	POINTER		0x10	/* p: void * (as hex) */
 #define	NOSKIP		0x20	/* [ or c: do not skip blanks */
+#define FASTINT		0x200	/* wfN: int_fastN_t */
 #define	LONGLONG	0x400	/* ll: long long (+ deprecated q: quad) */
 #define	INTMAXT		0x800	/* j: intmax_t */
 #define	PTRDIFFT	0x1000	/* t: ptrdiff_t */
@@ -555,6 +556,45 @@ literal:
 		case 't':
 			flags |= PTRDIFFT;
 			goto again;
+		case 'w':
+			/*
+			 * Fixed-width integer types.  On all platforms we
+			 * support, int8_t is equivalent to char, int16_t
+			 * is equivalent to short, int32_t is equivalent
+			 * to int, int64_t is equivalent to long long int.
+			 * Furthermore, int_fast8_t, int_fast16_t and
+			 * int_fast32_t are equivalent to int, and
+			 * int_fast64_t is equivalent to long long int.
+			 */
+			flags &= ~(SHORTSHORT|SHORT|LONG|LONGLONG|SIZET|INTMAXT|PTRDIFFT);
+			if (fmt[0] == 'f') {
+				flags |= FASTINT;
+				fmt++;
+			} else {
+				flags &= ~FASTINT;
+			}
+			if (fmt[0] == '8') {
+				if (!(flags & FASTINT))
+					flags |= SHORTSHORT;
+				else
+					/* no flag set = 32 */ ;
+				fmt += 1;
+			} else if (fmt[0] == '1' && fmt[1] == '6') {
+				if (!(flags & FASTINT))
+					flags |= SHORT;
+				else
+					/* no flag set = 32 */ ;
+				fmt += 2;
+			} else if (fmt[0] == '3' && fmt[1] == '2') {
+				/* no flag set = 32 */ ;
+				fmt += 2;
+			} else if (fmt[0] == '6' && fmt[1] == '4') {
+				flags |= LONGLONG;
+				fmt += 2;
+			} else {
+				goto match_failure;
+			}
+			goto again;
 		case 'z':
 			flags |= SIZET;
 			goto again;
diff --git a/lib/libc/stdio/vfwprintf.c b/lib/libc/stdio/vfwprintf.c
index 259a86467ea7..d298ed03f521 100644
--- a/lib/libc/stdio/vfwprintf.c
+++ b/lib/libc/stdio/vfwprintf.c
@@ -681,6 +681,49 @@ reswitch:	switch (ch) {
 		case 't':
 			flags |= PTRDIFFT;
 			goto rflag;
+		case 'w':
+			/*
+			 * Fixed-width integer types.  On all platforms we
+			 * support, int8_t is equivalent to char, int16_t
+			 * is equivalent to short, int32_t is equivalent
+			 * to int, int64_t is equivalent to long long int.
+			 * Furthermore, int_fast8_t, int_fast16_t and
+			 * int_fast32_t are equivalent to int, and
+			 * int_fast64_t is equivalent to long long int.
+			 */
+			flags &= ~(CHARINT|SHORTINT|LONGINT|LLONGINT|INTMAXT);
+			if (fmt[0] == 'f') {
+				flags |= FASTINT;
+				fmt++;
+			} else {
+				flags &= ~FASTINT;
+			}
+			if (fmt[0] == '8') {
+				if (!(flags & FASTINT))
+					flags |= CHARINT;
+				else
+					/* no flag set = 32 */ ;
+				fmt += 1;
+			} else if (fmt[0] == '1' && fmt[1] == '6') {
+				if (!(flags & FASTINT))
+					flags |= SHORTINT;
+				else
+					/* no flag set = 32 */ ;
+				fmt += 2;
+			} else if (fmt[0] == '3' && fmt[1] == '2') {
+				/* no flag set = 32 */ ;
+				fmt += 2;
+			} else if (fmt[0] == '6' && fmt[1] == '4') {
+				flags |= LLONGINT;
+				fmt += 2;
+			} else {
+				if (flags & FASTINT) {
+					flags &= ~FASTINT;
+					fmt--;
+				}
+				goto invalid;
+			}
+			goto rflag;
 		case 'z':
 			flags |= SIZET;
 			goto rflag;
@@ -993,6 +1036,7 @@ number:			if ((dprec = prec) >= 0)
 		default:	/* "%?" prints ?, unless ? is NUL */
 			if (ch == '\0')
 				goto done;
+invalid:
 			/* pretend it was %c with argument ch */
 			cp = buf;
 			*cp = ch;
diff --git a/lib/libc/stdio/vfwscanf.c b/lib/libc/stdio/vfwscanf.c
index b03c9dba0699..e2c730b5e7a9 100644
--- a/lib/libc/stdio/vfwscanf.c
+++ b/lib/libc/stdio/vfwscanf.c
@@ -73,6 +73,7 @@ static char sccsid[] = "@(#)vfscanf.c	8.1 (Berkeley) 6/4/93";
 #define	SUPPRESS	0x08	/* *: suppress assignment */
 #define	POINTER		0x10	/* p: void * (as hex) */
 #define	NOSKIP		0x20	/* [ or c: do not skip blanks */
+#define FASTINT		0x200	/* wfN: int_fastN_t */
 #define	LONGLONG	0x400	/* ll: long long (+ deprecated q: quad) */
 #define	INTMAXT		0x800	/* j: intmax_t */
 #define	PTRDIFFT	0x1000	/* t: ptrdiff_t */
@@ -539,6 +540,45 @@ literal:
 		case 't':
 			flags |= PTRDIFFT;
 			goto again;
+		case 'w':
+			/*
+			 * Fixed-width integer types.  On all platforms we
+			 * support, int8_t is equivalent to char, int16_t
+			 * is equivalent to short, int32_t is equivalent
+			 * to int, int64_t is equivalent to long long int.
+			 * Furthermore, int_fast8_t, int_fast16_t and
+			 * int_fast32_t are equivalent to int, and
+			 * int_fast64_t is equivalent to long long int.
+			 */
+			flags &= ~(SHORTSHORT|SHORT|LONG|LONGLONG|SIZET|INTMAXT|PTRDIFFT);
+			if (fmt[0] == 'f') {
+				flags |= FASTINT;
+				fmt++;
+			} else {
+				flags &= ~FASTINT;
+			}
+			if (fmt[0] == '8') {
+				if (!(flags & FASTINT))
+					flags |= SHORTSHORT;
+				else
+					/* no flag set = 32 */ ;
+				fmt += 1;
+			} else if (fmt[0] == '1' && fmt[1] == '6') {
+				if (!(flags & FASTINT))
+					flags |= SHORT;
+				else
+					/* no flag set = 32 */ ;
+				fmt += 2;
+			} else if (fmt[0] == '3' && fmt[1] == '2') {
+				/* no flag set = 32 */ ;
+				fmt += 2;
+			} else if (fmt[0] == '6' && fmt[1] == '4') {
+				flags |= LONGLONG;
+				fmt += 2;
+			} else {
+				goto match_failure;
+			}
+			goto again;
 		case 'z':
 			flags |= SIZET;
 			goto again;