+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.
+
2023-03-16 Bruno Haible <bruno@clisp.org>
timegm: Document under ISO C and POSIX substitutes.
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:
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:
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:
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:
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;
}
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
-# 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,
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
])
])
-# 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,
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
])
])
-# 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,
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
])
])
-# 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,
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
])
])
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;
}
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;
}
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;
}
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;
}