* strtol, strtoll, strtoul, strtoull: Make ISO C 23 compliant
@ 2023-03-16 15:05 Bruno Haible
2023-03-17 12:52 ` Eric Blake
0 siblings, 1 reply; 2+ messages in thread
From: Bruno Haible @ 2023-03-16 15:05 UTC (permalink / raw)
To: bug-gnulib
ISO C 23 § 7.24.1.7 in combination with § 6.4.4.1 specifies that strtol,
strtoll, strtoul, strtoull need to accept binary integer syntax as input,
e.g. "0b101010" for 42.
This patch implements it, and augments the unit tests accordingly.
2023-03-16 Bruno Haible <bruno@clisp.org>
strtol, strtoll, strtoul, strtoull: Make ISO C 23 compliant.
* lib/strtol.c (INTERNAL (strtol)): Treat 'b' and base 2 like 'x' and
base 16. Based on glibc commit 64924422a99690d147a166b4de3103f3bf3eaf6c
by Joseph Myers.
* m4/strtol.m4 (gl_FUNC_STRTOL): Test also whether parsing binary
integers works. Update cross-compilation guesses.
* m4/strtoll.m4 (gl_FUNC_STRTOLL): Likewise.
* m4/strtoul.m4 (gl_FUNC_STRTOUL): Likewise.
* m4/strtoull.m4 (gl_FUNC_STRTOULL): Likewise.
* tests/test-strtol.c (main): Add tests of parsing binary integers.
* tests/test-strtoll.c (main): Likewise.
* tests/test-strtoul.c (main): Likewise.
* tests/test-strtoull.c (main): Likewise.
* doc/posix-functions/strtol.texi: Mention the problem with parsing
binary integers.
* doc/posix-functions/strtoll.texi: Likewise.
* doc/posix-functions/strtoul.texi: Likewise.
* doc/posix-functions/strtoull.texi: Likewise.
diff --git a/doc/posix-functions/strtol.texi b/doc/posix-functions/strtol.texi
index 5ebcb284d4..061deea1b3 100644
--- a/doc/posix-functions/strtol.texi
+++ b/doc/posix-functions/strtol.texi
@@ -14,6 +14,9 @@
This function does not parse the leading @samp{0} when the input string is
@code{"0x"} and the base is 16 or 0 on some platforms:
Minix 3.3, mingw, MSVC 14.
+@item
+This function does not parse binary integers (with a @samp{0b} or @samp{0B}
+prefix) when the base is 2 or 0 on many platforms.
@end itemize
Portability problems not fixed by Gnulib:
diff --git a/doc/posix-functions/strtoll.texi b/doc/posix-functions/strtoll.texi
index b507fc33c6..42f73d3449 100644
--- a/doc/posix-functions/strtoll.texi
+++ b/doc/posix-functions/strtoll.texi
@@ -15,6 +15,9 @@
This function does not parse the leading @samp{0} when the input string is
@code{"0x"} and the base is 16 or 0 on some platforms:
Minix 3.3, mingw, MSVC 14.
+@item
+This function does not parse binary integers (with a @samp{0b} or @samp{0B}
+prefix) when the base is 2 or 0 on many platforms.
@end itemize
Portability problems not fixed by Gnulib:
diff --git a/doc/posix-functions/strtoul.texi b/doc/posix-functions/strtoul.texi
index 3b1fa7fb5e..c3a97ee39a 100644
--- a/doc/posix-functions/strtoul.texi
+++ b/doc/posix-functions/strtoul.texi
@@ -14,6 +14,9 @@
This function does not parse the leading @samp{0} when the input string is
@code{"0x"} and the base is 16 or 0 on some platforms:
Minix 3.3, mingw, MSVC 14.
+@item
+This function does not parse binary integers (with a @samp{0b} or @samp{0B}
+prefix) when the base is 2 or 0 on many platforms.
@end itemize
Portability problems not fixed by Gnulib:
diff --git a/doc/posix-functions/strtoull.texi b/doc/posix-functions/strtoull.texi
index 68ede343e1..ba976a77e6 100644
--- a/doc/posix-functions/strtoull.texi
+++ b/doc/posix-functions/strtoull.texi
@@ -15,6 +15,9 @@
This function does not parse the leading @samp{0} when the input string is
@code{"0x"} and the base is 16 or 0 on some platforms:
Minix 3.3, mingw, MSVC 14.
+@item
+This function does not parse binary integers (with a @samp{0b} or @samp{0B}
+prefix) when the base is 2 or 0 on many platforms.
@end itemize
Portability problems not fixed by Gnulib:
diff --git a/lib/strtol.c b/lib/strtol.c
index d11269b262..b93483dca4 100644
--- a/lib/strtol.c
+++ b/lib/strtol.c
@@ -288,6 +288,11 @@ INTERNAL (strtol) (const STRING_TYPE *nptr, STRING_TYPE **endptr,
s += 2;
base = 16;
}
+ else if ((base == 0 || base == 2) && TOUPPER (s[1]) == L_('B'))
+ {
+ s += 2;
+ base = 2;
+ }
else if (base == 0)
base = 8;
}
@@ -378,11 +383,14 @@ INTERNAL (strtol) (const STRING_TYPE *nptr, STRING_TYPE **endptr,
noconv:
/* We must handle a special case here: the base is 0 or 16 and the
first two characters are '0' and 'x', but the rest are no
- hexadecimal digits. This is no error case. We return 0 and
- ENDPTR points to the 'x'. */
+ hexadecimal digits. Likewise when the base is 0 or 2 and the
+ first two characters are '0' and 'b', but the rest are no binary
+ digits. This is no error case. We return 0 and ENDPTR points to
+ the 'x' or 'b'. */
if (endptr != NULL)
{
- if (save - nptr >= 2 && TOUPPER (save[-1]) == L_('X')
+ if (save - nptr >= 2
+ && (TOUPPER (save[-1]) == L_('X') || TOUPPER (save[-1]) == L_('B'))
&& save[-2] == L_('0'))
*endptr = (STRING_TYPE *) &save[-1];
else
diff --git a/m4/strtol.m4 b/m4/strtol.m4
index 7e3b0d0044..5cdd86adc7 100644
--- a/m4/strtol.m4
+++ b/m4/strtol.m4
@@ -1,4 +1,4 @@
-# strtol.m4 serial 7
+# strtol.m4 serial 8
dnl Copyright (C) 2002-2003, 2006, 2009-2023 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -24,15 +24,26 @@ AC_DEFUN([gl_FUNC_STRTOL]
if (term != input + 1)
result |= 1;
}
+ /* This test fails on pre-C23 platforms. */
+ {
+ const char input[] = "0b1";
+ (void) strtol (input, &term, 2);
+ if (term != input + 3)
+ result |= 2;
+ }
return result;
]])
],
[gl_cv_func_strtol_works=yes],
[gl_cv_func_strtol_works=no],
[case "$host_os" in
- # Guess no on native Windows.
- mingw*) gl_cv_func_strtol_works="guessing no" ;;
- *) gl_cv_func_strtol_works="$gl_cross_guess_normal" ;;
+ # Guess no on native Windows.
+ mingw*) gl_cv_func_strtol_works="guessing no" ;;
+ # Guess no on glibc systems.
+ *-gnu* | gnu*) gl_cv_func_strtol_works="guessing no" ;;
+ # Guess no on musl systems.
+ *-musl* | midipix*) gl_cv_func_strtol_works="guessing no" ;;
+ *) gl_cv_func_strtol_works="$gl_cross_guess_normal" ;;
esac
])
])
diff --git a/m4/strtoll.m4 b/m4/strtoll.m4
index ede630c606..ec09609cd4 100644
--- a/m4/strtoll.m4
+++ b/m4/strtoll.m4
@@ -1,4 +1,4 @@
-# strtoll.m4 serial 9
+# strtoll.m4 serial 10
dnl Copyright (C) 2002, 2004, 2006, 2008-2023 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -24,15 +24,26 @@ AC_DEFUN([gl_FUNC_STRTOLL]
if (term != input + 1)
result |= 1;
}
+ /* This test fails on pre-C23 platforms. */
+ {
+ const char input[] = "0b1";
+ (void) strtoll (input, &term, 2);
+ if (term != input + 3)
+ result |= 2;
+ }
return result;
]])
],
[gl_cv_func_strtoll_works=yes],
[gl_cv_func_strtoll_works=no],
[case "$host_os" in
- # Guess no on native Windows.
- mingw*) gl_cv_func_strtoll_works="guessing no" ;;
- *) gl_cv_func_strtoll_works="$gl_cross_guess_normal" ;;
+ # Guess no on native Windows.
+ mingw*) gl_cv_func_strtoll_works="guessing no" ;;
+ # Guess no on glibc systems.
+ *-gnu* | gnu*) gl_cv_func_strtoll_works="guessing no" ;;
+ # Guess no on musl systems.
+ *-musl* | midipix*) gl_cv_func_strtoll_works="guessing no" ;;
+ *) gl_cv_func_strtoll_works="$gl_cross_guess_normal" ;;
esac
])
])
diff --git a/m4/strtoul.m4 b/m4/strtoul.m4
index 30a83d7e19..9baa9729e6 100644
--- a/m4/strtoul.m4
+++ b/m4/strtoul.m4
@@ -1,4 +1,4 @@
-# strtoul.m4 serial 6
+# strtoul.m4 serial 7
dnl Copyright (C) 2002, 2006, 2009-2023 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -24,15 +24,26 @@ AC_DEFUN([gl_FUNC_STRTOUL]
if (term != input + 1)
result |= 1;
}
+ /* This test fails on pre-C23 platforms. */
+ {
+ const char input[] = "0b1";
+ (void) strtoul (input, &term, 2);
+ if (term != input + 3)
+ result |= 2;
+ }
return result;
]])
],
[gl_cv_func_strtoul_works=yes],
[gl_cv_func_strtoul_works=no],
[case "$host_os" in
- # Guess no on native Windows.
- mingw*) gl_cv_func_strtoul_works="guessing no" ;;
- *) gl_cv_func_strtoul_works="$gl_cross_guess_normal" ;;
+ # Guess no on native Windows.
+ mingw*) gl_cv_func_strtoul_works="guessing no" ;;
+ # Guess no on glibc systems.
+ *-gnu* | gnu*) gl_cv_func_strtoul_works="guessing no" ;;
+ # Guess no on musl systems.
+ *-musl* | midipix*) gl_cv_func_strtoul_works="guessing no" ;;
+ *) gl_cv_func_strtoul_works="$gl_cross_guess_normal" ;;
esac
])
])
diff --git a/m4/strtoull.m4 b/m4/strtoull.m4
index a9b0ddf9f2..4f895c76af 100644
--- a/m4/strtoull.m4
+++ b/m4/strtoull.m4
@@ -1,4 +1,4 @@
-# strtoull.m4 serial 9
+# strtoull.m4 serial 10
dnl Copyright (C) 2002, 2004, 2006, 2008-2023 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -24,15 +24,26 @@ AC_DEFUN([gl_FUNC_STRTOULL]
if (term != input + 1)
result |= 1;
}
+ /* This test fails on pre-C23 platforms. */
+ {
+ const char input[] = "0b1";
+ (void) strtoull (input, &term, 2);
+ if (term != input + 3)
+ result |= 2;
+ }
return result;
]])
],
[gl_cv_func_strtoull_works=yes],
[gl_cv_func_strtoull_works=no],
[case "$host_os" in
- # Guess no on native Windows.
- mingw*) gl_cv_func_strtoull_works="guessing no" ;;
- *) gl_cv_func_strtoull_works="$gl_cross_guess_normal" ;;
+ # Guess no on native Windows.
+ mingw*) gl_cv_func_strtoull_works="guessing no" ;;
+ # Guess no on glibc systems.
+ *-gnu* | gnu*) gl_cv_func_strtoull_works="guessing no" ;;
+ # Guess no on musl systems.
+ *-musl* | midipix*) gl_cv_func_strtoull_works="guessing no" ;;
+ *) gl_cv_func_strtoull_works="$gl_cross_guess_normal" ;;
esac
])
])
diff --git a/tests/test-strtol.c b/tests/test-strtol.c
index ba8a54de4d..065b442ba5 100644
--- a/tests/test-strtol.c
+++ b/tests/test-strtol.c
@@ -239,5 +239,67 @@ main (void)
ASSERT (errno == 0);
}
+ /* Binary integer syntax. */
+ {
+ const char input[] = "0b111010";
+ char *ptr;
+ long result;
+ errno = 0;
+ result = strtol (input, &ptr, 10);
+ ASSERT (result == 0L);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b111010";
+ char *ptr;
+ long result;
+ errno = 0;
+ result = strtol (input, &ptr, 2);
+ ASSERT (result == 58L);
+ ASSERT (ptr == input + 8);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b111010";
+ char *ptr;
+ long result;
+ errno = 0;
+ result = strtol (input, &ptr, 0);
+ ASSERT (result == 58L);
+ ASSERT (ptr == input + 8);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b";
+ char *ptr;
+ long result;
+ errno = 0;
+ result = strtol (input, &ptr, 10);
+ ASSERT (result == 0L);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b";
+ char *ptr;
+ long result;
+ errno = 0;
+ result = strtol (input, &ptr, 2);
+ ASSERT (result == 0L);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b";
+ char *ptr;
+ long result;
+ errno = 0;
+ result = strtol (input, &ptr, 0);
+ ASSERT (result == 0L);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+
return 0;
}
diff --git a/tests/test-strtoll.c b/tests/test-strtoll.c
index ecedbe6460..24cb4eb1e1 100644
--- a/tests/test-strtoll.c
+++ b/tests/test-strtoll.c
@@ -239,5 +239,67 @@ main (void)
ASSERT (errno == 0);
}
+ /* Binary integer syntax. */
+ {
+ const char input[] = "0b111010";
+ char *ptr;
+ long long result;
+ errno = 0;
+ result = strtoll (input, &ptr, 10);
+ ASSERT (result == 0LL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b111010";
+ char *ptr;
+ long long result;
+ errno = 0;
+ result = strtoll (input, &ptr, 2);
+ ASSERT (result == 58LL);
+ ASSERT (ptr == input + 8);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b111010";
+ char *ptr;
+ long long result;
+ errno = 0;
+ result = strtoll (input, &ptr, 0);
+ ASSERT (result == 58LL);
+ ASSERT (ptr == input + 8);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b";
+ char *ptr;
+ long long result;
+ errno = 0;
+ result = strtoll (input, &ptr, 10);
+ ASSERT (result == 0LL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b";
+ char *ptr;
+ long long result;
+ errno = 0;
+ result = strtoll (input, &ptr, 2);
+ ASSERT (result == 0LL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b";
+ char *ptr;
+ long long result;
+ errno = 0;
+ result = strtoll (input, &ptr, 0);
+ ASSERT (result == 0LL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+
return 0;
}
diff --git a/tests/test-strtoul.c b/tests/test-strtoul.c
index 7e8e5f78c6..434cea49ed 100644
--- a/tests/test-strtoul.c
+++ b/tests/test-strtoul.c
@@ -238,5 +238,67 @@ main (void)
ASSERT (errno == 0);
}
+ /* Binary integer syntax. */
+ {
+ const char input[] = "0b111010";
+ char *ptr;
+ unsigned long result;
+ errno = 0;
+ result = strtoul (input, &ptr, 10);
+ ASSERT (result == 0UL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b111010";
+ char *ptr;
+ unsigned long result;
+ errno = 0;
+ result = strtoul (input, &ptr, 2);
+ ASSERT (result == 58UL);
+ ASSERT (ptr == input + 8);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b111010";
+ char *ptr;
+ unsigned long result;
+ errno = 0;
+ result = strtoul (input, &ptr, 0);
+ ASSERT (result == 58UL);
+ ASSERT (ptr == input + 8);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b";
+ char *ptr;
+ unsigned long result;
+ errno = 0;
+ result = strtoul (input, &ptr, 10);
+ ASSERT (result == 0UL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b";
+ char *ptr;
+ unsigned long result;
+ errno = 0;
+ result = strtoul (input, &ptr, 2);
+ ASSERT (result == 0UL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b";
+ char *ptr;
+ unsigned long result;
+ errno = 0;
+ result = strtoul (input, &ptr, 0);
+ ASSERT (result == 0UL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+
return 0;
}
diff --git a/tests/test-strtoull.c b/tests/test-strtoull.c
index dd6ec2ad19..7b0027f621 100644
--- a/tests/test-strtoull.c
+++ b/tests/test-strtoull.c
@@ -238,5 +238,67 @@ main (void)
ASSERT (errno == 0);
}
+ /* Binary integer syntax. */
+ {
+ const char input[] = "0b111010";
+ char *ptr;
+ unsigned long long result;
+ errno = 0;
+ result = strtoull (input, &ptr, 10);
+ ASSERT (result == 0ULL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b111010";
+ char *ptr;
+ unsigned long long result;
+ errno = 0;
+ result = strtoull (input, &ptr, 2);
+ ASSERT (result == 58ULL);
+ ASSERT (ptr == input + 8);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b111010";
+ char *ptr;
+ unsigned long long result;
+ errno = 0;
+ result = strtoull (input, &ptr, 0);
+ ASSERT (result == 58ULL);
+ ASSERT (ptr == input + 8);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b";
+ char *ptr;
+ unsigned long long result;
+ errno = 0;
+ result = strtoull (input, &ptr, 10);
+ ASSERT (result == 0ULL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b";
+ char *ptr;
+ unsigned long long result;
+ errno = 0;
+ result = strtoull (input, &ptr, 2);
+ ASSERT (result == 0ULL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0b";
+ char *ptr;
+ unsigned long long result;
+ errno = 0;
+ result = strtoull (input, &ptr, 0);
+ ASSERT (result == 0ULL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+
return 0;
}
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: strtol, strtoll, strtoul, strtoull: Make ISO C 23 compliant
2023-03-16 15:05 strtol, strtoll, strtoul, strtoull: Make ISO C 23 compliant Bruno Haible
@ 2023-03-17 12:52 ` Eric Blake
0 siblings, 0 replies; 2+ messages in thread
From: Eric Blake @ 2023-03-17 12:52 UTC (permalink / raw)
To: Bruno Haible; +Cc: bug-gnulib
On Thu, Mar 16, 2023 at 04:05:18PM +0100, Bruno Haible wrote:
> ISO C 23 § 7.24.1.7 in combination with § 6.4.4.1 specifies that strtol,
> strtoll, strtoul, strtoull need to accept binary integer syntax as input,
> e.g. "0b101010" for 42.
>
> This patch implements it, and augments the unit tests accordingly.
>
>
> 2023-03-16 Bruno Haible <bruno@clisp.org>
>
> strtol, strtoll, strtoul, strtoull: Make ISO C 23 compliant.
> * lib/strtol.c (INTERNAL (strtol)): Treat 'b' and base 2 like 'x' and
> base 16. Based on glibc commit 64924422a99690d147a166b4de3103f3bf3eaf6c
> by Joseph Myers.
C23 also supports literals with thousands separators, such as
0b0000'1111 or 0xab'cd. Are strtol* required to support this as well?
/me goes and reads https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2626.pdf
"It is not proposed for the strto* family of functions from the C
Standard Library to support digit separators at this time"
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2023-03-17 12:53 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-03-16 15:05 strtol, strtoll, strtoul, strtoull: Make ISO C 23 compliant Bruno Haible
2023-03-17 12:52 ` Eric Blake
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).