"Gary E. Miller" <[email protected]> writes:
> The POSIX 2024 man page is here:
>
> https://pubs.opengroup.org/onlinepubs/9799919799/functions/iscntrl_l.html
>
> int iscntrl(int c);
>
> Been that way since POSIX.1-2008.
Yes, but you didn't quote enough. It says:
The c argument is a type int, the value of which the application shall
ensure is a character representable as an unsigned char or equal to
the value of the macro EOF. If the argument has any other value, the
behavior is undefined.
So if a is of type "char", and on that platform/compiler char is signed
(quite common), then if a holds for example é (value 233 decimal, 0xe9),
then when it is promoted to int, the results is -105. That is not
"representable as an unsigned char" and it is not EOF. Therefore the
behavior is undefined, and code that leads to UB is incorrect.
This leads to the general rule that you can't use arguments of type char
for ctype functions. If it's a char, it needs to be cast to unsigned
char. There are a massive number of such constructions already in the
code.
A quick grep pulls out a bunch; there are 187 casts to unsigned char and
most of them are for ctype; I delete a few lines from the below block
that were casts not immediately in a ctype call.
libgps/gpsutils.c: if (isdigit((unsigned char)*p)) {
libgps/gpsutils.c: while (isdigit((unsigned char) *p)) {
libgps/hex.c: if (isprint((unsigned char)*sp)) {
libgps/json.c: if (isspace((unsigned char) *cp)) {
libgps/json.c: if (isspace((unsigned char) *cp)) {
libgps/json.c: if (isspace((unsigned char) *cp) ||
libgps/json.c: if (isspace((unsigned char) *cp) ||
libgps/json.c: if (isspace((unsigned char) *cp)) {
libgps/json.c: while (*cp != '\0' && isspace((unsigned char)
*cp)) {
libgps/json.c: if (isdigit((unsigned char) valbuf[0])) {
libgps/json.c: if (isspace((unsigned char) *cp)) {
libgps/json.c: while (isspace((unsigned char)*cp)) {
libgps/json.c: while (isspace((unsigned char)*cp)) {
libgps/json.c: while (isspace((unsigned char)*cp)) {
libgps/json.c: if (isspace((unsigned char) *cp)) {