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
This commit is contained in:
Dag-Erling Smørgrav 2023-09-07 06:14:44 +00:00
parent 294bd2827e
commit bce0bef3c6
7 changed files with 201 additions and 2 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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 @@ again: c = *fmt++;
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;

View file

@ -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;

View file

@ -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 @@ again: c = *fmt++;
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;