aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2023-09-07 06:14:44 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2023-09-07 06:40:14 +0000
commitbce0bef3c6abab92c7ac8cc23b7cc632a382721e (patch)
tree916fe3a02348b3a7b0ecaf0bbdf5f95e2f55a1f3
parent294bd2827e61a78041f6613f4b82235fcc454157 (diff)
downloadsrc-bce0bef3c6abab92c7ac8cc23b7cc632a382721e.tar.gz
src-bce0bef3c6abab92c7ac8cc23b7cc632a382721e.zip
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
-rw-r--r--lib/libc/stdio/printf.34
-rw-r--r--lib/libc/stdio/printflocal.h1
-rw-r--r--lib/libc/stdio/scanf.330
-rw-r--r--lib/libc/stdio/vfprintf.c44
-rw-r--r--lib/libc/stdio/vfscanf.c40
-rw-r--r--lib/libc/stdio/vfwprintf.c44
-rw-r--r--lib/libc/stdio/vfwscanf.c40
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;