Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package black-hole-solver for 
openSUSE:Factory checked in at 2025-09-12 21:10:25
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/black-hole-solver (Old)
 and      /work/SRC/openSUSE:Factory/.black-hole-solver.new.1977 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "black-hole-solver"

Fri Sep 12 21:10:25 2025 rev:4 rq:1304218 version:1.14.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/black-hole-solver/black-hole-solver.changes      
2022-12-13 18:55:48.927314744 +0100
+++ 
/work/SRC/openSUSE:Factory/.black-hole-solver.new.1977/black-hole-solver.changes
    2025-09-12 21:11:24.879995219 +0200
@@ -1,0 +2,11 @@
+Fri Sep 12 07:04:29 UTC 2025 - Dirk Müller <dmuel...@suse.com>
+
+- update to 1.4.0:
+  * Fixed running black_hole_solver_run with the same
+    (or a smaller) iterations limit.  It ran indefinetely
+    then (Possible Denial-of-service?)
+  * Fix some hypothetical rresource leaks (e.g.: with "fopen()").
+  * Cleanups: add "const"s , convert "int" to "bool", etc.
+  * Add tests.
+
+-------------------------------------------------------------------

Old:
----
  black-hole-solver-1.12.0.tar.xz

New:
----
  black-hole-solver-1.14.0.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ black-hole-solver.spec ++++++
--- /var/tmp/diff_new_pack.QcXA8L/_old  2025-09-12 21:11:25.476020350 +0200
+++ /var/tmp/diff_new_pack.QcXA8L/_new  2025-09-12 21:11:25.476020350 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package black-hole-solver
 #
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2025 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -20,7 +20,7 @@
 # Missing perl(Env::Path), should also skip some tests like build-process
 %global run_tests 0
 Name:           black-hole-solver
-Version:        1.12.0
+Version:        1.14.0
 Release:        0
 Summary:        The Black Hole Solver Executable
 License:        MIT

++++++ black-hole-solver-1.12.0.tar.xz -> black-hole-solver-1.14.0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/CMakeLists.txt 
new/black-hole-solver-1.14.0/CMakeLists.txt
--- old/black-hole-solver-1.12.0/CMakeLists.txt 2021-12-11 06:47:47.000000000 
+0100
+++ new/black-hole-solver-1.14.0/CMakeLists.txt 2025-03-03 08:21:09.000000000 
+0100
@@ -1,4 +1,4 @@
-CMAKE_MINIMUM_REQUIRED(VERSION 3.5)
+CMAKE_MINIMUM_REQUIRED(VERSION 3.15)
 PROJECT(black-hole-solver)
 
 INCLUDE ("${CMAKE_SOURCE_DIR}/cmake/shlomif_common_bootstrap.cmake")
