From 3fc6e6c66c03a8ba889996b9ebc0b4f7c9cfbccc Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Wed, 14 Oct 2026 19:33:05 +1100 Subject: [PATCH 1/3] chore: renamed **examples/cpp/cstring.dynload** => **examples/cpp/dynload** and **examples/cpp/cstring.global_memory** => **examples/cpp/global_memory** --- examples/cpp/CMakeLists.txt | 4 ++-- examples/cpp/{cstring.dynload => dynload}/CMakeLists.txt | 0 examples/cpp/{cstring.dynload => dynload}/README.md | 0 examples/cpp/{cstring.dynload => dynload}/main.cpp | 0 .../{cstring.global_memory => global_memory}/CMakeLists.txt | 0 .../cpp/{cstring.global_memory => global_memory}/README.md | 0 .../cpp/{cstring.global_memory => global_memory}/main.cpp | 0 7 files changed, 2 insertions(+), 2 deletions(-) rename examples/cpp/{cstring.dynload => dynload}/CMakeLists.txt (100%) rename examples/cpp/{cstring.dynload => dynload}/README.md (100%) rename examples/cpp/{cstring.dynload => dynload}/main.cpp (100%) rename examples/cpp/{cstring.global_memory => global_memory}/CMakeLists.txt (100%) rename examples/cpp/{cstring.global_memory => global_memory}/README.md (100%) rename examples/cpp/{cstring.global_memory => global_memory}/main.cpp (100%) diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index 5d84add..7fecf66 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -1,7 +1,7 @@ if(_BUILD_AS_WIN32) - add_subdirectory(cstring.dynload) - add_subdirectory(cstring.global_memory) + add_subdirectory(dynload) + add_subdirectory(global_memory) endif(_BUILD_AS_WIN32) diff --git a/examples/cpp/cstring.dynload/CMakeLists.txt b/examples/cpp/dynload/CMakeLists.txt similarity index 100% rename from examples/cpp/cstring.dynload/CMakeLists.txt rename to examples/cpp/dynload/CMakeLists.txt diff --git a/examples/cpp/cstring.dynload/README.md b/examples/cpp/dynload/README.md similarity index 100% rename from examples/cpp/cstring.dynload/README.md rename to examples/cpp/dynload/README.md diff --git a/examples/cpp/cstring.dynload/main.cpp b/examples/cpp/dynload/main.cpp similarity index 100% rename from examples/cpp/cstring.dynload/main.cpp rename to examples/cpp/dynload/main.cpp diff --git a/examples/cpp/cstring.global_memory/CMakeLists.txt b/examples/cpp/global_memory/CMakeLists.txt similarity index 100% rename from examples/cpp/cstring.global_memory/CMakeLists.txt rename to examples/cpp/global_memory/CMakeLists.txt diff --git a/examples/cpp/cstring.global_memory/README.md b/examples/cpp/global_memory/README.md similarity index 100% rename from examples/cpp/cstring.global_memory/README.md rename to examples/cpp/global_memory/README.md diff --git a/examples/cpp/cstring.global_memory/main.cpp b/examples/cpp/global_memory/main.cpp similarity index 100% rename from examples/cpp/cstring.global_memory/main.cpp rename to examples/cpp/global_memory/main.cpp From 79c490b5fc7b48eef3100d49ee837951170237a9 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Wed, 14 Oct 2026 19:36:02 +1100 Subject: [PATCH 2/3] version --- CHANGES.md | 4 ++++ NEWS.md | 1 + include/cstring/cstring.h | 10 ++++++---- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index c322040..ca69f50 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,10 @@ # cstring - Changes +## 4.1.0-alpha2 - 16th October 2026 + + + ## 4.1.0-alpha1 - 6th October 2026 * Added 64-bit `djb2` hash functions: `cstring_hash_djb2()`, `cstring_hash_djb2_case()`, `cstring_hash_djb2_buf()`, and `cstring_hash_djb2_buf_case()`; diff --git a/NEWS.md b/NEWS.md index 8c8100c..0a3694f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,7 @@ | Date | News Item | Details | | ------------------- | ------------------------------------ | ------- | | Available from [**cstring** project on GitHub](https://synesissoftware.com/cstring): | +| 16th October 2026 | Release of [cstring 4.1.0-alpha2](https://github.com/synesissoftware/cstring/releases/tag/4.1.0-alpha2) | | | 6th October 2026 | Release of [cstring 4.1.0-alpha1](https://github.com/synesissoftware/cstring/releases/tag/4.1.0-alpha1) | `djb2`, `FNV-1a`, and `SDBM`; `cstring_equal()` / `cstring_compare()`; `--wide-strings`; counted copies stop at `cch` | | 4th October 2026 | Release of [cstring 4.0.19](https://github.com/synesissoftware/cstring/releases/tag/4.0.19) | lone CR ends a line; `numRead` includes EOL; readonly truncate; zero-size realloc frees; **test.performance.cstring_readline**; shortened test and example directories; **test.unit.cstring**; README usage modes | | 29th September 2026 | Release of [cstring 4.0.18](https://github.com/synesissoftware/cstring/releases/tag/4.0.18) | `_WIN32` arena gate; **win.c**; static `CoTaskMem*` (**ole32**) | diff --git a/include/cstring/cstring.h b/include/cstring/cstring.h index 92aa085..fb5500f 100644 --- a/include/cstring/cstring.h +++ b/include/cstring/cstring.h @@ -4,7 +4,7 @@ * Purpose: Definition of the cstring.core API. * * Created: 16th June 1994 - * Updated: 6th October 2026 + * Updated: 16th October 2026 * * Home: http://synesis.com.au/software/ * @@ -55,8 +55,8 @@ #ifndef CSTRING_DOCUMENTATION_SKIP_SECTION # define CSTRING_VER_CSTRING_H_CSTRING_MAJOR 3 # define CSTRING_VER_CSTRING_H_CSTRING_MINOR 13 -# define CSTRING_VER_CSTRING_H_CSTRING_REVISION 3 -# define CSTRING_VER_CSTRING_H_CSTRING_EDIT 100 +# define CSTRING_VER_CSTRING_H_CSTRING_REVISION 4 +# define CSTRING_VER_CSTRING_H_CSTRING_EDIT 101 #endif /* !CSTRING_DOCUMENTATION_SKIP_SECTION */ @@ -105,6 +105,7 @@ # define CSTRING_VER_4_0_18 0x040012ff # define CSTRING_VER_4_0_19 0x040013ff # define CSTRING_VER_4_1_0_A1 0x04010041 +# define CSTRING_VER_4_1_0_A2 0x04010042 #endif /* !CSTRING_DOCUMENTATION_SKIP_SECTION */ /** \def CSTRING_VER_MAJOR @@ -126,7 +127,7 @@ #define CSTRING_VER_MAJOR 4 #define CSTRING_VER_MINOR 1 #define CSTRING_VER_PATCH 0 -#define CSTRING_VER_ALPHABETA 0x41 +#define CSTRING_VER_ALPHABETA 0x42 #define CSTRING_VER \ (0\ @@ -146,6 +147,7 @@ */ #include + #include From 7507cdb38bee09a1b3004b8319fa9d3f0f4adb4b Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Sat, 24 Oct 2026 10:36:03 +1100 Subject: [PATCH 3/3] Merged 'master' into 'directory-names' --- CHANGES.md | 8 ++- Doxyfile | 2 +- NEWS.md | 3 +- include/cstring/cstring.h | 17 +++-- prepare_cmake.sh | 18 +++-- run_all_examples.cmd | 60 +++++++++++++--- run_all_examples.sh | 79 ++++++++++++++++++++- run_all_scratch_tests.cmd | 103 +++++++++++++++++++++++++-- run_all_scratch_tests.sh | 146 +++++++++++++++++++++++++++++++++++++- run_all_unit_tests.sh | 7 +- 10 files changed, 407 insertions(+), 36 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index ca69f50..146d781 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,10 +1,16 @@ # cstring - Changes -## 4.1.0-alpha2 - 16th October 2026 +## 4.1.0-beta2 - 25th October 2026 +## 4.1.0-beta1 - 21st October 2026 + +* Brought the tip CMake runners up to **misc-dev-scripts** 0.6.2 and merged that gold into **prepare_cmake.sh**, keeping the cstring `-D` flags and `--gap-groups`; +* Defined `CSTRING_VER_RELSTATUS` (`0x81`, beta 1) and aliased `CSTRING_VER_ALPHABETA` to it; + + ## 4.1.0-alpha1 - 6th October 2026 * Added 64-bit `djb2` hash functions: `cstring_hash_djb2()`, `cstring_hash_djb2_case()`, `cstring_hash_djb2_buf()`, and `cstring_hash_djb2_buf_case()`; diff --git a/Doxyfile b/Doxyfile index 516eed8..5cd00e2 100644 --- a/Doxyfile +++ b/Doxyfile @@ -2,7 +2,7 @@ PROJECT_NAME = "cstring" PROJECT_BRIEF = "Extensible C-style strings and vectors of such, for Unix and Windows" -PROJECT_NUMBER = 4.1.0-alpha1 +PROJECT_NUMBER = 4.1.0-beta1 # Prefer SIS_CMAKE_BUILD_DIR-aligned output (same convention as Diagnosticism). # ./dox/ remains gitignored for legacy/local runs that override OUTPUT_DIRECTORY. diff --git a/NEWS.md b/NEWS.md index 0a3694f..053005f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,7 +4,8 @@ | Date | News Item | Details | | ------------------- | ------------------------------------ | ------- | | Available from [**cstring** project on GitHub](https://synesissoftware.com/cstring): | -| 16th October 2026 | Release of [cstring 4.1.0-alpha2](https://github.com/synesissoftware/cstring/releases/tag/4.1.0-alpha2) | | +| 25th October 2026 | Release of [cstring 4.1.0-beta2](https://github.com/synesissoftware/cstring/releases/tag/4.1.0-beta2) | | +| 21st October 2026 | Release of [cstring 4.1.0-beta1](https://github.com/synesissoftware/cstring/releases/tag/4.1.0-beta1) | helper gold 0.6.2; `CSTRING_VER_RELSTATUS` | | 6th October 2026 | Release of [cstring 4.1.0-alpha1](https://github.com/synesissoftware/cstring/releases/tag/4.1.0-alpha1) | `djb2`, `FNV-1a`, and `SDBM`; `cstring_equal()` / `cstring_compare()`; `--wide-strings`; counted copies stop at `cch` | | 4th October 2026 | Release of [cstring 4.0.19](https://github.com/synesissoftware/cstring/releases/tag/4.0.19) | lone CR ends a line; `numRead` includes EOL; readonly truncate; zero-size realloc frees; **test.performance.cstring_readline**; shortened test and example directories; **test.unit.cstring**; README usage modes | | 29th September 2026 | Release of [cstring 4.0.18](https://github.com/synesissoftware/cstring/releases/tag/4.0.18) | `_WIN32` arena gate; **win.c**; static `CoTaskMem*` (**ole32**) | diff --git a/include/cstring/cstring.h b/include/cstring/cstring.h index fb5500f..e8150ef 100644 --- a/include/cstring/cstring.h +++ b/include/cstring/cstring.h @@ -4,7 +4,7 @@ * Purpose: Definition of the cstring.core API. * * Created: 16th June 1994 - * Updated: 16th October 2026 + * Updated: 21st October 2026 * * Home: http://synesis.com.au/software/ * @@ -55,8 +55,8 @@ #ifndef CSTRING_DOCUMENTATION_SKIP_SECTION # define CSTRING_VER_CSTRING_H_CSTRING_MAJOR 3 # define CSTRING_VER_CSTRING_H_CSTRING_MINOR 13 -# define CSTRING_VER_CSTRING_H_CSTRING_REVISION 4 -# define CSTRING_VER_CSTRING_H_CSTRING_EDIT 101 +# define CSTRING_VER_CSTRING_H_CSTRING_REVISION 5 +# define CSTRING_VER_CSTRING_H_CSTRING_EDIT 104 #endif /* !CSTRING_DOCUMENTATION_SKIP_SECTION */ @@ -106,6 +106,8 @@ # define CSTRING_VER_4_0_19 0x040013ff # define CSTRING_VER_4_1_0_A1 0x04010041 # define CSTRING_VER_4_1_0_A2 0x04010042 +# define CSTRING_VER_4_1_0_B1 0x04010081 +# define CSTRING_VER_4_1_0_B2 0x04010082 #endif /* !CSTRING_DOCUMENTATION_SKIP_SECTION */ /** \def CSTRING_VER_MAJOR @@ -120,6 +122,10 @@ * The patch version number of **cstring** */ +/** \def CSTRING_VER_RELSTATUS + * The release-status number of **cstring** + */ + /** \def CSTRING_VER * The current composite version number of **cstring** */ @@ -127,17 +133,18 @@ #define CSTRING_VER_MAJOR 4 #define CSTRING_VER_MINOR 1 #define CSTRING_VER_PATCH 0 -#define CSTRING_VER_ALPHABETA 0x42 +#define CSTRING_VER_RELSTATUS 0x82 #define CSTRING_VER \ (0\ | ( CSTRING_VER_MAJOR << 24 ) \ | ( CSTRING_VER_MINOR << 16 ) \ | ( CSTRING_VER_PATCH << 8 ) \ - | ( CSTRING_VER_ALPHABETA << 0 ) \ + | ( CSTRING_VER_RELSTATUS << 0 ) \ ) #ifndef CSTRING_DOCUMENTATION_SKIP_SECTION +# define CSTRING_VER_ALPHABETA CSTRING_VER_RELSTATUS # define CSTRING_VER_REVISION CSTRING_VER_PATCH #endif /* !CSTRING_DOCUMENTATION_SKIP_SECTION */ diff --git a/prepare_cmake.sh b/prepare_cmake.sh index ce66efe..946350c 100755 --- a/prepare_cmake.sh +++ b/prepare_cmake.sh @@ -34,16 +34,24 @@ Configuration=Release ExamplesDisabled=0 MinGW=$(sis_cmake_is_truey "${SIS_CMAKE_MINGW:-}" && echo 1 || echo 0) MSVC_MT=0 -NO_cxx=0 -NO_p99=0 -NO_shwild=0 RunMake=0 SisUseColours=0 -STLSoftDirGiven= TestingDisabled=0 VerboseMakefile=0 -WideStrings=0 +# ########################################################## +# PROJECT-SPECIFIC FLAGS (customise per library; keep marker) +# +# Add project-only options here (e.g. --no-cpp, --stlsoft-root-dir, +# --no-shwild). The common body below must stay aligned with +# misc-dev-scripts/shell-scripts/cmake-helpers/prepare_cmake.sh. + + +NO_cxx=0 +NO_p99=0 +NO_shwild=0 +STLSoftDirGiven= +WideStrings=0 # ########################################################## # colours diff --git a/run_all_examples.cmd b/run_all_examples.cmd index 11273cb..b10e3d2 100644 --- a/run_all_examples.cmd +++ b/run_all_examples.cmd @@ -4,6 +4,8 @@ SETLOCAL SET SCRIPT_DIRECTORY=%~dp0 SET SCRIPT_PATH_DOC=%~n0[%~x0] +SET "ALLOWED_TO_FAIL_FILE=%SCRIPT_DIRECTORY%.sis\ci_examples_allowed_to_fail.txt" +SET "PROGRAM_STATUS=0" IF DEFINED SIS_CMAKE_BUILD_DIR ( @@ -45,6 +47,22 @@ Flags/options: ^ displays this help and terminates ^ +^ + + files: ^ + +^ + + .sis\ci_examples_allowed_to_fail.txt ^ + + optional list of example programs ^(one name per line; ^ + + lines beginning with '#' are ignored^) that are allowed to fail; ^ + + such a program is still executed, but a non-zero exit is ^ + + reported as anticipated and does not stop the run ^ + EXIT /B 0 ) ELSE ( @@ -78,12 +96,36 @@ SET SIS_EXAMPLE_SMOKE=1 ECHO Running all %ProjectName% example programs -FOR /F "usebackq" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%" ^| FINDSTR /I example.*\.exe$`) DO ( - - ECHO . - ECHO executing %%f - %%f - IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% -) - -ENDLOCAL +FOR /F "usebackq" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%" ^| FINDSTR /I example.*\.exe$`) DO CALL :run_program "%%f" + +ENDLOCAL & EXIT /B %PROGRAM_STATUS% + + +REM ########################################################## +REM subroutines + +:run_program +IF %PROGRAM_STATUS% NEQ 0 EXIT /B 0 +ECHO . +ECHO executing %~1 +"%~1" +SET "FAILURE_STATUS=%ERRORLEVEL%" +IF %FAILURE_STATUS% EQU 0 EXIT /B 0 +CALL :is_allowed_to_fail "%~1" +IF NOT DEFINED ALLOWED_TO_FAIL GOTO run_program_failed +ECHO anticipated failure: %~1 exited with status %FAILURE_STATUS%; it is listed in .sis\ci_examples_allowed_to_fail.txt +EXIT /B 0 +:run_program_failed +SET "PROGRAM_STATUS=%FAILURE_STATUS%" +EXIT /B 0 + +:is_allowed_to_fail +SET "ALLOWED_TO_FAIL=" +IF NOT EXIST "%ALLOWED_TO_FAIL_FILE%" EXIT /B 0 +FOR /F "usebackq eol=# tokens=1" %%n IN ("%ALLOWED_TO_FAIL_FILE%") DO CALL :match_allowed "%%n" "%~n1" "%~nx1" +EXIT /B 0 + +:match_allowed +IF /I "%~1"=="%~2" SET "ALLOWED_TO_FAIL=1" +IF /I "%~1"=="%~3" SET "ALLOWED_TO_FAIL=1" +EXIT /B 0 diff --git a/run_all_examples.sh b/run_all_examples.sh index 967f82c..2f03c18 100755 --- a/run_all_examples.sh +++ b/run_all_examples.sh @@ -27,6 +27,7 @@ CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") ScriptPath=$0 +AllowedToFailFile="$Dir/.sis/ci_examples_allowed_to_fail.txt" AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} ListOnly=0 @@ -115,6 +116,49 @@ sis_cmake_build() { cmake "${args[@]}" } +# Reduces a program path to its (lowercase) name, without any directory or +# .exe suffix. +sis_program_stem() { + + local p="${1//\\//}" + + p="${p##*/}" + + case "$p" in + *.exe|*.EXE) p="${p%.*}" ;; + esac + + printf '%s' "$p" | tr '[:upper:]' '[:lower:]' +} + +# Succeeds if the program is named (by name or stem, case-insensitively) in +# the optional .sis/ci_examples_allowed_to_fail.txt file; blank lines and +# lines beginning with '#' are ignored. +sis_is_allowed_to_fail() { + + local name line + + [ -f "$AllowedToFailFile" ] || return 1 + + name=$(sis_program_stem "$1") + + while IFS= read -r line || [ -n "$line" ]; do + + line="${line//$'\r'/}" + + case "$line" in + ''|\#*) continue ;; + esac + + if [ "$name" = "$(sis_program_stem "$line")" ]; then + + return 0 + fi + done < "$AllowedToFailFile" + + return 1 +} + # ########################################################## # command-line handling @@ -160,6 +204,15 @@ Flags/options: does not execute a build before running programs + files: + + .sis/ci_examples_allowed_to_fail.txt + optional list of example programs (one name per line; blank lines + and lines beginning with '#' are ignored) that are allowed to fail; + such a program is still executed, but a non-zero exit is reported as + anticipated and neither stops the run nor affects the exit status + + standard flags: --help @@ -247,7 +300,13 @@ if [ $status -eq 0 ]; then if [ $ListOnly -ne 0 ]; then - echo "would execute ${fClr}:" + if sis_is_allowed_to_fail "$f"; then + + echo "would execute ${fClr} (allowed to fail):" + else + + echo "would execute ${fClr}:" + fi continue fi @@ -260,11 +319,25 @@ if [ $status -eq 0 ]; then : else - status=$? + fStatus=$? + + if sis_is_allowed_to_fail "$f"; then + + echo "${SisClr_Yellow}${SisClr_Bold}anticipated failure${SisClr_None}: ${fClr} exited with status ${fStatus}; it is listed in .sis/ci_examples_allowed_to_fail.txt" + + continue + fi + + status=$fStatus break 1 fi - done < <(find "$CMakeDir" -type f \( -name 'example*' ! -name '*.md' \) \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) + done < <(find "$CMakeDir" -type f \( -name 'example*' ! -name '*.md' \) \ + ! -path '*/CMakeFiles/*' \ + ! -name '*.a' \ + ! -name '*.d' \ + ! -name '*.lib' \ + \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) if [ $NumPrograms -eq 0 ]; then diff --git a/run_all_scratch_tests.cmd b/run_all_scratch_tests.cmd index 9b05623..b5436ef 100644 --- a/run_all_scratch_tests.cmd +++ b/run_all_scratch_tests.cmd @@ -1,9 +1,13 @@ @echo off -SETLOCAL +SETLOCAL ENABLEDELAYEDEXPANSION SET SCRIPT_DIRECTORY=%~dp0 SET SCRIPT_PATH_DOC=%~n0[%~x0] +SET "ALLOWED_TO_FAIL_FILE=%SCRIPT_DIRECTORY%.sis\ci_scratch_tests_allowed_to_fail.txt" +SET "SKIP_INTERACTIVE_FILE=%SCRIPT_DIRECTORY%.sis\ci_scratch_tests_skip_interactive.txt" +SET "PROGRAM_STATUS=0" +SET "SKIP_INTERACTIVE=0" IF DEFINED SIS_CMAKE_BUILD_DIR ( @@ -35,6 +39,14 @@ Flags/options: ^ behaviour: ^ +^ + + --skip-interactive ^ + + skips programs listed in .sis\ci_scratch_tests_skip_interactive.txt ^ + + ^(GUI / speech / desktop-interactive; unsuitable for headless CI^) ^ + ^ standard flags: ^ @@ -45,8 +57,35 @@ Flags/options: ^ displays this help and terminates ^ +^ + + files: ^ + +^ + + .sis\ci_scratch_tests_allowed_to_fail.txt ^ + + optional list of scratch-test programs ^(one name per line; ^ + + lines beginning with '#' are ignored^) that are allowed to fail; ^ + + such a program is still executed, but a non-zero exit is ^ + + reported as anticipated and does not stop the run ^ + +^ + + .sis\ci_scratch_tests_skip_interactive.txt ^ + + list of scratch-test programs skipped when --skip-interactive ^ + + is given ^(one name per line; blank lines and '#' ignored^) ^ + EXIT /B 0 + ) ELSE IF /I {--skip-interactive}=={%%a} ( + + SET "SKIP_INTERACTIVE=1" ) ELSE ( ECHO "%SCRIPT_DIRECTORY%: unrecognised argument '%%a'; use --help for usage" 1>&2 @@ -55,6 +94,13 @@ Flags/options: ^ ) ) +IF "%SKIP_INTERACTIVE%"=="1" IF NOT EXIST "%SKIP_INTERACTIVE_FILE%" ( + + ECHO %SCRIPT_PATH_DOC%: --skip-interactive: skip list not found at '%SKIP_INTERACTIVE_FILE%' 1>&2 + + EXIT /B 1 +) + if NOT EXIST "%CMAKE_DIR%" ( ECHO "CMake build directory '%CMAKE_DIR%' does not exist" @@ -74,12 +120,55 @@ IF NOT DEFINED ProjectName ( ECHO Running all %ProjectName% scratch-test programs -FOR /F "usebackq" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%" ^| FINDSTR /I test.*scratch.*\.exe$`) DO ( +FOR /F "usebackq" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%" ^| FINDSTR /I test.*scratch.*\.exe$`) DO CALL :run_program "%%f" + +ENDLOCAL & EXIT /B %PROGRAM_STATUS% + + +REM ########################################################## +REM subroutines + +:run_program +IF %PROGRAM_STATUS% NEQ 0 EXIT /B 0 +CALL :is_skipped_interactive "%~1" +IF DEFINED SKIPPED_INTERACTIVE ( ECHO . - ECHO executing %%f - %%f - IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% + ECHO skipping %~1 ^(interactive; --skip-interactive^) + EXIT /B 0 ) - -ENDLOCAL +ECHO . +ECHO executing %~1 +"%~1" +SET "FAILURE_STATUS=%ERRORLEVEL%" +IF %FAILURE_STATUS% EQU 0 EXIT /B 0 +CALL :is_allowed_to_fail "%~1" +IF NOT DEFINED ALLOWED_TO_FAIL GOTO run_program_failed +ECHO anticipated failure: %~1 exited with status %FAILURE_STATUS%; it is listed in .sis\ci_scratch_tests_allowed_to_fail.txt +EXIT /B 0 +:run_program_failed +SET "PROGRAM_STATUS=%FAILURE_STATUS%" +EXIT /B 0 + +:is_allowed_to_fail +SET "ALLOWED_TO_FAIL=" +IF NOT EXIST "%ALLOWED_TO_FAIL_FILE%" EXIT /B 0 +FOR /F "usebackq eol=# tokens=1" %%n IN ("%ALLOWED_TO_FAIL_FILE%") DO CALL :match_allowed "%%n" "%~n1" "%~nx1" +EXIT /B 0 + +:match_allowed +IF /I "%~1"=="%~2" SET "ALLOWED_TO_FAIL=1" +IF /I "%~1"=="%~3" SET "ALLOWED_TO_FAIL=1" +EXIT /B 0 + +:is_skipped_interactive +SET "SKIPPED_INTERACTIVE=" +IF NOT "%SKIP_INTERACTIVE%"=="1" EXIT /B 0 +IF NOT EXIST "%SKIP_INTERACTIVE_FILE%" EXIT /B 0 +FOR /F "usebackq eol=# tokens=1" %%n IN ("%SKIP_INTERACTIVE_FILE%") DO CALL :match_skip "%%n" "%~n1" "%~nx1" +EXIT /B 0 + +:match_skip +IF /I "%~1"=="%~2" SET "SKIPPED_INTERACTIVE=1" +IF /I "%~1"=="%~3" SET "SKIPPED_INTERACTIVE=1" +EXIT /B 0 diff --git a/run_all_scratch_tests.sh b/run_all_scratch_tests.sh index 5e6659a..0250180 100755 --- a/run_all_scratch_tests.sh +++ b/run_all_scratch_tests.sh @@ -27,10 +27,13 @@ CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") ScriptPath=$0 +AllowedToFailFile="$Dir/.sis/ci_scratch_tests_allowed_to_fail.txt" +SkipInteractiveFile="$Dir/.sis/ci_scratch_tests_skip_interactive.txt" AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} ListOnly=0 RunMake=1 +SkipInteractive=0 SisUseColours=0 @@ -115,6 +118,78 @@ sis_cmake_build() { cmake "${args[@]}" } +# Reduces a program path to its (lowercase) name, without any directory or +# .exe suffix. +sis_program_stem() { + + local p="${1//\\//}" + + p="${p##*/}" + + case "$p" in + *.exe|*.EXE) p="${p%.*}" ;; + esac + + printf '%s' "$p" | tr '[:upper:]' '[:lower:]' +} + +# Succeeds if the program is named (by name or stem, case-insensitively) in +# the optional .sis/ci_scratch_tests_allowed_to_fail.txt file; blank lines +# and lines beginning with '#' are ignored. +sis_is_allowed_to_fail() { + + local name line + + [ -f "$AllowedToFailFile" ] || return 1 + + name=$(sis_program_stem "$1") + + while IFS= read -r line || [ -n "$line" ]; do + + line="${line//$'\r'/}" + + case "$line" in + ''|\#*) continue ;; + esac + + if [ "$name" = "$(sis_program_stem "$line")" ]; then + + return 0 + fi + done < "$AllowedToFailFile" + + return 1 +} + +# Succeeds if --skip-interactive is active and the program is named in +# .sis/ci_scratch_tests_skip_interactive.txt (GUI / speech / similar). +sis_is_skipped_interactive() { + + local name line + + [ $SkipInteractive -ne 0 ] || return 1 + + [ -f "$SkipInteractiveFile" ] || return 1 + + name=$(sis_program_stem "$1") + + while IFS= read -r line || [ -n "$line" ]; do + + line="${line//$'\r'/}" + + case "$line" in + ''|\#*) continue ;; + esac + + if [ "$name" = "$(sis_program_stem "$line")" ]; then + + return 0 + fi + done < "$SkipInteractiveFile" + + return 1 +} + # ########################################################## # command-line handling @@ -134,6 +209,10 @@ while [[ $# -gt 0 ]]; do RunMake=0 ;; + --skip-interactive) + + SkipInteractive=1 + ;; --help) [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" @@ -159,6 +238,25 @@ Flags/options: --no-make does not execute a build before running programs + --skip-interactive + skips programs listed in .sis/ci_scratch_tests_skip_interactive.txt + (GUI / speech / desktop-interactive programs unsuitable for headless + CI; principally Windows MessageBox and speech sinks) + + + files: + + .sis/ci_scratch_tests_allowed_to_fail.txt + optional list of scratch-test programs (one name per line; blank + lines and lines beginning with '#' are ignored) that are allowed to + fail; such a program is still executed, but a non-zero exit is + reported as anticipated and neither stops the run nor affects the + exit status + + .sis/ci_scratch_tests_skip_interactive.txt + list of scratch-test programs skipped when --skip-interactive is + given (one name per line; blank lines and '#' comments ignored) + standard flags: @@ -180,6 +278,13 @@ EOF shift done +if [ $SkipInteractive -ne 0 ] && [ ! -f "$SkipInteractiveFile" ]; then + + >&2 echo "${ScriptPath}: --skip-interactive: skip list not found at '$SkipInteractiveFile'" + + exit 1 +fi + # ########################################################## # main() @@ -241,9 +346,29 @@ if [ $status -eq 0 ]; then fClr="${SisClr_Blue}${SisClr_Bold}${f}${SisClr_None}" + if sis_is_skipped_interactive "$f"; then + + if [ $ListOnly -ne 0 ]; then + + echo "would skip ${fClr} (interactive; --skip-interactive)" + else + + echo + echo "skipping ${fClr} (interactive; --skip-interactive)" + fi + + continue + fi + if [ $ListOnly -ne 0 ]; then - echo "would execute ${fClr}:" + if sis_is_allowed_to_fail "$f"; then + + echo "would execute ${fClr} (allowed to fail):" + else + + echo "would execute ${fClr}:" + fi continue fi @@ -256,11 +381,26 @@ if [ $status -eq 0 ]; then : else - status=$? + fStatus=$? + + if sis_is_allowed_to_fail "$f"; then + + echo "${SisClr_Yellow}${SisClr_Bold}anticipated failure${SisClr_None}: ${fClr} exited with status ${fStatus}; it is listed in .sis/ci_scratch_tests_allowed_to_fail.txt" + + continue + fi + + status=$fStatus break 1 fi - done < <(find "$CMakeDir" -type f \( -name 'test_scratch*' -o -name 'test.scratch.*' \) \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) + done < <(find "$CMakeDir" -type f \( -name 'test_scratch*' -o -name 'test.scratch.*' \) \ + ! -path '*/CMakeFiles/*' \ + ! -name '*.a' \ + ! -name '*.d' \ + ! -name '*.lib' \ + ! -name '*.log' \ + \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) if [ $NumPrograms -eq 0 ]; then diff --git a/run_all_unit_tests.sh b/run_all_unit_tests.sh index 301ccae..c7250bd 100755 --- a/run_all_unit_tests.sh +++ b/run_all_unit_tests.sh @@ -282,7 +282,12 @@ if [ $status -eq 0 ]; then break 1 fi - done < <(find "$CMakeDir" -type f \( -name 'test_unit*' -o -name 'test.unit.*' \) \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) + done < <(find "$CMakeDir" -type f \( -name 'test_unit*' -o -name 'test.unit.*' \) \ + ! -path '*/CMakeFiles/*' \ + ! -name '*.a' \ + ! -name '*.d' \ + ! -name '*.lib' \ + \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) if [ $NumPrograms -eq 0 ]; then