Re: gnulib-tool Python tracebacks after control-C

2024-05-15 Thread Collin Funk
On 5/15/24 8:45 PM, Bruno Haible wrote:
> Can you make gnulib-tool.py print a diagnostic in this case as well?
> It does not need to be exactly "caught signal SIGINT", like bash does.
> Just an indication that
>   - gnulib-tool.py
>   - is being terminated
>   - due to a signal 2.
> Preferrably formatted in the same way as the other fatal errors, i.e.
> starting with
>   '%s: *** ' % APP['name']
> 
> The exit code is nonzero (128 + 2); this is good.

Good point about the error number. I suppose we could just exit on
KeyboardInterrupt and print a message to stderr. Since after the
exception we just exit anyways something like this would work:

$ git diff .
diff --git a/pygnulib/main.py b/pygnulib/main.py
index b693e71d7f..0dea039957 100644
--- a/pygnulib/main.py
+++ b/pygnulib/main.py
@@ -1370,6 +1370,9 @@ def cli_exception(exc_type, exc_value, exc_traceback) -> 
None:
 thrown when Ctrl-C is pressed.'''
 if not issubclass(exc_type, KeyboardInterrupt):
 sys.__excepthook__(exc_type, exc_value, exc_traceback)
+else:
+sys.stderr.write('%s: *** Stop.\n' % APP['name'])
+sys.exit(1)

Then using it:

$ rm -rf ../testdir1; ./gnulib-tool.py --create-testdir --dir=../testdir1 
--single-configure stdbit-h
Module list with included dependencies (indented):
c99
extern-inline
gen-header
std-gnu11
  stdbit-h
stdbit-h-tests
stdbool
stdbool-tests
File list:
  lib/dummy.c
  lib/stdbit.c
  lib/stdbit.in.h
  m4/00gnulib.m4
  m4/c-bool.m4
  m4/extern-inline.m4
  m4/gnulib-common.m4
  m4/std-gnu11.m4
  m4/stdbit_h.m4
  m4/zzgnulib.m4
  tests/macros.h
  tests/test-stdbit-h.c
  tests/test-stdbool.c
executing aclocal -I glm4
^C/home/collin/.local/src/gnulib/gnulib-tool.py: *** Stop.
$ echo $?
1

Is that similar to what you were thinking of? I'm not sure what to put
for the error message. Feel free to commit something if this works for you.

Collin



Re: gnulib-tool Python tracebacks after control-C

2024-05-15 Thread Bruno Haible
Hi Collin,

> $ gnulib-tool --create-testdir --dir testdir1
> ^C
> $

It does not print any diagnostic. While gnulib-tool.sh and
subprocesses do print a diagnostic:

$ rm -rf ../testdir1; ./gnulib-tool.sh --create-testdir --dir=../testdir1 
--single-configure stdbit-h
Module list with included dependencies (indented):
c99
extern-inline
gen-header
std-gnu11
  stdbit-h
stdbit-h-tests
stdbool
stdbool-tests
File list:
  lib/dummy.c
  lib/stdbit.c
  lib/stdbit.in.h
  m4/00gnulib.m4
  m4/c-bool.m4
  m4/extern-inline.m4
  m4/gnulib-common.m4
  m4/std-gnu11.m4
  m4/stdbit_h.m4
  m4/zzgnulib.m4
  tests/macros.h
  tests/test-stdbit-h.c
  tests/test-stdbool.c
executing aclocal -I glm4
^Cautom4te: error: /usr/bin/m4 terminated by signal: 2
caught signal SIGINT
$ rm -rf ../testdir1; ./gnulib-tool.py --create-testdir --dir=../testdir1 
--single-configure stdbit-h
Module list with included dependencies (indented):
c99
extern-inline
gen-header
std-gnu11
  stdbit-h
stdbit-h-tests
stdbool
stdbool-tests
File list:
  lib/dummy.c
  lib/stdbit.c
  lib/stdbit.in.h
  m4/00gnulib.m4
  m4/c-bool.m4
  m4/extern-inline.m4
  m4/gnulib-common.m4
  m4/std-gnu11.m4
  m4/stdbit_h.m4
  m4/zzgnulib.m4
  tests/macros.h
  tests/test-stdbit-h.c
  tests/test-stdbool.c
executing aclocal -I glm4
executing autoconf
executing autoheader
^Cautom4te: error: /usr/bin/m4 terminated by signal: 2
autoheader: error: '/usr/bin/autom4te' terminated by signal: 2

Can you make gnulib-tool.py print a diagnostic in this case as well?
It does not need to be exactly "caught signal SIGINT", like bash does.
Just an indication that
  - gnulib-tool.py
  - is being terminated
  - due to a signal 2.
Preferrably formatted in the same way as the other fatal errors, i.e.
starting with
  '%s: *** ' % APP['name']

The exit code is nonzero (128 + 2); this is good.

Bruno






Re: gnulib-tool Python tracebacks after control-C

2024-05-15 Thread Collin Funk
Hi Pádraig,

On 5/13/24 2:32 PM, Pádraig Brady wrote:
> https://github.com/pixelb/crudini/blob/cbb3b85e/crudini.py#L1134
> Note that also handles a closed stdin (and stdout elsewhere in that util).

I just pushed the attached patch following your code there. Works well
for me. Thanks for the help.

$ gnulib-tool --create-testdir --dir testdir1
^C
$

CollinFrom 43ca9607f03b697df0dfc356ef1a3029551c9897 Mon Sep 17 00:00:00 2001
From: Collin Funk 
Date: Wed, 15 May 2024 20:25:38 -0700
Subject: [PATCH] gnulib-tool.py: Don't print tracebacks when Ctrl-C is
 pressed.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Suggested by Pádraig Brady in
.

* pygnulib/main.py (cli_exception): New function.
(main_with_exception_handling): Use it.
---
 ChangeLog|  8 
 pygnulib/main.py | 11 +++
 2 files changed, 19 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 9a69d7e2aa..7690099cde 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2024-05-15  Collin Funk  
+
+	gnulib-tool.py: Don't print tracebacks when Ctrl-C is pressed.
+	Suggested by Pádraig Brady in
+	.
+	* pygnulib/main.py (cli_exception): New function.
+	(main_with_exception_handling): Use it.
+
 2024-05-15  Bruno Haible  
 
 	stdbit-h: Add tests.
diff --git a/pygnulib/main.py b/pygnulib/main.py
index dc0b2f4366..b693e71d7f 100644
--- a/pygnulib/main.py
+++ b/pygnulib/main.py
@@ -1365,7 +1365,18 @@ def main(temp_directory: str) -> None:
 pass
 
 
+def cli_exception(exc_type, exc_value, exc_traceback) -> None:
+'''Exception hook that does not print a traceback for KeyboardInterrupts
+thrown when Ctrl-C is pressed.'''
+if not issubclass(exc_type, KeyboardInterrupt):
+sys.__excepthook__(exc_type, exc_value, exc_traceback)
+
+
 def main_with_exception_handling() -> None:
+# Don't print tracebacks for KeyboardInterrupts when stdin is a tty.
+if sys.stdin and sys.stdin.isatty():
+sys.excepthook = cli_exception
+
 try:  # Try to execute
 with tempfile.TemporaryDirectory(prefix='glpy') as temporary_directory:
 main(temporary_directory)
-- 
2.45.0



Re: stdbit-h, stdc_*: New modules, part of the stdbit module

2024-05-15 Thread Bruno Haible
Collin Funk wrote:
> Maybe it makes sense to provided a module covering all the stdbit.h
> functions?

Yes. That's why I wrote:

  We thus have the following modules:
- stdbit-h for just the header file,
- stdc_* for the 14 function groups,
- stdbit for all together.   <

> Also, should these functions be used to implement the count-* versions
> used previously and ffs, ffsl, ffsll? That way any optimization
> wizardry can be dealt with in a single place and benefit them all.

It might make sense. Paul, if it is among your plans to do this, how
about letting Collin do it? This would give Collin some more exercise with
the Gnulib idioms.

Bruno






Re: endian: New module.

2024-05-15 Thread Collin Funk
On 5/15/24 12:03 PM, Paul Eggert wrote:
>> If we can ensure byteswap.h functions are defined as functions,
>> wouldn't it make sense to just define these as macros to them?
> 
> Not sure why macros would be helpful. If functions suffice for good 
> performance when compiling with -O2, it's better to use functions than macros.

True. I'll revisit my patches and perfer inline functions. Your stdbit
implementation serves as a good example for me. Thanks!

Collin



stdbit-h: Add tests

2024-05-15 Thread Bruno Haible
Like for the other *.in.h files, it makes sense to add a unit test
for this .h file. Done through the second patch below.

It uncovers a compilation error:

g++ -ftrapv -DHAVE_CONFIG_H -I. -I../../gltests -I..  
-DGNULIB_STRICT_CHECKING=1 -DIN_GNULIB_TESTS=1 -I. -I../../gltests -I.. 
-I../../gltests/.. -I../gllib -I../../gltests/../gllib 
-I/media/develdata/devel/inst-x86_64-64/include -Wall  -Wno-error -O0 
-fno-omit-frame-pointer -ggdb -MT test-stdbit-h-c++.o -MD -MP -MF 
.deps/test-stdbit-h-c++.Tpo -c -o test-stdbit-h-c++.o 
../../gltests/test-stdbit-h-c++.cc
In file included from /usr/include/c++/11/bits/stringfwd.h:40,
 from /usr/include/c++/11/iosfwd:39,
 from /usr/include/c++/11/ios:38,
 from /usr/include/c++/11/ostream:38,
 from /usr/include/c++/11/iostream:39,
 from ../../gltests/test-stdbit-h-c++.cc:26:
/usr/include/c++/11/bits/memoryfwd.h:63:3: error: template with C linkage
   63 |   template
  |   ^~~~
In file included from ../../gltests/test-stdbit-h-c++.cc:22:
../gllib/stdbit.h:78:1: note: ‘extern "C"’ linkage started here
   78 | extern "C" {
  | ^~
In file included from /usr/include/c++/11/bits/stringfwd.h:40,
 from /usr/include/c++/11/iosfwd:39,
 from /usr/include/c++/11/ios:38,
 from /usr/include/c++/11/ostream:38,
 from /usr/include/c++/11/iostream:39,
 from ../../gltests/test-stdbit-h-c++.cc:26:
...

The first patch below fixes it.


2024-05-15  Bruno Haible  

stdbit-h: Add tests.
* tests/test-stdbit-h.c: New file.
* tests/test-stdbit-h-c++.cc: New file.
* modules/stdbit-h-tests: New file.
* modules/stdbit-h-c++-tests: New file.

2024-05-15  Bruno Haible  

stdbit-h: Make it work in C++ mode.
* lib/stdbit.in.h: Remove extraneous 'extern "C" {' marker.

>From 182c7eb43345f26178f9a3f794c85e684e96c370 Mon Sep 17 00:00:00 2001
From: Bruno Haible 
Date: Thu, 16 May 2024 01:20:08 +0200
Subject: [PATCH 1/2] stdbit-h: Make it work in C++ mode.

* lib/stdbit.in.h: Remove extraneous 'extern "C" {' marker.
---
 ChangeLog   | 5 +
 lib/stdbit.in.h | 4 
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 377dbe99bb..9ce6d303c6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2024-05-15  Bruno Haible  
+
+	stdbit-h: Make it work in C++ mode.
+	* lib/stdbit.in.h: Remove extraneous 'extern "C" {' marker.
+
 2024-05-15  Bruno Haible  
 
 	stdbit-h, stdc_*: New modules, part of the stdbit module.
diff --git a/lib/stdbit.in.h b/lib/stdbit.in.h
index 73b234791d..f241a5c573 100644
--- a/lib/stdbit.in.h
+++ b/lib/stdbit.in.h
@@ -73,10 +73,6 @@ _GL_INLINE_HEADER_BEGIN
 # define _GL_STDC_BIT_CEIL_INLINE _GL_INLINE
 #endif
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* An expression, preferably with the type of A, that has the value of B.  */
 #if ((defined __GNUC__ && 2 <= __GNUC__) \
  || (defined __clang_major__ && 4 <= __clang_major__) \
-- 
2.34.1

>From 1a016b72a9ea5d48c6eab35494282ec657db6e18 Mon Sep 17 00:00:00 2001
From: Bruno Haible 
Date: Thu, 16 May 2024 01:23:39 +0200
Subject: [PATCH 2/2] stdbit-h: Add tests.

* tests/test-stdbit-h.c: New file.
* tests/test-stdbit-h-c++.cc: New file.
* modules/stdbit-h-tests: New file.
* modules/stdbit-h-c++-tests: New file.
---
 ChangeLog  |  8 
 modules/stdbit-h-c++-tests | 17 
 modules/stdbit-h-tests | 12 
 tests/test-stdbit-h-c++.cc | 32 ++
 tests/test-stdbit-h.c  | 40 ++
 5 files changed, 109 insertions(+)
 create mode 100644 modules/stdbit-h-c++-tests
 create mode 100644 modules/stdbit-h-tests
 create mode 100644 tests/test-stdbit-h-c++.cc
 create mode 100644 tests/test-stdbit-h.c

diff --git a/ChangeLog b/ChangeLog
index 9ce6d303c6..9a69d7e2aa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2024-05-15  Bruno Haible  
+
+	stdbit-h: Add tests.
+	* tests/test-stdbit-h.c: New file.
+	* tests/test-stdbit-h-c++.cc: New file.
+	* modules/stdbit-h-tests: New file.
+	* modules/stdbit-h-c++-tests: New file.
+
 2024-05-15  Bruno Haible  
 
 	stdbit-h: Make it work in C++ mode.
diff --git a/modules/stdbit-h-c++-tests b/modules/stdbit-h-c++-tests
new file mode 100644
index 00..aad80e4f8d
--- /dev/null
+++ b/modules/stdbit-h-c++-tests
@@ -0,0 +1,17 @@
+Files:
+tests/test-stdbit-h-c++.cc
+
+Status:
+c++-test
+
+Depends-on:
+ansi-c++-opt
+
+configure.ac:
+
+Makefile.am:
+if ANSICXX
+TESTS += test-stdbit-h-c++
+check_PROGRAMS += test-stdbit-h-c++
+test_stdbit_h_c___SOURCES = test-stdbit-h-c++.cc
+endif
diff --git a/modules/stdbit-h-tests b/modules/stdbit-h-tests
new file mode 100644
index 00..67a8ff645c
--- /dev/null
+++ b/modules/stdbit-h-tests
@@ -0,0 +1,12 @@
+Files:
+tests/test-stdbit-h.c
+tests/macros.h
+
+Depends-on:
+stdbit-

Re: stdbit-h, stdc_*: New modules, part of the stdbit module

2024-05-15 Thread Collin Funk
Hi Bruno,

On 5/15/24 4:06 PM, Bruno Haible wrote:
> The module 'stdbit' defines 70 functions, grouped into 14 function-like
> macros. Most packages will only need 1 or 2 among these 14 function groups.
> (For example, diffutils needs only 'stdc_bit_width'.)

Maybe it makes sense to provided a module covering all the stdbit.h
functions?

I can see a program wanting a majority/all of them and in that case it
might be nicer just to import a single module.

Also, should these functions be used to implement the count-* versions
used previously and ffs, ffsl, ffsll? That way any optimization
wizardry can be dealt with in a single place and benefit them all.

Collin



stdbit-h, stdc_*: New modules, part of the stdbit module

2024-05-15 Thread Bruno Haible
The module 'stdbit' defines 70 functions, grouped into 14 function-like
macros. Most packages will only need 1 or 2 among these 14 function groups.
(For example, diffutils needs only 'stdc_bit_width'.)

The amount of code generated by the stdbit module is not negligible:

  With gcc -O0:
  $ size gllib/stdbit.o 
 textdata bss dec hex filename
 5346   0   0534614e2 gllib/stdbit.o

  With gcc -O2:
  $ size gllib/stdbit.o 
 textdata bss dec hex filename
 3811   0   03811 ee3 gllib/stdbit.o

Therefore it is useful to split the functionality into 14 modules.
The patch below does this, thus allowing the using packages to request
only the parts they need, and thereby shrink the resulting binaries by
3 to 5 KB.

We thus have the following modules:
  - stdbit-h for just the header file,
  - stdc_* for the 14 function groups,
  - stdbit for all together.

This is similar to the structure of the modules
  error
  glob
  pthread
  threads


2024-05-15  Bruno Haible  

stdbit-h, stdc_*: New modules, part of the stdbit module.
* lib/stdbit.in.h (_GL_STDC_*_INLINE): New macros.
Enclose function definitions in #if @GL_STDC_*@ conditionals.
* lib/stdc_leading_zeros.c: New file.
* lib/stdc_leading_ones.c: New file.
* lib/stdc_trailing_zeros.c: New file.
* lib/stdc_trailing_ones.c: New file.
* lib/stdc_first_leading_zero.c: New file.
* lib/stdc_first_leading_one.c: New file.
* lib/stdc_first_trailing_zero.c: New file.
* lib/stdc_first_trailing_one.c: New file.
* lib/stdc_count_zeros.c: New file.
* lib/stdc_count_ones.c: New file, based on lib/stdbit.c.
* lib/stdc_has_single_bit.c: New file.
* lib/stdc_bit_width.c: New file.
* lib/stdc_bit_floor.c: New file.
* lib/stdc_bit_ceil.c: New file.
* lib/stdbit.c (__gl_stdbit_popcount_support): Remove variable.
* m4/stdbit_h.m4 (gl_STDBIT_H): Initialize GL_STDC_* variables.
* modules/stdbit-h: New file, based on modules/stdbit.
(Depends-on): Add gen-header.
(Makefile.am): Substitute GL_STDC_* variables.
* modules/stdc_leading_zeros: New file.
* modules/stdc_leading_ones: New file.
* modules/stdc_trailing_zeros: New file.
* modules/stdc_trailing_ones: New file.
* modules/stdc_first_leading_zero: New file.
* modules/stdc_first_leading_one: New file.
* modules/stdc_first_trailing_zero: New file.
* modules/stdc_first_trailing_one: New file.
* modules/stdc_count_zeros: New file.
* modules/stdc_count_ones: New file.
* modules/stdc_has_single_bit: New file.
* modules/stdc_bit_width: New file.
* modules/stdc_bit_floor: New file.
* modules/stdc_bit_ceil: New file.
* modules/stdbit: Change to a pure composition module.
* modules/stdc_leading_zeros-tests: New file, based on
modules/stdbit-tests.
* modules/stdc_leading_ones-tests: New file, based on
modules/stdbit-tests.
* modules/stdc_trailing_zeros-tests: New file, based on
modules/stdbit-tests.
* modules/stdc_trailing_ones-tests: New file, based on
modules/stdbit-tests.
* modules/stdc_first_leading_zero-tests: New file, based on
modules/stdbit-tests.
* modules/stdc_first_leading_one-tests: New file, based on
modules/stdbit-tests.
* modules/stdc_first_trailing_zero-tests: New file, based on
modules/stdbit-tests.
* modules/stdc_first_trailing_one-tests: New file, based on
modules/stdbit-tests.
* modules/stdc_count_zeros-tests: New file, based on
modules/stdbit-tests.
* modules/stdc_count_ones-tests: New file, based on
modules/stdbit-tests.
* modules/stdc_has_single_bit-tests: New file, based on
modules/stdbit-tests.
* modules/stdc_bit_width-tests: New file, based on modules/stdbit-tests.
* modules/stdc_bit_floor-tests: New file, based on modules/stdbit-tests.
* modules/stdc_bit_ceil-tests: New file, based on modules/stdbit-tests.
* modules/stdbit-tests: Remove file.
* doc/posix-functions/stdc_leading_zeros.texi: Update.
* doc/posix-functions/stdc_leading_ones.texi: Likewise.
* doc/posix-functions/stdc_trailing_zeros.texi: Likewise.
* doc/posix-functions/stdc_trailing_ones.texi: Likewise.
* doc/posix-functions/stdc_first_leading_zero.texi: Likewise.
* doc/posix-functions/stdc_first_leading_one.texi: Likewise.
* doc/posix-functions/stdc_first_trailing_zero.texi: Likewise.
* doc/posix-functions/stdc_first_trailing_one.texi: Likewise.
* doc/posix-functions/stdc_count_zeros.texi: Likewise.
* doc/posix-functions/stdc_count_ones.texi: Likewise.
* doc/posix-functions/stdc_has_single_bit.texi: 

[PATCH 1/2] stdbit: tweak for non-GCC non-Clang

2024-05-15 Thread Paul Eggert
* lib/stdbit.in.h (__gl_stdbit_clz, __gl_stdbit_clzl)
(__gl_stdbit_clzll, __gl_stdbit_ctz, __gl_stdbit_ctzl)
(__gl_stdbit_ctzll): Work even if the argument is zero.
All callers changed.  This should help avoid branches
on non-GCC-like platforms.
---
 ChangeLog   |  9 ++
 lib/stdbit.in.h | 73 +++--
 2 files changed, 56 insertions(+), 26 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index af8fb1e409..f37d9f2796 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2024-05-15  Paul Eggert  
+
+   stdbit: tweak for non-GCC non-Clang
+   * lib/stdbit.in.h (__gl_stdbit_clz, __gl_stdbit_clzl)
+   (__gl_stdbit_clzll, __gl_stdbit_ctz, __gl_stdbit_ctzl)
+   (__gl_stdbit_ctzll): Work even if the argument is zero.
+   All callers changed.  This should help avoid branches
+   on non-GCC-like platforms.
+
 2024-05-15  Bruno Haible  
 
vasnprintf: Avoid a dummy memory allocation.
diff --git a/lib/stdbit.in.h b/lib/stdbit.in.h
index 18efaf2d7c..984ef44ef9 100644
--- a/lib/stdbit.in.h
+++ b/lib/stdbit.in.h
@@ -85,11 +85,23 @@ extern "C" {
 # endif
 #endif
 
-/* Count leading zeros of nonzero N.  */
+/* Count leading 0 bits of N, even if N is 0.  */
 #ifdef _GL_STDBIT_HAS_BUILTIN_CLZ
-# define __gl_stdbit_clz __builtin_clz
-# define __gl_stdbit_clzl __builtin_clzl
-# define __gl_stdbit_clzll __builtin_clzll
+_GL_STDBIT_INLINE int
+__gl_stdbit_clz (unsigned int n)
+{
+  return n ? __builtin_clz (n) : 8 * sizeof n;
+}
+_GL_STDBIT_INLINE int
+__gl_stdbit_clzl (unsigned long int n)
+{
+  return n ? __builtin_clzl (n) : 8 * sizeof n;
+}
+_GL_STDBIT_INLINE int
+__gl_stdbit_clzll (unsigned long long int n)
+{
+  return n ? __builtin_clzll (n) : 8 * sizeof n;
+}
 #elif defined _MSC_VER
 # pragma intrinsic (_BitScanReverse)
 # ifdef _M_X64
@@ -99,8 +111,7 @@ _GL_STDBIT_INLINE int
 __gl_stdbit_clzl (unsigned long int n)
 {
   unsigned long int r;
-  _BitScanReverse (&r, n);
-  return 8 * sizeof n - 1 - r;
+  return 8 * sizeof n - (_BitScanReverse (&r, n) ? r + 1 : 0);
 }
 _GL_STDBIT_INLINE int
 __gl_stdbit_clz (unsigned int n)
@@ -112,8 +123,7 @@ __gl_stdbit_clzll (unsigned long long int n)
 {
 # ifdef _M_X64
   unsigned long int r;
-  _BitScanReverse64 (&r, n);
-  return 64 - 1 - r;
+  return 8 * sizeof n - (_BitScanReverse (&r, n) ? r + 1 : 0);
 # else
   unsigned long int hi = n >> 32;
   return __gl_stdbit_clzl (hi ? hi : n) + (hi ? 0 : 32);
@@ -148,10 +158,23 @@ __gl_stdbit_clzl (unsigned long int n)
 }
 #endif
 
+/* Count trailing 0 bits of N, even if N is 0.  */
 #ifdef _GL_STDBIT_HAS_BUILTIN_CTZ
-# define __gl_stdbit_ctz __builtin_ctz
-# define __gl_stdbit_ctzl __builtin_ctzl
-# define __gl_stdbit_ctzll __builtin_ctzll
+_GL_STDBIT_INLINE int
+__gl_stdbit_ctz (unsigned int n)
+{
+  return n ? __builtin_ctz (n) : 8 * sizeof n;
+}
+_GL_STDBIT_INLINE int
+__gl_stdbit_ctzl (unsigned long int n)
+{
+  return n ? __builtin_ctzl (n) : 8 * sizeof n;
+}
+_GL_STDBIT_INLINE int
+__gl_stdbit_ctzll (unsigned long long int n)
+{
+  return n ? __builtin_ctzll (n) : 8 * sizeof n;
+}
 #elif defined _MSC_VER
 # pragma intrinsic (_BitScanForward)
 # ifdef _M_X64
@@ -161,21 +184,19 @@ _GL_STDBIT_INLINE int
 __gl_stdbit_ctzl (unsigned long int n)
 {
   unsigned long int r;
-  _BitScanForward (&r, n);
-  return r;
+  return _BitScanForward (&r, n) ? r : 8 * sizeof n;
 }
 _GL_STDBIT_INLINE int
 __gl_stdbit_ctz (unsigned int n)
 {
-  return __gl_stdbit_ctzl (n);
+  return __gl_stdbit_ctzl (n | (1ul << (8 * sizeof n - 1) << 1));
 }
 _GL_STDBIT_INLINE int
 __gl_stdbit_ctzll (unsigned long long int n)
 {
 # ifdef _M_X64
   unsigned long int r;
-  _BitScanForward64 (&r, n);
-  return r;
+  return _BitScanForward64 (&r, n) ? r : 8 * sizeof n;
 # else
   unsigned int lo = n;
   return __gl_stdbit_ctzl (lo ? lo : n >> 32) + (lo ? 0 : 32);
@@ -188,26 +209,26 @@ _GL_STDBIT_INLINE int
 _GL_STDBIT_INLINE int
 __gl_stdbit_ctz (unsigned int n)
 {
-  return 8 * sizeof n - 1 - __gl_stdbit_clz (n & -n);
+  return 8 * sizeof n - (n ? __gl_stdbit_clz (n & -n) + 1 : 0);
 }
 _GL_STDBIT_INLINE int
 __gl_stdbit_ctzl (unsigned long int n)
 {
-  return 8 * sizeof n - 1 - __gl_stdbit_clzl (n & -n);
+  return 8 * sizeof n - (n ? __gl_stdbit_clzl (n & -n) + 1 : 0);
 }
 _GL_STDBIT_INLINE int
 __gl_stdbit_ctzll (unsigned long long int n)
 {
-  return 8 * sizeof n - 1 - __gl_stdbit_clzll (n & -n);
+  return 8 * sizeof n - (n ? __gl_stdbit_clzll (n & -n) + 1 : 0);
 }
 #endif
 
+/* Count 1 bits in N.  */
 #ifdef _GL_STDBIT_HAS_BUILTIN_POPCOUNT
 # define __gl_stdbit_popcount __builtin_popcount
 # define __gl_stdbit_popcountl __builtin_popcountl
 # define __gl_stdbit_popcountll __builtin_popcountll
 #else
-/* Count the number of 1 bits in N.  */
 _GL_STDBIT_INLINE int
 __gl_stdbit_popcount_wide (unsigned long long int n)
 {
@@ -320,7 +341,7 @@ __gl_stdbit_popcountll (unsigned long long int n)
 _GL_STDBIT_INLINE unsigned int
 stdc_leading_zeros_ui (unsigned int n)
 {
-  return n ? __gl_stdbit_clz

[PATCH 2/2] stdbit: tweak first_leading for GCC

2024-05-15 Thread Paul Eggert
* lib/stdbit.in.h (stdc_first_leading_zero)
(stdc_first_leading_one, stdc_first_trailing_zero_uc)
(stdc_first_trailing_one_uc): Redo to avoid the need for a
conditional branch, at least on x86-64 with GCC 14.
---
 ChangeLog   |  7 +-
 lib/stdbit.in.h | 60 -
 2 files changed, 46 insertions(+), 21 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index f37d9f2796..049f27b3b8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,11 @@
 2024-05-15  Paul Eggert  
 
-   stdbit: tweak for non-GCC non-Clang
+   stdbit: tweak first_leading for GCC
+   * lib/stdbit.in.h (stdc_first_leading_zero)
+   (stdc_first_leading_one, stdc_first_trailing_zero_uc)
+   (stdc_first_trailing_one_uc): Redo to avoid the need for a
+   conditional branch, at least on x86-64 with GCC 14.
+
* lib/stdbit.in.h (__gl_stdbit_clz, __gl_stdbit_clzl)
(__gl_stdbit_clzll, __gl_stdbit_ctz, __gl_stdbit_ctzl)
(__gl_stdbit_ctzll): Work even if the argument is zero.
diff --git a/lib/stdbit.in.h b/lib/stdbit.in.h
index 984ef44ef9..ab328a7793 100644
--- a/lib/stdbit.in.h
+++ b/lib/stdbit.in.h
@@ -494,35 +494,40 @@ _GL_STDBIT_INLINE unsigned int
 stdc_first_leading_zero_uc (unsigned char n)
 {
   unsigned int count = stdc_leading_ones_uc (n);
-  return count == 8 * sizeof n ? 0 : count + 1;
+  unsigned int bits = 8 * sizeof n;
+  return count % bits + (count < bits);
 }
 
 _GL_STDBIT_INLINE unsigned int
 stdc_first_leading_zero_us (unsigned short int n)
 {
   unsigned int count = stdc_leading_ones_us (n);
-  return count == 8 * sizeof n ? 0 : count + 1;
+  unsigned int bits = 8 * sizeof n;
+  return count % bits + (count < bits);
 }
 
 _GL_STDBIT_INLINE unsigned int
 stdc_first_leading_zero_ui (unsigned int n)
 {
   unsigned int count = stdc_leading_ones_ui (n);
-  return count == 8 * sizeof n ? 0 : count + 1;
+  unsigned int bits = 8 * sizeof n;
+  return count % bits + (count < bits);
 }
 
 _GL_STDBIT_INLINE unsigned int
 stdc_first_leading_zero_ul (unsigned long int n)
 {
   unsigned int count = stdc_leading_ones_ul (n);
-  return count == 8 * sizeof n ? 0 : count + 1;
+  unsigned int bits = 8 * sizeof n;
+  return count % bits + (count < bits);
 }
 
 _GL_STDBIT_INLINE unsigned int
 stdc_first_leading_zero_ull (unsigned long long int n)
 {
   unsigned int count = stdc_leading_ones_ull (n);
-  return count == 8 * sizeof n ? 0 : count + 1;
+  unsigned int bits = 8 * sizeof n;
+  return count % bits + (count < bits);
 }
 
 #define stdc_first_leading_zero(n) \
@@ -537,35 +542,40 @@ _GL_STDBIT_INLINE unsigned int
 stdc_first_leading_one_uc (unsigned char n)
 {
   unsigned int count = stdc_leading_zeros_uc (n);
-  return count == 8 * sizeof n ? 0 : count + 1;
+  unsigned int bits = 8 * sizeof n;
+  return count % bits + (count < bits);
 }
 
 _GL_STDBIT_INLINE unsigned int
 stdc_first_leading_one_us (unsigned short int n)
 {
   unsigned int count = stdc_leading_zeros_us (n);
-  return count == 8 * sizeof n ? 0 : count + 1;
+  unsigned int bits = 8 * sizeof n;
+  return count % bits + (count < bits);
 }
 
 _GL_STDBIT_INLINE unsigned int
 stdc_first_leading_one_ui (unsigned int n)
 {
   unsigned int count = stdc_leading_zeros_ui (n);
-  return count == 8 * sizeof n ? 0 : count + 1;
+  unsigned int bits = 8 * sizeof n;
+  return count % bits + (count < bits);
 }
 
 _GL_STDBIT_INLINE unsigned int
 stdc_first_leading_one_ul (unsigned long int n)
 {
   unsigned int count = stdc_leading_zeros_ul (n);
-  return count == 8 * sizeof n ? 0 : count + 1;
+  unsigned int bits = 8 * sizeof n;
+  return count % bits + (count < bits);
 }
 
 _GL_STDBIT_INLINE unsigned int
 stdc_first_leading_one_ull (unsigned long long int n)
 {
   unsigned int count = stdc_leading_zeros_ull (n);
-  return count == 8 * sizeof n ? 0 : count + 1;
+  unsigned int bits = 8 * sizeof n;
+  return count % bits + (count < bits);
 }
 
 #define stdc_first_leading_one(n) \
@@ -580,35 +590,40 @@ _GL_STDBIT_INLINE unsigned int
 stdc_first_trailing_zero_uc (unsigned char n)
 {
   unsigned int count = stdc_trailing_ones_uc (n);
-  return count == 8 * sizeof n ? 0 : count + 1;
+  unsigned int bits = 8 * sizeof n;
+  return count % bits + (count < bits);
 }
 
 _GL_STDBIT_INLINE unsigned int
 stdc_first_trailing_zero_us (unsigned short int n)
 {
   unsigned int count = stdc_trailing_ones_us (n);
-  return count == 8 * sizeof n ? 0 : count + 1;
+  unsigned int bits = 8 * sizeof n;
+  return count % bits + (count < bits);
 }
 
 _GL_STDBIT_INLINE unsigned int
 stdc_first_trailing_zero_ui (unsigned int n)
 {
   unsigned int count = stdc_trailing_ones_ui (n);
-  return count == 8 * sizeof n ? 0 : count + 1;
+  unsigned int bits = 8 * sizeof n;
+  return count % bits + (count < bits);
 }
 
 _GL_STDBIT_INLINE unsigned int
 stdc_first_trailing_zero_ul (unsigned long int n)
 {
   unsigned int count = stdc_trailing_ones_ul (n);
-  return count == 8 * sizeof n ? 0 : count + 1;
+  unsigned int bits = 8 * sizeof n;
+  retur

Re: endian: New module.

2024-05-15 Thread Paul Eggert

On 2024-05-13 15:34, Collin Funk wrote:

To fix this, please use _GL_INLINE and implement with inline functions. And add 
please add test cases to catch these issues.

If we can ensure byteswap.h functions are defined as functions,
wouldn't it make sense to just define these as macros to them?


Not sure why macros would be helpful. If functions suffice for good 
performance when compiling with -O2, it's better to use functions than 
macros.





Re: -Walloc-size warning for mp_limbs_t in vasnprintf.c with GCC 14

2024-05-15 Thread Philip Withnall
Hi,

On Wed, 2024-05-15 at 17:14 +0200, Bruno Haible wrote:
> > The fix we’ve put together for GLib is here, and makes the obvious
> > switch from allocating one byte to allocating `sizeof (mp_limb_t)`:
> > https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4066/diffs?commit_id=cbc58085455b699e9ccd73f30eed72510ead5813
> 
> This approach has the drawback that runtime instrumentations will
> not detect if we accidentally read or write the first element of
> this array.

True.


> 
> In the end, I'm removing this 'malloc (1)' memory allocation; this
> should
> speed up the code in some cases.

Fair enough. Thanks for the fast fix!

Philip


signature.asc
Description: This is a digitally signed message part


Re: -Walloc-size warning for mp_limbs_t in vasnprintf.c with GCC 14

2024-05-15 Thread Bruno Haible
Hi,

Philip Withnall wrote:
> We’ve seen a compiler warning in the vasnprintf module (as copied into
> GLib) when building with GCC 14 (on msys2, although I don’t think
> that’s relevant).
> 
> ```
> ../glib/gnulib/vasnprintf.c: In function 'multiply':
> ../glib/gnulib/vasnprintf.c:382:21: error: allocation of insufficient
> size '1' for type 'mp_limb_t' {aka 'unsigned int'} with size '4' [-
> Werror=alloc-size]
>   382 |   dest->limbs = (mp_limb_t *) malloc (1);
>   | ^
> cc1.exe: all warnings being treated as errors
> ```
> 
> This is for the following code in vasnprintf.c:
> ```
> if (len1 == 0)
>   {
> /* src1 or src2 is zero.  */
> dest->nlimbs = 0;
> dest->limbs = (mp_limb_t *) malloc (1);
>   }
> ```
> 
> Given that it’s setting `nlimbs = 0`, I suspect that the allocation is
> a dummy and doesn’t actually need to contain a full `mp_limb_t`.

Correct.

> The compiler can’t know that though.

Correct. Only a runtime instrumentation (like valgrind or ASAN) can
distinguish between an allocation need of 0 words vs. 1 word.

> The fix we’ve put together for GLib is here, and makes the obvious
> switch from allocating one byte to allocating `sizeof (mp_limb_t)`:
> https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4066/diffs?commit_id=cbc58085455b699e9ccd73f30eed72510ead5813

This approach has the drawback that runtime instrumentations will
not detect if we accidentally read or write the first element of
this array.

> ... go with an
> alternative like using a pragma to ignore the -Walloc-size warning
> around that area of code.

I considered this. But -Walloc-size is sometimes a useful warning, and
4 to 7 lines of code to disable this warning is a pain.

In the end, I'm removing this 'malloc (1)' memory allocation; this should
speed up the code in some cases.


2024-05-15  Bruno Haible  

vasnprintf: Avoid a dummy memory allocation.
* lib/vasnprintf.c (NOMEM_PTR): New macro.
(multiply, divide): Return it instead of NULL in case of memory
allocation failure.
(scale10_round_decimal_decoded): Update.

diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c
index de20445894..6f06273081 100644
--- a/lib/vasnprintf.c
+++ b/lib/vasnprintf.c
@@ -408,6 +408,9 @@ is_infinite_or_zerol (long double x)
 
 #if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE
 
+/* An indicator for a failed memory allocation.  */
+# define NOMEM_PTR ((void *) (-1))
+
 /* Converting 'long double' to decimal without rare rounding bugs requires
real bignums.  We use the naming conventions of GNU gmp, but vastly simpler
(and slower) algorithms.  */
@@ -428,8 +431,8 @@ typedef struct
 } mpn_t;
 
 /* Compute the product of two bignums >= 0.
-   Return the allocated memory in case of success, NULL in case of memory
-   allocation failure.  */
+   Return the allocated memory (possibly NULL) in case of success, NOMEM_PTR
+   in case of memory allocation failure.  */
 static void *
 multiply (mpn_t src1, mpn_t src2, mpn_t *dest)
 {
@@ -457,7 +460,7 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest)
 {
   /* src1 or src2 is zero.  */
   dest->nlimbs = 0;
-  dest->limbs = (mp_limb_t *) malloc (1);
+  dest->limbs = NULL;
 }
   else
 {
@@ -469,7 +472,7 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest)
   dlen = len1 + len2;
   dp = (mp_limb_t *) malloc (dlen * sizeof (mp_limb_t));
   if (dp == NULL)
-return NULL;
+return NOMEM_PTR;
   for (k = len2; k > 0; )
 dp[--k] = 0;
   for (i = 0; i < len1; i++)
@@ -500,8 +503,8 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest)
the remainder.
Finally, round-to-even is performed: If r > b/2 or if r = b/2 and q is odd,
q is incremented.
-   Return the allocated memory in case of success, NULL in case of memory
-   allocation failure.  */
+   Return the allocated memory (possibly NULL) in case of success, NOMEM_PTR
+   in case of memory allocation failure.  */
 static void *
 divide (mpn_t a, mpn_t b, mpn_t *q)
 {
@@ -572,7 +575,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
  final rounding of q.)  */
   roomptr = (mp_limb_t *) malloc ((a_len + 2) * sizeof (mp_limb_t));
   if (roomptr == NULL)
-return NULL;
+return NOMEM_PTR;
 
   /* Normalise a.  */
   while (a_len > 0 && a_ptr[a_len - 1] == 0)
@@ -708,7 +711,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
   if (tmp_roomptr == NULL)
 {
   free (roomptr);
-  return NULL;
+  return NOMEM_PTR;
 }
   {
 const mp_limb_t *sourceptr = b_ptr;
@@ -1306,7 +1309,7 @@ scale10_round_decimal_decoded (int e, mpn_t m, void 
*memory, int n)
   mpn_t denominator;
   void *tmp_memory;
   tmp_memory = multiply (m, pow5, &numerator);
-  if (tmp_memory == NULL)
+  if (tmp_memory == NOMEM_PTR)
 {
   free (pow5_ptr);
   free (memory);
@@ -1379,7 +1382,7 @@ scale10_

-Walloc-size warning for mp_limbs_t in vasnprintf.c with GCC 14

2024-05-15 Thread Philip Withnall
Hello,

We’ve seen a compiler warning in the vasnprintf module (as copied into
GLib) when building with GCC 14 (on msys2, although I don’t think
that’s relevant).

```
../glib/gnulib/vasnprintf.c: In function 'multiply':
../glib/gnulib/vasnprintf.c:382:21: error: allocation of insufficient
size '1' for type 'mp_limb_t' {aka 'unsigned int'} with size '4' [-
Werror=alloc-size]
  382 |   dest->limbs = (mp_limb_t *) malloc (1);
  | ^
cc1.exe: all warnings being treated as errors
```

This is for the following code in vasnprintf.c:
```
if (len1 == 0)
  {
/* src1 or src2 is zero.  */
dest->nlimbs = 0;
dest->limbs = (mp_limb_t *) malloc (1);
  }
```

Given that it’s setting `nlimbs = 0`, I suspect that the allocation is
a dummy and doesn’t actually need to contain a full `mp_limb_t`. The
compiler can’t know that though.

The fix we’ve put together for GLib is here, and makes the obvious
switch from allocating one byte to allocating `sizeof (mp_limb_t)`:
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4066/diffs?commit_id=cbc58085455b699e9ccd73f30eed72510ead5813

I don’t know if you want to incorporate that fix, or to go with an
alternative like using a pragma to ignore the -Walloc-size warning
around that area of code.

(Please keep me in CC as I am not subscribed to this list.)

Thanks,
Philip


signature.asc
Description: This is a digitally signed message part


Re: [PATCH] getusershell: Add tests.

2024-05-15 Thread Bruno Haible
Hi Collin,

> Should all glibc functions have a signature check? For these ones I
> was conflicted on adding them since they are not standardized, but
> provided on BSD and glibc.

If Gnulib is not the only implementation, then yes it is advisable
to have the signature check.

For example, if on some platform getusershell were to return 'const char *'
instead of 'char *', it would be a portability problem because code such as

   char *s = getusershell ();

would be invalid. We want to know about such portability problems. Since
it is too time-consuming (and also not future-proof) to manually check the
unistd.h file of all platforms, the better way is to check the signature
in the unit test and arrange to run the unit tests on as many platforms as
possible.

Bruno






Re: [PATCH] getusershell: Add tests.

2024-05-15 Thread Collin Funk
Hi Bruno,

On 5/15/24 3:06 AM, Bruno Haible wrote:
> I'm adding a signature test. (So far, we have a signature test for these
> functions only in C++ mode, in tests/test-unistd-c++.cc.)

Thanks! I would have added them if I saw them there.

Should all glibc functions have a signature check? For these ones I
was conflicted on adding them since they are not standardized, but
provided on BSD and glibc.

Collin



Re: [PATCH] getusershell: Add tests.

2024-05-15 Thread Bruno Haible
Thanks.

I'm adding a signature test. (So far, we have a signature test for these
functions only in C++ mode, in tests/test-unistd-c++.cc.)


2024-05-15  Bruno Haible  

getusershell tests: Verify the function declarations.
* tests/test-getusershell.c: Include signature.h.
(getusershell, setusershell, endusershell): Check the signatures.
* modules/getusershell-tests (Files): Add tests/signature.h.

diff --git a/modules/getusershell-tests b/modules/getusershell-tests
index 0a65257c18..2491caaab5 100644
--- a/modules/getusershell-tests
+++ b/modules/getusershell-tests
@@ -1,5 +1,6 @@
 Files:
 tests/test-getusershell.c
+tests/signature.h
 tests/macros.h
 
 Depends-on:
diff --git a/tests/test-getusershell.c b/tests/test-getusershell.c
index 4ea13afd90..f009e8902a 100644
--- a/tests/test-getusershell.c
+++ b/tests/test-getusershell.c
@@ -18,7 +18,14 @@
 
 #include 
 
+/* Specification.  */
 #include 
+
+#include "signature.h"
+SIGNATURE_CHECK (getusershell, char *, (void));
+SIGNATURE_CHECK (setusershell, void, (void));
+SIGNATURE_CHECK (endusershell, void, (void));
+
 #include 
 #include 
 #include 






Re: gnulib-tool Python tracebacks after control-C

2024-05-15 Thread Collin Funk
Hi Pádraig,

On 5/13/24 2:32 PM, Pádraig Brady wrote:
> I've an 18 year old script template here that silences Ctrl-C spew:
> https://www.pixelbeat.org/talks/python/cli_skel.py

Ah, okay I think I understand this now. So basically the backtrace is
the default excepthook and your code skips running the excepthooks for
KeyboardIneterrupt and it's subclasses right? So a KeyboardInterrupt
would still enter the try block but skip the backtrace.

> You can see a more modern usage of that in crudini at:
> https://github.com/pixelb/crudini/blob/cbb3b85e/crudini.py#L1134
> Note that also handles a closed stdin (and stdout elsewhere in that util).

Interesting. Nice work. I see you dealt with the Python 2
compatability stuff in 'file_is_closed'. :)

Thanks for the idea. I'll have a look at adding it to gnulib-tool
later today or tomorrow.

Collin



[PATCH] getusershell: Add tests.

2024-05-15 Thread Collin Funk
* modules/getusershell-tests: New file.
* tests/test-getusershell.c: New file.
---
 ChangeLog  |  6 +++
 modules/getusershell-tests | 12 +
 tests/test-getusershell.c  | 96 ++
 3 files changed, 114 insertions(+)
 create mode 100644 modules/getusershell-tests
 create mode 100644 tests/test-getusershell.c

diff --git a/ChangeLog b/ChangeLog
index e0c6141e88..bf05fbc522 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2024-05-15  Collin Funk  
+
+   getusershell: Add tests.
+   * modules/getusershell-tests: New file.
+   * tests/test-getusershell.c: New file.
+
 2024-05-14  Collin Funk  
 
gnulib-tool.sh: Don't continue creating testdirs when destdir exists.
diff --git a/modules/getusershell-tests b/modules/getusershell-tests
new file mode 100644
index 00..0a65257c18
--- /dev/null
+++ b/modules/getusershell-tests
@@ -0,0 +1,12 @@
+Files:
+tests/test-getusershell.c
+tests/macros.h
+
+Depends-on:
+strdup
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-getusershell
+check_PROGRAMS += test-getusershell
diff --git a/tests/test-getusershell.c b/tests/test-getusershell.c
new file mode 100644
index 00..4ea13afd90
--- /dev/null
+++ b/tests/test-getusershell.c
@@ -0,0 +1,96 @@
+/* Test the getusershell, setusershell, endusershell functions.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published
+   by the Free Software Foundation, either version 3 of the License,
+   or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see .  */
+
+/* Written by Collin Funk , 2024.  */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+#include "macros.h"
+
+/* The shell names in the order they appear in '/etc/shells'.  */
+static char **shells = NULL;
+static size_t shell_count = 0;
+
+/* Prepare the shells array.  */
+static void
+first_pass (void)
+{
+  char *ptr;
+  size_t i = 0;
+
+  /* Avoid reallocation.  */
+  shell_count = 16;
+  shells = malloc (shell_count * sizeof (char *));
+
+  for (; (ptr = getusershell ()); ++i)
+{
+  /* Make sure comments are ignored.  */
+  ASSERT (ptr[0] != '#');
+  if (i >= shell_count)
+{
+  shell_count *= 2;
+  shells = realloc (shells, shell_count * sizeof (char *));
+  ASSERT (shells != NULL);
+}
+  shells[i] = strdup (ptr);
+  ASSERT (shells[i] != NULL);
+}
+
+  shell_count = i;
+}
+
+/* Assuming that '/etc/shells' does not change during the duration of this
+   test, check that setusershell puts us back at the start of the file.  */
+static void
+second_pass (void)
+{
+  size_t i;
+  char *ptr;
+
+  /* Return to the start of the file.  */
+  setusershell ();
+
+  /* Make sure order is preserved.  */
+  for (i = 0; i < shell_count; ++i)
+{
+  ptr = getusershell ();
+  ASSERT (ptr != NULL);
+  ASSERT (STREQ (ptr, shells[i]));
+  printf ("%s\n", ptr);
+  free (shells[i]);
+}
+
+  /* End of file.  */
+  ASSERT (getusershell () == NULL);
+
+  /* Clean up.  */
+  free (shells);
+  endusershell ();
+}
+
+int
+main (void)
+{
+  first_pass ();
+  second_pass ();
+
+  return 0;
+}
-- 
2.45.0




Re: Python './gnulib-tool --create-testdir --dir F' should quickly warn if F exists

2024-05-15 Thread Bruno Haible
Collin Funk wrote:
> I've committed the attached patch.

Looks good. Thanks.

Bruno