@@ -13,6 +13,8 @@
 option (LINK_TO_STATIC "Link the executables to the static library")
 option (DISABLE_APPLYING_RPATH "Disable applying rpath")
 option (ENABLE_DISPLAYING_MAX_NUM_PLAYED_CARDS "Allow recording and displaying 
the maximal number of played/\"moved\" cards. Enabling it may make the 
non-related run time somewhat slower.")
+option (USE_SIGNED_CHARS "-fsigned-char")
+option (USE_UNSIGNED_CHARS "-funsigned-char")
 
 INCLUDE(FindPkgConfig)
 
@@ -33,7 +35,7 @@
 
 SET (BHS_STATE_STORAGE "BHS_STATE_STORAGE_INTERNAL_HASH" CACHE STRING "The 
State Storage Type")
 SET (FCS_IA_PACK_SIZE 64 CACHE STRING "Size of a single pack in kilo-bytes.")
-SET (IA_STATE_PACKS_GROW_BY 32 CACHE STRING "Amount to Grow State Packs By")
+SET (IA_STATE_PACKS_GROW_BY 32 CACHE STRING "Amount to Grow State Packs By ( 
UNUSED! Kept for backward compatibility. )")
 SET (base_with_ver "black_hole_solver-[0-9]+\\\\.[0-9]+\\\\.[0-9]+")
 SET(CPACK_SOURCE_GENERATOR "TXZ")
 SET(CPACK_SOURCE_IGNORE_FILES
@@ -133,6 +135,7 @@
 
 IF ("$ENV{FCS_CLANG}")
     ADD_DEFINITIONS("-Weverything -Wno-language-extension-token 
-Wno-gnu-statement-expression -Wno-used-but-marked-unused -Wno-padded 
-Wno-cast-align -Wno-extra-semi-stmt")
+    ADD_DEFINITIONS("-Wno-declaration-after-statement")
 ENDIF ()
 
 IF ("$ENV{FCS_GCC}")
@@ -146,6 +149,15 @@
 ENDIF ()
 ADD_DEFINITIONS("-Wno-unknown-pragmas")
 
+IF (USE_UNSIGNED_CHARS)
+    ADD_DEFINITIONS("-funsigned-char")
+    IF (USE_SIGNED_CHARS)
+        MESSAGE(FATAL_ERROR "Cannot have both USE_SIGNED_CHARS and 
USE_UNSIGNED_CHARS !")
+    ENDIF ()
+ELSEIF (USE_SIGNED_CHARS)
+    ADD_DEFINITIONS("-fsigned-char")
+ENDIF ()
+
 # So it can find config.h
 INCLUDE_DIRECTORIES(BEFORE "${CMAKE_CURRENT_SOURCE_DIR}")
 INCLUDE_DIRECTORIES(BEFORE "${CMAKE_CURRENT_BINARY_DIR}")
@@ -207,7 +219,7 @@
 )
 
 SET_TARGET_PROPERTIES(
-    "${LIB_BASE}" PROPERTIES VERSION 1.0.1 SOVERSION 1
+    "${LIB_BASE}" PROPERTIES VERSION 1.0.2 SOVERSION 1
 )
 
 SET (LIBS "${LIB_BASE}")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/NEWS.asciidoc 
new/black-hole-solver-1.14.0/NEWS.asciidoc
--- old/black-hole-solver-1.12.0/NEWS.asciidoc  2022-03-28 12:28:47.000000000 
+0200
+++ new/black-hole-solver-1.14.0/NEWS.asciidoc  2025-03-03 07:56:03.000000000 
+0100
@@ -1,9 +1,21 @@
 Black Hole Solver's News File
 =============================
 Shlomi Fish <shlo...@cpan.org>
-:Date: 2020-06-28
+:Date: 2025-03-03
 :Revision: $Id$
 
+1.14.0       ( 03 March 2025 ):
+-------------------------------
+
+* Fixed running black_hole_solver_run with the same (or a smaller) iterations
+limit.  It ran indefinetely then (Possible Denial-of-service?)
+
+* Fix some hypothetical rresource leaks (e.g.: with "fopen()").
+
+* Cleanups: add "const"s , convert "int" to "bool", etc.
+
+* Add tests.
+
 1.12.0       ( 28 March 2022 ):
 -------------------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/black-hole-solver.spec 
new/black-hole-solver-1.14.0/black-hole-solver.spec
--- old/black-hole-solver-1.12.0/black-hole-solver.spec 2022-03-28 
12:29:16.000000000 +0200
+++ new/black-hole-solver-1.14.0/black-hole-solver.spec 2025-03-03 
07:57:04.000000000 +0100
@@ -1,5 +1,5 @@
 Name: black-hole-solver
-Version: 1.12.0
+Version: 1.14.0
 Release: 1
 License: MIT
 Group: Amusement/Games
@@ -41,22 +41,20 @@
 Group: Amusement/Games
 
 %description -n libblack_hole_solver1
-Contains the Blach Hole Solitaire libraries.
+Contains the Black Hole Solitaire libraries.
 
 This package is mandatory for the Black Hole Solitaire executable too.
 
 %package -n libblack_hole_solver1-devel
-Summary: The Freecell Solver development tools for solving Freecell games
+Summary: The Black Hole Solitaire development tools
 Group: Amusement/Games
 Requires: libblack_hole_solver1 = %{version}
 
 %description -n libblack_hole_solver1-devel
-Freecell Solver is a library for automatically solving boards of Freecell and
-similar variants of card Solitaire. This package contains the header files and
-static libraries necessary for developing programs using Freecell Solver.
+Contains the Black Hole Solitaire development libraries.
 
 You should install it if you are a game developer who would like to use
-Freecell Solver from within your programs.
+Black Hole Solitaire Solver from within your programs.
 
 %prep
 %setup
@@ -92,81 +90,5 @@
 rm -rf $RPM_BUILD_ROOT
 
 %changelog
-* Tue Mar 31 2009 Shlomi Fish <shlo...@cpan.org> 2.21.2-1
-- Adapted to the CMake build system.
-- Changed the license from "Public Domain" to "MIT".
-
-* Mon Oct 24 2005 Shlomi Fish <shlo...@cpan.org> 2.8.11-1
-- Changed "Copyright" to "License"
-
-* Fri Jul 30 2004 Shlomi Fish <shlo...@cpan.org> 2.8.7-1
-- Added some unpackaged files
-- deleted make-microsoft-freecell-board so it won't be reported as
-  unpacked
-- removed some old cd's that are now useless
-- removed the serial tags - they are just trouble.
-
-* Mon Sep 02 2002 Shlomi Fish <shlo...@cpan.org> 2.7.15-1
-- Used strip on the range solver
-- Added the presets' related files
-
-* Sat Feb 16 2002 Shlomi Fish <shlo...@cpan.org> 2.1.10-1
-- updated to version 2.1.10
-- removed the man pages symlinks (they were superceded by the ".so" links).
-
-* Fri Jan 04 2002 Shlomi Fish <shlo...@cpan.org> 2.0.1-1
-- updated to version 2.0.1
-- added freecell-solver-range-parallel-solve to the /usr/bin programs
-
-* Tue Dec 18 2001 Shlomi Fish <shlo...@cpan.org> 2.0.0-1
-- updated to version 2.0.0
-
-* Fri Nov 23 2001 Shlomi Fish <shlo...@cpan.org> 1.10.3-1
-- updated to version 1.10.3
-
-* Thu Nov 22 2001 Shlomi Fish <shlo...@cpan.org> 1.10.2-1
-- updated to version 1.10.2
-
-* Tue Oct 02 2001 Shlomi Fish <shlo...@cpan.org> 1.10.0-1
-- updated to version 1.10.0
-
-* Sat Sep 22 2001 Shlomi Fish <shlo...@cpan.org> 1.8.2-1
-- updated to version 1.8.2
-
-* Sat Sep 01 2001 Shlomi Fish <shlo...@cpan.org> 1.8.0-1
-- Changed the version to 1.8.0
-- Removed the -autconf suffix from the archive.
-
-* Sat Jul 07 2001 Shlomi Fish <shlo...@cpan.org> 1.6.7-2
-- Fixed the man pages.
-- Included a paragraph about the board_gen programs in the description of
-  the executable package.
-
-* Sat Jun 09 2001 Shlomi Fish <shlo...@cpan.org> 1.6.7-1
-- Changed the version to 1.6.7.
-- Added support for the man pages.
-- Added the symlinked man pages.
-- Added the board_gen sub-dir in the documentation directory. (using a rather
-crude hack)
-- Known Bugs:
-    1 - The man pages need a little rework, there are some typos and they
-        don't look very standard.
-
-
-* Thu May 24 2001 Shlomi Fish <shlo...@cpan.org> 1.6.4-3
-- Added the board generation programs into the RPM.
-- Changed the package to my name and E-mail. Done through the home-dir conf
-file, not by editting the SPEC, but what the heck.
-
-* Sat May 19 2001 Shlomi Fish <shlo...@cpan.org> 1.6.4-2
-- Changed the descriptions and summaries to something more meaningful
-- Removed the dependency on "Serial" in "Requires".
-
-* Fri May 18 2001 Shlomi Fish <shlo...@cpan.org> 1.6.4-1
-- First working version with libs and executable support.
-- Known Bugs:
-      1 - No "devel" package.
-      2 - No options passed to "configure".
-- Added calls to strip.
-- "configure" is now OK with all the options set.
-- Added Headers and a working freecell-solver-devel
+* Mon Feb 10 2025 Shlomi Fish <shlo...@cpan.org> 1.12.0-1
+- Trim the old, freecell-solver, changelog.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/black-hole-solver.spec.in 
new/black-hole-solver-1.14.0/black-hole-solver.spec.in
--- old/black-hole-solver-1.12.0/black-hole-solver.spec.in      2020-11-27 
09:09:50.000000000 +0100
+++ new/black-hole-solver-1.14.0/black-hole-solver.spec.in      2025-02-10 
11:00:17.000000000 +0100
@@ -41,22 +41,20 @@
 Group: Amusement/Games
 
 %description -n libblack_hole_solver1
-Contains the Blach Hole Solitaire libraries.
+Contains the Black Hole Solitaire libraries.
 
 This package is mandatory for the Black Hole Solitaire executable too.
 
 %package -n libblack_hole_solver1-devel
-Summary: The Freecell Solver development tools for solving Freecell games
+Summary: The Black Hole Solitaire development tools
 Group: Amusement/Games
 Requires: libblack_hole_solver1 = %{version}
 
 %description -n libblack_hole_solver1-devel
-Freecell Solver is a library for automatically solving boards of Freecell and
-similar variants of card Solitaire. This package contains the header files and
-static libraries necessary for developing programs using Freecell Solver.
+Contains the Black Hole Solitaire development libraries.
 
 You should install it if you are a game developer who would like to use
-Freecell Solver from within your programs.
+Black Hole Solitaire Solver from within your programs.
 
 %prep
 %setup
@@ -92,81 +90,5 @@
 rm -rf $RPM_BUILD_ROOT
 
 %changelog
-* Tue Mar 31 2009 Shlomi Fish <shlo...@cpan.org> 2.21.2-1
-- Adapted to the CMake build system.
-- Changed the license from "Public Domain" to "MIT".
-
-* Mon Oct 24 2005 Shlomi Fish <shlo...@cpan.org> 2.8.11-1
-- Changed "Copyright" to "License"
-
-* Fri Jul 30 2004 Shlomi Fish <shlo...@cpan.org> 2.8.7-1
-- Added some unpackaged files
-- deleted make-microsoft-freecell-board so it won't be reported as
-  unpacked
-- removed some old cd's that are now useless
-- removed the serial tags - they are just trouble.
-
-* Mon Sep 02 2002 Shlomi Fish <shlo...@cpan.org> 2.7.15-1
-- Used strip on the range solver
-- Added the presets' related files
-
-* Sat Feb 16 2002 Shlomi Fish <shlo...@cpan.org> 2.1.10-1
-- updated to version 2.1.10
-- removed the man pages symlinks (they were superceded by the ".so" links).
-
-* Fri Jan 04 2002 Shlomi Fish <shlo...@cpan.org> 2.0.1-1
-- updated to version 2.0.1
-- added freecell-solver-range-parallel-solve to the /usr/bin programs
-
-* Tue Dec 18 2001 Shlomi Fish <shlo...@cpan.org> 2.0.0-1
-- updated to version 2.0.0
-
-* Fri Nov 23 2001 Shlomi Fish <shlo...@cpan.org> 1.10.3-1
-- updated to version 1.10.3
-
-* Thu Nov 22 2001 Shlomi Fish <shlo...@cpan.org> 1.10.2-1
-- updated to version 1.10.2
-
-* Tue Oct 02 2001 Shlomi Fish <shlo...@cpan.org> 1.10.0-1
-- updated to version 1.10.0
-
-* Sat Sep 22 2001 Shlomi Fish <shlo...@cpan.org> 1.8.2-1
-- updated to version 1.8.2
-
-* Sat Sep 01 2001 Shlomi Fish <shlo...@cpan.org> 1.8.0-1
-- Changed the version to 1.8.0
-- Removed the -autconf suffix from the archive.
-
-* Sat Jul 07 2001 Shlomi Fish <shlo...@cpan.org> 1.6.7-2
-- Fixed the man pages.
-- Included a paragraph about the board_gen programs in the description of
-  the executable package.
-
-* Sat Jun 09 2001 Shlomi Fish <shlo...@cpan.org> 1.6.7-1
-- Changed the version to 1.6.7.
-- Added support for the man pages.
-- Added the symlinked man pages.
-- Added the board_gen sub-dir in the documentation directory. (using a rather
-crude hack)
-- Known Bugs:
-    1 - The man pages need a little rework, there are some typos and they
-        don't look very standard.
-
-
-* Thu May 24 2001 Shlomi Fish <shlo...@cpan.org> 1.6.4-3
-- Added the board generation programs into the RPM.
-- Changed the package to my name and E-mail. Done through the home-dir conf
-file, not by editting the SPEC, but what the heck.
-
-* Sat May 19 2001 Shlomi Fish <shlo...@cpan.org> 1.6.4-2
-- Changed the descriptions and summaries to something more meaningful
-- Removed the dependency on "Serial" in "Requires".
-
-* Fri May 18 2001 Shlomi Fish <shlo...@cpan.org> 1.6.4-1
-- First working version with libs and executable support.
-- Known Bugs:
-      1 - No "devel" package.
-      2 - No options passed to "configure".
-- Added calls to strip.
-- "configure" is now OK with all the options set.
-- Added Headers and a working freecell-solver-devel
+* Mon Feb 10 2025 Shlomi Fish <shlo...@cpan.org> 1.12.0-1
+- Trim the old, freecell-solver, changelog.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/cmake/Shlomif_Common.cmake 
new/black-hole-solver-1.14.0/cmake/Shlomif_Common.cmake
--- old/black-hole-solver-1.12.0/cmake/Shlomif_Common.cmake     2021-09-23 
10:42:02.000000000 +0200
+++ new/black-hole-solver-1.14.0/cmake/Shlomif_Common.cmake     2025-02-23 
18:26:45.000000000 +0100
@@ -224,11 +224,14 @@
     FILE (WRITE "${TO}" "${contents}")
 ENDMACRO()
 
+# See: https://github.com/shlomif/shlomif-cmake-modules/issues/1
+SET (SHLOMIF_SYSTEM_INSTALL_DIR "/usr/share/cmake/Modules" CACHE STRING "cmake 
sys installation dir")
+
 MACRO(SHLOMIF_COMMON_SETUP private_mod_path)
     SET (private_mod "Shlomif_Common.cmake")
     SET (_dest "${private_mod_path}/${private_mod}")
     IF (NOT EXISTS "${_dest}")
-        SHLOMIF_PHYS_COPY_FILE( "/usr/share/cmake/Modules/${private_mod}" 
"${_dest}")
+        SHLOMIF_PHYS_COPY_FILE( "${SHLOMIF_SYSTEM_INSTALL_DIR}/${private_mod}" 
"${_dest}")
     ENDIF ()
 ENDMACRO()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/cmake/pod2man-wrapper.pl 
new/black-hole-solver-1.14.0/cmake/pod2man-wrapper.pl
--- old/black-hole-solver-1.12.0/cmake/pod2man-wrapper.pl       2019-01-14 
01:59:57.000000000 +0100
+++ new/black-hole-solver-1.14.0/cmake/pod2man-wrapper.pl       2025-02-10 
11:02:19.000000000 +0100
@@ -4,8 +4,8 @@
 use warnings;
 
 use Getopt::Long;
-use File::Temp qw/tempdir/;
-use File::Copy;
+use File::Temp qw/ tempdir /;
+use File::Copy qw/ copy /;
 
 my ( $src, $dest, $sect, $center, $release );
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/config.h.in 
new/black-hole-solver-1.14.0/config.h.in
--- old/black-hole-solver-1.12.0/config.h.in    2020-10-25 10:56:51.000000000 
+0100
+++ new/black-hole-solver-1.14.0/config.h.in    2025-02-10 11:05:23.000000000 
+0100
@@ -14,8 +14,8 @@
  * ${AUTOGENERATED_CONFIG_H}
 */
 
-#ifndef FC_SOLVE__CONFIG_H
-#define FC_SOLVE__CONFIG_H
+#ifndef BLACK_HOLE_SOLVE__CONFIG_H
+#define BLACK_HOLE_SOLVE__CONFIG_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -23,17 +23,6 @@
 
 #cmakedefine CARD_DEBUG_PRES
 
-/*
-    The sort margin size for the previous states array.
-*/
-#define PREV_STATES_SORT_MARGIN 32
-
-/*
-    The amount the pack pointers array grows by. Shouldn't be too high
-    because it doesn't happen too often.
-*/
-#cmakedefine IA_STATE_PACKS_GROW_BY 32
-
 /* The size of a single pack in alloc.c/alloc.h measured in 1024 chars. */
 #cmakedefine FCS_IA_PACK_SIZE ${FCS_IA_PACK_SIZE}
 
@@ -53,5 +42,4 @@
 }
 #endif
 
-#endif    /* #ifndef FC_SOLVE__CONFIG_H */
-
+#endif    /* #ifndef BLACK_HOLE_SOLVE__CONFIG_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/fcs_hash.c 
new/black-hole-solver-1.14.0/fcs_hash.c
--- old/black-hole-solver-1.12.0/fcs_hash.c     2019-12-28 20:43:33.000000000 
+0100
+++ new/black-hole-solver-1.14.0/fcs_hash.c     2025-02-10 12:32:15.000000000 
+0100
@@ -27,21 +27,20 @@
 // hash table, allowing for smaller chains, and faster lookup.
 static inline bool bh_solve_hash_rehash(bh_solve_hash_t *hash)
 {
-    bh_solve_hash_symlink_t *new_entries;
-
     const_AUTO(old_size, hash->size);
 
     const_AUTO(new_size, old_size << 1);
     const_AUTO(new_size_bitmask, new_size - 1);
 
-    if (unlikely(!(new_entries = calloc(
-                       (size_t)new_size, sizeof(bh_solve_hash_symlink_t)))))
+    bh_solve_hash_symlink_t *new_entries;
+    if (unlikely(
+            !(new_entries = calloc((size_t)new_size, sizeof(new_entries[0])))))
     {
         return true;
     }
 
     /* Copy the items to the new hash while not allocating them again */
-    for (bh_solve_hash_value_t i = 0; i < old_size; i++)
+    for (bh_solve_hash_value_t i = 0; i < old_size; ++i)
     {
         var_AUTO(item, hash->entries[i].first_item);
         /* traverse the chain item by item */
@@ -76,7 +75,7 @@
     return false;
 }
 
-int bh_solve_hash_init(bh_solve_hash_t *hash, meta_allocator *const meta_alloc)
+bool bh_solve_hash_init(bh_solve_hash_t *hash, meta_allocator *const 
meta_alloc)
 {
     const bh_solve_hash_value_t size = 256;
 
@@ -90,7 +89,7 @@
     if (!(hash->entries =
                 calloc((size_t)size, sizeof(bh_solve_hash_symlink_t))))
     {
-        return 1;
+        return true;
     }
 #ifdef BHS_WITH_HASH_VACANT_ITEMS
     hash->list_of_vacant_items = NULL;
@@ -101,10 +100,10 @@
     {
         free(hash->entries);
         hash->entries = NULL;
-        return 1;
+        return true;
     }
 
-    return 0;
+    return false;
 }
 
 int bh_solve_hash_insert(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/fcs_hash.h 
new/black-hole-solver-1.14.0/fcs_hash.h
--- old/black-hole-solver-1.12.0/fcs_hash.h     2019-06-30 19:39:36.000000000 
+0200
+++ new/black-hole-solver-1.14.0/fcs_hash.h     2025-02-10 12:32:52.000000000 
+0100
@@ -90,7 +90,7 @@
 
 } bh_solve_hash_t;
 
-extern int bh_solve_hash_init(bh_solve_hash_t *hash, meta_allocator *);
+extern bool bh_solve_hash_init(bh_solve_hash_t *hash, meta_allocator *);
 
 // Returns false if the key is new and the key/val pair was inserted.
 // Returns true if the key is not new and *existing_key / *existing_val
@@ -111,6 +111,7 @@
     memset(hash->entries, '\0', sizeof(hash->entries[0]) * hash->size);
     hash->num_elems = 0;
 }
+
 static inline void bh_solve_hash_get(
     bh_solve_hash_t *hash, bhs_state_key_t *key_ptr, bhs_state_value_t *result)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/black-hole-solver-1.12.0/include/black-hole-solver/fcs_dllexport.h 
new/black-hole-solver-1.14.0/include/black-hole-solver/fcs_dllexport.h
--- old/black-hole-solver-1.12.0/include/black-hole-solver/fcs_dllexport.h      
2019-04-16 21:17:00.000000000 +0200
+++ new/black-hole-solver-1.14.0/include/black-hole-solver/fcs_dllexport.h      
2024-04-04 09:36:25.000000000 +0200
@@ -1,5 +1,4 @@
-#ifndef FC_SOLVE__FCS_DLLEXPORT_H
-#define FC_SOLVE__FCS_DLLEXPORT_H
+#pragma once
 
 #ifdef _MSC_VER
 #ifdef BUILDING_DLL
@@ -15,5 +14,3 @@
 #define DLLEXPORT
 #define DLLLOCAL
 #endif
-
-#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/lib.c 
new/black-hole-solver-1.14.0/lib.c
--- old/black-hole-solver-1.12.0/lib.c  2020-11-27 09:09:50.000000000 +0100
+++ new/black-hole-solver-1.14.0/lib.c  2025-02-20 16:54:58.000000000 +0100
@@ -49,7 +49,7 @@
     INVALID_SUIT = -1
 };
 
-static int suit_char_to_index(char suit)
+static int suit_char_to_index(const char suit)
 {
     switch (suit)
     {
@@ -173,7 +173,7 @@
     fc_solve_meta_compact_allocator_init(&(ret->meta_alloc));
     if (unlikely(bh_solve_hash_init(&(ret->positions), &(ret->meta_alloc))))
     {
-        fc_solve_meta_compact_allocator_finish(&(ret->meta_alloc));
+        bh_solve_meta_compact_allocator_finish(&(ret->meta_alloc));
         free(ret);
         *ret_instance = NULL;
         return BLACK_HOLE_SOLVER__OUT_OF_MEMORY;
@@ -549,7 +549,7 @@
     next_queue_item.s.packed.value.prev_foundation = prev_foundation;
 
     next_queue_item.rank_counts = queue_item_copy_ptr->rank_counts;
-    next_queue_item.rank_counts.c[(ssize_t)card]--;
+    --next_queue_item.rank_counts.c[(ssize_t)card];
 
     const int ret =
         bh_solve_hash_insert(&(solver->positions), 
&(next_queue_item.s.packed));
@@ -629,7 +629,7 @@
 }
 
 extern int DLLEXPORT black_hole_solver_config_setup(
-    black_hole_solver_instance_t *instance_proto)
+    black_hole_solver_instance_t *const instance_proto)
 {
     bhs_solver_t *const solver = (bhs_solver_t *)instance_proto;
     setup_config(solver);
@@ -637,14 +637,14 @@
 }
 
 extern int DLLEXPORT black_hole_solver_setup(
-    black_hole_solver_instance_t *instance_proto)
+    black_hole_solver_instance_t *const instance_proto)
 {
     bhs_solver_t *const solver = (bhs_solver_t *)instance_proto;
     return setup_init_state(solver);
 }
 
 extern int DLLEXPORT black_hole_solver_run(
-    black_hole_solver_instance_t *instance_proto)
+    black_hole_solver_instance_t *const instance_proto)
 {
     bhs_solver_t *const solver = (bhs_solver_t *)instance_proto;
 
@@ -661,6 +661,11 @@
         max_reached_depths_stack_len, solver->max_reached_depths_stack_len);
     var_AUTO(current_depths_stack_len, solver->current_depths_stack_len);
 
+    if (iterations_num >= max_iters_limit)
+    {
+        return BLACK_HOLE_SOLVER__OUT_OF_ITERS;
+    }
+
     while (solver->queue_len > 0)
     {
         const_AUTO(prev_len, solver->queue_len);
@@ -754,8 +759,9 @@
 
             return BLACK_HOLE_SOLVER__SUCCESS;
         }
-        else if (iterations_num == max_iters_limit)
+        else if (iterations_num >= max_iters_limit)
         {
+            assert(iterations_num == max_iters_limit);
             solver->max_reached_depths_stack_len = 
max_reached_depths_stack_len;
             solver->iterations_num = iterations_num;
             solver->current_depths_stack_len = current_depths_stack_len;
@@ -772,7 +778,7 @@
 }
 
 extern int DLLEXPORT black_hole_solver_recycle(
-    black_hole_solver_instance_t *instance_proto)
+    black_hole_solver_instance_t *const instance_proto)
 {
     bhs_solver_t *const solver = (bhs_solver_t *)instance_proto;
 
@@ -788,7 +794,7 @@
 }
 
 DLLEXPORT void black_hole_solver_init_solution_moves(
-    black_hole_solver_instance_t *instance_proto)
+    black_hole_solver_instance_t *const instance_proto)
 {
     bhs_solver_t *const solver = (bhs_solver_t *)instance_proto;
     const_SLOT(num_columns, solver);
@@ -824,7 +830,7 @@
                 states[num_states + 1].packed.value.prev_foundation;
             unsigned char *data = states[num_states + 1].packed.key.data;
             for (size_t i = 0; i < TALON_PTR_BITS;
-                 ++i, new_moved_card_height >>= 1)
+                ++i, new_moved_card_height >>= 1)
             {
                 data[0] &= (~(1 << (i)));
                 data[0] |= ((new_moved_card_height & 0x1) << (i));
@@ -841,7 +847,7 @@
             var_AUTO(offset, TALON_PTR_BITS + bits_per_column * col_idx);
             unsigned char *data = states[num_states + 1].packed.key.data;
             for (size_t i = 0; i < bits_per_column;
-                 ++i, ++offset, new_moved_card_height >>= 1)
+                ++i, ++offset, new_moved_card_height >>= 1)
             {
                 data[offset >> 3] &= (~(1 << (offset & 0x7)));
                 data[offset >> 3] |=
@@ -905,14 +911,14 @@
 
 DLLEXPORT extern unsigned long __attribute__((pure))
 black_hole_solver_get_iterations_num(
-    black_hole_solver_instance_t *instance_proto)
+    black_hole_solver_instance_t *const instance_proto)
 {
     return ((bhs_solver_t *)instance_proto)->iterations_num;
 }
 
 DLLEXPORT extern unsigned long __attribute__((pure))
 black_hole_solver_get_max_num_played_cards(
-    black_hole_solver_instance_t *instance_proto)
+    black_hole_solver_instance_t *const instance_proto)
 {
     const_AUTO(
         ret, ((bhs_solver_t *)instance_proto)->max_reached_depths_stack_len);
@@ -920,7 +926,7 @@
 }
 
 DLLEXPORT extern int black_hole_solver_get_current_solution_board(
-    black_hole_solver_instance_t *instance_proto, char *const output)
+    black_hole_solver_instance_t *const instance_proto, char *const output)
 {
     bhs_solver_t *const solver = (bhs_solver_t *)instance_proto;
 
@@ -982,12 +988,12 @@
 }
 
 extern int DLLEXPORT black_hole_solver_free(
-    black_hole_solver_instance_t *instance_proto)
+    black_hole_solver_instance_t *const instance_proto)
 {
     bhs_solver_t *const solver = (bhs_solver_t *)instance_proto;
 
     bh_solve_hash_free(&(solver->positions));
-    fc_solve_meta_compact_allocator_finish(&(solver->meta_alloc));
+    bh_solve_meta_compact_allocator_finish(&(solver->meta_alloc));
 
     free(solver);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/meta_alloc.c 
new/black-hole-solver-1.14.0/meta_alloc.c
--- old/black-hole-solver-1.12.0/meta_alloc.c   2019-08-16 10:35:02.000000000 
+0200
+++ new/black-hole-solver-1.14.0/meta_alloc.c   2025-02-10 12:04:05.000000000 
+0100
@@ -30,12 +30,12 @@
     }
 }
 
-int fc_solve_compact_allocator_extend(compact_allocator *const allocator)
+bool bh_solve_compact_allocator_extend(compact_allocator *const allocator)
 {
     char *const new_data = meta_request_new_buffer(allocator->meta);
     if (unlikely(!new_data))
     {
-        return 1;
+        return true;
     }
 
     FCS__COMPACT_ALLOC__OLD_LIST_NEXT(new_data) = allocator->old_list;
@@ -43,15 +43,15 @@
 
     allocator->ptr = allocator->rollback_ptr = OLD_LIST_DATA(new_data);
     allocator->max_ptr = new_data + ALLOCED_SIZE;
-    return 0;
+    return false;
 }
 
-void fc_solve_meta_compact_allocator_finish(meta_allocator *const meta_alloc)
+void bh_solve_meta_compact_allocator_finish(meta_allocator *const meta_alloc)
 {
     char *iter = meta_alloc->recycle_bin;
     char *iter_next = iter ? FCS__COMPACT_ALLOC__OLD_LIST_NEXT(iter) : NULL;
     for (; iter_next;
-         iter = iter_next, iter_next = FCS__COMPACT_ALLOC__OLD_LIST_NEXT(iter))
+        iter = iter_next, iter_next = FCS__COMPACT_ALLOC__OLD_LIST_NEXT(iter))
     {
         free(iter);
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/meta_alloc.h 
new/black-hole-solver-1.14.0/meta_alloc.h
--- old/black-hole-solver-1.12.0/meta_alloc.h   2019-08-16 10:35:02.000000000 
+0200
+++ new/black-hole-solver-1.14.0/meta_alloc.h   2025-02-10 12:09:37.000000000 
+0100
@@ -16,6 +16,7 @@
 extern "C" {
 #endif
 
+#include <stdbool.h>
 #include <stddef.h>
 #include "rinutils/likely.h"
 #include "rinutils/typeof_wrap.h"
@@ -39,14 +40,14 @@
     meta_allocator *meta;
 } compact_allocator;
 
-extern int fc_solve_compact_allocator_extend(compact_allocator *);
+extern bool bh_solve_compact_allocator_extend(compact_allocator *);
 
 /* To be called after the meta_alloc was set. */
-static inline int fc_solve_compact_allocator_init_helper(
+static inline bool fc_solve_compact_allocator_init_helper(
     compact_allocator *const allocator)
 {
     allocator->old_list = NULL;
-    return fc_solve_compact_allocator_extend(allocator);
+    return bh_solve_compact_allocator_extend(allocator);
 }
 
 static inline void fc_solve_meta_compact_allocator_init(
@@ -55,7 +56,7 @@
     meta->recycle_bin = NULL;
 }
 
-extern void fc_solve_meta_compact_allocator_finish(meta_allocator *);
+extern void bh_solve_meta_compact_allocator_finish(meta_allocator *);
 
 static inline void *fcs_compact_alloc_ptr(
     compact_allocator *const allocator, const size_t how_much_proto)
@@ -68,7 +69,7 @@
 
     if ((size_t)(allocator->max_ptr - allocator->ptr) < how_much)
     {
-        if (unlikely(fc_solve_compact_allocator_extend(allocator)))
+        if (unlikely(bh_solve_compact_allocator_extend(allocator)))
         {
             return NULL;
         }
@@ -97,8 +98,8 @@
     // Enqueue all the allocated buffers in the meta allocator for re-use.
     for (iter = allocator->old_list,
         iter_next = FCS__COMPACT_ALLOC__OLD_LIST_NEXT(iter);
-         iter_next;
-         iter = iter_next, iter_next = FCS__COMPACT_ALLOC__OLD_LIST_NEXT(iter))
+        iter_next;
+        iter = iter_next, iter_next = FCS__COMPACT_ALLOC__OLD_LIST_NEXT(iter))
     {
         FCS__COMPACT_ALLOC__OLD_LIST_NEXT(iter) = bin;
         bin = iter;
@@ -115,7 +116,7 @@
     fc_solve_compact_allocator_init_helper(allocator);
 }
 
-static inline int fc_solve_compact_allocator_init(
+static inline bool fc_solve_compact_allocator_init(
     compact_allocator *const allocator, meta_allocator *const meta_alloc)
 {
     allocator->meta = meta_alloc;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/multi_solver.c 
new/black-hole-solver-1.14.0/multi_solver.c
--- old/black-hole-solver-1.12.0/multi_solver.c 2020-11-27 09:09:50.000000000 
+0100
+++ new/black-hole-solver-1.14.0/multi_solver.c 2025-02-10 12:39:44.000000000 
+0100
@@ -12,7 +12,14 @@
     {
         char *const filename = argv[arg_idx];
         fprintf(settings.out_fh, "[= Starting file %s =]\n", filename);
-        solve_filename(filename, &settings);
+        bool should_abort;
+        const int ret = solve_filename(filename, &settings, &should_abort);
+        if (ret && should_abort)
+        {
+            fflush(settings.out_fh);
+            solve_free(&settings);
+            return ret;
+        }
         fprintf(settings.out_fh, "[= END of file %s =]\n", filename);
     }
     fflush(settings.out_fh);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/multi_solver_stats.c 
new/black-hole-solver-1.14.0/multi_solver_stats.c
--- old/black-hole-solver-1.12.0/multi_solver_stats.c   2021-11-24 
07:59:54.000000000 +0100
+++ new/black-hole-solver-1.14.0/multi_solver_stats.c   2025-03-02 
12:28:49.000000000 +0100
@@ -3,7 +3,7 @@
 // Distributed under terms of the Expat license.
 #include <solver_common.h>
 
-static inline void output_stats__solve_file(
+static inline int output_stats__solve_file(
     const char *const filename, bhs_settings *const settings_ptr)
 {
 #define settings (*settings_ptr)
@@ -14,7 +14,7 @@
         if (!fh)
         {
             fprintf(stderr, "Cannot open '%s' for reading!\n", filename);
-            return;
+            return -1;
         }
     }
     char board[MAX_LEN_BOARD_STRING];
@@ -59,6 +59,7 @@
 
     if (!solver_ret_code)
     {
+        fputs("Solved!\n", out_fh);
     }
     else if (solver_ret_code == BLACK_HOLE_SOLVER__OUT_OF_MEMORY)
     {
@@ -72,12 +73,19 @@
     else
     {
         fputs("Unsolved!\n", out_fh);
-        fprintf(out_fh, "At most %lu cards could be played.\n",
-            black_hole_solver_get_max_num_played_cards(solver));
     }
 
+    fprintf(out_fh, "At most %lu cards could be played.\n",
+        black_hole_solver_get_max_num_played_cards(solver));
+    fprintf(out_fh,
+        "Total number of states checked is %lu.\n"
+        "This scan generated %lu states.\n",
+        black_hole_solver_get_iterations_num(solver),
+        black_hole_solver_get_num_states_in_collection(solver));
+
     black_hole_solver_recycle(solver);
 #undef settings
+    return 0;
 }
 
 int main(int argc, char *argv[])
@@ -89,7 +97,12 @@
     {
         char *const filename = argv[arg_idx];
         fprintf(settings.out_fh, "[= Starting file %s =]\n", filename);
-        output_stats__solve_file(filename, &settings);
+        const int ret = output_stats__solve_file(filename, &settings);
+        if (unlikely(ret))
+        {
+            solve_free(&settings);
+            return -1;
+        }
         fprintf(settings.out_fh, "[= END of file %s =]\n", filename);
     }
     fflush(settings.out_fh);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/rank_reach_prune.h 
new/black-hole-solver-1.14.0/rank_reach_prune.h
--- old/black-hole-solver-1.12.0/rank_reach_prune.h     2019-04-16 
21:17:00.000000000 +0200
+++ new/black-hole-solver-1.14.0/rank_reach_prune.h     2024-09-29 
16:29:30.000000000 +0200
@@ -74,7 +74,7 @@
 
         static const int LINKS[2] = {-1, 1};
         for (size_t link_idx = 0; link_idx < (sizeof(LINKS) / 
sizeof(LINKS[0]));
-             link_idx++)
+            ++link_idx)
         {
             signed char offset_rank = (signed char)(rank + LINKS[link_idx]);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/run-tests.pl 
new/black-hole-solver-1.14.0/run-tests.pl
--- old/black-hole-solver-1.12.0/run-tests.pl   2021-04-25 07:09:31.000000000 
+0200
+++ new/black-hole-solver-1.14.0/run-tests.pl   2024-04-04 09:36:25.000000000 
+0200
@@ -6,8 +6,8 @@
 use autodie;
 
 use Getopt::Long qw/ GetOptions /;
-use Env::Path ();
-use Path::Tiny qw/ path /;
+use Env::Path    ();
+use Path::Tiny   qw/ path /;
 
 my $src_dir = path(__FILE__)->parent->absolute;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/black-hole-solver-1.12.0/scripts/gen-c-lookup-files.pl 
new/black-hole-solver-1.14.0/scripts/gen-c-lookup-files.pl
--- old/black-hole-solver-1.12.0/scripts/gen-c-lookup-files.pl  2019-06-30 
20:26:54.000000000 +0200
+++ new/black-hole-solver-1.14.0/scripts/gen-c-lookup-files.pl  2025-02-10 
12:48:08.000000000 +0100
@@ -6,37 +6,32 @@
 use autodie;
 use Path::Tiny qw/ path /;
 
-my $FALSE = 0;
-my $TRUE  = 1;
+sub emit
+{
+    my ( $DECL, $bn, $header_headers, $contents, $types ) = @_;
+    $types //= '';
 
-my $MAX_RANK              = $ENV{FCS_MAX_RANK} || 13;
-my $NUM_SUITS             = 4;
-my @SUITS                 = ( 0 .. $NUM_SUITS - 1 );
-my @RANKS                 = ( 1 .. $MAX_RANK );
-my @PARENT_RANKS          = ( 2 .. $MAX_RANK );
-my $MAX_NUM_DECKS         = 1;
-my $FCS_POS_BY_RANK_WIDTH = ( $MAX_NUM_DECKS << 3 );
+    my $header_fn = "$bn.h";
 
-sub make_card
-{
-    my ( $rank, $suit ) = @_;
-    return ( ( $rank << 2 ) | $suit );
-}
+    path($header_fn)
+        ->spew_utf8( "#pragma once\n"
+            . join( '', map { qq{#include $_\n} } @$header_headers )
+            . $types
+            . "extern $DECL;\n" );
+    path("$bn.c")
+        ->spew_utf8( qq/#include "$header_fn"\n\n$DECL = {/
+            . join( ',', @$contents )
+            . "};\n" );
 
-sub key
-{
-    my ( $parent, $child ) = @_;
-    return "${parent}\t${child}";
+    return;
 }
 
-my $NUM_CHILD_CARDS  = 64;
-my $NUM_PARENT_CARDS = make_card( $MAX_RANK, $SUITS[-1] ) + 1;
-my @is_king          = ( ($FALSE) x $NUM_PARENT_CARDS );
-my %lookup;
-my @state_pos = ( map { [ (0) x $NUM_SUITS ] } 0 .. $MAX_RANK );
-my @card_pos;
-my @positions_by_rank__lookup;
-my @pos_by_rank;
+my $FALSE = 0;
+my $TRUE  = 1;
+
+my $MAX_RANK = $ENV{FCS_MAX_RANK} || 13;
+my @RANKS    = ( 1 .. $MAX_RANK );
+
 my @can_move;
 
 foreach my $wrap_ranks ( 0, 1 )
@@ -58,41 +53,6 @@
     }
 }
 
-path('board_gen_lookup1.h')->spew_utf8(
-    "#pragma once\n",
-    'static const size_t offset_by_i[52] = {',
-    join(
-        ',',
-        map {
-            my $i   = $_;
-            my $col = ( $i & ( 8 - 1 ) );
-            3 *
-                ( $col * 7 - ( ( $col > 4 ) ? ( $col - 4 ) : 0 ) + ( $i >> 3 ) 
)
-        } 0 .. ( 52 - 1 )
-    ),
-    "};\n"
-);
-
-sub emit
-{
-    my ( $DECL, $bn, $header_headers, $contents, $types ) = @_;
-    $types //= '';
-
-    my $header_fn = "$bn.h";
-
-    path($header_fn)
-        ->spew_utf8( "#pragma once\n"
-            . join( '', map { qq{#include $_\n} } @$header_headers )
-            . $types
-            . "extern $DECL;\n" );
-    path("$bn.c")
-        ->spew_utf8( qq/#include "$header_fn"\n\n$DECL = {/
-            . join( ',', @$contents )
-            . "};\n" );
-
-    return;
-}
-
 emit(
 qq#const bool 
black_hole_solver__can_move[2][@{[$MAX_RANK+1]}][@{[$MAX_RANK]}]#,
     'can_move',
@@ -104,8 +64,7 @@
                 ',',
                 map {
                     my $row = $_;
-                    '{'
-                        . join( ',', map { $_ ? 'true' : 'false' } @$row ) . 
'}'
+                    '{' . join( ',', map { $_ ? 'true' : 'false' } @$row ) . 
'}'
                 } @{$table}
                 )
                 . '}'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/single_board_main.c 
new/black-hole-solver-1.14.0/single_board_main.c
--- old/black-hole-solver-1.12.0/single_board_main.c    2020-11-27 
09:09:50.000000000 +0100
+++ new/black-hole-solver-1.14.0/single_board_main.c    2025-02-10 
13:15:49.000000000 +0100
@@ -12,13 +12,41 @@
     char *filename = NULL;
     if (argc > arg_idx)
     {
-        if (strcmp(argv[arg_idx], "-"))
+        bool dashdash = false;
+        if (argv[arg_idx][0] == '-')
         {
+            if (strcmp(argv[arg_idx], "--"))
+            {
+                dashdash = true;
+                ++arg_idx;
+            }
+        }
+        if (arg_idx < argc - 1)
+        {
+            fprintf(stderr,
+                "Too many filenames given; only one is accepted.\nStarting "
+                "from %s .\n",
+                argv[arg_idx]);
+            solve_free(&settings);
+            return -1;
+        }
+        if (dashdash || strcmp(argv[arg_idx], "-"))
+        {
+            if (argv[arg_idx][0] == '-')
+            {
+                if (!dashdash)
+                {
+                    fprintf(stderr, "Unknown flag '%s' .\n", argv[arg_idx]);
+                    solve_free(&settings);
+                    return -1;
+                }
+            }
             filename = argv[arg_idx];
         }
     }
 
-    const int ret = solve_filename(filename, &settings);
+    bool should_abort;
+    const int ret = solve_filename(filename, &settings, &should_abort);
     solve_free(&settings);
     return ret;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/solver_common.h 
new/black-hole-solver-1.14.0/solver_common.h
--- old/black-hole-solver-1.12.0/solver_common.h        2020-11-27 
09:09:50.000000000 +0100
+++ new/black-hole-solver-1.14.0/solver_common.h        2025-02-27 
15:56:27.000000000 +0100
@@ -27,7 +27,7 @@
     GAME__GOLF
 };
 
-static inline void out_board(FILE *out_fh,
+static inline void out_board(FILE *const out_fh,
     black_hole_solver_instance_t *const solver, const bool display_boards)
 {
     if (!display_boards)
@@ -74,11 +74,12 @@
     bool quiet_output;
     bool wrap_ranks;
     bool show_max_num_played_cards;
+    bool was_output_filepath_set;
 } bhs_settings;
 #pragma clang diagnostic pop
 
 static inline bhs_settings parse_cmd_line(
-    int argc, char *argv[], int *out_arg_idx)
+    const int argc, char *argv[], int *const out_arg_idx)
 {
     bhs_settings settings;
     settings.out_fh = stdout;
@@ -91,6 +92,7 @@
     settings.wrap_ranks = true;
     settings.max_iters_limit = ULONG_MAX;
     settings.show_max_num_played_cards = false;
+    settings.was_output_filepath_set = false;
 
     int arg_idx = 1;
     while (argc > arg_idx)
@@ -113,7 +115,15 @@
                 fputs("Error! --output requires an argument.\n", stderr);
                 exit(-1);
             }
+            if (settings.was_output_filepath_set)
+            {
+                fputs("Error! --output can only be used once in order to avoid 
"
+                      "filehandles leaks.\n",
+                    stderr);
+                exit(-1);
+            }
             settings.out_fh = fopen(argv[arg_idx++], "wt");
+            settings.was_output_filepath_set = true;
         }
         else if (!strcmp(argv[arg_idx], "--max-iters"))
         {
@@ -234,11 +244,12 @@
     return settings;
 }
 
-static inline int solve_filename(
-    const char *const filename, bhs_settings *const settings_ptr)
+static inline int solve_filename(const char *const filename,
+    bhs_settings *const settings_ptr, bool *const should_abort)
 {
 #define settings (*settings_ptr)
     int ret = 0;
+    *should_abort = false;
 
     FILE *fh = stdin;
     if (filename)
@@ -247,6 +258,7 @@
         if (!fh)
         {
             fprintf(stderr, "Cannot open '%s' for reading!\n", filename);
+            *should_abort = true;
             return -1;
         }
     }
@@ -329,6 +341,7 @@
                 fprintf(stderr, "%s - %d\n",
                     "Get next move routine returned the wrong error code.",
                     next_move_ret_code);
+                *should_abort = true;
                 ret = -1;
             }
         }
@@ -336,6 +349,7 @@
     else if (solver_ret_code == BLACK_HOLE_SOLVER__OUT_OF_MEMORY)
     {
         fputs("Out of memory!\n", stderr);
+        *should_abort = true;
         exit(-1);
     }
     else if (solver_ret_code == BLACK_HOLE_SOLVER__OUT_OF_ITERS)
@@ -367,7 +381,7 @@
 
 static inline void solve_free(bhs_settings *const settings_ptr)
 {
-    if (settings_ptr->out_fh != stdout)
+    if (settings_ptr->was_output_filepath_set)
     {
         fclose(settings_ptr->out_fh);
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/solver_run.h 
new/black-hole-solver-1.14.0/solver_run.h
--- old/black-hole-solver-1.12.0/solver_run.h   2019-04-16 21:17:00.000000000 
+0200
+++ new/black-hole-solver-1.14.0/solver_run.h   2025-02-20 16:58:51.000000000 
+0100
@@ -3,10 +3,17 @@
 //
 // Distributed under terms of the Expat license.
 #pragma once
+#include <assert.h>
 
 static inline int solver_run(black_hole_solver_instance_t *const solver,
     const unsigned long max_iters_limit, const unsigned long 
iters_display_step)
 {
+    if (iters_display_step == 0)
+    {
+        // fprintf(stderr, "iters_display_step is 0.\n");
+        black_hole_solver_set_max_iters_limit(solver, max_iters_limit);
+        return black_hole_solver_run(solver);
+    }
     unsigned long iters_limit = min(iters_display_step, max_iters_limit);
     black_hole_solver_set_max_iters_limit(solver, iters_limit);
     unsigned long iters_num;
@@ -16,15 +23,15 @@
     {
         solver_ret_code = black_hole_solver_run(solver);
         iters_num = black_hole_solver_get_iterations_num(solver);
-        if (iters_limit == iters_num)
+        if (iters_limit <= iters_num)
         {
-            printf("Iteration: %lu\n", iters_limit);
+            printf("Iteration: %lu\n", iters_num);
             fflush(stdout);
         }
         iters_limit += iters_display_step;
         iters_limit = min(iters_limit, max_iters_limit);
         black_hole_solver_set_max_iters_limit(solver, iters_limit);
     } while ((solver_ret_code == BLACK_HOLE_SOLVER__OUT_OF_ITERS) &&
-             (iters_num < max_iters_limit));
+             (iters_num <= max_iters_limit));
     return solver_ret_code;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/t/all-in-a-row-output.t 
new/black-hole-solver-1.14.0/t/all-in-a-row-output.t
--- old/black-hole-solver-1.12.0/t/all-in-a-row-output.t        2020-10-26 
08:47:35.000000000 +0100
+++ new/black-hole-solver-1.14.0/t/all-in-a-row-output.t        2024-04-04 
09:36:25.000000000 +0200
@@ -19,7 +19,7 @@
     return $exit_code = system(@_);
 }
 
-use Dir::Manifest ();
+use Dir::Manifest        ();
 use Dir::Manifest::Slurp qw/ as_lf /;
 my $mani = Dir::Manifest->new(
     {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/t/black-hole-output.t 
new/black-hole-solver-1.14.0/t/black-hole-output.t
--- old/black-hole-solver-1.12.0/t/black-hole-output.t  2020-11-27 
09:09:50.000000000 +0100
+++ new/black-hole-solver-1.14.0/t/black-hole-output.t  2025-03-02 
13:24:18.000000000 +0100
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 24;
+use Test::More tests => 25;
 use Test::Differences qw/ eq_or_diff /;
 use Test::Some;
 
@@ -11,7 +11,9 @@
     trap $trap :flow:stderr(systemsafe):stdout(systemsafe):warn
 );
 
-use Path::Tiny qw/ path /;
+use Path::Tiny qw/ path tempdir /;
+
+use Games::Solitaire::BlackHole::Test qw/ _test_multiple_verdict_lines /;
 
 my $bin_dir   = path(__FILE__)->parent->absolute;
 my $data_dir  = $bin_dir->child('data');
@@ -33,7 +35,7 @@
 # TEST
 ok( !($exit_code), "Running the program successfully." );
 
-use Dir::Manifest ();
+use Dir::Manifest        ();
 use Dir::Manifest::Slurp qw/ as_lf /;
 my $mani = Dir::Manifest->new(
     {
@@ -255,35 +257,71 @@
     );
 }
 
+my $master_tmp = tempdir();
 {
-    my $out_fn = "golf1to20out.txt";
-    trap
+    my $count = 0;
     {
-        mysys(
-            './multi-bhs-solver',
-            '--output',
-            $out_fn,
-            '--game',
-            'golf',
-            '--display-boards',
-            '--wrap-ranks',
-            ( map { $mani->fh("golf$_.board") } 1 .. 20 )
-        );
-    };
+        my $tmp = $master_tmp->child( "multibhs-" . ++$count );
+        $tmp->mkdir();
 
-    # TEST
-    ok( !($exit_code), "Exit code for --display-boards for golf board #906." );
-
-    my $stdout = as_lf( path($out_fn)->slurp_raw );
-    $stdout =~
-        s#^(\[= (?:Starting|END of) file )(\S+)#$1 . path($2)->basename#egms;
+        my $out_fn = $tmp->child("golf1to20out.txt");
+        trap
+        {
+            mysys(
+                './multi-bhs-solver',
+                '--output',
+                $out_fn,
+                '--game',
+                'golf',
+                '--display-boards',
+                '--wrap-ranks',
+                ( map { $mani->fh("golf$_.board") } 1 .. 20 )
+            );
+        };
+
+        # TEST
+        ok( !($exit_code),
+            "Exit code for --display-boards for golf board #906." );
+
+        my $stdout = as_lf( path($out_fn)->slurp_raw );
+        $stdout =~
+s#^(\[= (?:Starting|END of) file )(\S+)#$1 . path($2)->basename#egms;
+
+        # TEST
+        is(
+            $stdout,
+            $mani->text( "golf-1to20.sol.txt", { lf => 1 } ),
+            "recycling works",
+        );
+    }
 
-    # TEST
-    is(
-        $stdout,
-        $mani->text( "golf-1to20.sol.txt", { lf => 1 } ),
-        "recycling works",
-    );
+    {
+        my $tmp = $master_tmp->child( "multibhs-" . ++$count );
+        $tmp->mkdir();
+        my $out_fn = $tmp->child("golf1to20out.txt");
+        trap
+        {
+            mysys(
+                './multi-bhs-solver',
+                '--output',
+                $out_fn,
+                '--game',
+                'golf',
+                '--display-boards',
+                '--wrap-ranks',
+                ( map { $mani->fh("golf$_.board") } 1 .. 2 ),
+                $tmp->child("not--------exist.c"),
+                ( map { $mani->fh("golf$_.board") } 3 .. 4 ),
+            );
+        };
+
+        # TEST
+        ok( $exit_code, "Exit code for --display-boards for golf board #906." 
);
+
+        my $stdout = as_lf( path($out_fn)->slurp_raw );
+        $stdout =~
+s#^(\[= (?:Starting|END of) file )(\S+)#$1 . path($2)->basename#egms;
+    }
 }
 
 my $MAX_NUM_PLAYED_CARDS_RE =
@@ -327,7 +365,7 @@
 
 # TEST
 subtest 'max_num_played' => sub {
-    plan tests => 10;
+    plan tests => 12;
     trap
     {
         mysys( './black-hole-solve', '--game', 'black_hole',
@@ -422,5 +460,53 @@
             input_text   => scalar( $trap->stdout() ),
         },
     );
+
+    {
+        my $count = 0;
+        my $tmp   = $master_tmp->child( "statsmultibhs-" . ++$count );
+        $tmp->mkdir();
+
+        my @deals_indexes = ( 1 .. 20 );
+        my $out_fn        = $tmp->child("golf1to20out.txt");
+        trap
+        {
+            mysys(
+                './stats-multi-bhs-solver',
+                '--output',
+                $out_fn,
+                '--game',
+                'golf',
+                '--display-boards',
+                '--wrap-ranks',
+                ( map { $mani->fh("golf$_.board") } 1 .. 20 )
+            );
+        };
+
+        ok( !($exit_code),
+            "Exit code for --display-boards for golf board #906." );
+
+        _test_multiple_verdict_lines(
+            {
+                name             => "test multiple verdict lines",
+                expected_results => [
+                    "Solved!", "Solved!", "Solved!",   "Solved!",
+                    "Solved!", "Solved!", "Solved!",   "Solved!",
+                    "Solved!", "Solved!", "Unsolved!", "Solved!",
+                    "Solved!", "Solved!", "Solved!",   "Solved!",
+                    "Solved!", "Solved!", "Solved!",   "Solved!",
+                ],
+                expected_files_checks => sub {
+                    my $i       = shift;
+                    my $dealidx = $deals_indexes[$i];
+                    my $fn      = path(shift);
+                    my $bn      = $fn->basename();
+
+                    return ( $bn =~ m#golf\Q$dealidx\E\.board#ms );
+                },
+                input_lines => [ path($out_fn)->lines_utf8() ],
+            }
+        );
+
+    }
     },
     '!no_max_num_played';
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/black-hole-solver-1.12.0/t/lib/Games/Solitaire/BlackHole/RankReachPrune/PP.pm
 
new/black-hole-solver-1.14.0/t/lib/Games/Solitaire/BlackHole/RankReachPrune/PP.pm
--- 
old/black-hole-solver-1.12.0/t/lib/Games/Solitaire/BlackHole/RankReachPrune/PP.pm
   2019-01-14 01:59:57.000000000 +0100
+++ 
new/black-hole-solver-1.14.0/t/lib/Games/Solitaire/BlackHole/RankReachPrune/PP.pm
   2024-09-29 16:34:40.000000000 +0200
@@ -27,7 +27,7 @@
     # Count the foundation - the starting point - in.
     if ( $rank_counts->[$foundation] == 0 )
     {
-        $full_max++;
+        ++$full_max;
     }
 
     my $full_count = 0;
@@ -45,7 +45,7 @@
         }
 
         $reached[$rank] = $TRUE;
-        $full_count++;
+        ++$full_count;
 
         for my $link ( -1, 1 )
         {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/black-hole-solver-1.12.0/t/lib/Games/Solitaire/BlackHole/RankReachPrune/XS.pm
 
new/black-hole-solver-1.14.0/t/lib/Games/Solitaire/BlackHole/RankReachPrune/XS.pm
--- 
old/black-hole-solver-1.12.0/t/lib/Games/Solitaire/BlackHole/RankReachPrune/XS.pm
   2020-10-07 12:53:32.000000000 +0200
+++ 
new/black-hole-solver-1.14.0/t/lib/Games/Solitaire/BlackHole/RankReachPrune/XS.pm
   2024-09-29 16:34:35.000000000 +0200
@@ -12,7 +12,7 @@
 int call_prune(int foundation, AV * rank_counts_av)
 {
     bhs_rank_counts rank_counts;
-    for (int i = 0; i < NUM_RANKS; i++)
+    for (int i = 0; i < NUM_RANKS; ++i)
     {
         SV * * item = av_fetch(rank_counts_av, i, false);
         assert(item);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/black-hole-solver-1.12.0/t/lib/Games/Solitaire/BlackHole/Test.pm 
new/black-hole-solver-1.14.0/t/lib/Games/Solitaire/BlackHole/Test.pm
--- old/black-hole-solver-1.12.0/t/lib/Games/Solitaire/BlackHole/Test.pm        
1970-01-01 01:00:00.000000000 +0100
+++ new/black-hole-solver-1.14.0/t/lib/Games/Solitaire/BlackHole/Test.pm        
2025-03-02 13:17:56.000000000 +0100
@@ -0,0 +1,115 @@
+package Games::Solitaire::BlackHole::Test;
+
+use strict;
+use warnings;
+
+use Test::More;
+
+use Dir::Manifest::Slurp qw/ as_lf /;
+use Test::Differences    qw/ eq_or_diff /;
+
+our @ISA         = qw(Exporter);
+our %EXPORT_TAGS = ( 'all' => [qw( _test_multiple_verdict_lines )] );
+our @EXPORT_OK   = ( @{ $EXPORT_TAGS{'all'} } );
+require Exporter;
+
+# We intend this test subroutine to be used by more than one
+# subproject.
+sub _test_multiple_verdict_lines
+{
+    my %is_verdict_line = map { $_ => 1, }
+        ( "Solved!", "Unsolved!", "Exceeded max_iters_limit !" );
+    my ($args) = @_;
+    my ( $name, $expected_files_checks, $want, $input_lines ) =
+        @{$args}{qw/ name expected_files_checks expected_results input_lines/};
+    local $Test::Builder::Level = $Test::Builder::Level + 1;
+    return subtest $name => sub {
+        plan tests => 2;
+        $input_lines =
+            [ map { my $l = as_lf($_); chomp $l; $l } @$input_lines ];
+        my @matches;
+        my $deal_idx = 0;
+        while (@$input_lines)
+        {
+            my $dealstart = shift @$input_lines;
+            my ($fn) = $dealstart =~ /^\[\= Starting file (\S+) \=\]$/ms
+                or die "cannot match";
+            if ( not $expected_files_checks->( $deal_idx, $fn ) )
+            {
+                die "filename check";
+            }
+            my $dealverdict = shift @$input_lines;
+            if ( $is_verdict_line{$dealverdict} )
+            {
+                push @matches, $dealverdict;
+            }
+            else
+            {
+                die "mismatch";
+            }
+            my $at_most_num_cards__line = 0;
+            if (    @$input_lines
+                and $input_lines->[0] =~
+                /^At most (?:(?:0)|(?:[1-9][0-9]*)) cards could be 
played\.\z/ms
+                )
+            {
+                $at_most_num_cards__line = 1;
+                shift @$input_lines;
+            }
+            my $traversed_states_count__line = 0;
+            if (    @$input_lines
+                and $input_lines->[0] =~
+/^Total number of states checked is (?:(?:0)|(?:[1-9][0-9]*))\.\z/ms,
+                )
+            {
+                $traversed_states_count__line = 1;
+                shift @$input_lines;
+            }
+            my $generated_states_count__line = 0;
+            if (    @$input_lines
+                and $input_lines->[0] =~
+                /^This scan generated (?:(?:0)|(?:[1-9][0-9]*)) states\.\z/ms )
+            {
+                $generated_states_count__line = 1;
+                shift @$input_lines;
+            }
+            if (0)
+            {
+                while ( @$input_lines and $input_lines->[0] !~ /^\[\= /ms )
+                {
+                    diag( "unrecognised: '" . $input_lines->[0] . "'" );
+                    shift @$input_lines;
+                }
+            }
+            my $dealend = shift @$input_lines;
+            if ( $dealend ne "[= END of file $fn =]" )
+            {
+                die "dealend mismatch";
+            }
+            if ( not $at_most_num_cards__line )
+            {
+                die "At most cards played line is absent";
+            }
+            if ( not $traversed_states_count__line )
+            {
+                die "'checked states' line is absent";
+            }
+            if ( not $generated_states_count__line )
+            {
+                die "'This scan generated' line is absent";
+            }
+        }
+        continue
+        {
+            ++$deal_idx;
+        }
+
+        is( scalar(@matches), scalar(@$want), "lines count." );
+
+        eq_or_diff( [@matches], [@$want], "expected results.", );
+    };
+}
+
+1;
+
+__END__
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/t/perltidy.t 
new/black-hole-solver-1.14.0/t/perltidy.t
--- old/black-hole-solver-1.12.0/t/perltidy.t   2019-01-14 01:59:57.000000000 
+0100
+++ new/black-hole-solver-1.14.0/t/perltidy.t   2024-04-04 09:36:25.000000000 
+0200
@@ -9,6 +9,17 @@
     Test::More::plan( 'skip_all' =>
             "Skipping perltidy test because FCS_TEST_SKIP_PERLTIDY was set" );
 }
+
+{
+    my $key = "AUTHOR_TESTING";
+    if ( not $ENV{$key} )
+    {
+        require Test::More;
+        Test::More::plan(
+            'skip_all' => "Skipping perltidy test because $key was not set" );
+    }
+}
+
 require Test::Code::TidyAll;
 
 Test::Code::TidyAll::tidyall_ok( conf_file => "$ENV{FCS_SRC_PATH}/.tidyallrc",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/t/valgrind.t 
new/black-hole-solver-1.14.0/t/valgrind.t
--- old/black-hole-solver-1.12.0/t/valgrind.t   2020-07-04 17:23:27.000000000 
+0200
+++ new/black-hole-solver-1.14.0/t/valgrind.t   2024-04-04 09:36:25.000000000 
+0200
@@ -5,7 +5,7 @@
 
 use Test::More;
 use Test::RunValgrind ();
-use Path::Tiny qw/ path /;
+use Path::Tiny        qw/ path /;
 
 my $bin_dir  = path($0)->parent->absolute;
 my $data_dir = $bin_dir->child('data');
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/black-hole-solver-1.12.0/ver.txt 
new/black-hole-solver-1.14.0/ver.txt
--- old/black-hole-solver-1.12.0/ver.txt        2022-03-28 12:22:05.000000000 
+0200
+++ new/black-hole-solver-1.14.0/ver.txt        2025-03-03 07:56:29.000000000 
+0100
@@ -1 +1 @@
-1.12.0
+1.14.0

Reply via email to