From 176cb20930afbf96fbe4ac95ac2dc28fe43d2682 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Fri, 2 Jun 2023 00:23:43 +0200
Subject: [PATCH] git subrepo pull packages/CLI11

subrepo:
  subdir:   "packages/CLI11"
  merged:   "784fa3ebd"
upstream:
  origin:   "git@github.com:CLIUtils/CLI11.git"
  branch:   "main"
  commit:   "784fa3ebd"
git-subrepo:
  version:  "0.4.6"
  origin:   "git@github.com:ingydotnet/git-subrepo.git"
  commit:   "110b9eb"
---
 packages/CLI11/.appveyor.yml                  |  38 ----
 packages/CLI11/.codecov.yml                   |   4 +
 packages/CLI11/.github/CONTRIBUTING.md        |  13 --
 .../.github/actions/quick_cmake/action.yml    |   2 +-
 packages/CLI11/.github/codecov.yml            |   2 +-
 packages/CLI11/.github/dependabot.yml         |   4 +-
 packages/CLI11/.github/workflows/fuzz.yml     |  54 ++++++
 packages/CLI11/.github/workflows/tests.yml    |  99 +++++++---
 packages/CLI11/.gitignore                     |   5 +
 packages/CLI11/.gitrepo                       |   6 +-
 packages/CLI11/.pre-commit-config.yaml        |  19 +-
 packages/CLI11/CHANGELOG.md                   |  70 +++++++
 packages/CLI11/CLI11.hpp.in                   |  14 +-
 packages/CLI11/CMakeLists.txt                 |  11 +-
 packages/CLI11/CPPLINT.cfg                    |   1 +
 packages/CLI11/LICENSE                        |   2 +-
 packages/CLI11/README.md                      | 157 +++++++++++++--
 packages/CLI11/azure-pipelines.yml            |  26 +--
 packages/CLI11/book/chapters/config.md        |   4 +
 packages/CLI11/book/chapters/internals.md     |   4 +-
 packages/CLI11/conanfile.py                   |  49 -----
 .../CLI11/examples/callback_passthrough.cpp   |   2 +-
 packages/CLI11/examples/config_app.cpp        |   2 +-
 packages/CLI11/examples/custom_parse.cpp      |   2 +-
 packages/CLI11/examples/digit_args.cpp        |   2 +-
 packages/CLI11/examples/enum.cpp              |   2 +-
 packages/CLI11/examples/enum_ostream.cpp      |   2 +-
 packages/CLI11/examples/formatter.cpp         |   2 +-
 packages/CLI11/examples/groups.cpp            |   2 +-
 .../CLI11/examples/inter_argument_order.cpp   |   2 +-
 packages/CLI11/examples/modhelp.cpp           |   2 +-
 packages/CLI11/examples/nested.cpp            |   2 +-
 packages/CLI11/examples/option_groups.cpp     |   2 +-
 packages/CLI11/examples/positional_arity.cpp  |   2 +-
 .../CLI11/examples/positional_validation.cpp  |   2 +-
 packages/CLI11/examples/prefix_command.cpp    |   2 +-
 packages/CLI11/examples/ranges.cpp            |   2 +-
 packages/CLI11/examples/retired.cpp           |   2 +-
 packages/CLI11/examples/shapes.cpp            |   2 +-
 packages/CLI11/examples/simple.cpp            |   2 +-
 packages/CLI11/examples/subcom_help.cpp       |   2 +-
 .../examples/subcom_in_files/subcommand_a.cpp |   2 +-
 .../examples/subcom_in_files/subcommand_a.hpp |   2 +-
 .../subcom_in_files/subcommand_main.cpp       |   2 +-
 .../CLI11/examples/subcom_partitioned.cpp     |   2 +-
 packages/CLI11/examples/subcommands.cpp       |   2 +-
 packages/CLI11/examples/testEXE.cpp           |   2 +-
 packages/CLI11/examples/validators.cpp        |   2 +-
 packages/CLI11/fuzz/CMakeLists.txt            |  48 +++++
 packages/CLI11/fuzz/cli11_app_fuzz.cpp        |  30 +++
 packages/CLI11/fuzz/cli11_file_fuzz.cpp       |  31 +++
 packages/CLI11/fuzz/fuzzApp.cpp               |  85 ++++++++
 packages/CLI11/fuzz/fuzzApp.hpp               |  92 +++++++++
 packages/CLI11/fuzz/fuzzCommand.cpp           |  24 +++
 packages/CLI11/fuzz/fuzz_dictionary1.txt      |  34 ++++
 packages/CLI11/fuzz/fuzz_dictionary2.txt      |  37 ++++
 packages/CLI11/include/CLI/App.hpp            |  63 ++++--
 packages/CLI11/include/CLI/Argv.hpp           |  25 +++
 packages/CLI11/include/CLI/CLI.hpp            |   6 +-
 packages/CLI11/include/CLI/Config.hpp         |   4 +-
 packages/CLI11/include/CLI/ConfigFwd.hpp      |   4 +-
 packages/CLI11/include/CLI/Encoding.hpp       |  54 ++++++
 packages/CLI11/include/CLI/Error.hpp          |   2 +-
 packages/CLI11/include/CLI/Formatter.hpp      |   2 +-
 packages/CLI11/include/CLI/FormatterFwd.hpp   |   6 +-
 packages/CLI11/include/CLI/Macros.hpp         |  58 +++++-
 packages/CLI11/include/CLI/Option.hpp         |   2 +-
 packages/CLI11/include/CLI/Split.hpp          |   2 +-
 packages/CLI11/include/CLI/StringTools.hpp    |   2 +-
 packages/CLI11/include/CLI/Timer.hpp          |   2 +-
 packages/CLI11/include/CLI/TypeTools.hpp      | 179 +++++++++++++----
 packages/CLI11/include/CLI/Validators.hpp     |  56 ++----
 packages/CLI11/include/CLI/Version.hpp        |   8 +-
 packages/CLI11/include/CLI/impl/App_inl.hpp   | 164 ++++++++++++++--
 packages/CLI11/include/CLI/impl/Argv_inl.hpp  | 183 ++++++++++++++++++
 .../CLI11/include/CLI/impl/Config_inl.hpp     |   8 +-
 .../CLI11/include/CLI/impl/Encoding_inl.hpp   | 154 +++++++++++++++
 .../CLI11/include/CLI/impl/Formatter_inl.hpp  |  20 +-
 .../CLI11/include/CLI/impl/Option_inl.hpp     |   2 +-
 packages/CLI11/include/CLI/impl/Split_inl.hpp |   4 +-
 .../include/CLI/impl/StringTools_inl.hpp      |   2 +-
 .../CLI11/include/CLI/impl/Validators_inl.hpp |  10 +-
 packages/CLI11/scripts/MakeSingleHeader.py    |   4 +-
 packages/CLI11/scripts/mdlint_style.rb        |   1 +
 packages/CLI11/src/CMakeLists.txt             |  60 +++---
 packages/CLI11/src/Precompile.cpp             |   4 +-
 packages/CLI11/test_package/CMakeLists.txt    |  16 --
 packages/CLI11/test_package/conanfile.py      |  21 --
 packages/CLI11/test_package/example.cpp       |  20 --
 packages/CLI11/tests/AppTest.cpp              |  98 +++++++++-
 packages/CLI11/tests/BoostOptionTypeTest.cpp  |   2 +-
 packages/CLI11/tests/CMakeLists.txt           |  80 +++++++-
 packages/CLI11/tests/ComplexTypeTest.cpp      |   4 +-
 packages/CLI11/tests/ConfigFileTest.cpp       | 137 ++++++++++++-
 packages/CLI11/tests/CreationTest.cpp         |  24 ++-
 packages/CLI11/tests/DeprecatedTest.cpp       |   4 +-
 packages/CLI11/tests/EncodingTest.cpp         | 104 ++++++++++
 packages/CLI11/tests/FormatterTest.cpp        |  14 +-
 packages/CLI11/tests/FuzzFailTest.cpp         |  37 ++++
 packages/CLI11/tests/HelpTest.cpp             |  55 +++++-
 packages/CLI11/tests/HelpersTest.cpp          |  12 +-
 packages/CLI11/tests/NewParseTest.cpp         | 147 ++++++++++++--
 packages/CLI11/tests/OptionGroupTest.cpp      |  10 +-
 packages/CLI11/tests/OptionTypeTest.cpp       | 112 ++++++++++-
 packages/CLI11/tests/OptionalTest.cpp         |   2 +-
 packages/CLI11/tests/SetTest.cpp              |  19 +-
 packages/CLI11/tests/SimpleTest.cpp           |   2 +-
 packages/CLI11/tests/StringParseTest.cpp      |   2 +-
 packages/CLI11/tests/SubcommandTest.cpp       | 152 ++++++++++++++-
 packages/CLI11/tests/TimerTest.cpp            |   4 +-
 packages/CLI11/tests/TransformTest.cpp        |   2 +-
 packages/CLI11/tests/TrueFalseTest.cpp        |   2 +-
 packages/CLI11/tests/WindowsTest.cpp          |   2 +-
 packages/CLI11/tests/app_helper.hpp           |  56 ++++++
 .../CLI11/tests/applications/system_args.cpp  |  22 +++
 packages/CLI11/tests/catch.hpp                |  24 ++-
 packages/CLI11/tests/data/unicode.txt         |   1 +
 packages/CLI11/tests/fuzzFail/fuzz_app_fail1  | Bin 0 -> 41 bytes
 packages/CLI11/tests/fuzzFail/fuzz_app_fail2  |   1 +
 packages/CLI11/tests/informational.cpp        |   2 +-
 packages/CLI11/tests/link_test_1.cpp          |   2 +-
 packages/CLI11/tests/link_test_2.cpp          |   2 +-
 packages/CLI11/tests/main.cpp                 |   2 +-
 packages/CLI11/tests/meson.build              |  41 +++-
 packages/CLI11/tests/mesonTest/main.cpp       |   2 +-
 125 files changed, 2830 insertions(+), 519 deletions(-)
 delete mode 100644 packages/CLI11/.appveyor.yml
 create mode 100644 packages/CLI11/.github/workflows/fuzz.yml
 delete mode 100644 packages/CLI11/conanfile.py
 create mode 100644 packages/CLI11/fuzz/CMakeLists.txt
 create mode 100644 packages/CLI11/fuzz/cli11_app_fuzz.cpp
 create mode 100644 packages/CLI11/fuzz/cli11_file_fuzz.cpp
 create mode 100644 packages/CLI11/fuzz/fuzzApp.cpp
 create mode 100644 packages/CLI11/fuzz/fuzzApp.hpp
 create mode 100644 packages/CLI11/fuzz/fuzzCommand.cpp
 create mode 100644 packages/CLI11/fuzz/fuzz_dictionary1.txt
 create mode 100644 packages/CLI11/fuzz/fuzz_dictionary2.txt
 create mode 100644 packages/CLI11/include/CLI/Argv.hpp
 create mode 100644 packages/CLI11/include/CLI/Encoding.hpp
 create mode 100644 packages/CLI11/include/CLI/impl/Argv_inl.hpp
 create mode 100644 packages/CLI11/include/CLI/impl/Encoding_inl.hpp
 delete mode 100644 packages/CLI11/test_package/CMakeLists.txt
 delete mode 100644 packages/CLI11/test_package/conanfile.py
 delete mode 100644 packages/CLI11/test_package/example.cpp
 create mode 100644 packages/CLI11/tests/EncodingTest.cpp
 create mode 100644 packages/CLI11/tests/FuzzFailTest.cpp
 create mode 100644 packages/CLI11/tests/applications/system_args.cpp
 create mode 100644 packages/CLI11/tests/data/unicode.txt
 create mode 100644 packages/CLI11/tests/fuzzFail/fuzz_app_fail1
 create mode 100644 packages/CLI11/tests/fuzzFail/fuzz_app_fail2

diff --git a/packages/CLI11/.appveyor.yml b/packages/CLI11/.appveyor.yml
deleted file mode 100644
index 56b090cd8..000000000
--- a/packages/CLI11/.appveyor.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-version: 2.2.0.{build}
-
-branches:
-  only:
-    - main
-    - v1
-
-install:
-  - git submodule update --init --recursive
-  - py -3 --version
-  - set PATH=C:\Python38-x64;C:\Python38-x64\Scripts;%PATH%
-  - cmake --version
-  - python --version
-  - python -m pip --version
-  - python -m pip install conan
-  - conan user
-  - conan --version
-
-build_script:
-  - mkdir build
-  - cd build
-  - ps:
-      cmake .. -DCLI11_WARNINGS_AS_ERRORS=ON -DCLI11_SINGLE_FILE_TESTS=ON
-      -DCMAKE_BUILD_TYPE=Debug -DCMAKE_GENERATOR="Visual Studio 14 2015"
-  - ps: cmake --build .
-  - cd ..
-  - conan create . CLIUtils/CLI11
-
-test_script:
-  - cd build
-  - ps: ctest --output-on-failure -C Debug
-
-notifications:
-  - provider: Webhook
-    url: https://webhooks.gitter.im/e/0185e91c5d989a476d7b
-    on_build_success: false
-    on_build_failure: true
-    on_build_status_changed: true
diff --git a/packages/CLI11/.codecov.yml b/packages/CLI11/.codecov.yml
index 185bbad3f..61c2e2f21 100644
--- a/packages/CLI11/.codecov.yml
+++ b/packages/CLI11/.codecov.yml
@@ -1,3 +1,7 @@
 ignore:
   - "tests"
   - "examples"
+  - "book"
+  - "docs"
+  - "test_package"
+  - "fuzz"
diff --git a/packages/CLI11/.github/CONTRIBUTING.md b/packages/CLI11/.github/CONTRIBUTING.md
index 7d376345b..93b7651cc 100644
--- a/packages/CLI11/.github/CONTRIBUTING.md
+++ b/packages/CLI11/.github/CONTRIBUTING.md
@@ -60,19 +60,6 @@ name, pre-commit):
 pre-commit install
 ```
 
-## For developers releasing to Conan.io
-
-This is now done by the CI system on tagged releases. Previously, the steps to
-make a Conan.io release were:
-
-```bash
-conan remove '*' # optional, I like to be clean
-conan create . cliutils/stable
-conan upload "*" -r cli11 --all
-```
-
-Here I've assumed that the remote is `cli11`.
-
 ## For maintainers: remember to add contributions
 
 In a commit to a PR, just add
diff --git a/packages/CLI11/.github/actions/quick_cmake/action.yml b/packages/CLI11/.github/actions/quick_cmake/action.yml
index 811f73fe2..8359fb0d0 100644
--- a/packages/CLI11/.github/actions/quick_cmake/action.yml
+++ b/packages/CLI11/.github/actions/quick_cmake/action.yml
@@ -13,7 +13,7 @@ runs:
   using: composite
   steps:
     - name: CMake ${{ inputs.cmake-version }}
-      uses: jwlawson/actions-setup-cmake@v1.12
+      uses: jwlawson/actions-setup-cmake@v1.13
       with:
         cmake-version: "${{ inputs.cmake-version }}"
     - run: |
diff --git a/packages/CLI11/.github/codecov.yml b/packages/CLI11/.github/codecov.yml
index a0b066745..0e106f710 100644
--- a/packages/CLI11/.github/codecov.yml
+++ b/packages/CLI11/.github/codecov.yml
@@ -1,6 +1,6 @@
 codecov:
   notify:
-    after_n_builds: 4
+    after_n_builds: 8
 coverage:
   status:
     project:
diff --git a/packages/CLI11/.github/dependabot.yml b/packages/CLI11/.github/dependabot.yml
index 2c7d17083..f265d88d9 100644
--- a/packages/CLI11/.github/dependabot.yml
+++ b/packages/CLI11/.github/dependabot.yml
@@ -4,4 +4,6 @@ updates:
   - package-ecosystem: "github-actions"
     directory: "/"
     schedule:
-      interval: "daily"
+      interval: "weekly"
+    target-branch: "main"
+    open-pull-requests-limit: 10
diff --git a/packages/CLI11/.github/workflows/fuzz.yml b/packages/CLI11/.github/workflows/fuzz.yml
new file mode 100644
index 000000000..75d161b38
--- /dev/null
+++ b/packages/CLI11/.github/workflows/fuzz.yml
@@ -0,0 +1,54 @@
+name: Fuzz
+on:
+  workflow_dispatch:
+  push:
+    branches:
+      - main
+      - v*
+  pull_request:
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  quick_fuzz1:
+    name: quickfuzz1
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          fetch-depth: 0
+
+      - name: Configure
+        run: |
+          cmake -S . -B build \
+            -DCMAKE_CXX_STANDARD=17 \
+            -DCLI11_SINGLE_FILE_TESTS=OFF \
+            -DCLI11_BUILD_EXAMPLES=OFF \
+            -DCLI11_FUZZ_TARGET=ON \
+            -DCLI11_BUILD_TESTS=OFF \
+            -DCLI11_BUILD_DOCS=OFF \
+            -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_COMPILER_FORCED=ON \
+            -DCMAKE_CXX_FLAGS="-g -O1 -fsanitize=fuzzer,undefined,address"
+
+      - name: Build
+        run: cmake --build build -j4
+
+      - name: Test
+        run: |
+          cd build
+          make QUICK_CLI11_APP_FUZZ
+
+      - name: Test2
+        run: |
+          cd build
+          make QUICK_CLI11_FILE_FUZZ
+
+
+      - name: artifacts
+        if: failure()
+        uses: actions/upload-artifact@v3
+        with:
+          name: file_failure
+          path: ./build/fuzz/cli11_*_fail_artifact.txt
diff --git a/packages/CLI11/.github/workflows/tests.yml b/packages/CLI11/.github/workflows/tests.yml
index a0b9e6c81..2ab5a6669 100644
--- a/packages/CLI11/.github/workflows/tests.yml
+++ b/packages/CLI11/.github/workflows/tests.yml
@@ -20,6 +20,8 @@ jobs:
         precompile: ["ON", "OFF"]
     steps:
       - uses: actions/checkout@v3
+        with:
+          fetch-depth: 0
 
       - name: Get LCov
         run: |
@@ -46,16 +48,15 @@ jobs:
       - name: Prepare coverage
         run: |
           lcov --directory . --capture --output-file coverage.info
-          lcov --remove coverage.info '*/tests/*' '*/examples/*' '/usr/*' --output-file coverage.info
+          lcov --remove coverage.info '*/tests/*' '*/examples/*' '/usr/*' '*/book/*' '*/fuzz/*' --output-file coverage.info
           lcov --list coverage.info
         working-directory: build
 
-      - name: Upload coverage
-        run: |
-          curl -Os https://uploader.codecov.io/latest/linux/codecov
-          chmod +x codecov
-          ./codecov
-        working-directory: build
+      - uses: codecov/codecov-action@v3
+        with:
+          files: build/coverage.info
+          fail_ci_if_error: true
+          functionalities: fixes
 
   clang-tidy:
     name: Clang-Tidy
@@ -73,18 +74,31 @@ jobs:
       - name: Build
         run: cmake --build build -j4 -- --keep-going
 
-  cuda-build:
-    name: CUDA build only
+  cuda11-build:
+    name: CUDA 11 build only
     runs-on: ubuntu-latest
-    container: nvidia/cuda:10.2-devel-ubuntu18.04
+    container: nvidia/cuda:11.8.0-devel-ubuntu22.04
     steps:
-      - uses: actions/checkout@v1
+      - name: Add build tools
+        run: apt-get update && apt-get install -y wget git cmake
+      - uses: actions/checkout@v3
+        with:
+          submodules: true
+      - name: Configure
+        run: cmake -S . -B build -DCLI11_CUDA_TESTS=ON
+      - name: Build
+        run: cmake --build build -j2
+
+  cuda12-build:
+    name: CUDA 12 build only
+    runs-on: ubuntu-latest
+    container: nvidia/cuda:12.1.0-devel-ubuntu22.04
+    steps:
+      - name: Add build tools
+        run: apt-get update && apt-get install -y wget git cmake
+      - uses: actions/checkout@v3
         with:
           submodules: true
-      - name: Add wget
-        run: apt-get update && apt-get install -y wget
-      - name: Get cmake
-        uses: jwlawson/actions-setup-cmake@v1.12
       - name: Configure
         run: cmake -S . -B build -DCLI11_CUDA_TESTS=ON
       - name: Build
@@ -92,16 +106,15 @@ jobs:
 
   boost-build:
     name: Boost build
-    runs-on: ubuntu-latest
-    container: zouzias/boost:1.76.0
+    runs-on: ubuntu-20.04
     steps:
-      - uses: actions/checkout@v1
+      - uses: actions/checkout@v3
         with:
           submodules: true
-      - name: Add deps
-        run: apt-get update && apt-get install make
-      - name: Get CMake
-        uses: jwlawson/actions-setup-cmake@v1.12
+      - name: Add boost
+        run: sudo apt-get update && sudo apt-get install -y libboost-dev
+      # NOTE: If a boost version matching all requirements cannot be found,
+      # this build step will fail
       - name: Configure
         run: cmake -S . -B build -DCLI11_BOOST=ON
       - name: Build
@@ -127,9 +140,9 @@ jobs:
       - name: Build
         run: meson compile -C build-meson
 
-  cmake-config:
-    name: CMake config check
-    runs-on: ubuntu-latest
+  cmake-config-ubuntu-1804:
+    name: CMake config check (Ubuntu 18.04)
+    runs-on: ubuntu-18.04
     steps:
       - uses: actions/checkout@v3
 
@@ -174,6 +187,12 @@ jobs:
           cmake-version: "3.10"
         if: success() || failure()
 
+  cmake-config-ubuntu-2004:
+    name: CMake config check (Ubuntu 20.04)
+    runs-on: ubuntu-20.04
+    steps:
+      - uses: actions/checkout@v3
+
       - name: Check CMake 3.11 (full)
         uses: ./.github/actions/quick_cmake
         with:
@@ -211,6 +230,12 @@ jobs:
           cmake-version: "3.16"
         if: success() || failure()
 
+  cmake-config-ubuntu-2204:
+    name: CMake config check (Ubuntu 22.04)
+    runs-on: ubuntu-22.04
+    steps:
+      - uses: actions/checkout@v3
+
       - name: Check CMake 3.17
         uses: ./.github/actions/quick_cmake
         with:
@@ -235,16 +260,34 @@ jobs:
           cmake-version: "3.20"
         if: success() || failure()
 
-      - name: Check CMake 3.21 (full)
+      - name: Check CMake 3.21
         uses: ./.github/actions/quick_cmake
         with:
           cmake-version: "3.21"
-          args: -DCLI11_SANITIZERS=ON -DCLI11_BUILD_EXAMPLES_JSON=ON
         if: success() || failure()
 
-      - name: Check CMake 3.22 (full)
+      - name: Check CMake 3.22
         uses: ./.github/actions/quick_cmake
         with:
           cmake-version: "3.22"
+        if: success() || failure()
+
+      - name: Check CMake 3.23 
+        uses: ./.github/actions/quick_cmake
+        with:
+          cmake-version: "3.23"
+        if: success() || failure()
+
+      - name: Check CMake 3.24 (full)
+        uses: ./.github/actions/quick_cmake
+        with:
+          cmake-version: "3.24"
+          args: -DCLI11_SANITIZERS=ON -DCLI11_BUILD_EXAMPLES_JSON=ON
+        if: success() || failure()
+
+      - name: Check CMake 3.25 (full)
+        uses: ./.github/actions/quick_cmake
+        with:
+          cmake-version: "3.25"
           args: -DCLI11_SANITIZERS=ON -DCLI11_BUILD_EXAMPLES_JSON=ON
         if: success() || failure()
diff --git a/packages/CLI11/.gitignore b/packages/CLI11/.gitignore
index cc1b9d0c7..7b9bcb27f 100644
--- a/packages/CLI11/.gitignore
+++ b/packages/CLI11/.gitignore
@@ -6,10 +6,15 @@ a.out*
 /CMakeFiles/*
 /cmake_install.cmake
 /*.kdev4
+/.vscode
 /html/*
 !/meson.build
+/CMakeUserPresets.json
 
 /node_modules/*
 /package.json
 /yarn.lock
 /CLI11.hpp
+
+/subprojects/Catch2-*
+/subprojects/packagecache
diff --git a/packages/CLI11/.gitrepo b/packages/CLI11/.gitrepo
index 9d9e10f1c..925d8dcce 100644
--- a/packages/CLI11/.gitrepo
+++ b/packages/CLI11/.gitrepo
@@ -6,7 +6,7 @@
 [subrepo]
 	remote = git@github.com:CLIUtils/CLI11.git
 	branch = main
-	commit = faea921e4004af91763b8fde905de3baf24d3945
-	parent = 8a1fd5ded4230d6e9b9bf69951058fc12a19ad4a
+	commit = 784fa3ebd387e63feef41d174f587bbe4cfec4da
+	parent = 164bbb3a73dc902c29aa7ccabfaba50cefa6345d
 	method = merge
-	cmdver = 0.4.3
+	cmdver = 0.4.6
diff --git a/packages/CLI11/.pre-commit-config.yaml b/packages/CLI11/.pre-commit-config.yaml
index 0d6d0c011..febf04dd2 100644
--- a/packages/CLI11/.pre-commit-config.yaml
+++ b/packages/CLI11/.pre-commit-config.yaml
@@ -1,27 +1,32 @@
+exclude: ^(.github/workflows/|docs/img/)
 ci:
   autoupdate_commit_msg: "chore(deps): pre-commit.ci autoupdate"
   autofix_commit_msg: "style: pre-commit.ci fixes"
 
 repos:
   - repo: https://github.com/psf/black
-    rev: 22.6.0
+    rev: 23.3.0
     hooks:
       - id: black
 
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.3.0
+    rev: v4.4.0
     hooks:
       - id: check-added-large-files
       - id: check-case-conflict
       - id: check-merge-conflict
       - id: check-symlinks
       - id: check-yaml
+      - id: check-toml
       - id: end-of-file-fixer
       - id: mixed-line-ending
       - id: trailing-whitespace
+      - id: check-shebang-scripts-are-executable
+      - id: check-executables-have-shebangs
+      - id: debug-statements
 
   - repo: https://github.com/pre-commit/mirrors-clang-format
-    rev: v14.0.6
+    rev: v16.0.3
     hooks:
       - id: clang-format
         types_or: [c++, c, cuda]
@@ -33,17 +38,19 @@ repos:
         additional_dependencies: [pyyaml]
 
   - repo: https://github.com/pre-commit/mirrors-prettier
-    rev: "v2.7.1"
+    rev: "v3.0.0-alpha.9-for-vscode"
     hooks:
       - id: prettier
         types_or: [yaml, markdown, html, css, scss, javascript, json]
         args: [--prose-wrap=always]
 
   - repo: https://github.com/markdownlint/markdownlint
-    rev: v0.11.0
+    rev: v0.12.0
     hooks:
       - id: markdownlint
         args: ["--style=scripts/mdlint_style.rb"]
+        # Uncomment on macOS - Apple has deprecated Ruby, so macOS is stuck on 2.6
+        # language_version: 3.1.2
 
   # - repo: local
   #   hooks:
@@ -80,7 +87,7 @@ repos:
         exclude: .pre-commit-config.yaml
 
   - repo: https://github.com/codespell-project/codespell
-    rev: v2.1.0
+    rev: v2.2.4
     hooks:
       - id: codespell
         args: ["-L", "atleast,ans,doub,inout"]
diff --git a/packages/CLI11/CHANGELOG.md b/packages/CLI11/CHANGELOG.md
index 04b9cd2a9..4fc3ccdd1 100644
--- a/packages/CLI11/CHANGELOG.md
+++ b/packages/CLI11/CHANGELOG.md
@@ -1,5 +1,75 @@
 # Changelog
 
+## Version 2.3: Precompilation Support
+
+This version adds a pre-compiled mode to CLI11, which allows you to precompile
+the library, saving time on incremental rebuilds, making CLI11 more competitive
+on compile time with classic compiled CLI libraries. The header-only mode is
+still default, and is not yet distributed via binaries.
+
+- Add `CLI11_PRECOMPILED` as an option. [#762][]
+- Bugfix: Include `<functional>` in `FormatterFwd` [#727][]
+- Bugfix: Add missing `Macros.hpp` to `Error.hpp` [#755][]
+- Bugfix: Fix subcommand callback trigger [#733][]
+- Bugfix: Variable rename to avoid warning [#734][]
+- Bugfix: `split_program_name` single file name error [#740][]
+- Bugfix: Better support for min/max overrides on MSVC [#741][]
+- Bugfix: Support MSVC 2022 [#748][]
+- Bugfix: Support negated flag in config file [#775][]
+- Bugfix: Better errors for some confusing config file situations [#781][]
+- Backend: Restore coverage testing (lost with Travis CI) [#747][]
+
+[#727]: https://github.com/CLIUtils/CLI11/pull/727
+[#733]: https://github.com/CLIUtils/CLI11/pull/733
+[#734]: https://github.com/CLIUtils/CLI11/pull/734
+[#740]: https://github.com/CLIUtils/CLI11/pull/740
+[#741]: https://github.com/CLIUtils/CLI11/pull/741
+[#747]: https://github.com/CLIUtils/CLI11/pull/747
+[#748]: https://github.com/CLIUtils/CLI11/pull/748
+[#755]: https://github.com/CLIUtils/CLI11/pull/755
+[#762]: https://github.com/CLIUtils/CLI11/pull/762
+[#775]: https://github.com/CLIUtils/CLI11/pull/775
+[#781]: https://github.com/CLIUtils/CLI11/pull/781
+
+### Version 2.3.1: Missing implementation
+
+A function implementation was missing after the pre-compile move, missed due to
+the fact we lost 100% after losing coverage checking. We are working on filling
+out 100% coverage again to ensure this doesn't happen again!
+
+- Bugfix: `App::get_option_group` implementation missing [#793][]
+- Bugfix: Fix spacing when setting an empty footer [#796][]
+- Bugfix: Address Klocwork static analysis checking issues [#785][]
+
+[#785]: https://github.com/CLIUtils/CLI11/pull/785
+[#793]: https://github.com/CLIUtils/CLI11/pull/793
+[#796]: https://github.com/CLIUtils/CLI11/pull/796
+
+### Version 2.3.2: Minor maintenance
+
+This version provides a few fixes collected over the last three months before
+adding features for 2.4.
+
+- Bugfix: Consistently use ADL for `lexical_cast`, making it easier to extend
+  for custom template types [#820][]
+- Bugfix: Tweak the parsing of files for flags with `disable_flag_override`
+  [#800][]
+- Bugfix: Handle out of bounds long long [#807][]
+- Bugfix: Spacing of `make_description` min option output [#808][]
+- Bugfix: Print last parsed subcommand's help message [#822][]
+- Bugfix: Avoid floating point warning in GCC 12 [#803][]
+- Bugfix: Fix a few gcc warnings [#813][]
+- Backend: Max CMake tested 3.22 -> 3.24 [#823][]
+
+[#800]: https://github.com/CLIUtils/CLI11/pull/800
+[#803]: https://github.com/CLIUtils/CLI11/pull/803
+[#807]: https://github.com/CLIUtils/CLI11/pull/807
+[#808]: https://github.com/CLIUtils/CLI11/pull/808
+[#813]: https://github.com/CLIUtils/CLI11/pull/813
+[#820]: https://github.com/CLIUtils/CLI11/pull/820
+[#822]: https://github.com/CLIUtils/CLI11/pull/822
+[#823]: https://github.com/CLIUtils/CLI11/pull/823
+
 ## Version 2.2: Option and Configuration Flexibility
 
 New features include support for output of an empty vector, a summing option
diff --git a/packages/CLI11/CLI11.hpp.in b/packages/CLI11/CLI11.hpp.in
index 83f228ebf..edc16bb15 100644
--- a/packages/CLI11/CLI11.hpp.in
+++ b/packages/CLI11/CLI11.hpp.in
@@ -5,7 +5,7 @@
 // This is a standalone header file generated by MakeSingleHeader.py in CLI11/scripts
 // from: {git}
 //
-// CLI11 {version} Copyright (c) 2017-2022 University of Cincinnati, developed by Henry
+// CLI11 {version} Copyright (c) 2017-2023 University of Cincinnati, developed by Henry
 // Schreiner under NSF AWARD 1414736. All rights reserved.
 //
 // Redistribution and use in source and binary forms of CLI11, with or without
@@ -42,8 +42,20 @@
 
 {validators_hpp_filesystem}
 
+{encoding_includes}
+
+{argv_inl_includes}
+
 namespace {namespace} {{
 
+{encoding_hpp}
+
+{encoding_inl_hpp}
+
+{argv_hpp}
+
+{argv_inl_hpp}
+
 {string_tools_hpp}
 
 {string_tools_inl_hpp}
diff --git a/packages/CLI11/CMakeLists.txt b/packages/CLI11/CMakeLists.txt
index 31bbbbb6c..cdc2011d8 100644
--- a/packages/CLI11/CMakeLists.txt
+++ b/packages/CLI11/CMakeLists.txt
@@ -2,14 +2,14 @@ cmake_minimum_required(VERSION 3.4)
 # Note: this is a header only library. If you have an older CMake than 3.4,
 # just add the CLI11/include directory and that's all you need to do.
 
-# Make sure users don't get warnings on a tested (3.4 to 3.22) version
+# Make sure users don't get warnings on a tested (3.4 to 3.24) version
 # of CMake. For most of the policies, the new version is better (hence the change).
-# We don't use the 3.4...3.21 syntax because of a bug in an older MSVC's
+# We don't use the 3.4...3.24 syntax because of a bug in an older MSVC's
 # built-in and modified CMake 3.11
-if(${CMAKE_VERSION} VERSION_LESS 3.22)
+if(${CMAKE_VERSION} VERSION_LESS 3.25)
   cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
 else()
-  cmake_policy(VERSION 3.22)
+  cmake_policy(VERSION 3.25)
 endif()
 
 set(VERSION_REGEX "#define CLI11_VERSION[ \t]+\"(.+)\"")
@@ -132,6 +132,9 @@ endif()
 
 include(CLI11Warnings)
 
+# build the fuzzing example or fuzz entry point
+add_subdirectory(fuzz)
+
 add_subdirectory(src)
 
 # Allow tests to be run on CUDA
diff --git a/packages/CLI11/CPPLINT.cfg b/packages/CLI11/CPPLINT.cfg
index 24dd86524..40bec3714 100644
--- a/packages/CLI11/CPPLINT.cfg
+++ b/packages/CLI11/CPPLINT.cfg
@@ -4,6 +4,7 @@ linelength=120  # As in .clang-format
 # Unused filters
 filter=-build/c++11  # Reports e.g. chrono and thread, which overlap with Chromium's API. Not applicable to general C++ projects.
 filter=-build/include_order  # Requires unusual include order that encourages creating not self-contained headers
+filter=-build/include_subdir  # Prevents including files in current directory for whatever reason
 filter=-readability/nolint  # Conflicts with clang-tidy
 filter=-readability/check  # Catch uses CHECK(a == b) (Tests only)
 filter=-build/namespaces  # Currently using it for one test (Tests only)
diff --git a/packages/CLI11/LICENSE b/packages/CLI11/LICENSE
index 71c477031..aae15855e 100644
--- a/packages/CLI11/LICENSE
+++ b/packages/CLI11/LICENSE
@@ -1,4 +1,4 @@
-CLI11 2.2 Copyright (c) 2017-2022 University of Cincinnati, developed by Henry
+CLI11 2.2 Copyright (c) 2017-2023 University of Cincinnati, developed by Henry
 Schreiner under NSF AWARD 1414736. All rights reserved.
 
 Redistribution and use in source and binary forms of CLI11, with or without
diff --git a/packages/CLI11/README.md b/packages/CLI11/README.md
index 989ef43b2..bd9e58db7 100644
--- a/packages/CLI11/README.md
+++ b/packages/CLI11/README.md
@@ -50,6 +50,7 @@ set with a simple and intuitive interface.
   - [Formatting](#formatting)
   - [Subclassing](#subclassing)
   - [How it works](#how-it-works)
+  - [Unicode support](#unicode-support)
   - [Utilities](#utilities)
   - [Other libraries](#other-libraries)
 - [API](#api)
@@ -164,9 +165,6 @@ this library:
   option to disable it).
 - Autocomplete: This might eventually be added to both Plumbum and CLI11, but it
   is not supported yet.
-- Wide strings / unicode: Since this uses the standard library only, it might be
-  hard to properly implement, but I would be open to suggestions in how to do
-  this.
 
 ## Install
 
@@ -278,13 +276,13 @@ To set up, add options, and run, your main function will look something like
 this:
 
 ```cpp
-int main(int argc, char** argv) {
+int main() {
     CLI::App app{"App description"};
 
     std::string filename = "default";
     app.add_option("-f,--file", filename, "A help string");
 
-    CLI11_PARSE(app, argc, argv);
+    CLI11_PARSE(app);
     return 0;
 }
 ```
@@ -293,7 +291,7 @@ int main(int argc, char** argv) {
 
 ```cpp
 try {
-    app.parse(argc, argv);
+    app.parse();
 } catch (const CLI::ParseError &e) {
     return app.exit(e);
 }
@@ -306,6 +304,25 @@ inside the catch block; for example, help flags intentionally short-circuit all
 other processing for speed and to ensure required options and the like do not
 interfere.
 
+</p></details>
+
+<details><summary>Note: Why are argc and argv not used? (click to expand)</summary><p>
+
+`argc` and `argv` may contain incorrect information on Windows when unicode text
+is passed in. Check out a section on [unicode support](#unicode-support) below.
+
+If this is not a concern, you can explicitly pass `argc` and `argv` from main or
+from an external preprocessor of CLI arguments to `parse`:
+
+```cpp
+int main(int argc, char** argv) {
+    // ...
+
+    CLI11_PARSE(app, argc, argv);
+    return 0;
+}
+```
+
 </p></details>
 </br>
 
@@ -530,7 +547,7 @@ Before parsing, you can set the following options:
   are `CLI::MultiOptionPolicy::Throw`, `CLI::MultiOptionPolicy::Throw`,
   `CLI::MultiOptionPolicy::TakeLast`, `CLI::MultiOptionPolicy::TakeFirst`,
   `CLI::MultiOptionPolicy::Join`, `CLI::MultiOptionPolicy::TakeAll`, and
-  `CLI::MultiOptionPolicy::Sum` 🚧.
+  `CLI::MultiOptionPolicy::Sum` 🆕.
 - `->check(std::string(const std::string &), validator_name="",validator_description="")`:
   Define a check function. The function should return a non empty string with
   the error message if the check fails
@@ -571,7 +588,7 @@ Before parsing, you can set the following options:
 - `->trigger_on_parse()`: If set, causes the callback and all associated
   validation checks for the option to be executed when the option value is
   parsed vs. at the end of all parsing. This could cause the callback to be
-  executed multiple times. Also works with positional options 🆕.
+  executed multiple times. Also works with positional options.
 
 These options return the `Option` pointer, so you can chain them together, and
 even skip storing the pointer entirely. The `each` function takes any function
@@ -658,7 +675,7 @@ CLI11 has several Validators built-in that perform some common checks
 - `CLI::ExistingDirectory`: Requires that the directory exists.
 - `CLI::ExistingPath`: Requires that the path (file or directory) exists.
 - `CLI::NonexistentPath`: Requires that the path does not exist.
-- `CLI::FileOnDefaultPath`: 🆕 Best used as a transform, Will check that a file
+- `CLI::FileOnDefaultPath`: Best used as a transform, Will check that a file
   exists either directly or in a default path and update the path appropriately.
   See [Transforming Validators](#transforming-validators) for more details
 - `CLI::Range(min,max)`: Requires that the option be between min and max (make
@@ -938,6 +955,20 @@ nameless subcommands are allowed. Callbacks for nameless subcommands are only
 triggered if any options from the subcommand were parsed. Subcommand names given
 through the `add_subcommand` method have the same restrictions as option names.
 
+🚧 Options or flags in a subcommand may be directly specified using dot notation
+
+- `--subcommand.long=val` (long subcommand option)
+- `--subcommand.long val` (long subcommand option)
+- `--subcommand.f=val` (short form subcommand option)
+- `--subcommand.f val` (short form subcommand option)
+- `--subcommand.f` (short form subcommand flag)
+- `--subcommand1.subsub.f val` (short form nested subcommand option)
+
+The use of dot notation in this form is equivalent `--subcommand.long <args>` =>
+`subcommand --long <args> ++`. Nested subcommands also work `"sub1.subsub"`
+would trigger the subsub subcommand in `sub1`. This is equivalent to "sub1
+subsub"
+
 #### Subcommand options
 
 There are several options that are supported on the main app and subcommands and
@@ -1062,6 +1093,10 @@ option_groups. These are:
 - `.prefix_command()`: Like `allow_extras`, but stop immediately on the first
   unrecognized item. It is ideal for allowing your app or subcommand to be a
   "prefix" to calling another app.
+- `.usage(message)`: Replace text to appear at the start of the help string
+  after description.
+- `.usage(std::string())`: Set a callback to generate a string that will appear
+  at the start of the help string after description.
 - `.footer(message)`: Set text to appear at the bottom of the help string.
 - `.footer(std::string())`: Set a callback to generate a string that will appear
   at the end of the help string.
@@ -1356,8 +1391,9 @@ multiple calls or using `|` operations with the transform.
 Many of the defaults for subcommands and even options are inherited from their
 creators. The inherited default values for subcommands are `allow_extras`,
 `prefix_command`, `ignore_case`, `ignore_underscore`, `fallthrough`, `group`,
-`footer`,`immediate_callback` and maximum number of required subcommands. The
-help flag existence, name, and description are inherited, as well.
+`usage`, `footer`, `immediate_callback` and maximum number of required
+subcommands. The help flag existence, name, and description are inherited, as
+well.
 
 Options have defaults for `group`, `required`, `multi_option_policy`,
 `ignore_case`, `ignore_underscore`, `delimiter`, and `disable_flag_override`. To
@@ -1435,11 +1471,10 @@ provide a custom `operator>>` with an `istream` (inside the CLI namespace is
 fine if you don't want to interfere with an existing `operator>>`).
 
 If you wanted to extend this to support a completely new type, use a lambda or
-add a specialization of the `lexical_cast` function template in the namespace of
-the type you need to convert to. Some examples of some new parsers for
-`complex<double>` that support all of the features of a standard `add_options`
-call are in [one of the tests](./tests/NewParseTest.cpp). A simpler example is
-shown below:
+add an overload of the `lexical_cast` function in the namespace of the type you
+need to convert to. Some examples of some new parsers for `complex<double>` that
+support all of the features of a standard `add_options` call are in
+[one of the tests](./tests/NewParseTest.cpp). A simpler example is shown below:
 
 #### Example
 
@@ -1450,6 +1485,96 @@ app.add_option("--fancy-count", [](std::vector<std::string> val){
     });
 ```
 
+### Unicode support
+
+CLI11 supports Unicode and wide strings as defined in the
+[UTF-8 Everywhere](http://utf8everywhere.org/) manifesto. In particular:
+
+- The library can parse a wide version of command-line arguments on Windows,
+  which are converted internally to UTF-8 (more on this below);
+- You can store option values in `std::wstring`, in which case they will be
+  converted to a correct wide string encoding on your system (UTF-16 on Windows
+  and UTF-32 on most other systems);
+- Instead of storing wide strings, it is recommended to use provided `widen` and
+  `narrow` functions to convert to and from wide strings when actually necessary
+  (such as when calling into Windows APIs).
+
+When using the command line on Windows with unicode arguments, your `main`
+function may already receive broken Unicode. Parsing `argv` at that point will
+not give you a correct string. To fix this, you have three options:
+
+1. If you pass unmodified command-line arguments to CLI11, call `app.parse()`
+   instead of `app.parse(argc, argv)` (or `CLI11_PARSE(app)` instead of
+   `CLI11_PARSE(app, argc, argv)`). The library will find correct arguments
+   itself.
+
+   ```cpp
+   int main() {
+       CLI::App app;
+       // ...
+       CLI11_PARSE(app);
+   }
+   ```
+
+2. Get correct arguments with which the program was originally executed using
+   provided functions: `CLI::argc()` and `CLI::argv()`. These two methods are
+   the only cross-platform ways of handling unicode correctly.
+
+   ```cpp
+   int main() {
+       CLI::App app;
+       // ...
+       CLI11_PARSE(app, CLI::argc(), CLI::argv());
+   }
+   ```
+
+3. Use the Windows-only non-standard `wmain` function, which accepts
+   `wchar_t *argv[]` instead of `char* argv[]`. Parsing this will allow CLI to
+   convert wide strings to UTF-8 without losing information.
+
+   ```cpp
+   int wmain(int argc, wchar_t *argv[]) {
+       CLI::App app;
+       // ...
+       CLI11_PARSE(app, argc, argv);
+   }
+   ```
+
+4. Retrieve arguments yourself by using Windows APIs like
+   [`CommandLineToArgvW`](https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw)
+   and pass them to CLI. This is what the library is doing under the hood in
+   `CLI::argv()`.
+
+The library provides functions to convert between UTF-8 and wide strings:
+
+```cpp
+namespace CLI {
+    std::string narrow(const std::wstring &str);
+    std::string narrow(const wchar_t *str);
+    std::string narrow(const wchar_t *str, std::size_t size);
+    std::string narrow(std::wstring_view str);  // C++17
+
+    std::wstring widen(const std::string &str);
+    std::wstring widen(const char *str);
+    std::wstring widen(const char *str, std::size_t size);
+    std::wstring widen(std::string_view str);  // C++17
+}
+```
+
+#### Note on using Unicode paths
+
+When creating a `filesystem::path` from a UTF-8 path on Windows, you need to
+convert it to a wide string first. CLI11 provides a platform-independent
+`to_path` function, which will convert a UTF-8 string to path, the right way:
+
+```cpp
+std::string utf8_name = "Hello Halló Привет 你好 👩‍🚀❤️.txt";
+
+std::filesystem::path p = CLI::to_path(utf8_name);
+std::ifstream stream(CLI::to_path(utf8_name));
+// etc.
+```
+
 ### Utilities
 
 There are a few other utilities that are often useful in CLI programming. These
diff --git a/packages/CLI11/azure-pipelines.yml b/packages/CLI11/azure-pipelines.yml
index c519e153b..1bb4d0771 100644
--- a/packages/CLI11/azure-pipelines.yml
+++ b/packages/CLI11/azure-pipelines.yml
@@ -28,7 +28,6 @@ jobs:
       - bash: cpplint --counting=detailed --recursive examples include/CLI tests
         displayName: Checking against google style guide
 
-  # TODO: Fix macOS error and windows warning in c++17 mode
   - job: Native
     strategy:
       matrix:
@@ -38,13 +37,13 @@ jobs:
           vmImage: "ubuntu-latest"
           cli11.precompile: ON
         macOS17:
-          vmImage: "macOS-latest"
+          vmImage: "macOS-12"
           cli11.std: 17
         macOS11:
-          vmImage: "macOS-latest"
+          vmImage: "macOS-11"
           cli11.std: 11
         macOS11PC:
-          vmImage: "macOS-latest"
+          vmImage: "macOS-11"
           cli11.std: 11
           cli11.precompile: ON
         Windows17:
@@ -57,10 +56,14 @@ jobs:
         Windows11:
           vmImage: "windows-2019"
           cli11.std: 11
-        WindowsLatest:
-          vmImage: "windows-2019"
+        Windows20:
+          vmImage: "windows-2022"
           cli11.std: 20
-          cli11.options: -DCMAKE_CXX_FLAGS="/std:c++latest /EHsc"
+          cli11.options: -DCMAKE_CXX_FLAGS="/EHsc"
+        WindowsLatest:
+          vmImage: "windows-2022"
+          cli11.std: 23
+          cli11.options: -DCMAKE_CXX_FLAGS="/EHsc"
         Linux17nortti:
           vmImage: "ubuntu-latest"
           cli11.std: 17
@@ -106,13 +109,14 @@ jobs:
         gcc11:
           containerImage: gcc:11
           cli11.std: 20
-        gcc8:
-          containerImage: gcc:8
-          cli11.std: 17
+          cli11.options: -DCMAKE_CXX_FLAGS="-Wredundant-decls -Wconversion"
+        gcc7:
+          containerImage: gcc:7
+          cli11.std: 14
+          cli11.options: -DCMAKE_CXX_FLAGS="-Wconversion"
         gcc4.8:
           containerImage: helics/buildenv:gcc4-8-builder
           cli11.std: 11
-          cli11.options:
         clang3.4:
           containerImage: silkeh/clang:3.4
           cli11.std: 11
diff --git a/packages/CLI11/book/chapters/config.md b/packages/CLI11/book/chapters/config.md
index d062c6595..30ca48eff 100644
--- a/packages/CLI11/book/chapters/config.md
+++ b/packages/CLI11/book/chapters/config.md
@@ -87,6 +87,10 @@ app.allow_config_extras(CLI::config_extras_mode::ignore_all);
 will completely ignore any mismatches, extras, or other issues with the config
 file
 
+Config file extras are stored in the remaining output as two components. The
+first is the name of the field including subcommands using dot notation the
+second (or more) are the argument fields.
+
 ### Getting the used configuration file name
 
 If it is needed to get the configuration file name used this can be obtained via
diff --git a/packages/CLI11/book/chapters/internals.md b/packages/CLI11/book/chapters/internals.md
index f8479c545..c2c98b75b 100644
--- a/packages/CLI11/book/chapters/internals.md
+++ b/packages/CLI11/book/chapters/internals.md
@@ -8,9 +8,9 @@ classes or inheritance. This is accomplished through lambda functions.
 This looks like:
 
 ```cpp
-Option* add_option(string name, T item) {
+Option* add_option(string name, T &item) {
     this->function = [&item](string value){
-        item = detail::lexical_cast<T>(value);
+        return lexical_cast(value, item);
     }
 }
 ```
diff --git a/packages/CLI11/conanfile.py b/packages/CLI11/conanfile.py
deleted file mode 100644
index 9dc6ce3ad..000000000
--- a/packages/CLI11/conanfile.py
+++ /dev/null
@@ -1,49 +0,0 @@
-from conans import ConanFile, CMake
-from conans.tools import load, cross_building
-import re
-
-
-def get_version():
-    try:
-        content = load("include/CLI/Version.hpp")
-        version = re.search(r'#define CLI11_VERSION "(.*)"', content).group(1)
-        return version
-    except Exception:
-        return None
-
-
-class CLI11Conan(ConanFile):
-    name = "CLI11"
-    version = get_version()
-    description = "Command Line Interface toolkit for C++11"
-    topics = ("cli", "c++11", "parser", "cli11")
-    url = "https://github.com/CLIUtils/CLI11"
-    homepage = "https://github.com/CLIUtils/CLI11"
-    author = "Henry Schreiner <hschrein@cern.ch>"
-    license = "BSD-3-Clause"
-
-    settings = "os", "compiler", "arch", "build_type"
-    exports_sources = (
-        "LICENSE",
-        "README.md",
-        "include/*",
-        "src/*",
-        "extern/*",
-        "cmake/*",
-        "CMakeLists.txt",
-        "CLI11.CPack.Description.txt",
-        "tests/*",
-    )
-
-    def build(self):  # this is not building a library, just tests
-        cmake = CMake(self)
-        cmake.definitions["CLI11_EXAMPLES"] = "OFF"
-        cmake.definitions["CLI11_SINGLE_FILE"] = "OFF"
-        cmake.configure()
-        cmake.build()
-        if not cross_building(self.settings):
-            cmake.test()
-        cmake.install()
-
-    def package_id(self):
-        self.info.header_only()
diff --git a/packages/CLI11/examples/callback_passthrough.cpp b/packages/CLI11/examples/callback_passthrough.cpp
index 833ef6fcf..1aac0df6b 100644
--- a/packages/CLI11/examples/callback_passthrough.cpp
+++ b/packages/CLI11/examples/callback_passthrough.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/config_app.cpp b/packages/CLI11/examples/config_app.cpp
index 986e80d9e..a0426ad61 100644
--- a/packages/CLI11/examples/config_app.cpp
+++ b/packages/CLI11/examples/config_app.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/custom_parse.cpp b/packages/CLI11/examples/custom_parse.cpp
index 793ddfab2..eaaedd552 100644
--- a/packages/CLI11/examples/custom_parse.cpp
+++ b/packages/CLI11/examples/custom_parse.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/digit_args.cpp b/packages/CLI11/examples/digit_args.cpp
index 023be6c63..a0785ddbd 100644
--- a/packages/CLI11/examples/digit_args.cpp
+++ b/packages/CLI11/examples/digit_args.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/enum.cpp b/packages/CLI11/examples/enum.cpp
index 90684333f..133adde9a 100644
--- a/packages/CLI11/examples/enum.cpp
+++ b/packages/CLI11/examples/enum.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/enum_ostream.cpp b/packages/CLI11/examples/enum_ostream.cpp
index 4ccc6a00c..1f8ac57e4 100644
--- a/packages/CLI11/examples/enum_ostream.cpp
+++ b/packages/CLI11/examples/enum_ostream.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/formatter.cpp b/packages/CLI11/examples/formatter.cpp
index 09d6dce10..4973cf95f 100644
--- a/packages/CLI11/examples/formatter.cpp
+++ b/packages/CLI11/examples/formatter.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/groups.cpp b/packages/CLI11/examples/groups.cpp
index 2ebc1e88a..09c5d6ba2 100644
--- a/packages/CLI11/examples/groups.cpp
+++ b/packages/CLI11/examples/groups.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/inter_argument_order.cpp b/packages/CLI11/examples/inter_argument_order.cpp
index 8fe063e39..e8c489c2a 100644
--- a/packages/CLI11/examples/inter_argument_order.cpp
+++ b/packages/CLI11/examples/inter_argument_order.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/modhelp.cpp b/packages/CLI11/examples/modhelp.cpp
index ac2ba1759..d0f8cf875 100644
--- a/packages/CLI11/examples/modhelp.cpp
+++ b/packages/CLI11/examples/modhelp.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/nested.cpp b/packages/CLI11/examples/nested.cpp
index 07aa75fb8..3587023ac 100644
--- a/packages/CLI11/examples/nested.cpp
+++ b/packages/CLI11/examples/nested.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/option_groups.cpp b/packages/CLI11/examples/option_groups.cpp
index 9799bdc6e..3a282536b 100644
--- a/packages/CLI11/examples/option_groups.cpp
+++ b/packages/CLI11/examples/option_groups.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/positional_arity.cpp b/packages/CLI11/examples/positional_arity.cpp
index e8c45c4d6..d2d9b9c89 100644
--- a/packages/CLI11/examples/positional_arity.cpp
+++ b/packages/CLI11/examples/positional_arity.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/positional_validation.cpp b/packages/CLI11/examples/positional_validation.cpp
index ce676d9d1..6b552daa5 100644
--- a/packages/CLI11/examples/positional_validation.cpp
+++ b/packages/CLI11/examples/positional_validation.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/prefix_command.cpp b/packages/CLI11/examples/prefix_command.cpp
index 61639411f..843f40374 100644
--- a/packages/CLI11/examples/prefix_command.cpp
+++ b/packages/CLI11/examples/prefix_command.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/ranges.cpp b/packages/CLI11/examples/ranges.cpp
index 42b1659c3..ec14905bf 100644
--- a/packages/CLI11/examples/ranges.cpp
+++ b/packages/CLI11/examples/ranges.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/retired.cpp b/packages/CLI11/examples/retired.cpp
index 0a3a5fbee..28f61da04 100644
--- a/packages/CLI11/examples/retired.cpp
+++ b/packages/CLI11/examples/retired.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/shapes.cpp b/packages/CLI11/examples/shapes.cpp
index d9f47cab1..d3f48ac73 100644
--- a/packages/CLI11/examples/shapes.cpp
+++ b/packages/CLI11/examples/shapes.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/simple.cpp b/packages/CLI11/examples/simple.cpp
index 5f94bc835..b7095dd2c 100644
--- a/packages/CLI11/examples/simple.cpp
+++ b/packages/CLI11/examples/simple.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/subcom_help.cpp b/packages/CLI11/examples/subcom_help.cpp
index 952060de9..65030eb86 100644
--- a/packages/CLI11/examples/subcom_help.cpp
+++ b/packages/CLI11/examples/subcom_help.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/subcom_in_files/subcommand_a.cpp b/packages/CLI11/examples/subcom_in_files/subcommand_a.cpp
index 9ad65e01e..bb1a6a13d 100644
--- a/packages/CLI11/examples/subcom_in_files/subcommand_a.cpp
+++ b/packages/CLI11/examples/subcom_in_files/subcommand_a.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/subcom_in_files/subcommand_a.hpp b/packages/CLI11/examples/subcom_in_files/subcommand_a.hpp
index cfa4883ea..6a8395d1a 100644
--- a/packages/CLI11/examples/subcom_in_files/subcommand_a.hpp
+++ b/packages/CLI11/examples/subcom_in_files/subcommand_a.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/subcom_in_files/subcommand_main.cpp b/packages/CLI11/examples/subcom_in_files/subcommand_main.cpp
index 1ff5fdad9..e65339c90 100644
--- a/packages/CLI11/examples/subcom_in_files/subcommand_main.cpp
+++ b/packages/CLI11/examples/subcom_in_files/subcommand_main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/subcom_partitioned.cpp b/packages/CLI11/examples/subcom_partitioned.cpp
index 493ac0e38..b6273eaed 100644
--- a/packages/CLI11/examples/subcom_partitioned.cpp
+++ b/packages/CLI11/examples/subcom_partitioned.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/subcommands.cpp b/packages/CLI11/examples/subcommands.cpp
index 44d4df925..e69c04eed 100644
--- a/packages/CLI11/examples/subcommands.cpp
+++ b/packages/CLI11/examples/subcommands.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/testEXE.cpp b/packages/CLI11/examples/testEXE.cpp
index b63fa9499..b2cac7fba 100644
--- a/packages/CLI11/examples/testEXE.cpp
+++ b/packages/CLI11/examples/testEXE.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/examples/validators.cpp b/packages/CLI11/examples/validators.cpp
index 050be00fb..87eb07ab2 100644
--- a/packages/CLI11/examples/validators.cpp
+++ b/packages/CLI11/examples/validators.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/fuzz/CMakeLists.txt b/packages/CLI11/fuzz/CMakeLists.txt
new file mode 100644
index 000000000..21df4028f
--- /dev/null
+++ b/packages/CLI11/fuzz/CMakeLists.txt
@@ -0,0 +1,48 @@
+# Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
+# under NSF AWARD 1414736 and by the respective contributors.
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(CMAKE_CXX_STANDARD GREATER 16)
+  if(CLI11_FUZZ_TARGET)
+
+    add_executable(cli11_app_fuzzer cli11_app_fuzz.cpp fuzzApp.cpp fuzzApp.hpp)
+    target_link_libraries(cli11_app_fuzzer PUBLIC CLI11)
+    set_property(TARGET cli11_app_fuzzer PROPERTY FOLDER "Tests")
+
+    add_executable(cli11_file_fuzzer cli11_file_fuzz.cpp fuzzApp.cpp fuzzApp.hpp)
+    target_link_libraries(cli11_file_fuzzer PUBLIC CLI11)
+    set_property(TARGET cli11_file_fuzzer PROPERTY FOLDER "Tests")
+
+    if(NOT CLI11_FUZZ_ARTIFACT_PATH)
+      set(CLI11_FUZZ_ARTIFACT_PATH ${PROJECT_BINARY_DIR}/fuzz)
+    endif()
+
+    if(NOT CLI11_FUZZ_TIME)
+      set(CLI11_FUZZ_TIME 360)
+    endif()
+    add_custom_target(
+      QUICK_CLI11_APP_FUZZ
+      COMMAND ${CMAKE_COMMAND} -E make_directory corp
+      COMMAND
+        cli11_app_fuzzer corp -max_total_time=${CLI11_FUZZ_TIME} -max_len=2048
+        -dict=${CMAKE_CURRENT_SOURCE_DIR}/fuzz_dictionary1.txt
+        -exact_artifact_path=${CLI11_FUZZ_ARTIFACT_PATH}/cli11_app_fail_artifact.txt)
+
+    add_custom_target(
+      QUICK_CLI11_FILE_FUZZ
+      COMMAND ${CMAKE_COMMAND} -E make_directory corp
+      COMMAND
+        cli11_file_fuzzer corp -max_total_time=${CLI11_FUZZ_TIME} -max_len=2048
+        -dict=${CMAKE_CURRENT_SOURCE_DIR}/fuzz_dictionary2.txt
+        -exact_artifact_path=${CLI11_FUZZ_ARTIFACT_PATH}/cli11_file_fail_artifact.txt)
+
+  else()
+    if(CLI11_BUILD_EXAMPLES)
+      add_executable(cli11Fuzz fuzzCommand.cpp fuzzApp.cpp fuzzApp.hpp)
+      target_link_libraries(cli11Fuzz PUBLIC CLI11)
+      set_property(TARGET cli11Fuzz PROPERTY FOLDER "Examples")
+    endif()
+  endif()
+endif()
diff --git a/packages/CLI11/fuzz/cli11_app_fuzz.cpp b/packages/CLI11/fuzz/cli11_app_fuzz.cpp
new file mode 100644
index 000000000..7cd10b889
--- /dev/null
+++ b/packages/CLI11/fuzz/cli11_app_fuzz.cpp
@@ -0,0 +1,30 @@
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
+// under NSF AWARD 1414736 and by the respective contributors.
+// All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include "fuzzApp.hpp"
+#include <CLI/CLI.hpp>
+#include <cstring>
+#include <exception>
+#include <string>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+    if(Size == 0) {
+        return 0;
+    }
+    std::string parseString(reinterpret_cast<const char *>(Data), Size);
+
+    CLI::FuzzApp fuzzdata;
+
+    auto app = fuzzdata.generateApp();
+    try {
+        app->parse(parseString);
+    } catch(const CLI::ParseError &e) {
+        //(app)->exit(e);
+        // this just indicates we caught an error known by CLI
+    }
+
+    return 0;  // Non-zero return values are reserved for future use.
+}
diff --git a/packages/CLI11/fuzz/cli11_file_fuzz.cpp b/packages/CLI11/fuzz/cli11_file_fuzz.cpp
new file mode 100644
index 000000000..e769114eb
--- /dev/null
+++ b/packages/CLI11/fuzz/cli11_file_fuzz.cpp
@@ -0,0 +1,31 @@
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
+// under NSF AWARD 1414736 and by the respective contributors.
+// All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include "fuzzApp.hpp"
+#include <CLI/CLI.hpp>
+#include <cstring>
+#include <exception>
+#include <sstream>
+#include <string>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+    if(Size == 0) {
+        return 0;
+    }
+    std::string parseString(reinterpret_cast<const char *>(Data), Size);
+    std::stringstream out(parseString);
+    CLI::FuzzApp fuzzdata;
+
+    auto app = fuzzdata.generateApp();
+    try {
+        app->parse_from_stream(out);
+    } catch(const CLI::ParseError &e) {
+        (app)->exit(e);
+        // this just indicates we caught an error known by CLI
+    }
+
+    return 0;  // Non-zero return values are reserved for future use.
+}
diff --git a/packages/CLI11/fuzz/fuzzApp.cpp b/packages/CLI11/fuzz/fuzzApp.cpp
new file mode 100644
index 000000000..dc401f933
--- /dev/null
+++ b/packages/CLI11/fuzz/fuzzApp.cpp
@@ -0,0 +1,85 @@
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
+// under NSF AWARD 1414736 and by the respective contributors.
+// All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include "fuzzApp.hpp"
+
+namespace CLI {
+/*
+int32_t val32{0};
+    int16_t val16{0};
+    int8_t val8{0};
+    int64_t val64{0};
+
+    uint32_t uval32{0};
+    uint16_t uval16{0};
+    uint8_t uval8{0};
+    uint64_t uval64{0};
+
+    std::atomic<int64_t> atomicval64{0};
+    std::atomic<uint64_t> atomicuval64{0};
+
+    double v1{0};
+    float v2{0};
+
+    std::vector<double> vv1;
+    std::vector<std::string> vstr;
+    std::vector<std::vector<double>> vecvecd;
+    std::vector<std::vector<std::string>> vvs;
+    std::optional<double> od1;
+    std::optional<std::string> ods;
+    std::pair<double, std::string> p1;
+    std::pair<std::vector<double>, std::string> p2;
+    std::tuple<int64_t, uint16_t, std::optional<double>> t1;
+    std::tuple<std::tuple<std::tuple<std::string, double, std::vector<int>>,std::string, double>,std::vector<int>,
+std::optional<std::string>> tcomplex; std::string_view vstrv;
+
+    bool flag1{false};
+    int flagCnt{0};
+    std::atomic<bool> flagAtomic{false};
+    */
+std::shared_ptr<CLI::App> FuzzApp::generateApp() {
+    auto fApp = std::make_shared<CLI::App>("fuzzing App", "fuzzer");
+    fApp->set_config("--config");
+    fApp->add_flag("-a,--flag");
+    fApp->add_flag("-b,--flag2", flag1);
+    fApp->add_flag("-c{34},--flag3{1}", flagCnt)->disable_flag_override();
+    fApp->add_flag("-e,--flagA", flagAtomic);
+
+    fApp->add_option("-d,--opt1", val8);
+    fApp->add_option("--opt2", val16);
+    fApp->add_option("--opt3", val32);
+    fApp->add_option("--opt4", val64);
+
+    fApp->add_option("--opt5", uval8);
+    fApp->add_option("--opt6", uval16);
+    fApp->add_option("--opt7", uval32);
+    fApp->add_option("--opt8", uval64);
+
+    fApp->add_option("--aopt1", atomicval64);
+    fApp->add_option("--aopt2", atomicuval64);
+
+    fApp->add_option("--dopt1", v1);
+    fApp->add_option("--dopt2", v2);
+
+    fApp->add_option("--vopt1", vv1);
+    fApp->add_option("--vopt2", vvs);
+    fApp->add_option("--vopt3", vstr);
+    fApp->add_option("--vopt4", vecvecd);
+
+    fApp->add_option("--oopt1", od1);
+    fApp->add_option("--oopt2", ods);
+
+    fApp->add_option("--tup1", p1);
+    fApp->add_option("--tup2", t1);
+    fApp->add_option("--tup4", tcomplex);
+
+    fApp->add_option("--dwrap", dwrap);
+    fApp->add_option("--iwrap", iwrap);
+
+    return fApp;
+}
+
+}  // namespace CLI
diff --git a/packages/CLI11/fuzz/fuzzApp.hpp b/packages/CLI11/fuzz/fuzzApp.hpp
new file mode 100644
index 000000000..01600cc25
--- /dev/null
+++ b/packages/CLI11/fuzz/fuzzApp.hpp
@@ -0,0 +1,92 @@
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
+// under NSF AWARD 1414736 and by the respective contributors.
+// All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+#pragma once
+
+#ifdef CLI11_SINGLE_FILE
+#include "CLI11.hpp"
+#else
+#include "CLI/CLI.hpp"
+#endif
+
+#include <atomic>
+#include <iostream>
+#include <memory>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <vector>
+
+namespace CLI {
+
+class intWrapper64 {
+  public:
+    intWrapper64() = default;
+    explicit intWrapper64(int64_t v) : val(v){};
+    CLI11_NODISCARD int64_t value() const { return val; }
+
+  private:
+    int64_t val{0};
+};
+
+class doubleWrapper {
+  public:
+    doubleWrapper() = default;
+    explicit doubleWrapper(double v) : val(v){};
+    CLI11_NODISCARD double value() const { return val; }
+
+  private:
+    double val{0.0};
+};
+
+class FuzzApp {
+  public:
+    FuzzApp() = default;
+
+    std::shared_ptr<CLI::App> generateApp();
+
+    int32_t val32{0};
+    int16_t val16{0};
+    int8_t val8{0};
+    int64_t val64{0};
+
+    uint32_t uval32{0};
+    uint16_t uval16{0};
+    uint8_t uval8{0};
+    uint64_t uval64{0};
+
+    std::atomic<int64_t> atomicval64{0};
+    std::atomic<uint64_t> atomicuval64{0};
+
+    double v1{0};
+    float v2{0};
+
+    std::vector<double> vv1{};
+    std::vector<std::string> vstr{};
+    std::vector<std::vector<double>> vecvecd{};
+    std::vector<std::vector<std::string>> vvs{};
+    std::optional<double> od1{};
+    std::optional<std::string> ods{};
+    std::pair<double, std::string> p1{};
+    std::pair<std::vector<double>, std::string> p2{};
+    std::tuple<int64_t, uint16_t, std::optional<double>> t1{};
+    std::tuple<std::tuple<std::tuple<std::string, double, std::vector<int>>, std::string, double>,
+               std::vector<int>,
+               std::optional<std::string>>
+        tcomplex{};
+    std::tuple<std::tuple<std::tuple<std::string, double, std::vector<int>>, std::string, double>,
+               std::vector<int>,
+               std::optional<std::string>>
+        tcomplex2{};
+    std::string_view vstrv = "";
+
+    bool flag1{false};
+    int flagCnt{0};
+    std::atomic<bool> flagAtomic{false};
+
+    intWrapper64 iwrap{0};
+    doubleWrapper dwrap{0.0};
+};
+}  // namespace CLI
diff --git a/packages/CLI11/fuzz/fuzzCommand.cpp b/packages/CLI11/fuzz/fuzzCommand.cpp
new file mode 100644
index 000000000..07ab0df2e
--- /dev/null
+++ b/packages/CLI11/fuzz/fuzzCommand.cpp
@@ -0,0 +1,24 @@
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
+// under NSF AWARD 1414736 and by the respective contributors.
+// All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include "fuzzApp.hpp"
+#include <CLI/CLI.hpp>
+#include <iostream>
+
+int main(int argc, char **argv) {
+
+    CLI::FuzzApp fuzzdata;
+
+    auto app = fuzzdata.generateApp();
+    try {
+
+        app->parse(argc, argv);
+    } catch(const CLI::ParseError &e) {
+        (app)->exit(e);
+        // this just indicates we caught an error known by CLI
+    }
+    return 0;
+}
diff --git a/packages/CLI11/fuzz/fuzz_dictionary1.txt b/packages/CLI11/fuzz/fuzz_dictionary1.txt
new file mode 100644
index 000000000..c044eecd4
--- /dev/null
+++ b/packages/CLI11/fuzz/fuzz_dictionary1.txt
@@ -0,0 +1,34 @@
+###### Recommended dictionary.
+"-a"
+"-b"
+"-c"
+"-d"
+"-e"
+"--flag1"
+"--flag"
+"--flag2"
+"--flagA"
+"--opt1"
+"--opt2"
+"--opt3"
+"--opt4"
+"--opt5"
+"--opt6"
+"--opt7"
+"--opt8"
+"--opt9"
+"--aopt1"
+"--aopt2"
+"--dopt1"
+"--dopt2"
+"--vopt1"
+"--vopt2"
+"--vopt3"
+"--vopt4"
+"--oopt1"
+"--oopt2"
+"--tup1"
+"--tup2"
+"--tup4"
+"--dwrap"
+"--iwrap"
diff --git a/packages/CLI11/fuzz/fuzz_dictionary2.txt b/packages/CLI11/fuzz/fuzz_dictionary2.txt
new file mode 100644
index 000000000..12dd8f1f6
--- /dev/null
+++ b/packages/CLI11/fuzz/fuzz_dictionary2.txt
@@ -0,0 +1,37 @@
+###### Recommended dictionary.
+"a"
+"b"
+"c"
+"d"
+"e"
+"flag1"
+"flag"
+"flag2"
+"flagA"
+"opt1"
+"opt2"
+"opt3"
+"opt4"
+"opt5"
+"opt6"
+"opt7"
+"opt8"
+"opt9"
+"aopt1"
+"aopt2"
+"dopt1"
+"dopt2"
+"vopt1"
+"vopt2"
+"vopt3"
+"vopt4"
+"="
+"oopt1"
+"oopt2"
+"tup1"
+"tup2"
+"tup4"
+"tup2"
+"tup4"
+"dwrap"
+"iwrap"
diff --git a/packages/CLI11/include/CLI/App.hpp b/packages/CLI11/include/CLI/App.hpp
index d29aa6a89..2676445d1 100644
--- a/packages/CLI11/include/CLI/App.hpp
+++ b/packages/CLI11/include/CLI/App.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -35,9 +35,9 @@ namespace CLI {
 // [CLI11:app_hpp:verbatim]
 
 #ifndef CLI11_PARSE
-#define CLI11_PARSE(app, argc, argv)                                                                                   \
+#define CLI11_PARSE(app, ...)                                                                                          \
     try {                                                                                                              \
-        (app).parse((argc), (argv));                                                                                   \
+        (app).parse(__VA_ARGS__);                                                                                      \
     } catch(const CLI::ParseError &e) {                                                                                \
         return (app).exit(e);                                                                                          \
     }
@@ -49,8 +49,11 @@ struct AppFriend;
 }  // namespace detail
 
 namespace FailureMessage {
-std::string simple(const App *app, const Error &e);
-std::string help(const App *app, const Error &e);
+/// Printout a clean, simple message on error (the default in CLI11 1.5+)
+CLI11_INLINE std::string simple(const App *app, const Error &e);
+
+/// Printout the full help string on error (if this fn is set, the old default for CLI11)
+CLI11_INLINE std::string help(const App *app, const Error &e);
 }  // namespace FailureMessage
 
 /// enumeration of modes of how to deal with extras in config files
@@ -147,6 +150,12 @@ class App {
     /// @name Help
     ///@{
 
+    /// Usage to put after program/subcommand description in the help output INHERITABLE
+    std::string usage_{};
+
+    /// This is a function that generates a usage to put after program/subcommand description in help output
+    std::function<std::string()> usage_callback_{};
+
     /// Footer to put after all options in the help output INHERITABLE
     std::string footer_{};
 
@@ -623,7 +632,8 @@ class App {
                      std::string flag_description = "") {
 
         CLI::callback_t fun = [&flag_result](const CLI::results_t &res) {
-            return CLI::detail::lexical_cast(res[0], flag_result);
+            using CLI::detail::lexical_cast;
+            return lexical_cast(res[0], flag_result);
         };
         auto *opt = _add_flag_internal(flag_name, std::move(fun), std::move(flag_description));
         return detail::default_flag_modifiers<T>(opt);
@@ -639,8 +649,9 @@ class App {
         CLI::callback_t fun = [&flag_results](const CLI::results_t &res) {
             bool retval = true;
             for(const auto &elem : res) {
+                using CLI::detail::lexical_cast;
                 flag_results.emplace_back();
-                retval &= detail::lexical_cast(elem, flag_results.back());
+                retval &= lexical_cast(elem, flag_results.back());
             }
             return retval;
         };
@@ -826,15 +837,25 @@ class App {
     /// Reset the parsed data
     void clear();
 
+    /// Parse the command-line arguments passed to the main function of the executable.
+    /// This overload will correctly parse unicode arguments on Windows.
+    void parse();
+
     /// Parses the command line - throws errors.
     /// This must be called after the options are in but before the rest of the program.
     void parse(int argc, const char *const *argv);
+    void parse(int argc, const wchar_t *const *argv);
+
+  private:
+    template <class CharT> void parse_char_t(int argc, const CharT *const *argv);
 
+  public:
     /// Parse a single string as if it contained command line arguments.
     /// This function splits the string into arguments then calls parse(std::vector<std::string> &)
     /// the function takes an optional boolean argument specifying if the programName is included in the string to
     /// process
     void parse(std::string commandline, bool program_name_included = false);
+    void parse(std::wstring commandline, bool program_name_included = false);
 
     /// The real work is done here. Expects a reversed vector.
     /// Changes the vector to the remaining options.
@@ -942,6 +963,16 @@ class App {
     /// @name Help
     ///@{
 
+    /// Set usage.
+    App *usage(std::string usage_string) {
+        usage_ = std::move(usage_string);
+        return this;
+    }
+    /// Set usage.
+    App *usage(std::function<std::string()> usage_function) {
+        usage_callback_ = std::move(usage_function);
+        return this;
+    }
     /// Set footer.
     App *footer(std::string footer_string) {
         footer_ = std::move(footer_string);
@@ -1050,6 +1081,11 @@ class App {
     /// Get the group of this subcommand
     CLI11_NODISCARD const std::string &get_group() const { return group_; }
 
+    /// Generate and return the usage.
+    CLI11_NODISCARD std::string get_usage() const {
+        return (usage_callback_) ? usage_callback_() + '\n' + usage_ : usage_;
+    }
+
     /// Generate and return the footer.
     CLI11_NODISCARD std::string get_footer() const {
         return (footer_callback_) ? footer_callback_() + '\n' + footer_ : footer_;
@@ -1259,8 +1295,9 @@ class App {
     bool _parse_subcommand(std::vector<std::string> &args);
 
     /// Parse a short (false) or long (true) argument, must be at the top of the list
+    /// if local_processing_only is set to true then fallthrough is disabled will return false if not found
     /// return true if the argument was processed or false if nothing was done
-    bool _parse_arg(std::vector<std::string> &args, detail::Classifier current_type);
+    bool _parse_arg(std::vector<std::string> &args, detail::Classifier current_type, bool local_processing_only);
 
     /// Trigger the pre_parse callback if needed
     void _trigger_pre_parse(std::size_t remaining_args);
@@ -1352,16 +1389,6 @@ CLI11_INLINE void retire_option(App *app, const std::string &option_name);
 /// Helper function to mark an option as retired
 CLI11_INLINE void retire_option(App &app, const std::string &option_name);
 
-namespace FailureMessage {
-
-/// Printout a clean, simple message on error (the default in CLI11 1.5+)
-CLI11_INLINE std::string simple(const App *app, const Error &e);
-
-/// Printout the full help string on error (if this fn is set, the old default for CLI11)
-CLI11_INLINE std::string help(const App *app, const Error &e);
-
-}  // namespace FailureMessage
-
 namespace detail {
 /// This class is simply to allow tests access to App's protected functions
 struct AppFriend {
diff --git a/packages/CLI11/include/CLI/Argv.hpp b/packages/CLI11/include/CLI/Argv.hpp
new file mode 100644
index 000000000..35d81a6ea
--- /dev/null
+++ b/packages/CLI11/include/CLI/Argv.hpp
@@ -0,0 +1,25 @@
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
+// under NSF AWARD 1414736 and by the respective contributors.
+// All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+#pragma once
+
+#include <CLI/Macros.hpp>
+
+namespace CLI {
+// [CLI11:argv_hpp:verbatim]
+
+/// argc as passed in to this executable.
+CLI11_INLINE int argc();
+
+/// argv as passed in to this executable, converted to utf-8 on Windows.
+CLI11_INLINE const char *const *argv();
+
+// [CLI11:argv_hpp:end]
+}  // namespace CLI
+
+#ifndef CLI11_COMPILE
+#include "impl/Argv_inl.hpp"
+#endif
diff --git a/packages/CLI11/include/CLI/CLI.hpp b/packages/CLI11/include/CLI/CLI.hpp
index 0b6c3448a..fa9d4bb53 100644
--- a/packages/CLI11/include/CLI/CLI.hpp
+++ b/packages/CLI11/include/CLI/CLI.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -13,6 +13,10 @@
 
 #include "Macros.hpp"
 
+#include "Encoding.hpp"
+
+#include "Argv.hpp"
+
 #include "StringTools.hpp"
 
 #include "Error.hpp"
diff --git a/packages/CLI11/include/CLI/Config.hpp b/packages/CLI11/include/CLI/Config.hpp
index 685981c2f..a91f0da6e 100644
--- a/packages/CLI11/include/CLI/Config.hpp
+++ b/packages/CLI11/include/CLI/Config.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -14,7 +14,7 @@
 #include <string>
 #include <utility>
 #include <vector>
-// [CLI11:public_includes:set]
+// [CLI11:public_includes:end]
 
 #include "App.hpp"
 #include "ConfigFwd.hpp"
diff --git a/packages/CLI11/include/CLI/ConfigFwd.hpp b/packages/CLI11/include/CLI/ConfigFwd.hpp
index 44454b41a..a9ae2176a 100644
--- a/packages/CLI11/include/CLI/ConfigFwd.hpp
+++ b/packages/CLI11/include/CLI/ConfigFwd.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -61,7 +61,7 @@ class Config {
         if(item.inputs.empty()) {
             return "{}";
         }
-        throw ConversionError::TooManyInputsFlag(item.fullname());
+        throw ConversionError::TooManyInputsFlag(item.fullname());  // LCOV_EXCL_LINE
     }
 
     /// Parse a config file, throw an error (ParseError:ConfigParseError or FileError) on failure
diff --git a/packages/CLI11/include/CLI/Encoding.hpp b/packages/CLI11/include/CLI/Encoding.hpp
new file mode 100644
index 000000000..379e33b20
--- /dev/null
+++ b/packages/CLI11/include/CLI/Encoding.hpp
@@ -0,0 +1,54 @@
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
+// under NSF AWARD 1414736 and by the respective contributors.
+// All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+#pragma once
+
+#include <CLI/Macros.hpp>
+
+// [CLI11:public_includes:set]
+#include <string>
+// [CLI11:public_includes:end]
+
+// [CLI11:encoding_includes:verbatim]
+#ifdef CLI11_CPP17
+#include <string_view>
+#endif  // CLI11_CPP17
+
+#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
+#include <filesystem>
+#include <string_view>  // NOLINT(build/include)
+#endif                  // CLI11_HAS_FILESYSTEM
+// [CLI11:encoding_includes:end]
+
+namespace CLI {
+// [CLI11:encoding_hpp:verbatim]
+
+/// Convert a wide string to a narrow string.
+CLI11_INLINE std::string narrow(const std::wstring &str);
+CLI11_INLINE std::string narrow(const wchar_t *str);
+CLI11_INLINE std::string narrow(const wchar_t *str, std::size_t size);
+
+/// Convert a narrow string to a wide string.
+CLI11_INLINE std::wstring widen(const std::string &str);
+CLI11_INLINE std::wstring widen(const char *str);
+CLI11_INLINE std::wstring widen(const char *str, std::size_t size);
+
+#ifdef CLI11_CPP17
+CLI11_INLINE std::string narrow(std::wstring_view str);
+CLI11_INLINE std::wstring widen(std::string_view str);
+#endif  // CLI11_CPP17
+
+#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
+/// Convert a char-string to a native path correctly.
+CLI11_INLINE std::filesystem::path to_path(std::string_view str);
+#endif  // CLI11_HAS_FILESYSTEM
+
+// [CLI11:encoding_hpp:end]
+}  // namespace CLI
+
+#ifndef CLI11_COMPILE
+#include "impl/Encoding_inl.hpp"
+#endif
diff --git a/packages/CLI11/include/CLI/Error.hpp b/packages/CLI11/include/CLI/Error.hpp
index 45df83bb6..0900da53c 100644
--- a/packages/CLI11/include/CLI/Error.hpp
+++ b/packages/CLI11/include/CLI/Error.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/include/CLI/Formatter.hpp b/packages/CLI11/include/CLI/Formatter.hpp
index c1eceac12..f58058f27 100644
--- a/packages/CLI11/include/CLI/Formatter.hpp
+++ b/packages/CLI11/include/CLI/Formatter.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/include/CLI/FormatterFwd.hpp b/packages/CLI11/include/CLI/FormatterFwd.hpp
index 792ebbc88..5ef0a5b58 100644
--- a/packages/CLI11/include/CLI/FormatterFwd.hpp
+++ b/packages/CLI11/include/CLI/FormatterFwd.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -57,6 +57,8 @@ class FormatterBase {
     FormatterBase() = default;
     FormatterBase(const FormatterBase &) = default;
     FormatterBase(FormatterBase &&) = default;
+    FormatterBase &operator=(const FormatterBase &) = default;
+    FormatterBase &operator=(FormatterBase &&) = default;
 
     /// Adding a destructor in this form to work around bug in GCC 4.7
     virtual ~FormatterBase() noexcept {}  // NOLINT(modernize-use-equals-default)
@@ -118,6 +120,8 @@ class Formatter : public FormatterBase {
     Formatter() = default;
     Formatter(const Formatter &) = default;
     Formatter(Formatter &&) = default;
+    Formatter &operator=(const Formatter &) = default;
+    Formatter &operator=(Formatter &&) = default;
 
     /// @name Overridables
     ///@{
diff --git a/packages/CLI11/include/CLI/Macros.hpp b/packages/CLI11/include/CLI/Macros.hpp
index 690670619..c7ac94e87 100644
--- a/packages/CLI11/include/CLI/Macros.hpp
+++ b/packages/CLI11/include/CLI/Macros.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -66,6 +66,62 @@
 #endif
 #endif
 
+/** <filesystem> availability */
+#if defined CLI11_CPP17 && defined __has_include && !defined CLI11_HAS_FILESYSTEM
+#if __has_include(<filesystem>)
+// Filesystem cannot be used if targeting macOS < 10.15
+#if defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
+#define CLI11_HAS_FILESYSTEM 0
+#elif defined(__wasi__)
+// As of wasi-sdk-14, filesystem is not implemented
+#define CLI11_HAS_FILESYSTEM 0
+#else
+#include <filesystem>
+#if defined __cpp_lib_filesystem && __cpp_lib_filesystem >= 201703
+#if defined _GLIBCXX_RELEASE && _GLIBCXX_RELEASE >= 9
+#define CLI11_HAS_FILESYSTEM 1
+#elif defined(__GLIBCXX__)
+// if we are using gcc and Version <9 default to no filesystem
+#define CLI11_HAS_FILESYSTEM 0
+#else
+#define CLI11_HAS_FILESYSTEM 1
+#endif
+#else
+#define CLI11_HAS_FILESYSTEM 0
+#endif
+#endif
+#endif
+#endif
+
+/** <codecvt> availability */
+#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) && __GNUC__ < 5
+#define CLI11_HAS_CODECVT 0
+#else
+#define CLI11_HAS_CODECVT 1
+#include <codecvt>
+#endif
+
+/** disable deprecations */
+#if defined(__GNUC__)  // GCC or clang
+#define CLI11_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
+#define CLI11_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
+
+#define CLI11_DIAGNOSTIC_IGNORE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
+
+#elif defined(_MSC_VER)
+#define CLI11_DIAGNOSTIC_PUSH __pragma(warning(push))
+#define CLI11_DIAGNOSTIC_POP __pragma(warning(pop))
+
+#define CLI11_DIAGNOSTIC_IGNORE_DEPRECATED __pragma(warning(disable : 4996))
+
+#else
+#define CLI11_DIAGNOSTIC_PUSH
+#define CLI11_DIAGNOSTIC_POP
+
+#define CLI11_DIAGNOSTIC_IGNORE_DEPRECATED
+
+#endif
+
 /** Inline macro **/
 #ifdef CLI11_COMPILE
 #define CLI11_INLINE
diff --git a/packages/CLI11/include/CLI/Option.hpp b/packages/CLI11/include/CLI/Option.hpp
index 458d9ffcb..d32350738 100644
--- a/packages/CLI11/include/CLI/Option.hpp
+++ b/packages/CLI11/include/CLI/Option.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/include/CLI/Split.hpp b/packages/CLI11/include/CLI/Split.hpp
index 14be82289..d00e7f8cb 100644
--- a/packages/CLI11/include/CLI/Split.hpp
+++ b/packages/CLI11/include/CLI/Split.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/include/CLI/StringTools.hpp b/packages/CLI11/include/CLI/StringTools.hpp
index a891b1279..2a31005c8 100644
--- a/packages/CLI11/include/CLI/StringTools.hpp
+++ b/packages/CLI11/include/CLI/StringTools.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/include/CLI/Timer.hpp b/packages/CLI11/include/CLI/Timer.hpp
index c6898204e..b185d3302 100644
--- a/packages/CLI11/include/CLI/Timer.hpp
+++ b/packages/CLI11/include/CLI/Timer.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/include/CLI/TypeTools.hpp b/packages/CLI11/include/CLI/TypeTools.hpp
index e3c97b17e..9d43ea361 100644
--- a/packages/CLI11/include/CLI/TypeTools.hpp
+++ b/packages/CLI11/include/CLI/TypeTools.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -7,6 +7,7 @@
 #pragma once
 
 // [CLI11:public_includes:set]
+#include <cmath>
 #include <cstdint>
 #include <exception>
 #include <limits>
@@ -17,6 +18,7 @@
 #include <vector>
 // [CLI11:public_includes:end]
 
+#include "Encoding.hpp"
 #include "StringTools.hpp"
 
 namespace CLI {
@@ -42,7 +44,9 @@ constexpr enabler dummy = {};
 template <bool B, class T = void> using enable_if_t = typename std::enable_if<B, T>::type;
 
 /// A copy of std::void_t from C++17 (helper for C++11 and C++14)
-template <typename... Ts> struct make_void { using type = void; };
+template <typename... Ts> struct make_void {
+    using type = void;
+};
 
 /// A copy of std::void_t from C++17 - same reasoning as enable_if_t, it does not hurt to redefine
 template <typename... Ts> using void_t = typename make_void<Ts...>::type;
@@ -71,10 +75,14 @@ template <typename T> struct is_copyable_ptr {
 };
 
 /// This can be specialized to override the type deduction for IsMember.
-template <typename T> struct IsMemberType { using type = T; };
+template <typename T> struct IsMemberType {
+    using type = T;
+};
 
 /// The main custom type needed here is const char * should be a string.
-template <> struct IsMemberType<const char *> { using type = std::string; };
+template <> struct IsMemberType<const char *> {
+    using type = std::string;
+};
 
 namespace detail {
 
@@ -84,7 +92,9 @@ namespace detail {
 /// pointer_traits<T> be valid.
 
 /// not a pointer
-template <typename T, typename Enable = void> struct element_type { using type = T; };
+template <typename T, typename Enable = void> struct element_type {
+    using type = T;
+};
 
 template <typename T> struct element_type<T, typename std::enable_if<is_copyable_ptr<T>::value>::type> {
     using type = typename std::pointer_traits<T>::element_type;
@@ -92,7 +102,9 @@ template <typename T> struct element_type<T, typename std::enable_if<is_copyable
 
 /// Combination of the element type and value type - remove pointer (including smart pointers) and get the value_type of
 /// the container
-template <typename T> struct element_value_type { using type = typename element_type<T>::type::value_type; };
+template <typename T> struct element_value_type {
+    using type = typename element_type<T>::type::value_type;
+};
 
 /// Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost nothing.
 template <typename T, typename _ = void> struct pair_adaptor : std::false_type {
@@ -147,11 +159,19 @@ template <typename T, typename C> class is_direct_constructible {
     static auto test(int, std::true_type) -> decltype(
 // NVCC warns about narrowing conversions here
 #ifdef __CUDACC__
+#ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
+#pragma nv_diag_suppress 2361
+#else
 #pragma diag_suppress 2361
+#endif
 #endif
         TT{std::declval<CC>()}
 #ifdef __CUDACC__
+#ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
+#pragma nv_diag_default 2361
+#else
 #pragma diag_default 2361
+#endif
 #endif
         ,
         std::is_move_assignable<TT>());
@@ -231,8 +251,10 @@ struct is_mutable_container<
                          decltype(std::declval<T>().clear()),
                          decltype(std::declval<T>().insert(std::declval<decltype(std::declval<T>().end())>(),
                                                            std::declval<const typename T::value_type &>()))>,
-                  void>>
-    : public conditional_t<std::is_constructible<T, std::string>::value, std::false_type, std::true_type> {};
+                  void>> : public conditional_t<std::is_constructible<T, std::string>::value ||
+                                                    std::is_constructible<T, std::wstring>::value,
+                                                std::false_type,
+                                                std::true_type> {};
 
 // check to see if an object is a mutable container (fail by default)
 template <typename T, typename _ = void> struct is_readable_container : std::false_type {};
@@ -353,7 +375,9 @@ auto value_string(const T &value) -> decltype(to_string(value)) {
 }
 
 /// template to get the underlying value type if it exists or use a default
-template <typename T, typename def, typename Enable = void> struct wrapped_type { using type = def; };
+template <typename T, typename def, typename Enable = void> struct wrapped_type {
+    using type = def;
+};
 
 /// Type size for regular object types that do not look like a tuple
 template <typename T, typename def> struct wrapped_type<T, def, typename std::enable_if<is_wrapper<T>::value>::type> {
@@ -361,7 +385,9 @@ template <typename T, typename def> struct wrapped_type<T, def, typename std::en
 };
 
 /// This will only trigger for actual void type
-template <typename T, typename Enable = void> struct type_count_base { static const int value{0}; };
+template <typename T, typename Enable = void> struct type_count_base {
+    static const int value{0};
+};
 
 /// Type size for regular object types that do not look like a tuple
 template <typename T>
@@ -391,7 +417,9 @@ template <typename T> struct subtype_count;
 template <typename T> struct subtype_count_min;
 
 /// This will only trigger for actual void type
-template <typename T, typename Enable = void> struct type_count { static const int value{0}; };
+template <typename T, typename Enable = void> struct type_count {
+    static const int value{0};
+};
 
 /// Type size for regular object types that do not look like a tuple
 template <typename T>
@@ -442,7 +470,9 @@ template <typename T> struct subtype_count {
 };
 
 /// This will only trigger for actual void type
-template <typename T, typename Enable = void> struct type_count_min { static const int value{0}; };
+template <typename T, typename Enable = void> struct type_count_min {
+    static const int value{0};
+};
 
 /// Type size for regular object types that do not look like a tuple
 template <typename T>
@@ -491,7 +521,9 @@ template <typename T> struct subtype_count_min {
 };
 
 /// This will only trigger for actual void type
-template <typename T, typename Enable = void> struct expected_count { static const int value{0}; };
+template <typename T, typename Enable = void> struct expected_count {
+    static const int value{0};
+};
 
 /// For most types the number of expected items is 1
 template <typename T>
@@ -525,6 +557,8 @@ enum class object_category : int {
     // string like types
     string_assignable = 23,
     string_constructible = 24,
+    wstring_assignable = 25,
+    wstring_constructible = 26,
     other = 45,
     // special wrapper or container types
     wrapper_value = 50,
@@ -592,6 +626,27 @@ struct classify_object<
     static constexpr object_category value{object_category::string_constructible};
 };
 
+/// Wide strings
+template <typename T>
+struct classify_object<T,
+                       typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
+                                               !std::is_assignable<T &, std::string>::value &&
+                                               !std::is_constructible<T, std::string>::value &&
+                                               std::is_assignable<T &, std::wstring>::value>::type> {
+    static constexpr object_category value{object_category::wstring_assignable};
+};
+
+template <typename T>
+struct classify_object<
+    T,
+    typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
+                            !std::is_assignable<T &, std::string>::value &&
+                            !std::is_constructible<T, std::string>::value &&
+                            !std::is_assignable<T &, std::wstring>::value && (type_count<T>::value == 1) &&
+                            std::is_constructible<T, std::wstring>::value>::type> {
+    static constexpr object_category value{object_category::wstring_constructible};
+};
+
 /// Enumerations
 template <typename T> struct classify_object<T, typename std::enable_if<std::is_enum<T>::value>::type> {
     static constexpr object_category value{object_category::enumeration};
@@ -604,12 +659,13 @@ template <typename T> struct classify_object<T, typename std::enable_if<is_compl
 /// Handy helper to contain a bunch of checks that rule out many common types (integers, string like, floating point,
 /// vectors, and enumerations
 template <typename T> struct uncommon_type {
-    using type = typename std::conditional<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
-                                               !std::is_assignable<T &, std::string>::value &&
-                                               !std::is_constructible<T, std::string>::value && !is_complex<T>::value &&
-                                               !is_mutable_container<T>::value && !std::is_enum<T>::value,
-                                           std::true_type,
-                                           std::false_type>::type;
+    using type = typename std::conditional<
+        !std::is_floating_point<T>::value && !std::is_integral<T>::value &&
+            !std::is_assignable<T &, std::string>::value && !std::is_constructible<T, std::string>::value &&
+            !std::is_assignable<T &, std::wstring>::value && !std::is_constructible<T, std::wstring>::value &&
+            !is_complex<T>::value && !is_mutable_container<T>::value && !std::is_enum<T>::value,
+        std::true_type,
+        std::false_type>::type;
     static constexpr bool value = type::value;
 };
 
@@ -655,7 +711,8 @@ struct classify_object<
     typename std::enable_if<is_tuple_like<T>::value &&
                             ((type_count<T>::value >= 2 && !is_wrapper<T>::value) ||
                              (uncommon_type<T>::value && !is_direct_constructible<T, double>::value &&
-                              !is_direct_constructible<T, int>::value))>::type> {
+                              !is_direct_constructible<T, int>::value) ||
+                             (uncommon_type<T>::value && type_count<T>::value >= 2))>::type> {
     static constexpr object_category value{object_category::tuple_value};
     // the condition on this class requires it be like a tuple, but on some compilers (like Xcode) tuples can be
     // constructed from just the first element so tuples of <string, int,int> can be constructed from a string, which
@@ -794,11 +851,15 @@ inline std::string type_name() {
 /// Convert to an unsigned integral
 template <typename T, enable_if_t<std::is_unsigned<T>::value, detail::enabler> = detail::dummy>
 bool integral_conversion(const std::string &input, T &output) noexcept {
-    if(input.empty()) {
+    if(input.empty() || input.front() == '-') {
         return false;
     }
     char *val = nullptr;
+    errno = 0;
     std::uint64_t output_ll = std::strtoull(input.c_str(), &val, 0);
+    if(errno == ERANGE) {
+        return false;
+    }
     output = static_cast<T>(output_ll);
     if(val == (input.c_str() + input.size()) && static_cast<std::uint64_t>(output) == output_ll) {
         return true;
@@ -819,7 +880,11 @@ bool integral_conversion(const std::string &input, T &output) noexcept {
         return false;
     }
     char *val = nullptr;
+    errno = 0;
     std::int64_t output_ll = std::strtoll(input.c_str(), &val, 0);
+    if(errno == ERANGE) {
+        return false;
+    }
     output = static_cast<T>(output_ll);
     if(val == (input.c_str() + input.size()) && static_cast<std::int64_t>(output) == output_ll) {
         return true;
@@ -936,18 +1001,18 @@ bool lexical_cast(const std::string &input, T &output) {
     bool worked = false;
     auto nloc = str1.find_last_of("+-");
     if(nloc != std::string::npos && nloc > 0) {
-        worked = detail::lexical_cast(str1.substr(0, nloc), x);
+        worked = lexical_cast(str1.substr(0, nloc), x);
         str1 = str1.substr(nloc);
         if(str1.back() == 'i' || str1.back() == 'j')
             str1.pop_back();
-        worked = worked && detail::lexical_cast(str1, y);
+        worked = worked && lexical_cast(str1, y);
     } else {
         if(str1.back() == 'i' || str1.back() == 'j') {
             str1.pop_back();
-            worked = detail::lexical_cast(str1, y);
+            worked = lexical_cast(str1, y);
             x = XC{0};
         } else {
-            worked = detail::lexical_cast(str1, x);
+            worked = lexical_cast(str1, x);
             y = XC{0};
         }
     }
@@ -975,6 +1040,23 @@ bool lexical_cast(const std::string &input, T &output) {
     return true;
 }
 
+/// Wide strings
+template <
+    typename T,
+    enable_if_t<classify_object<T>::value == object_category::wstring_assignable, detail::enabler> = detail::dummy>
+bool lexical_cast(const std::string &input, T &output) {
+    output = widen(input);
+    return true;
+}
+
+template <
+    typename T,
+    enable_if_t<classify_object<T>::value == object_category::wstring_constructible, detail::enabler> = detail::dummy>
+bool lexical_cast(const std::string &input, T &output) {
+    output = T{widen(input)};
+    return true;
+}
+
 /// Enumerations
 template <typename T,
           enable_if_t<classify_object<T>::value == object_category::enumeration, detail::enabler> = detail::dummy>
@@ -1103,7 +1185,9 @@ template <typename AssignTo,
           typename ConvertTo,
           enable_if_t<std::is_same<AssignTo, ConvertTo>::value &&
                           (classify_object<AssignTo>::value == object_category::string_assignable ||
-                           classify_object<AssignTo>::value == object_category::string_constructible),
+                           classify_object<AssignTo>::value == object_category::string_constructible ||
+                           classify_object<AssignTo>::value == object_category::wstring_assignable ||
+                           classify_object<AssignTo>::value == object_category::wstring_constructible),
                       detail::enabler> = detail::dummy>
 bool lexical_assign(const std::string &input, AssignTo &output) {
     return lexical_cast(input, output);
@@ -1114,7 +1198,9 @@ template <typename AssignTo,
           typename ConvertTo,
           enable_if_t<std::is_same<AssignTo, ConvertTo>::value && std::is_assignable<AssignTo &, AssignTo>::value &&
                           classify_object<AssignTo>::value != object_category::string_assignable &&
-                          classify_object<AssignTo>::value != object_category::string_constructible,
+                          classify_object<AssignTo>::value != object_category::string_constructible &&
+                          classify_object<AssignTo>::value != object_category::wstring_assignable &&
+                          classify_object<AssignTo>::value != object_category::wstring_constructible,
                       detail::enabler> = detail::dummy>
 bool lexical_assign(const std::string &input, AssignTo &output) {
     if(input.empty()) {
@@ -1153,9 +1239,17 @@ bool lexical_assign(const std::string &input, AssignTo &output) {
         output = 0;
         return true;
     }
-    int val = 0;
+    int val{0};
     if(lexical_cast(input, val)) {
+#if defined(__clang__)
+/* on some older clang compilers */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
         output = val;
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
         return true;
     }
     return false;
@@ -1168,7 +1262,7 @@ template <typename AssignTo,
                       detail::enabler> = detail::dummy>
 bool lexical_assign(const std::string &input, AssignTo &output) {
     ConvertTo val{};
-    bool parse_result = (!input.empty()) ? lexical_cast<ConvertTo>(input, val) : true;
+    bool parse_result = (!input.empty()) ? lexical_cast(input, val) : true;
     if(parse_result) {
         output = val;
     }
@@ -1184,7 +1278,7 @@ template <
                 detail::enabler> = detail::dummy>
 bool lexical_assign(const std::string &input, AssignTo &output) {
     ConvertTo val{};
-    bool parse_result = input.empty() ? true : lexical_cast<ConvertTo>(input, val);
+    bool parse_result = input.empty() ? true : lexical_cast(input, val);
     if(parse_result) {
         output = AssignTo(val);  // use () form of constructor to allow some implicit conversions
     }
@@ -1210,11 +1304,13 @@ template <typename AssignTo,
                       detail::enabler> = detail::dummy>
 bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
     // the remove const is to handle pair types coming from a container
-    typename std::remove_const<typename std::tuple_element<0, ConvertTo>::type>::type v1;
-    typename std::tuple_element<1, ConvertTo>::type v2;
-    bool retval = lexical_assign<decltype(v1), decltype(v1)>(strings[0], v1);
+    using FirstType = typename std::remove_const<typename std::tuple_element<0, ConvertTo>::type>::type;
+    using SecondType = typename std::tuple_element<1, ConvertTo>::type;
+    FirstType v1;
+    SecondType v2;
+    bool retval = lexical_assign<FirstType, FirstType>(strings[0], v1);
     if(strings.size() > 1) {
-        retval = retval && lexical_assign<decltype(v2), decltype(v2)>(strings[1], v2);
+        retval = retval && lexical_assign<SecondType, SecondType>(strings[1], v2);
     }
     if(retval) {
         output = AssignTo{v1, v2};
@@ -1262,7 +1358,7 @@ bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &outpu
         if(str1.back() == 'i' || str1.back() == 'j') {
             str1.pop_back();
         }
-        auto worked = detail::lexical_cast(strings[0], x) && detail::lexical_cast(str1, y);
+        auto worked = lexical_cast(strings[0], x) && lexical_cast(str1, y);
         if(worked) {
             output = ConvertTo{x, y};
         }
@@ -1374,7 +1470,7 @@ tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
 
     std::size_t index{subtype_count_min<ConvertTo>::value};
     const std::size_t mx_count{subtype_count<ConvertTo>::value};
-    const std::size_t mx{(std::max)(mx_count, strings.size())};
+    const std::size_t mx{(std::min)(mx_count, strings.size() - 1)};
 
     while(index < mx) {
         if(is_separator(strings[index])) {
@@ -1384,7 +1480,11 @@ tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
     }
     bool retval = lexical_conversion<AssignTo, ConvertTo>(
         std::vector<std::string>(strings.begin(), strings.begin() + static_cast<std::ptrdiff_t>(index)), output);
-    strings.erase(strings.begin(), strings.begin() + static_cast<std::ptrdiff_t>(index) + 1);
+    if(strings.size() > index) {
+        strings.erase(strings.begin(), strings.begin() + static_cast<std::ptrdiff_t>(index) + 1);
+    } else {
+        strings.clear();
+    }
     return retval;
 }
 
@@ -1526,7 +1626,7 @@ inline std::string sum_string_vector(const std::vector<std::string> &values) {
     std::string output;
     for(const auto &arg : values) {
         double tv{0.0};
-        auto comp = detail::lexical_cast<double>(arg, tv);
+        auto comp = lexical_cast(arg, tv);
         if(!comp) {
             try {
                 tv = static_cast<double>(detail::to_flag_value(arg));
@@ -1544,8 +1644,7 @@ inline std::string sum_string_vector(const std::vector<std::string> &values) {
     } else {
         if(val <= static_cast<double>((std::numeric_limits<std::int64_t>::min)()) ||
            val >= static_cast<double>((std::numeric_limits<std::int64_t>::max)()) ||
-           // NOLINTNEXTLINE(clang-diagnostic-float-equal,bugprone-narrowing-conversions)
-           val == static_cast<std::int64_t>(val)) {
+           std::ceil(val) == std::floor(val)) {
             output = detail::value_string(static_cast<int64_t>(val));
         } else {
             output = detail::value_string(val);
diff --git a/packages/CLI11/include/CLI/Validators.hpp b/packages/CLI11/include/CLI/Validators.hpp
index 9a6a364e3..59d800de8 100644
--- a/packages/CLI11/include/CLI/Validators.hpp
+++ b/packages/CLI11/include/CLI/Validators.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -26,34 +26,6 @@
 
 // [CLI11:validators_hpp_filesystem:verbatim]
 
-// C standard library
-// Only needed for existence checking
-#if defined CLI11_CPP17 && defined __has_include && !defined CLI11_HAS_FILESYSTEM
-#if __has_include(<filesystem>)
-// Filesystem cannot be used if targeting macOS < 10.15
-#if defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
-#define CLI11_HAS_FILESYSTEM 0
-#elif defined(__wasi__)
-// As of wasi-sdk-14, filesystem is not implemented
-#define CLI11_HAS_FILESYSTEM 0
-#else
-#include <filesystem>
-#if defined __cpp_lib_filesystem && __cpp_lib_filesystem >= 201703
-#if defined _GLIBCXX_RELEASE && _GLIBCXX_RELEASE >= 9
-#define CLI11_HAS_FILESYSTEM 1
-#elif defined(__GLIBCXX__)
-// if we are using gcc and Version <9 default to no filesystem
-#define CLI11_HAS_FILESYSTEM 0
-#else
-#define CLI11_HAS_FILESYSTEM 1
-#endif
-#else
-#define CLI11_HAS_FILESYSTEM 0
-#endif
-#endif
-#endif
-#endif
-
 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
 #include <filesystem>  // NOLINT(build/include)
 #else
@@ -270,8 +242,9 @@ template <typename DesiredType> class TypeValidator : public Validator {
   public:
     explicit TypeValidator(const std::string &validator_name)
         : Validator(validator_name, [](std::string &input_string) {
+              using CLI::detail::lexical_cast;
               auto val = DesiredType();
-              if(!detail::lexical_cast(input_string, val)) {
+              if(!lexical_cast(input_string, val)) {
                   return std::string("Failed parsing ") + input_string + " as a " + detail::type_name<DesiredType>();
               }
               return std::string();
@@ -305,8 +278,9 @@ class Range : public Validator {
         }
 
         func_ = [min_val, max_val](std::string &input) {
+            using CLI::detail::lexical_cast;
             T val;
-            bool converted = detail::lexical_cast(input, val);
+            bool converted = lexical_cast(input, val);
             if((!converted) || (val < min_val || val > max_val)) {
                 std::stringstream out;
                 out << "Value " << input << " not in range [";
@@ -342,8 +316,9 @@ class Bound : public Validator {
         description(out.str());
 
         func_ = [min_val, max_val](std::string &input) {
+            using CLI::detail::lexical_cast;
             T val;
-            bool converted = detail::lexical_cast(input, val);
+            bool converted = lexical_cast(input, val);
             if(!converted) {
                 return std::string("Value ") + input + " could not be converted";
             }
@@ -534,8 +509,9 @@ class IsMember : public Validator {
         // This is the function that validates
         // It stores a copy of the set pointer-like, so shared_ptr will stay alive
         func_ = [set, filter_fn](std::string &input) {
+            using CLI::detail::lexical_cast;
             local_item_t b;
-            if(!detail::lexical_cast(input, b)) {
+            if(!lexical_cast(input, b)) {
                 throw ValidationError(input);  // name is added later
             }
             if(filter_fn) {
@@ -602,8 +578,9 @@ class Transformer : public Validator {
         desc_function_ = [mapping]() { return detail::generate_map(detail::smart_deref(mapping)); };
 
         func_ = [mapping, filter_fn](std::string &input) {
+            using CLI::detail::lexical_cast;
             local_item_t b;
-            if(!detail::lexical_cast(input, b)) {
+            if(!lexical_cast(input, b)) {
                 return std::string();
                 // there is no possible way we can match anything in the mapping if we can't convert so just return
             }
@@ -671,8 +648,9 @@ class CheckedTransformer : public Validator {
         desc_function_ = tfunc;
 
         func_ = [mapping, tfunc, filter_fn](std::string &input) {
+            using CLI::detail::lexical_cast;
             local_item_t b;
-            bool converted = detail::lexical_cast(input, b);
+            bool converted = lexical_cast(input, b);
             if(converted) {
                 if(filter_fn) {
                     b = filter_fn(b);
@@ -750,7 +728,7 @@ class AsNumberWithUnit : public Validator {
 
         // transform function
         func_ = [mapping, opts](std::string &input) -> std::string {
-            Number num;
+            Number num{};
 
             detail::rtrim(input);
             if(input.empty()) {
@@ -774,7 +752,8 @@ class AsNumberWithUnit : public Validator {
                 unit = detail::to_lower(unit);
             }
             if(unit.empty()) {
-                if(!detail::lexical_cast(input, num)) {
+                using CLI::detail::lexical_cast;
+                if(!lexical_cast(input, num)) {
                     throw ValidationError(std::string("Value ") + input + " could not be converted to " +
                                           detail::type_name<Number>());
                 }
@@ -792,7 +771,8 @@ class AsNumberWithUnit : public Validator {
             }
 
             if(!input.empty()) {
-                bool converted = detail::lexical_cast(input, num);
+                using CLI::detail::lexical_cast;
+                bool converted = lexical_cast(input, num);
                 if(!converted) {
                     throw ValidationError(std::string("Value ") + input + " could not be converted to " +
                                           detail::type_name<Number>());
diff --git a/packages/CLI11/include/CLI/Version.hpp b/packages/CLI11/include/CLI/Version.hpp
index b03141b82..d5c817a9c 100644
--- a/packages/CLI11/include/CLI/Version.hpp
+++ b/packages/CLI11/include/CLI/Version.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -9,8 +9,8 @@
 // [CLI11:version_hpp:verbatim]
 
 #define CLI11_VERSION_MAJOR 2
-#define CLI11_VERSION_MINOR 2
-#define CLI11_VERSION_PATCH 0
-#define CLI11_VERSION "2.2.0"
+#define CLI11_VERSION_MINOR 3
+#define CLI11_VERSION_PATCH 2
+#define CLI11_VERSION "2.3.2"
 
 // [CLI11:version_hpp:end]
diff --git a/packages/CLI11/include/CLI/impl/App_inl.hpp b/packages/CLI11/include/CLI/impl/App_inl.hpp
index bbda621df..7d487442f 100644
--- a/packages/CLI11/include/CLI/impl/App_inl.hpp
+++ b/packages/CLI11/include/CLI/impl/App_inl.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -9,6 +9,9 @@
 // This include is only needed for IDEs to discover symbols
 #include <CLI/App.hpp>
 
+#include <CLI/Argv.hpp>
+#include <CLI/Encoding.hpp>
+
 // [CLI11:public_includes:set]
 #include <algorithm>
 #include <memory>
@@ -46,6 +49,7 @@ CLI11_INLINE App::App(std::string app_description, std::string app_name, App *pa
         configurable_ = parent_->configurable_;
         allow_windows_style_options_ = parent_->allow_windows_style_options_;
         group_ = parent_->group_;
+        usage_ = parent_->usage_;
         footer_ = parent_->footer_;
         formatter_ = parent_->formatter_;
         config_formatter_ = parent_->config_formatter_;
@@ -265,8 +269,9 @@ CLI11_INLINE Option *App::add_flag_callback(std::string flag_name,
                                             std::string flag_description) {
 
     CLI::callback_t fun = [function](const CLI::results_t &res) {
+        using CLI::detail::lexical_cast;
         bool trigger{false};
-        auto result = CLI::detail::lexical_cast(res[0], trigger);
+        auto result = lexical_cast(res[0], trigger);
         if(result && trigger) {
             function();
         }
@@ -281,8 +286,9 @@ App::add_flag_function(std::string flag_name,
                        std::string flag_description) {
 
     CLI::callback_t fun = [function](const CLI::results_t &res) {
+        using CLI::detail::lexical_cast;
         std::int64_t flag_count{0};
-        CLI::detail::lexical_cast(res[0], flag_count);
+        lexical_cast(res[0], flag_count);
         function(flag_count);
         return true;
     };
@@ -433,6 +439,15 @@ CLI11_NODISCARD CLI11_INLINE CLI::App_p App::get_subcommand_ptr(int index) const
     throw OptionNotFound(std::to_string(index));
 }
 
+CLI11_NODISCARD CLI11_INLINE CLI::App *App::get_option_group(std::string group_name) const {
+    for(const App_p &app : subcommands_) {
+        if(app->name_.empty() && app->group_ == group_name) {
+            return app.get();
+        }
+    }
+    throw OptionNotFound(group_name);
+}
+
 CLI11_NODISCARD CLI11_INLINE std::size_t App::count_all() const {
     std::size_t cnt{0};
     for(const auto &opt : options_) {
@@ -462,17 +477,31 @@ CLI11_INLINE void App::clear() {
     }
 }
 
-CLI11_INLINE void App::parse(int argc, const char *const *argv) {
+CLI11_INLINE void App::parse() { parse(argc(), argv()); }  // LCOV_EXCL_LINE
+
+CLI11_INLINE void App::parse(int argc, const char *const *argv) { parse_char_t(argc, argv); }
+CLI11_INLINE void App::parse(int argc, const wchar_t *const *argv) { parse_char_t(argc, argv); }
+
+namespace detail {
+
+// Do nothing or perform narrowing
+CLI11_INLINE const char *maybe_narrow(const char *str) { return str; }
+CLI11_INLINE std::string maybe_narrow(const wchar_t *str) { return narrow(str); }
+
+}  // namespace detail
+
+template <class CharT> CLI11_INLINE void App::parse_char_t(int argc, const CharT *const *argv) {
     // If the name is not set, read from command line
     if(name_.empty() || has_automatic_name_) {
         has_automatic_name_ = true;
-        name_ = argv[0];
+        name_ = detail::maybe_narrow(argv[0]);
     }
 
     std::vector<std::string> args;
     args.reserve(static_cast<std::size_t>(argc) - 1U);
     for(auto i = static_cast<std::size_t>(argc) - 1U; i > 0U; --i)
-        args.emplace_back(argv[i]);
+        args.emplace_back(detail::maybe_narrow(argv[i]));
+
     parse(std::move(args));
 }
 
@@ -503,6 +532,10 @@ CLI11_INLINE void App::parse(std::string commandline, bool program_name_included
     parse(std::move(args));
 }
 
+CLI11_INLINE void App::parse(std::wstring commandline, bool program_name_included) {
+    parse(narrow(commandline), program_name_included);
+}
+
 CLI11_INLINE void App::parse(std::vector<std::string> &args) {
     // Clear if parsed
     if(parsed_ > 0)
@@ -657,7 +690,7 @@ CLI11_NODISCARD CLI11_INLINE std::string App::help(std::string prev, AppFormatMo
     // Delegate to subcommand if needed
     auto selected_subcommands = get_subcommands();
     if(!selected_subcommands.empty()) {
-        return selected_subcommands.at(0)->help(prev, mode);
+        return selected_subcommands.back()->help(prev, mode);
     }
     return formatter_->make_help(this, prev, mode);
 }
@@ -964,6 +997,16 @@ CLI11_NODISCARD CLI11_INLINE detail::Classifier App::_recognize(const std::strin
         return detail::Classifier::WINDOWS_STYLE;
     if((current == "++") && !name_.empty() && parent_ != nullptr)
         return detail::Classifier::SUBCOMMAND_TERMINATOR;
+    auto dotloc = current.find_first_of('.');
+    if(dotloc != std::string::npos) {
+        auto *cm = _find_subcommand(current.substr(0, dotloc), true, ignore_used_subcommands);
+        if(cm != nullptr) {
+            auto res = cm->_recognize(current.substr(dotloc + 1), ignore_used_subcommands);
+            if(res == detail::Classifier::SUBCOMMAND) {
+                return res;
+            }
+        }
+    }
     return detail::Classifier::NONE;
 }
 
@@ -1371,6 +1414,9 @@ CLI11_INLINE bool App::_parse_single_config(const ConfigItem &item, std::size_t
         if(get_allow_config_extras() == config_extras_mode::capture)
             // Should we worry about classifying the extras properly?
             missing_.emplace_back(detail::Classifier::NONE, item.fullname());
+        for(const auto &input : item.inputs) {
+            missing_.emplace_back(detail::Classifier::NONE, input);
+        }
         return false;
     }
 
@@ -1384,16 +1430,38 @@ CLI11_INLINE bool App::_parse_single_config(const ConfigItem &item, std::size_t
     if(op->empty()) {
 
         if(op->get_expected_min() == 0) {
-            // Flag parsing
-            auto res = config_formatter_->to_flag(item);
-            res = op->get_flag_value(item.name, res);
+            if(item.inputs.size() <= 1) {
+                // Flag parsing
+                auto res = config_formatter_->to_flag(item);
+                bool converted{false};
+                if(op->get_disable_flag_override()) {
+
+                    try {
+                        auto val = detail::to_flag_value(res);
+                        if(val == 1) {
+                            res = op->get_flag_value(item.name, "{}");
+                            converted = true;
+                        }
+                    } catch(...) {
+                    }
+                }
 
-            op->add_result(res);
+                if(!converted) {
+                    res = op->get_flag_value(item.name, res);
+                }
 
-        } else {
-            op->add_result(item.inputs);
-            op->run_callback();
+                op->add_result(res);
+                return true;
+            }
+            if(static_cast<int>(item.inputs.size()) > op->get_items_expected_max()) {
+                if(op->get_items_expected_max() > 1) {
+                    throw ArgumentMismatch::AtMost(item.fullname(), op->get_items_expected_max(), item.inputs.size());
+                }
+                throw ConversionError::TooManyInputsFlag(item.fullname());
+            }
         }
+        op->add_result(item.inputs);
+        op->run_callback();
     }
 
     return true;
@@ -1424,7 +1492,7 @@ CLI11_INLINE bool App::_parse_single(std::vector<std::string> &args, bool &posit
     case detail::Classifier::SHORT:
     case detail::Classifier::WINDOWS_STYLE:
         // If already parsed a subcommand, don't accept options_
-        _parse_arg(args, classifier);
+        _parse_arg(args, classifier, false);
         break;
     case detail::Classifier::NONE:
         // Probably a positional or something for a parent (sub)command
@@ -1612,6 +1680,17 @@ CLI11_INLINE bool App::_parse_subcommand(std::vector<std::string> &args) {
         return true;
     }
     auto *com = _find_subcommand(args.back(), true, true);
+    if(com == nullptr) {
+        // the main way to get here is using .notation
+        auto dotloc = args.back().find_first_of('.');
+        if(dotloc != std::string::npos) {
+            com = _find_subcommand(args.back().substr(0, dotloc), true, true);
+            if(com != nullptr) {
+                args.back() = args.back().substr(dotloc + 1);
+                args.push_back(com->get_display_name());
+            }
+        }
+    }
     if(com != nullptr) {
         args.pop_back();
         if(!com->silent_) {
@@ -1634,7 +1713,8 @@ CLI11_INLINE bool App::_parse_subcommand(std::vector<std::string> &args) {
     return false;
 }
 
-CLI11_INLINE bool App::_parse_arg(std::vector<std::string> &args, detail::Classifier current_type) {
+CLI11_INLINE bool
+App::_parse_arg(std::vector<std::string> &args, detail::Classifier current_type, bool local_processing_only) {
 
     std::string current = args.back();
 
@@ -1676,7 +1756,7 @@ CLI11_INLINE bool App::_parse_arg(std::vector<std::string> &args, detail::Classi
     if(op_ptr == std::end(options_)) {
         for(auto &subc : subcommands_) {
             if(subc->name_.empty() && !subc->disabled_) {
-                if(subc->_parse_arg(args, current_type)) {
+                if(subc->_parse_arg(args, current_type, local_processing_only)) {
                     if(!subc->pre_parse_called_) {
                         subc->_trigger_pre_parse(args.size());
                     }
@@ -1690,9 +1770,57 @@ CLI11_INLINE bool App::_parse_arg(std::vector<std::string> &args, detail::Classi
             return false;
         }
 
+        // now check for '.' notation of subcommands
+        auto dotloc = arg_name.find_first_of('.', 1);
+        if(dotloc != std::string::npos) {
+            // using dot notation is equivalent to single argument subcommand
+            auto *sub = _find_subcommand(arg_name.substr(0, dotloc), true, false);
+            if(sub != nullptr) {
+                auto v = args.back();
+                args.pop_back();
+                arg_name = arg_name.substr(dotloc + 1);
+                if(arg_name.size() > 1) {
+                    args.push_back(std::string("--") + v.substr(dotloc + 3));
+                    current_type = detail::Classifier::LONG;
+                } else {
+                    auto nval = v.substr(dotloc + 2);
+                    nval.front() = '-';
+                    if(nval.size() > 2) {
+                        // '=' not allowed in short form arguments
+                        args.push_back(nval.substr(3));
+                        nval.resize(2);
+                    }
+                    args.push_back(nval);
+                    current_type = detail::Classifier::SHORT;
+                }
+                auto val = sub->_parse_arg(args, current_type, true);
+                if(val) {
+                    if(!sub->silent_) {
+                        parsed_subcommands_.push_back(sub);
+                    }
+                    // deal with preparsing
+                    increment_parsed();
+                    _trigger_pre_parse(args.size());
+                    // run the parse complete callback since the subcommand processing is now complete
+                    if(sub->parse_complete_callback_) {
+                        sub->_process_env();
+                        sub->_process_callbacks();
+                        sub->_process_help_flags();
+                        sub->_process_requirements();
+                        sub->run_callback(false, true);
+                    }
+                    return true;
+                }
+                args.pop_back();
+                args.push_back(v);
+            }
+        }
+        if(local_processing_only) {
+            return false;
+        }
         // If a subcommand, try the main command
         if(parent_ != nullptr && fallthrough_)
-            return _get_fallthrough_parent()->_parse_arg(args, current_type);
+            return _get_fallthrough_parent()->_parse_arg(args, current_type, false);
 
         // Otherwise, add to missing
         args.pop_back();
diff --git a/packages/CLI11/include/CLI/impl/Argv_inl.hpp b/packages/CLI11/include/CLI/impl/Argv_inl.hpp
new file mode 100644
index 000000000..3d00a570d
--- /dev/null
+++ b/packages/CLI11/include/CLI/impl/Argv_inl.hpp
@@ -0,0 +1,183 @@
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
+// under NSF AWARD 1414736 and by the respective contributors.
+// All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+#pragma once
+
+// This include is only needed for IDEs to discover symbols
+#include <CLI/Argv.hpp>
+
+#include <CLI/Encoding.hpp>
+
+// [CLI11:public_includes:set]
+#include <algorithm>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <vector>
+// [CLI11:public_includes:end]
+
+// [CLI11:argv_inl_includes:verbatim]
+#if defined(_WIN32)
+#if !(defined(_AMD64_) || defined(_X86_) || defined(_ARM_))
+#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) ||           \
+    defined(_M_AMD64)
+#define _AMD64_
+#elif defined(i386) || defined(__i386) || defined(__i386__) || defined(__i386__) || defined(_M_IX86)
+#define _X86_
+#elif defined(__arm__) || defined(_M_ARM) || defined(_M_ARMT)
+#define _ARM_
+#endif
+#endif
+
+// first
+#ifndef NOMINMAX
+// if NOMINMAX is already defined we don't want to mess with that either way
+#define NOMINMAX
+#include <windef.h>
+#undef NOMINMAX
+#else
+#include <windef.h>
+#endif
+
+// second
+#include <winbase.h>
+// third
+#include <processthreadsapi.h>
+#include <shellapi.h>
+
+#elif defined(__APPLE__)
+#include <crt_externs.h>
+#endif
+// [CLI11:argv_inl_includes:end]
+
+namespace CLI {
+// [CLI11:argv_inl_hpp:verbatim]
+
+namespace detail {
+
+#ifdef __APPLE__
+// Copy argc and argv as early as possible to avoid modification
+static const std::vector<const char *> static_args = [] {
+    static const std::vector<std::string> static_args_as_strings = [] {
+        std::vector<std::string> args_as_strings;
+        int argc = *_NSGetArgc();
+        char **argv = *_NSGetArgv();
+
+        args_as_strings.reserve(static_cast<size_t>(argc));
+        for(size_t i = 0; i < static_cast<size_t>(argc); i++) {
+            args_as_strings.push_back(argv[i]);
+        }
+
+        return args_as_strings;
+    }();
+
+    std::vector<const char *> static_args_result;
+    static_args_result.reserve(static_args_as_strings.size());
+
+    for(const auto &arg : static_args_as_strings) {
+        static_args_result.push_back(arg.data());
+    }
+
+    return static_args_result;
+}();
+#endif
+
+/// Command-line arguments, as passed in to this executable, converted to utf-8 on Windows.
+CLI11_INLINE const std::vector<const char *> &args() {
+    // This function uses initialization via lambdas extensively to take advantage of the thread safety of static
+    // variable initialization [stmt.dcl.3]
+
+#ifdef _WIN32
+    static const std::vector<const char *> static_args = [] {
+        static const std::vector<std::string> static_args_as_strings = [] {
+            // On Windows, take arguments from GetCommandLineW and convert them to utf-8.
+            std::vector<std::string> args_as_strings;
+            int argc = 0;
+
+            auto deleter = [](wchar_t **ptr) { LocalFree(ptr); };
+            // NOLINTBEGIN(*-avoid-c-arrays)
+            auto wargv =
+                std::unique_ptr<wchar_t *[], decltype(deleter)>(CommandLineToArgvW(GetCommandLineW(), &argc), deleter);
+            // NOLINTEND(*-avoid-c-arrays)
+
+            if(wargv == nullptr) {
+                throw std::runtime_error("CommandLineToArgvW failed with code " + std::to_string(GetLastError()));
+            }
+
+            args_as_strings.reserve(static_cast<size_t>(argc));
+            for(size_t i = 0; i < static_cast<size_t>(argc); ++i) {
+                args_as_strings.push_back(narrow(wargv[i]));
+            }
+
+            return args_as_strings;
+        }();
+
+        std::vector<const char *> static_args_result;
+        static_args_result.reserve(static_args_as_strings.size());
+
+        for(const auto &arg : static_args_as_strings) {
+            static_args_result.push_back(arg.data());
+        }
+
+        return static_args_result;
+    }();
+
+    return static_args;
+
+#elif defined(__APPLE__)
+
+    return static_args;
+
+#else
+    static const std::vector<const char *> static_args = [] {
+        static const std::vector<char> static_cmdline = [] {
+            // On posix, retrieve arguments from /proc/self/cmdline, separated by null terminators.
+            std::vector<char> cmdline;
+
+            auto deleter = [](FILE *f) { std::fclose(f); };
+            std::unique_ptr<FILE, decltype(deleter)> fp_unique(std::fopen("/proc/self/cmdline", "r"), deleter);
+            FILE *fp = fp_unique.get();
+            if(!fp) {
+                throw std::runtime_error("could not open /proc/self/cmdline for reading");  // LCOV_EXCL_LINE
+            }
+
+            size_t size = 0;
+            while(std::feof(fp) == 0) {
+                cmdline.resize(size + 128);
+                size += std::fread(cmdline.data() + size, 1, 128, fp);
+
+                if(std::ferror(fp) != 0) {
+                    throw std::runtime_error("error during reading /proc/self/cmdline");  // LCOV_EXCL_LINE
+                }
+            }
+            cmdline.resize(size);
+
+            return cmdline;
+        }();
+
+        std::size_t argc = static_cast<std::size_t>(std::count(static_cmdline.begin(), static_cmdline.end(), '\0'));
+        std::vector<const char *> static_args_result;
+        static_args_result.reserve(argc);
+
+        for(auto it = static_cmdline.begin(); it != static_cmdline.end();
+            it = std::find(it, static_cmdline.end(), '\0') + 1) {
+            static_args_result.push_back(static_cmdline.data() + (it - static_cmdline.begin()));
+        }
+
+        return static_args_result;
+    }();
+
+    return static_args;
+#endif
+}
+
+}  // namespace detail
+
+CLI11_INLINE const char *const *argv() { return detail::args().data(); }
+CLI11_INLINE int argc() { return static_cast<int>(detail::args().size()); }
+
+// [CLI11:argv_inl_hpp:end]
+}  // namespace CLI
diff --git a/packages/CLI11/include/CLI/impl/Config_inl.hpp b/packages/CLI11/include/CLI/impl/Config_inl.hpp
index 0f9695f29..8021d5f63 100644
--- a/packages/CLI11/include/CLI/impl/Config_inl.hpp
+++ b/packages/CLI11/include/CLI/impl/Config_inl.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -31,8 +31,9 @@ CLI11_INLINE std::string convert_arg_for_ini(const std::string &arg, char string
     }
     // floating point conversion can convert some hex codes, but don't try that here
     if(arg.compare(0, 2, "0x") != 0 && arg.compare(0, 2, "0X") != 0) {
+        using CLI::detail::lexical_cast;
         double val = 0.0;
-        if(detail::lexical_cast(arg, val)) {
+        if(lexical_cast(arg, val)) {
             return arg;
         }
     }
@@ -344,6 +345,9 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description,
                 }
 
                 if(!value.empty()) {
+                    if(!opt->get_fnames().empty()) {
+                        value = opt->get_flag_value(name, value);
+                    }
                     if(write_description && opt->has_description()) {
                         out << '\n';
                         out << commentLead << detail::fix_newlines(commentLead, opt->get_description()) << '\n';
diff --git a/packages/CLI11/include/CLI/impl/Encoding_inl.hpp b/packages/CLI11/include/CLI/impl/Encoding_inl.hpp
new file mode 100644
index 000000000..f5d7e9a83
--- /dev/null
+++ b/packages/CLI11/include/CLI/impl/Encoding_inl.hpp
@@ -0,0 +1,154 @@
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
+// under NSF AWARD 1414736 and by the respective contributors.
+// All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+#pragma once
+
+// This include is only needed for IDEs to discover symbols
+#include <CLI/Encoding.hpp>
+#include <CLI/Macros.hpp>
+
+// [CLI11:public_includes:set]
+#include <array>
+#include <clocale>
+#include <cstdlib>
+#include <cstring>
+#include <cwchar>
+#include <locale>
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+#include <utility>
+// [CLI11:public_includes:end]
+
+namespace CLI {
+// [CLI11:encoding_inl_hpp:verbatim]
+
+namespace detail {
+
+#if !CLI11_HAS_CODECVT
+/// Attempt to set one of the acceptable unicode locales for conversion
+CLI11_INLINE void set_unicode_locale() {
+    static const std::array<const char *, 3> unicode_locales{{"C.UTF-8", "en_US.UTF-8", ".UTF-8"}};
+
+    for(const auto &locale_name : unicode_locales) {
+        if(std::setlocale(LC_ALL, locale_name) != nullptr) {
+            return;
+        }
+    }
+    throw std::runtime_error("CLI::narrow: could not set locale to C.UTF-8");
+}
+
+template <typename F> struct scope_guard_t {
+    F closure;
+
+    explicit scope_guard_t(F closure_) : closure(closure_) {}
+    ~scope_guard_t() { closure(); }
+};
+
+template <typename F> CLI11_NODISCARD CLI11_INLINE scope_guard_t<F> scope_guard(F &&closure) {
+    return scope_guard_t<F>{std::forward<F>(closure)};
+}
+
+#endif  // !CLI11_HAS_CODECVT
+
+CLI11_DIAGNOSTIC_PUSH
+CLI11_DIAGNOSTIC_IGNORE_DEPRECATED
+
+CLI11_INLINE std::string narrow_impl(const wchar_t *str, std::size_t str_size) {
+#if CLI11_HAS_CODECVT
+#ifdef _WIN32
+    return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().to_bytes(str, str + str_size);
+
+#else
+    return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(str, str + str_size);
+
+#endif  // _WIN32
+#else   // CLI11_HAS_CODECVT
+    (void)str_size;
+    std::mbstate_t state = std::mbstate_t();
+    const wchar_t *it = str;
+
+    std::string old_locale = std::setlocale(LC_ALL, nullptr);
+    auto sg = scope_guard([&] { std::setlocale(LC_ALL, old_locale.c_str()); });
+    set_unicode_locale();
+
+    std::size_t new_size = std::wcsrtombs(nullptr, &it, 0, &state);
+    if(new_size == static_cast<std::size_t>(-1)) {
+        throw std::runtime_error("CLI::narrow: conversion error in std::wcsrtombs at offset " +
+                                 std::to_string(it - str));
+    }
+    std::string result(new_size, '\0');
+    std::wcsrtombs(const_cast<char *>(result.data()), &str, new_size, &state);
+
+    return result;
+
+#endif  // CLI11_HAS_CODECVT
+}
+
+CLI11_INLINE std::wstring widen_impl(const char *str, std::size_t str_size) {
+#if CLI11_HAS_CODECVT
+#ifdef _WIN32
+    return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().from_bytes(str, str + str_size);
+
+#else
+    return std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(str, str + str_size);
+
+#endif  // _WIN32
+#else   // CLI11_HAS_CODECVT
+    (void)str_size;
+    std::mbstate_t state = std::mbstate_t();
+    const char *it = str;
+
+    std::string old_locale = std::setlocale(LC_ALL, nullptr);
+    auto sg = scope_guard([&] { std::setlocale(LC_ALL, old_locale.c_str()); });
+    set_unicode_locale();
+
+    std::size_t new_size = std::mbsrtowcs(nullptr, &it, 0, &state);
+    if(new_size == static_cast<std::size_t>(-1)) {
+        throw std::runtime_error("CLI::widen: conversion error in std::mbsrtowcs at offset " +
+                                 std::to_string(it - str));
+    }
+    std::wstring result(new_size, L'\0');
+    std::mbsrtowcs(const_cast<wchar_t *>(result.data()), &str, new_size, &state);
+
+    return result;
+
+#endif  // CLI11_HAS_CODECVT
+}
+
+CLI11_DIAGNOSTIC_POP
+
+}  // namespace detail
+
+CLI11_INLINE std::string narrow(const wchar_t *str, std::size_t str_size) { return detail::narrow_impl(str, str_size); }
+CLI11_INLINE std::string narrow(const std::wstring &str) { return detail::narrow_impl(str.data(), str.size()); }
+// Flawfinder: ignore
+CLI11_INLINE std::string narrow(const wchar_t *str) { return detail::narrow_impl(str, std::wcslen(str)); }
+
+CLI11_INLINE std::wstring widen(const char *str, std::size_t str_size) { return detail::widen_impl(str, str_size); }
+CLI11_INLINE std::wstring widen(const std::string &str) { return detail::widen_impl(str.data(), str.size()); }
+// Flawfinder: ignore
+CLI11_INLINE std::wstring widen(const char *str) { return detail::widen_impl(str, std::strlen(str)); }
+
+#ifdef CLI11_CPP17
+CLI11_INLINE std::string narrow(std::wstring_view str) { return detail::narrow_impl(str.data(), str.size()); }
+CLI11_INLINE std::wstring widen(std::string_view str) { return detail::widen_impl(str.data(), str.size()); }
+#endif  // CLI11_CPP17
+
+#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
+CLI11_INLINE std::filesystem::path to_path(std::string_view str) {
+    return std::filesystem::path{
+#ifdef _WIN32
+        widen(str)
+#else
+        str
+#endif  // _WIN32
+    };
+}
+#endif  // CLI11_HAS_FILESYSTEM
+
+// [CLI11:encoding_inl_hpp:end]
+}  // namespace CLI
diff --git a/packages/CLI11/include/CLI/impl/Formatter_inl.hpp b/packages/CLI11/include/CLI/impl/Formatter_inl.hpp
index 37249e082..84652fefa 100644
--- a/packages/CLI11/include/CLI/impl/Formatter_inl.hpp
+++ b/packages/CLI11/include/CLI/impl/Formatter_inl.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -69,13 +69,13 @@ CLI11_INLINE std::string Formatter::make_description(const App *app) const {
     auto min_options = app->get_require_option_min();
     auto max_options = app->get_require_option_max();
     if(app->get_required()) {
-        desc += " REQUIRED ";
+        desc += " " + get_label("REQUIRED") + " ";
     }
     if((max_options == min_options) && (min_options > 0)) {
         if(min_options == 1) {
             desc += " \n[Exactly 1 of the following options is required]";
         } else {
-            desc += " \n[Exactly " + std::to_string(min_options) + "options from the following list are required]";
+            desc += " \n[Exactly " + std::to_string(min_options) + " options from the following list are required]";
         }
     } else if(max_options > 0) {
         if(min_options > 0) {
@@ -91,6 +91,11 @@ CLI11_INLINE std::string Formatter::make_description(const App *app) const {
 }
 
 CLI11_INLINE std::string Formatter::make_usage(const App *app, std::string name) const {
+    std::string usage = app->get_usage();
+    if(!usage.empty()) {
+        return usage + "\n";
+    }
+
     std::stringstream out;
 
     out << get_label("Usage") << ":" << (name.empty() ? "" : " ") << name;
@@ -137,7 +142,7 @@ CLI11_INLINE std::string Formatter::make_footer(const App *app) const {
     if(footer.empty()) {
         return std::string{};
     }
-    return footer + "\n";
+    return "\n" + footer + "\n";
 }
 
 CLI11_INLINE std::string Formatter::make_help(const App *app, std::string name, AppFormatMode mode) const {
@@ -159,7 +164,7 @@ CLI11_INLINE std::string Formatter::make_help(const App *app, std::string name,
     out << make_positionals(app);
     out << make_groups(app, mode);
     out << make_subcommands(app, mode);
-    out << '\n' << make_footer(app);
+    out << make_footer(app);
 
     return out.str();
 }
@@ -208,7 +213,10 @@ CLI11_INLINE std::string Formatter::make_subcommands(const App *app, AppFormatMo
 
 CLI11_INLINE std::string Formatter::make_subcommand(const App *sub) const {
     std::stringstream out;
-    detail::format_help(out, sub->get_display_name(true), sub->get_description(), column_width_);
+    detail::format_help(out,
+                        sub->get_display_name(true) + (sub->get_required() ? " " + get_label("REQUIRED") : ""),
+                        sub->get_description(),
+                        column_width_);
     return out.str();
 }
 
diff --git a/packages/CLI11/include/CLI/impl/Option_inl.hpp b/packages/CLI11/include/CLI/impl/Option_inl.hpp
index a97346235..a24df9ab2 100644
--- a/packages/CLI11/include/CLI/impl/Option_inl.hpp
+++ b/packages/CLI11/include/CLI/impl/Option_inl.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/include/CLI/impl/Split_inl.hpp b/packages/CLI11/include/CLI/impl/Split_inl.hpp
index 03478b209..d974f80a6 100644
--- a/packages/CLI11/include/CLI/impl/Split_inl.hpp
+++ b/packages/CLI11/include/CLI/impl/Split_inl.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -34,7 +34,7 @@ CLI11_INLINE bool split_short(const std::string &current, std::string &name, std
 }
 
 CLI11_INLINE bool split_long(const std::string &current, std::string &name, std::string &value) {
-    if(current.size() > 2 && current.substr(0, 2) == "--" && valid_first_char(current[2])) {
+    if(current.size() > 2 && current.compare(0, 2, "--") == 0 && valid_first_char(current[2])) {
         auto loc = current.find_first_of('=');
         if(loc != std::string::npos) {
             name = current.substr(2, loc - 2);
diff --git a/packages/CLI11/include/CLI/impl/StringTools_inl.hpp b/packages/CLI11/include/CLI/impl/StringTools_inl.hpp
index 1a7cdd818..9b81fbde3 100644
--- a/packages/CLI11/include/CLI/impl/StringTools_inl.hpp
+++ b/packages/CLI11/include/CLI/impl/StringTools_inl.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/include/CLI/impl/Validators_inl.hpp b/packages/CLI11/include/CLI/impl/Validators_inl.hpp
index f2fe5e55d..a2295ecdf 100644
--- a/packages/CLI11/include/CLI/impl/Validators_inl.hpp
+++ b/packages/CLI11/include/CLI/impl/Validators_inl.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -8,6 +8,7 @@
 
 #include <CLI/Validators.hpp>
 
+#include <CLI/Encoding.hpp>
 #include <CLI/Macros.hpp>
 #include <CLI/StringTools.hpp>
 #include <CLI/TypeTools.hpp>
@@ -127,12 +128,12 @@ namespace detail {
 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
 CLI11_INLINE path_type check_path(const char *file) noexcept {
     std::error_code ec;
-    auto stat = std::filesystem::status(file, ec);
+    auto stat = std::filesystem::status(to_path(file), ec);
     if(ec) {
         return path_type::nonexistent;
     }
     switch(stat.type()) {
-    case std::filesystem::file_type::none:
+    case std::filesystem::file_type::none:  // LCOV_EXCL_LINE
     case std::filesystem::file_type::not_found:
         return path_type::nonexistent;
     case std::filesystem::file_type::directory:
@@ -219,7 +220,8 @@ CLI11_INLINE IPV4Validator::IPV4Validator() : Validator("IPV4") {
         }
         int num = 0;
         for(const auto &var : result) {
-            bool retval = detail::lexical_cast(var, num);
+            using CLI::detail::lexical_cast;
+            bool retval = lexical_cast(var, num);
             if(!retval) {
                 return std::string("Failed parsing number (") + var + ')';
             }
diff --git a/packages/CLI11/scripts/MakeSingleHeader.py b/packages/CLI11/scripts/MakeSingleHeader.py
index 4bc53dd15..7cca6f70a 100755
--- a/packages/CLI11/scripts/MakeSingleHeader.py
+++ b/packages/CLI11/scripts/MakeSingleHeader.py
@@ -80,7 +80,7 @@ class HeaderGroups(dict):
         """
         for key in self:
             if isinstance(self[key], set):
-                self[key] = "\n".join(self[key])
+                self[key] = "\n".join(sorted(self[key]))
 
 
 def make_header(output, main_header, files, tag, namespace, macro=None, version=None):
@@ -100,6 +100,8 @@ def make_header(output, main_header, files, tag, namespace, macro=None, version=
         groups["git"] = ""
 
     for f in files:
+        if os.path.isdir(f):
+            continue
         groups.read_header(f)
 
     groups["namespace"] = namespace
diff --git a/packages/CLI11/scripts/mdlint_style.rb b/packages/CLI11/scripts/mdlint_style.rb
index 6fca85b1a..5cb3a9792 100644
--- a/packages/CLI11/scripts/mdlint_style.rb
+++ b/packages/CLI11/scripts/mdlint_style.rb
@@ -6,3 +6,4 @@ exclude_rule 'MD034'  # Bare URL (for now)
 
 rule 'MD026', punctuation: '.,;:!'  # Trailing punctuation in header (& in this case)
 rule 'MD029', style: :ordered
+rule 'MD007', indent: 2
diff --git a/packages/CLI11/src/CMakeLists.txt b/packages/CLI11/src/CMakeLists.txt
index 341cae42c..4f7af6ad1 100644
--- a/packages/CLI11/src/CMakeLists.txt
+++ b/packages/CLI11/src/CMakeLists.txt
@@ -2,7 +2,6 @@ set(CLI11_headerLoc "${PROJECT_SOURCE_DIR}/include/CLI")
 
 set(CLI11_headers
     ${CLI11_headerLoc}/App.hpp
-    ${CLI11_headerLoc}/CLI.hpp
     ${CLI11_headerLoc}/Config.hpp
     ${CLI11_headerLoc}/ConfigFwd.hpp
     ${CLI11_headerLoc}/Error.hpp
@@ -12,10 +11,11 @@ set(CLI11_headers
     ${CLI11_headerLoc}/Option.hpp
     ${CLI11_headerLoc}/Split.hpp
     ${CLI11_headerLoc}/StringTools.hpp
-    ${CLI11_headerLoc}/Timer.hpp
     ${CLI11_headerLoc}/TypeTools.hpp
     ${CLI11_headerLoc}/Validators.hpp
-    ${CLI11_headerLoc}/Version.hpp)
+    ${CLI11_headerLoc}/Version.hpp
+    ${CLI11_headerLoc}/Encoding.hpp
+    ${CLI11_headerLoc}/Argv.hpp)
 
 set(CLI11_implLoc "${PROJECT_SOURCE_DIR}/include/CLI/impl")
 
@@ -26,12 +26,17 @@ set(CLI11_impl_headers
     ${CLI11_implLoc}/Option_inl.hpp
     ${CLI11_implLoc}/Split_inl.hpp
     ${CLI11_implLoc}/StringTools_inl.hpp
-    ${CLI11_implLoc}/Validators_inl.hpp)
+    ${CLI11_implLoc}/Validators_inl.hpp
+    ${CLI11_implLoc}/Encoding_inl.hpp
+    ${CLI11_implLoc}/Argv_inl.hpp)
+
+set(CLI11_library_headers ${CLI11_headerLoc}/CLI.hpp ${CLI11_headerLoc}/Timer.hpp)
 
 if(CLI11_PRECOMPILED)
   # Create static lib
   file(GLOB CLI11_precompile_sources "${PROJECT_SOURCE_DIR}/src/*.cpp")
-  add_library(CLI11 STATIC ${CLI11_headers} ${CLI11_impl_headers} ${CLI11_precompile_sources})
+  add_library(CLI11 STATIC ${CLI11_headers} ${CLI11_library_headers} ${CLI11_impl_headers}
+                           ${CLI11_precompile_sources})
   target_compile_definitions(CLI11 PUBLIC -DCLI11_COMPILE)
 
   set(PUBLIC_OR_INTERFACE PUBLIC)
@@ -39,7 +44,7 @@ else()
   add_library(CLI11 INTERFACE)
   if(CMAKE_VERSION VERSION_GREATER 3.19)
     # This is only useful for visual studio and other IDE builds
-    target_sources(CLI11 PRIVATE ${CLI11_headers} ${CLI11_impl_headers})
+    target_sources(CLI11 PRIVATE ${CLI11_headers} ${CLI11_library_headers} ${CLI11_impl_headers})
   endif()
 
   set(PUBLIC_OR_INTERFACE INTERFACE)
@@ -48,25 +53,35 @@ endif()
 # Allow IDE's to group targets into folders
 add_library(CLI11::CLI11 ALIAS CLI11) # for add_subdirectory calls
 
+if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
+  set(SYSTEM_INCL "")
+else()
+  # If this project is included from somewhere else, we mark our headers as system headers to avoid
+  # the compiler emitting any warnings about them
+  set(SYSTEM_INCL "SYSTEM")
+endif()
+
 # Duplicated because CMake adds the current source dir if you don't.
 target_include_directories(
-  CLI11 ${PUBLIC_OR_INTERFACE} $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
+  CLI11 ${SYSTEM_INCL} ${PUBLIC_OR_INTERFACE} $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
   $<INSTALL_INTERFACE:include>)
 
-if(CMAKE_VERSION VERSION_LESS 3.8)
-  # This might not be a complete list
-  target_compile_features(
-    CLI11
-    INTERFACE cxx_lambdas
-              cxx_nullptr
-              cxx_override
-              cxx_range_for
-              cxx_right_angle_brackets
-              cxx_strong_enums
-              cxx_constexpr
-              cxx_auto_type)
-else()
-  target_compile_features(CLI11 INTERFACE cxx_std_11)
+if(CMAKE_CXX_STANDARD LESS 14)
+  if(CMAKE_VERSION VERSION_LESS 3.8)
+    # This might not be a complete list
+    target_compile_features(
+      CLI11
+      INTERFACE cxx_lambdas
+                cxx_nullptr
+                cxx_override
+                cxx_range_for
+                cxx_right_angle_brackets
+                cxx_strong_enums
+                cxx_constexpr
+                cxx_auto_type)
+  else()
+    target_compile_features(CLI11 INTERFACE cxx_std_11)
+  endif()
 endif()
 
 if(CLI11_SINGLE_FILE)
@@ -112,7 +127,8 @@ if(CLI11_INSTALL)
   # Make an export target
   install(TARGETS CLI11 EXPORT CLI11Targets)
   if(NOT CLI11_SINGLE_FILE)
-    install(FILES ${CLI11_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/CLI")
+    install(FILES ${CLI11_headers} ${CLI11_library_headers}
+            DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/CLI")
     if(NOT CLI11_COMPILE)
       install(FILES ${CLI11_impl_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/CLI/impl")
     endif()
diff --git a/packages/CLI11/src/Precompile.cpp b/packages/CLI11/src/Precompile.cpp
index 81900ced3..5afd54cb9 100644
--- a/packages/CLI11/src/Precompile.cpp
+++ b/packages/CLI11/src/Precompile.cpp
@@ -1,11 +1,13 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
 // SPDX-License-Identifier: BSD-3-Clause
 
 #include <CLI/impl/App_inl.hpp>
+#include <CLI/impl/Argv_inl.hpp>
 #include <CLI/impl/Config_inl.hpp>
+#include <CLI/impl/Encoding_inl.hpp>
 #include <CLI/impl/Formatter_inl.hpp>
 #include <CLI/impl/Option_inl.hpp>
 #include <CLI/impl/Split_inl.hpp>
diff --git a/packages/CLI11/test_package/CMakeLists.txt b/packages/CLI11/test_package/CMakeLists.txt
deleted file mode 100644
index 48f6d9903..000000000
--- a/packages/CLI11/test_package/CMakeLists.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-project(PackageTest CXX)
-cmake_minimum_required(VERSION 3.1)
-
-include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
-conan_basic_setup()
-
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_EXTENSIONS OFF)
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-
-message(STATUS "${CMAKE_PREFIX_PATH}")
-
-find_package(CLI11 CONFIG REQUIRED)
-
-add_executable(example example.cpp)
-target_link_libraries(example CLI11::CLI11)
diff --git a/packages/CLI11/test_package/conanfile.py b/packages/CLI11/test_package/conanfile.py
deleted file mode 100644
index 4c5c028ec..000000000
--- a/packages/CLI11/test_package/conanfile.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from conans import ConanFile, CMake, tools
-import os
-
-
-class HelloTestConan(ConanFile):
-    settings = "os", "compiler", "build_type", "arch"
-    generators = "cmake"
-
-    def build(self):
-        cmake = CMake(self)
-        cmake.configure()
-        cmake.build()
-
-    def imports(self):
-        self.copy("*.dll", dst="bin", src="bin")
-        self.copy("*.dylib*", dst="bin", src="lib")
-
-    def test(self):
-        if not tools.cross_building(self.settings):
-            os.chdir("bin")
-            self.run(".%sexample" % os.sep)
diff --git a/packages/CLI11/test_package/example.cpp b/packages/CLI11/test_package/example.cpp
deleted file mode 100644
index 464cf7518..000000000
--- a/packages/CLI11/test_package/example.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-// This file is a "Hello, world!" CLI11 program
-
-#include "CLI/CLI.hpp"
-
-#include <iostream>
-
-int main(int argc, char **argv) {
-
-    CLI::App app("Some nice description");
-
-    int x = 0;
-    app.add_option("-x", x, "an integer value")->capture_default_str();
-
-    bool flag;
-    app.add_flag("-f,--flag", flag, "a flag option");
-
-    CLI11_PARSE(app, argc, argv);
-
-    return 0;
-}
diff --git a/packages/CLI11/tests/AppTest.cpp b/packages/CLI11/tests/AppTest.cpp
index 994c890ca..2cdefc4ee 100644
--- a/packages/CLI11/tests/AppTest.cpp
+++ b/packages/CLI11/tests/AppTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -7,6 +7,7 @@
 #include "app_helper.hpp"
 #include <cmath>
 
+#include <array>
 #include <complex>
 #include <cstdint>
 #include <cstdlib>
@@ -141,8 +142,6 @@ TEST_CASE_METHOD(TApp, "StrangeFlagNames", "[app]") {
 }
 
 TEST_CASE_METHOD(TApp, "RequireOptionsError", "[app]") {
-    using Catch::Matchers::Contains;
-
     app.add_flag("-c");
     app.add_flag("--q");
     app.add_flag("--this,--that");
@@ -261,6 +260,28 @@ TEST_CASE_METHOD(TApp, "OneString", "[app]") {
     CHECK("mystring" == str);
 }
 
+TEST_CASE_METHOD(TApp, "OneWideString", "[app]") {
+    std::wstring str;
+    app.add_option("-s,--string", str);
+    args = {"--string", "mystring"};
+    run();
+    CHECK(app.count("-s") == 1u);
+    CHECK(app.count("--string") == 1u);
+    CHECK(L"mystring" == str);
+}
+
+TEST_CASE_METHOD(TApp, "OneStringWideInput", "[app][unicode]") {
+    std::string str;
+    app.add_option("-s,--string", str);
+
+    std::array<const wchar_t *, 3> cmdline{{L"app", L"--string", L"mystring"}};
+    app.parse(static_cast<int>(cmdline.size()), cmdline.data());
+
+    CHECK(app.count("-s") == 1u);
+    CHECK(app.count("--string") == 1u);
+    CHECK("mystring" == str);
+}
+
 TEST_CASE_METHOD(TApp, "OneStringWindowsStyle", "[app]") {
     std::string str;
     app.add_option("-s,--string", str);
@@ -282,6 +303,16 @@ TEST_CASE_METHOD(TApp, "OneStringSingleStringInput", "[app]") {
     CHECK("mystring" == str);
 }
 
+TEST_CASE_METHOD(TApp, "OneStringSingleWideStringInput", "[app][unicode]") {
+    std::string str;
+    app.add_option("-s,--string", str);
+
+    app.parse(L"--string mystring");
+    CHECK(app.count("-s") == 1u);
+    CHECK(app.count("--string") == 1u);
+    CHECK("mystring" == str);
+}
+
 TEST_CASE_METHOD(TApp, "OneStringEqualVersion", "[app]") {
     std::string str;
     app.add_option("-s,--string", str);
@@ -981,7 +1012,9 @@ TEST_CASE_METHOD(TApp, "emptyVectorReturn", "[app]") {
 
     std::vector<std::string> strs;
     std::vector<std::string> strs2;
+    std::vector<std::string> strs3;
     auto *opt1 = app.add_option("--str", strs)->required()->expected(0, 2);
+    app.add_option("--str3", strs3)->expected(1, 3);
     app.add_option("--str2", strs2);
     args = {"--str"};
 
@@ -1004,6 +1037,11 @@ TEST_CASE_METHOD(TApp, "emptyVectorReturn", "[app]") {
 
     CHECK_NOTHROW(run());
     CHECK(strs.empty());
+    opt1->required(false);
+    args = {"--str3", "{}"};
+
+    CHECK_NOTHROW(run());
+    CHECK_FALSE(strs3.empty());
 }
 
 TEST_CASE_METHOD(TApp, "RequiredOptsDoubleShort", "[app]") {
@@ -1988,6 +2026,31 @@ TEST_CASE_METHOD(TApp, "typeCheck", "[app]") {
     CHECK_THROWS_AS(run(), CLI::ValidationError);
 }
 
+TEST_CASE_METHOD(TApp, "NeedsTrue", "[app]") {
+    std::string str;
+    app.add_option("-s,--string", str);
+    app.add_flag("--opt1")->check([&](const std::string &) {
+        return (str != "val_with_opt1") ? std::string("--opt1 requires --string val_with_opt1") : std::string{};
+    });
+
+    run();
+
+    args = {"--opt1"};
+    CHECK_THROWS_AS(run(), CLI::ValidationError);
+
+    args = {"--string", "val"};
+    run();
+
+    args = {"--string", "val", "--opt1"};
+    CHECK_THROWS_AS(run(), CLI::ValidationError);
+
+    args = {"--string", "val_with_opt1", "--opt1"};
+    run();
+
+    args = {"--opt1", "--string", "val_with_opt1"};  // order is not revelant
+    run();
+}
+
 // Check to make sure programmatic access to left over is available
 TEST_CASE_METHOD(TApp, "AllowExtras", "[app]") {
 
@@ -2086,21 +2149,23 @@ TEST_CASE_METHOD(TApp, "AllowExtrasArgModify", "[app]") {
 TEST_CASE_METHOD(TApp, "CheckShortFail", "[app]") {
     args = {"--two"};
 
-    CHECK_THROWS_AS(CLI::detail::AppFriend::parse_arg(&app, args, CLI::detail::Classifier::SHORT), CLI::HorribleError);
+    CHECK_THROWS_AS(CLI::detail::AppFriend::parse_arg(&app, args, CLI::detail::Classifier::SHORT, false),
+                    CLI::HorribleError);
 }
 
 // Test horrible error
 TEST_CASE_METHOD(TApp, "CheckLongFail", "[app]") {
     args = {"-t"};
 
-    CHECK_THROWS_AS(CLI::detail::AppFriend::parse_arg(&app, args, CLI::detail::Classifier::LONG), CLI::HorribleError);
+    CHECK_THROWS_AS(CLI::detail::AppFriend::parse_arg(&app, args, CLI::detail::Classifier::LONG, false),
+                    CLI::HorribleError);
 }
 
 // Test horrible error
 TEST_CASE_METHOD(TApp, "CheckWindowsFail", "[app]") {
     args = {"-t"};
 
-    CHECK_THROWS_AS(CLI::detail::AppFriend::parse_arg(&app, args, CLI::detail::Classifier::WINDOWS_STYLE),
+    CHECK_THROWS_AS(CLI::detail::AppFriend::parse_arg(&app, args, CLI::detail::Classifier::WINDOWS_STYLE, false),
                     CLI::HorribleError);
 }
 
@@ -2108,7 +2173,8 @@ TEST_CASE_METHOD(TApp, "CheckWindowsFail", "[app]") {
 TEST_CASE_METHOD(TApp, "CheckOtherFail", "[app]") {
     args = {"-t"};
 
-    CHECK_THROWS_AS(CLI::detail::AppFriend::parse_arg(&app, args, CLI::detail::Classifier::NONE), CLI::HorribleError);
+    CHECK_THROWS_AS(CLI::detail::AppFriend::parse_arg(&app, args, CLI::detail::Classifier::NONE, false),
+                    CLI::HorribleError);
 }
 
 // Test horrible error
@@ -2428,3 +2494,21 @@ TEST_CASE("C20_compile", "simple") {
     app.parse("--flag");
     CHECK_FALSE(flag->empty());
 }
+
+// #14
+TEST_CASE("System Args", "[app]") {
+    const char *commandline = CLI11_SYSTEM_ARGS_EXE " 1234 false \"hello world\"";
+    int retval = std::system(commandline);
+
+    if(retval == -1) {
+        FAIL("Executable '" << commandline << "' reported different argc count");
+    }
+
+    if(retval > 0) {
+        FAIL("Executable '" << commandline << "' reported different argv at index " << (retval - 1));
+    }
+
+    if(retval != 0) {
+        FAIL("Executable '" << commandline << "' failed with an unknown return code");
+    }
+}
diff --git a/packages/CLI11/tests/BoostOptionTypeTest.cpp b/packages/CLI11/tests/BoostOptionTypeTest.cpp
index c3cd81852..1dabc37da 100644
--- a/packages/CLI11/tests/BoostOptionTypeTest.cpp
+++ b/packages/CLI11/tests/BoostOptionTypeTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/tests/CMakeLists.txt b/packages/CLI11/tests/CMakeLists.txt
index 7d89e128b..7bd47744c 100644
--- a/packages/CLI11/tests/CMakeLists.txt
+++ b/packages/CLI11/tests/CMakeLists.txt
@@ -4,7 +4,7 @@ if(CLI11_SANITIZERS)
     sanitizers
     GIT_REPOSITORY https://github.com/arsenm/sanitizers-cmake.git
     GIT_SHALLOW 1
-    GIT_TAG 99e159e)
+    GIT_TAG c3dc841)
 
   FetchContent_GetProperties(sanitizers)
 
@@ -49,46 +49,92 @@ set(CLI11_TESTS
     StringParseTest
     ComplexTypeTest
     TrueFalseTest
-    OptionGroupTest)
+    OptionGroupTest
+    EncodingTest)
 
 if(WIN32)
   list(APPEND CLI11_TESTS WindowsTest)
 endif()
 
+if(CMAKE_CXX_STANDARD GREATER 16)
+  list(APPEND CLI11_TESTS FuzzFailTest)
+endif()
+
 if(Boost_FOUND)
   list(APPEND CLI11_TESTS BoostOptionTypeTest)
 endif()
 
 set(CLI11_MULTIONLY_TESTS TimerTest)
 
-add_library(catch_main main.cpp catch.hpp)
-target_include_directories(catch_main PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
-
 find_package(Catch2 CONFIG)
 
 if(Catch2_FOUND)
   if(NOT TARGET Catch2::Catch2)
     message(FATAL_ERROR "Found Catch2 at ${Catch2_DIR} but targets are missing.")
   endif()
-  message(STATUS "Found Catch2")
-  target_link_libraries(catch_main PUBLIC Catch2::Catch2)
+  message(STATUS "Found Catch2 ${Catch2_VERSION}")
+
+  if(Catch2_VERSION VERSION_LESS 3)
+    add_library(catch_main main.cpp catch.hpp)
+    target_include_directories(catch_main PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
+    target_link_libraries(catch_main PUBLIC Catch2::Catch2)
+  else()
+    add_library(catch_main ALIAS Catch2::Catch2WithMain)
+    target_compile_definitions(Catch2::Catch2WithMain INTERFACE -DCLI11_CATCH3)
+  endif()
 else()
   message(STATUS "Downloading Catch2")
 
   # FetchContent would be better, but requires newer CMake.
   file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/catch2")
-  set(url https://github.com/philsquared/Catch/releases/download/v2.13.7/catch.hpp)
+  set(url https://github.com/philsquared/Catch/releases/download/v2.13.10/catch.hpp)
   file(
     DOWNLOAD ${url} "${CMAKE_CURRENT_BINARY_DIR}/catch2/catch.hpp"
     STATUS status
-    EXPECTED_HASH SHA256=ea379c4a3cb5799027b1eb451163dff065a3d641aaba23bf4e24ee6b536bd9bc)
+    EXPECTED_HASH SHA256=3725c0f0a75f376a5005dde31ead0feb8f7da7507644c201b814443de8355170)
   list(GET status 0 error)
   if(error)
     message(FATAL_ERROR "Could not download ${url}, and Catch2 not found on your system.")
   endif()
-  target_include_directories(catch_main PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
+  add_library(catch_main main.cpp catch.hpp)
+  target_include_directories(catch_main PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}"
+                                               "${CMAKE_CURRENT_BINARY_DIR}")
 endif()
 
+# Add special target that copies the data directory for tests
+file(
+  GLOB_RECURSE DATA_FILES
+  LIST_DIRECTORIES false
+  RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
+  "${CMAKE_CURRENT_SOURCE_DIR}/data/*")
+
+foreach(DATA_FILE IN LISTS DATA_FILES)
+  add_custom_command(
+    OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${DATA_FILE}"
+    COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/${DATA_FILE}"
+            "${CMAKE_CURRENT_BINARY_DIR}/${DATA_FILE}"
+    MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/${DATA_FILE}"
+    VERBATIM)
+  target_sources(catch_main PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/${DATA_FILE}")
+endforeach()
+
+# Build dependent applications which are launched from test code
+set(CLI11_DEPENDENT_APPLICATIONS system_args)
+
+foreach(APP IN LISTS CLI11_DEPENDENT_APPLICATIONS)
+  add_executable(${APP} applications/${APP}.cpp)
+  target_include_directories(${APP} PRIVATE ${CMAKE_SOURCE_DIR}/include)
+  add_dependencies(catch_main ${APP})
+endforeach()
+
+function(add_dependent_application_definitions TARGET)
+  foreach(APP IN LISTS CLI11_DEPENDENT_APPLICATIONS)
+    string(TOUPPER ${APP} APP_UPPERCASE)
+    target_compile_definitions(${TARGET}
+                               PRIVATE CLI11_${APP_UPPERCASE}_EXE="$<TARGET_FILE:${APP}>")
+  endforeach()
+endfunction()
+
 # Target must already exist
 macro(add_catch_test TESTNAME)
   target_link_libraries(${TESTNAME} PUBLIC catch_main)
@@ -108,6 +154,8 @@ foreach(T IN LISTS CLI11_TESTS)
     set_property(SOURCE ${T}.cpp PROPERTY LANGUAGE CUDA)
   endif()
   add_executable(${T} ${T}.cpp)
+
+  add_dependent_application_definitions(${T})
   add_sanitizers(${T})
   if(NOT CLI11_CUDA_TESTS)
     target_link_libraries(${T} PRIVATE CLI11_warnings)
@@ -117,6 +165,7 @@ foreach(T IN LISTS CLI11_TESTS)
 
   if(CLI11_SINGLE_FILE AND CLI11_SINGLE_FILE_TESTS)
     add_executable(${T}_Single ${T}.cpp)
+    add_dependent_application_definitions(${T}_Single)
     target_link_libraries(${T}_Single PRIVATE CLI11_SINGLE)
     add_catch_test(${T}_Single)
     set_property(TARGET ${T}_Single PROPERTY FOLDER "Tests Single File")
@@ -125,11 +174,22 @@ endforeach()
 
 foreach(T IN LISTS CLI11_MULTIONLY_TESTS)
   add_executable(${T} ${T}.cpp)
+  add_dependent_application_definitions(${T})
   add_sanitizers(${T})
   target_link_libraries(${T} PUBLIC CLI11)
   add_catch_test(${T})
 endforeach()
 
+if(CMAKE_CXX_STANDARD GREATER 16)
+  set(TEST_FILE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
+  target_compile_definitions(FuzzFailTest PUBLIC -DTEST_FILE_FOLDER="${TEST_FILE_FOLDER}")
+  target_sources(FuzzFailTest PUBLIC ${PROJECT_SOURCE_DIR}/fuzz/fuzzApp.cpp)
+  if(CLI11_SINGLE_FILE AND CLI11_SINGLE_FILE_TESTS)
+    target_compile_definitions(FuzzFailTest_Single PUBLIC -DTEST_FILE_FOLDER="${TEST_FILE_FOLDER}")
+    target_sources(FuzzFailTest_Single PUBLIC ${PROJECT_SOURCE_DIR}/fuzz/fuzzApp.cpp)
+  endif()
+endif()
+
 # Add -Wno-deprecated-declarations to DeprecatedTest
 set(no-deprecated-declarations $<$<CXX_COMPILER_ID:MSVC>:/wd4996>
                                $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wno-deprecated-declarations>)
diff --git a/packages/CLI11/tests/ComplexTypeTest.cpp b/packages/CLI11/tests/ComplexTypeTest.cpp
index 156798bad..adcd26c4b 100644
--- a/packages/CLI11/tests/ComplexTypeTest.cpp
+++ b/packages/CLI11/tests/ComplexTypeTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -9,8 +9,6 @@
 #include <complex>
 #include <cstdint>
 
-using Catch::Matchers::Contains;
-
 using cx = std::complex<double>;
 
 CLI::Option *
diff --git a/packages/CLI11/tests/ConfigFileTest.cpp b/packages/CLI11/tests/ConfigFileTest.cpp
index 0b11ffefb..206872728 100644
--- a/packages/CLI11/tests/ConfigFileTest.cpp
+++ b/packages/CLI11/tests/ConfigFileTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -9,8 +9,6 @@
 #include <cstdio>
 #include <sstream>
 
-using Catch::Matchers::Contains;
-
 TEST_CASE("StringBased: convert_arg_for_ini", "[config]") {
 
     CHECK("\"\"" == CLI::detail::convert_arg_for_ini(std::string{}));
@@ -435,6 +433,8 @@ TEST_CASE("StringBased: file_error", "[config]") {
     CHECK_THROWS_AS(CLI::ConfigINI().from_file("nonexist_file"), CLI::FileError);
 }
 
+static const int fclear1 = fileClear("TestIniTmp.ini");
+
 TEST_CASE_METHOD(TApp, "IniNotRequired", "[config]") {
 
     TempFile tmpini{"TestIniTmp.ini"};
@@ -507,10 +507,47 @@ TEST_CASE_METHOD(TApp, "IniGetRemainingOption", "[config]") {
     int two{0};
     app.add_option("--two", two);
     REQUIRE_NOTHROW(run());
-    std::vector<std::string> ExpectedRemaining = {ExtraOption};
+    std::vector<std::string> ExpectedRemaining = {ExtraOption, "3"};
     CHECK(ExpectedRemaining == app.remaining());
 }
 
+TEST_CASE_METHOD(TApp, "IniRemainingSub", "[config]") {
+    TempFile tmpini{"TestIniTmp.ini"};
+
+    app.set_config("--config", tmpini);
+    auto *map = app.add_subcommand("map");
+    map->allow_config_extras();
+
+    {
+        std::ofstream out{tmpini};
+        out << "[map]\n";
+        out << "a = 1\n";
+        out << "b=[1,2,3]\n";
+        out << "c = 3" << std::endl;
+    }
+
+    REQUIRE_NOTHROW(run());
+    std::vector<std::string> rem = map->remaining();
+    REQUIRE(rem.size() == 8U);
+    CHECK(rem[0] == "map.a");
+    CHECK(rem[2] == "map.b");
+    CHECK(rem[6] == "map.c");
+    CHECK(rem[5] == "3");
+
+    int a{0};
+    int c{0};
+    std::vector<int> b;
+    map->add_option("-a", a);
+    map->add_option("-b", b);
+    map->add_option("-c", c);
+
+    CHECK_NOTHROW(app.parse(app.remaining_for_passthrough()));
+    CHECK(a == 1);
+    CHECK(c == 3);
+    REQUIRE(b.size() == 3U);
+    CHECK(b[1] == 2);
+}
+
 TEST_CASE_METHOD(TApp, "IniGetNoRemaining", "[config]") {
     TempFile tmpini{"TestIniTmp.ini"};
 
@@ -595,6 +632,8 @@ TEST_CASE_METHOD(TApp, "IniNotRequiredbadConfigurator", "[config]") {
     REQUIRE_NOTHROW(run());
 }
 
+static const int fclear2 = fileClear("TestIniTmp2.ini");
+
 TEST_CASE_METHOD(TApp, "IniNotRequiredNotDefault", "[config]") {
 
     TempFile tmpini{"TestIniTmp.ini"};
@@ -1017,17 +1056,19 @@ TEST_CASE_METHOD(TApp, "TOMLStringVector", "[config]") {
         out << "zero1=[]\n";
         out << "zero2={}\n";
         out << "zero3={}\n";
+        out << "zero4=[\"{}\",\"\"]\n";
         out << "nzero={}\n";
         out << "one=[\"1\"]\n";
         out << "two=[\"2\",\"3\"]\n";
         out << "three=[\"1\",\"2\",\"3\"]\n";
     }
 
-    std::vector<std::string> nzero, zero1, zero2, zero3, one, two, three;
+    std::vector<std::string> nzero, zero1, zero2, zero3, zero4, one, two, three;
     app.add_option("--zero1", zero1)->required()->expected(0, 99)->default_str("{}");
     app.add_option("--zero2", zero2)->required()->expected(0, 99)->default_val(std::vector<std::string>{});
     // if no default is specified the argument results in an empty string
     app.add_option("--zero3", zero3)->required()->expected(0, 99);
+    app.add_option("--zero4", zero4)->required()->expected(0, 99);
     app.add_option("--nzero", nzero)->required();
     app.add_option("--one", one)->required();
     app.add_option("--two", two)->required();
@@ -1038,6 +1079,7 @@ TEST_CASE_METHOD(TApp, "TOMLStringVector", "[config]") {
     CHECK(zero1 == std::vector<std::string>({}));
     CHECK(zero2 == std::vector<std::string>({}));
     CHECK(zero3 == std::vector<std::string>({""}));
+    CHECK(zero4 == std::vector<std::string>({"{}"}));
     CHECK(nzero == std::vector<std::string>({"{}"}));
     CHECK(one == std::vector<std::string>({"1"}));
     CHECK(two == std::vector<std::string>({"2", "3"}));
@@ -1735,6 +1777,23 @@ TEST_CASE_METHOD(TApp, "IniFlagDual", "[config]") {
     CHECK_THROWS_AS(run(), CLI::ConversionError);
 }
 
+TEST_CASE_METHOD(TApp, "IniVectorMax", "[config]") {
+
+    TempFile tmpini{"TestIniTmp.ini"};
+
+    std::vector<std::string> v1;
+    app.config_formatter(std::make_shared<CLI::ConfigINI>());
+    app.add_option("--vec", v1)->expected(0, 2);
+    app.set_config("--config", tmpini);
+
+    {
+        std::ofstream out{tmpini};
+        out << "vec=[a,b,c]" << std::endl;
+    }
+
+    CHECK_THROWS_AS(run(), CLI::ArgumentMismatch);
+}
+
 TEST_CASE_METHOD(TApp, "IniShort", "[config]") {
 
     TempFile tmpini{"TestIniTmp.ini"};
@@ -2000,6 +2059,51 @@ TEST_CASE_METHOD(TApp, "IniFalseFlagsDefDisableOverrideSuccess", "[config]") {
     CHECK(val == 15);
 }
 
+static const int fclear3 = fileClear("TestIniTmp3.ini");
+
+TEST_CASE_METHOD(TApp, "IniDisableFlagOverride", "[config]") {
+
+    TempFile tmpini{"TestIniTmp.ini"};
+    TempFile tmpini2{"TestIniTmp2.ini"};
+    TempFile tmpini3{"TestIniTmp3.ini"};
+
+    app.set_config("--config", tmpini);
+
+    {
+        std::ofstream out{tmpini};
+        out << "[default]" << std::endl;
+        out << "two=2" << std::endl;
+    }
+
+    {
+        std::ofstream out{tmpini2};
+        out << "[default]" << std::endl;
+        out << "two=7" << std::endl;
+    }
+
+    {
+        std::ofstream out{tmpini3};
+        out << "[default]" << std::endl;
+        out << "three=true" << std::endl;
+    }
+
+    int val{0};
+    app.add_flag("--one{1},--two{2},--three{3}", val)->disable_flag_override();
+
+    run();
+    CHECK(tmpini.c_str() == app["--config"]->as<std::string>());
+    CHECK(val == 2);
+
+    args = {"--config", tmpini2};
+    CHECK_THROWS_AS(run(), CLI::ArgumentMismatch);
+
+    args = {"--config", tmpini3};
+    run();
+
+    CHECK(val == 3);
+    CHECK(tmpini3.c_str() == app.get_config_ptr()->as<std::string>());
+}
+
 TEST_CASE_METHOD(TApp, "TomlOutputSimple", "[config]") {
 
     int v{0};
@@ -2497,6 +2601,29 @@ TEST_CASE_METHOD(TApp, "ConfigWriteReadWrite", "[config]") {
     CHECK(config2 == config1);
 }
 
+TEST_CASE_METHOD(TApp, "ConfigWriteReadNegated", "[config]") {
+
+    TempFile tmpini{"TestIniTmp.ini"};
+    bool flag{true};
+    app.add_flag("!--no-flag", flag);
+    args = {"--no-flag"};
+    run();
+
+    // Save config, with default values too
+    std::string config1 = app.config_to_str(false, false);
+    {
+        std::ofstream out{tmpini};
+        out << config1 << std::endl;
+    }
+    CHECK_FALSE(flag);
+    args.clear();
+    flag = true;
+    app.set_config("--config", tmpini, "Read an ini file", true);
+    run();
+
+    CHECK_FALSE(flag);
+}
+
 /////// INI output tests
 
 TEST_CASE_METHOD(TApp, "IniOutputSimple", "[config]") {
diff --git a/packages/CLI11/tests/CreationTest.cpp b/packages/CLI11/tests/CreationTest.cpp
index b58e0aabe..a51abd488 100644
--- a/packages/CLI11/tests/CreationTest.cpp
+++ b/packages/CLI11/tests/CreationTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -455,6 +455,7 @@ TEST_CASE_METHOD(TApp, "SubcommandDefaults", "[creation]") {
     CHECK(!app.get_configurable());
     CHECK(!app.get_validate_positionals());
 
+    CHECK(app.get_usage().empty());
     CHECK(app.get_footer().empty());
     CHECK("Subcommands" == app.get_group());
     CHECK(0u == app.get_require_subcommand_min());
@@ -474,6 +475,7 @@ TEST_CASE_METHOD(TApp, "SubcommandDefaults", "[creation]") {
 
     app.fallthrough();
     app.validate_positionals();
+    app.usage("ussy");
     app.footer("footy");
     app.group("Stuff");
     app.require_subcommand(2, 3);
@@ -494,6 +496,7 @@ TEST_CASE_METHOD(TApp, "SubcommandDefaults", "[creation]") {
     CHECK(app2->get_fallthrough());
     CHECK(app2->get_validate_positionals());
     CHECK(app2->get_configurable());
+    CHECK("ussy" == app2->get_usage());
     CHECK("footy" == app2->get_footer());
     CHECK("Stuff" == app2->get_group());
     CHECK(0u == app2->get_require_subcommand_min());
@@ -549,6 +552,25 @@ TEST_CASE_METHOD(TApp, "GetOptionList", "[creation]") {
     }
 }
 
+TEST_CASE_METHOD(TApp, "GetOptionListFilter", "[creation]") {
+    int two{0};
+    auto *flag = app.add_flag("--one");
+    app.add_option("--two", two);
+
+    const CLI::App &const_app = app;  // const alias to force use of const-methods
+    std::vector<const CLI::Option *> opt_listc =
+        const_app.get_options([](const CLI::Option *opt) { return opt->get_name() == "--one"; });
+
+    REQUIRE(static_cast<std::size_t>(1) == opt_listc.size());
+    CHECK(flag == opt_listc.at(0));
+
+    std::vector<CLI::Option *> opt_list =
+        app.get_options([](const CLI::Option *opt) { return opt->get_name() == "--one"; });
+
+    REQUIRE(static_cast<std::size_t>(1) == opt_list.size());
+    CHECK(flag == opt_list.at(0));
+}
+
 TEST_CASE("ValidatorTests: TestValidatorCreation", "[creation]") {
     std::function<std::string(std::string &)> op1 = [](std::string &val) {
         return (val.size() >= 5) ? std::string{} : val;
diff --git a/packages/CLI11/tests/DeprecatedTest.cpp b/packages/CLI11/tests/DeprecatedTest.cpp
index 8c45f2495..063c67e5e 100644
--- a/packages/CLI11/tests/DeprecatedTest.cpp
+++ b/packages/CLI11/tests/DeprecatedTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -6,8 +6,6 @@
 
 #include "app_helper.hpp"
 
-using Catch::Matchers::Contains;
-
 TEST_CASE("Deprecated: Empty", "[deprecated]") {
     // No deprecated features at this time.
     CHECK(true);
diff --git a/packages/CLI11/tests/EncodingTest.cpp b/packages/CLI11/tests/EncodingTest.cpp
new file mode 100644
index 000000000..b026ee014
--- /dev/null
+++ b/packages/CLI11/tests/EncodingTest.cpp
@@ -0,0 +1,104 @@
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
+// under NSF AWARD 1414736 and by the respective contributors.
+// All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include "app_helper.hpp"
+
+#include <array>
+#include <string>
+
+#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
+#include <filesystem>
+#endif  // CLI11_HAS_FILESYSTEM
+
+// "abcd"
+static const std::string abcd_str = "abcd";     // NOLINT(runtime/string)
+static const std::wstring abcd_wstr = L"abcd";  // NOLINT(runtime/string)
+
+// "𓂀𓂀𓂀" - 4-byte utf8 characters
+static const std::array<uint8_t, 12 + 1> egypt_utf8_codeunits{
+    {0xF0, 0x93, 0x82, 0x80, 0xF0, 0x93, 0x82, 0x80, 0xF0, 0x93, 0x82, 0x80}};
+static const std::string egypt_str(reinterpret_cast<const char *>(egypt_utf8_codeunits.data()));
+
+#ifdef _WIN32
+static const std::array<uint16_t, 6 + 1> egypt_utf16_codeunits{{0xD80C, 0xDC80, 0xD80C, 0xDC80, 0xD80C, 0xDC80}};
+static const std::wstring egypt_wstr(reinterpret_cast<const wchar_t *>(egypt_utf16_codeunits.data()));
+
+#else
+static const std::array<uint32_t, 3 + 1> egypt_utf32_codeunits{{0x00013080, 0x00013080, 0x00013080}};
+static const std::wstring egypt_wstr(reinterpret_cast<const wchar_t *>(egypt_utf32_codeunits.data()));
+
+#endif
+
+// "Hello Halló Привет 你好 👩‍🚀❤️" - many languages and complex emojis
+static const std::array<uint8_t, 50 + 1> hello_utf8_codeunits{
+    {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x48, 0x61, 0x6c, 0x6c, 0xc3, 0xb3, 0x20, 0xd0, 0x9f, 0xd1, 0x80,
+     0xd0, 0xb8, 0xd0, 0xb2, 0xd0, 0xb5, 0xd1, 0x82, 0x20, 0xe4, 0xbd, 0xa0, 0xe5, 0xa5, 0xbd, 0x20, 0xf0,
+     0x9f, 0x91, 0xa9, 0xe2, 0x80, 0x8d, 0xf0, 0x9f, 0x9a, 0x80, 0xe2, 0x9d, 0xa4, 0xef, 0xb8, 0x8f}};
+static const std::string hello_str(reinterpret_cast<const char *>(hello_utf8_codeunits.data()));
+
+#ifdef _WIN32
+static const std::array<uint16_t, 29 + 1> hello_utf16_codeunits{
+    {0x0048, 0x0065, 0x006c, 0x006c, 0x006f, 0x0020, 0x0048, 0x0061, 0x006c, 0x006c,
+     0x00f3, 0x0020, 0x041f, 0x0440, 0x0438, 0x0432, 0x0435, 0x0442, 0x0020, 0x4f60,
+     0x597d, 0x0020, 0xd83d, 0xdc69, 0x200d, 0xd83d, 0xde80, 0x2764, 0xfe0f}};
+static const std::wstring hello_wstr(reinterpret_cast<const wchar_t *>(hello_utf16_codeunits.data()));
+
+#else
+static const std::array<uint32_t, 27 + 1> hello_utf32_codeunits{
+    {0x00000048, 0x00000065, 0x0000006c, 0x0000006c, 0x0000006f, 0x00000020, 0x00000048, 0x00000061, 0x0000006c,
+     0x0000006c, 0x000000f3, 0x00000020, 0x0000041f, 0x00000440, 0x00000438, 0x00000432, 0x00000435, 0x00000442,
+     0x00000020, 0x00004f60, 0x0000597d, 0x00000020, 0x0001f469, 0x0000200d, 0x0001f680, 0x00002764, 0x0000fe0f}};
+static const std::wstring hello_wstr(reinterpret_cast<const wchar_t *>(hello_utf32_codeunits.data()));
+
+#endif
+
+// #14
+TEST_CASE("Encoding: Widen", "[unicode]") {
+    using CLI::widen;
+
+    CHECK(abcd_wstr == widen(abcd_str));
+    CHECK(egypt_wstr == widen(egypt_str));
+    CHECK(hello_wstr == widen(hello_str));
+
+    CHECK(hello_wstr == widen(hello_str.c_str()));
+    CHECK(hello_wstr == widen(hello_str.c_str(), hello_str.size()));
+
+#ifdef CLI11_CPP17
+    CHECK(hello_wstr == widen(std::string_view{hello_str}));
+#endif  // CLI11_CPP17
+}
+
+// #14
+TEST_CASE("Encoding: Narrow", "[unicode]") {
+    using CLI::narrow;
+
+    CHECK(abcd_str == narrow(abcd_wstr));
+    CHECK(egypt_str == narrow(egypt_wstr));
+    CHECK(hello_str == narrow(hello_wstr));
+
+    CHECK(hello_str == narrow(hello_wstr.c_str()));
+    CHECK(hello_str == narrow(hello_wstr.c_str(), hello_wstr.size()));
+
+#ifdef CLI11_CPP17
+    CHECK(hello_str == narrow(std::wstring_view{hello_wstr}));
+#endif  // CLI11_CPP17
+}
+
+#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
+// #14
+TEST_CASE("Encoding: to_path roundtrip", "[unicode]") {
+    using std::filesystem::path;
+
+#ifdef _WIN32
+    std::wstring native_str = CLI::widen(hello_str);
+#else
+    std::string native_str = hello_str;
+#endif  // _WIN32
+
+    CHECK(CLI::to_path(hello_str).native() == native_str);
+}
+
+#endif  // CLI11_HAS_FILESYSTEM
diff --git a/packages/CLI11/tests/FormatterTest.cpp b/packages/CLI11/tests/FormatterTest.cpp
index 7f68cf176..2563c9421 100644
--- a/packages/CLI11/tests/FormatterTest.cpp
+++ b/packages/CLI11/tests/FormatterTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -13,8 +13,6 @@
 #include "catch.hpp"
 #include <fstream>
 
-using Catch::Matchers::Contains;
-
 class SimpleFormatter : public CLI::FormatterBase {
   public:
     SimpleFormatter() : FormatterBase() {}
@@ -63,7 +61,7 @@ TEST_CASE("Formatter: OptCustomize", "[formatter]") {
                   "Usage: [OPTIONS]\n\n"
                   "Options:\n"
                   "  -h,--help              Print this help message and exit\n"
-                  "  --opt INT (MUST HAVE)  Something\n\n");
+                  "  --opt INT (MUST HAVE)  Something\n");
 }
 
 TEST_CASE("Formatter: OptCustomizeSimple", "[formatter]") {
@@ -82,7 +80,7 @@ TEST_CASE("Formatter: OptCustomizeSimple", "[formatter]") {
                   "Usage: [OPTIONS]\n\n"
                   "Options:\n"
                   "  -h,--help              Print this help message and exit\n"
-                  "  --opt INT (MUST HAVE)  Something\n\n");
+                  "  --opt INT (MUST HAVE)  Something\n");
 }
 
 TEST_CASE("Formatter: OptCustomizeOptionText", "[formatter]") {
@@ -100,7 +98,7 @@ TEST_CASE("Formatter: OptCustomizeOptionText", "[formatter]") {
                   "Usage: [OPTIONS]\n\n"
                   "Options:\n"
                   "  -h,--help              Print this help message and exit\n"
-                  "  --opt (ARG)            Something\n\n");
+                  "  --opt (ARG)            Something\n");
 }
 
 TEST_CASE("Formatter: FalseFlagExample", "[formatter]") {
@@ -140,7 +138,7 @@ TEST_CASE("Formatter: AppCustomize", "[formatter]") {
                   "  -h,--help         Print this help message and exit\n\n"
                   "Subcommands:\n"
                   "  subcom1           This\n"
-                  "  subcom2           This\n\n");
+                  "  subcom2           This\n");
 }
 
 TEST_CASE("Formatter: AppCustomizeSimple", "[formatter]") {
@@ -159,7 +157,7 @@ TEST_CASE("Formatter: AppCustomizeSimple", "[formatter]") {
                   "  -h,--help         Print this help message and exit\n\n"
                   "Subcommands:\n"
                   "  subcom1           This\n"
-                  "  subcom2           This\n\n");
+                  "  subcom2           This\n");
 }
 
 TEST_CASE("Formatter: AllSub", "[formatter]") {
diff --git a/packages/CLI11/tests/FuzzFailTest.cpp b/packages/CLI11/tests/FuzzFailTest.cpp
new file mode 100644
index 000000000..221483688
--- /dev/null
+++ b/packages/CLI11/tests/FuzzFailTest.cpp
@@ -0,0 +1,37 @@
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
+// under NSF AWARD 1414736 and by the respective contributors.
+// All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include "../fuzz/fuzzApp.hpp"
+#include "app_helper.hpp"
+
+std::string loadFailureFile(const std::string &type, int index) {
+    std::string fileName(TEST_FILE_FOLDER "/fuzzFail/");
+    fileName.append(type);
+    fileName += std::to_string(index);
+    std::ifstream crashFile(fileName, std::ios::in | std::ios::binary);
+    if(crashFile) {
+        std::vector<char> buffer(std::istreambuf_iterator<char>(crashFile), {});
+
+        std::string cdata(buffer.begin(), buffer.end());
+        return cdata;
+    }
+    return std::string{};
+}
+
+TEST_CASE("app_fail") {
+    CLI::FuzzApp fuzzdata;
+
+    auto app = fuzzdata.generateApp();
+
+    int index = GENERATE(range(1, 3));
+
+    auto parseData = loadFailureFile("fuzz_app_fail", index);
+    try {
+
+        app->parse(parseData);
+    } catch(const CLI::ParseError & /*e*/) {
+    }
+}
diff --git a/packages/CLI11/tests/HelpTest.cpp b/packages/CLI11/tests/HelpTest.cpp
index eb0edd6a0..c4403f754 100644
--- a/packages/CLI11/tests/HelpTest.cpp
+++ b/packages/CLI11/tests/HelpTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -13,8 +13,6 @@
 #include "catch.hpp"
 #include <fstream>
 
-using Catch::Matchers::Contains;
-
 TEST_CASE("THelp: Basic", "[help]") {
     CLI::App app{"My prog"};
 
@@ -26,6 +24,43 @@ TEST_CASE("THelp: Basic", "[help]") {
     CHECK_THAT(help, Contains("Usage:"));
 }
 
+TEST_CASE("THelp: Usage", "[help]") {
+    CLI::App app{"My prog"};
+    app.usage("use: just use it");
+
+    std::string help = app.help();
+
+    CHECK_THAT(help, Contains("My prog"));
+    CHECK_THAT(help, Contains("-h,--help"));
+    CHECK_THAT(help, Contains("Options:"));
+    CHECK_THAT(help, Contains("use: just use it"));
+}
+
+TEST_CASE("THelp: UsageCallback", "[help]") {
+    CLI::App app{"My prog"};
+    app.usage([]() { return "use: just use it"; });
+
+    std::string help = app.help();
+
+    CHECK_THAT(help, Contains("My prog"));
+    CHECK_THAT(help, Contains("-h,--help"));
+    CHECK_THAT(help, Contains("Options:"));
+    CHECK_THAT(help, Contains("use: just use it"));
+}
+
+TEST_CASE("THelp: UsageCallbackBoth", "[help]") {
+    CLI::App app{"My prog"};
+    app.usage([]() { return "use: just use it"; });
+    app.usage("like 1, 2, and 3");
+    std::string help = app.help();
+
+    CHECK_THAT(help, Contains("My prog"));
+    CHECK_THAT(help, Contains("-h,--help"));
+    CHECK_THAT(help, Contains("Options:"));
+    CHECK_THAT(help, Contains("use: just use it"));
+    CHECK_THAT(help, Contains("like 1, 2, and 3"));
+}
+
 TEST_CASE("THelp: Footer", "[help]") {
     CLI::App app{"My prog"};
     app.footer("Report bugs to bugs@example.com");
@@ -813,7 +848,7 @@ TEST_CASE_METHOD(CapturedHelp, "CallForAllHelpOutput", "[help]") {
                        "  One description\n\n"
                        "two\n"
                        "  Options:\n"
-                       "    --three                     \n\n\n");
+                       "    --three                     \n\n");
 }
 TEST_CASE_METHOD(CapturedHelp, "NewFormattedHelp", "[help]") {
     app.formatter_fn([](const CLI::App *, std::string, CLI::AppFormatMode) { return "New Help"; });
@@ -974,6 +1009,16 @@ TEST_CASE("THelp: GroupOrder", "[help]") {
     CHECK(aee_loc > zee_loc);
 }
 
+TEST_CASE("THelp: GroupNameError", "[help]") {
+    CLI::App app;
+
+    auto *f1 = app.add_flag("--one");
+    auto *f2 = app.add_flag("--two");
+
+    CHECK_THROWS_AS(f1->group("evil group name\non two lines"), CLI::IncorrectConstruction);
+    CHECK_THROWS_AS(f2->group(std::string(5, '\0')), CLI::IncorrectConstruction);
+}
+
 TEST_CASE("THelp: ValidatorsText", "[help]") {
     CLI::App app;
 
@@ -1266,7 +1311,7 @@ TEST_CASE("TVersion: parse_throw", "[help]") {
     try {
         app.parse("--Version");
     } catch(const CLI::CallForVersion &v) {
-        CHECK_THAT(CLI11_VERSION, Catch::Equals(v.what()));
+        CHECK_THAT(CLI11_VERSION, Equals(v.what()));
         CHECK(0 == v.get_exit_code());
         const auto &appc = app;
         const auto *cptr = appc.get_version_ptr();
diff --git a/packages/CLI11/tests/HelpersTest.cpp b/packages/CLI11/tests/HelpersTest.cpp
index 798a6d13d..5186b47fc 100644
--- a/packages/CLI11/tests/HelpersTest.cpp
+++ b/packages/CLI11/tests/HelpersTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -525,6 +525,10 @@ TEST_CASE("Validators: ProgramNameSplit", "[helpers]") {
     res = CLI::detail::split_program_name(std::string("  ./") + std::string(myfile) + "    ");
     CHECK(std::string("./") + std::string(myfile) == res.first);
     CHECK(res.second.empty());
+
+    res = CLI::detail::split_program_name("'odd_program_name.exe --arg --arg2=5");
+    CHECK("'odd_program_name.exe" == res.first);
+    CHECK_FALSE(res.second.empty());
 }
 
 TEST_CASE("CheckedMultiply: Int", "[helpers]") {
@@ -1065,6 +1069,10 @@ TEST_CASE("Types: LexicalCastInt", "[helpers]") {
     std::string extra_input = "912i";
     CHECK_FALSE(CLI::detail::lexical_cast(extra_input, y));
 
+    extra_input = "true";
+    CHECK(CLI::detail::lexical_cast(extra_input, x_signed));
+    CHECK(x_signed != 0);
+
     std::string empty_input{};
     CHECK_FALSE(CLI::detail::lexical_cast(empty_input, x_signed));
     CHECK_FALSE(CLI::detail::lexical_cast(empty_input, x_unsigned));
@@ -1228,6 +1236,8 @@ TEST_CASE("Types: LexicalConversionTuple3", "[helpers]") {
 TEST_CASE("Types: LexicalConversionTuple4", "[helpers]") {
     CLI::results_t input = {"9.12", "19", "18.6", "5.87"};
     std::array<double, 4> x;
+    auto tsize = CLI::detail::type_count<decltype(x)>::value;
+    CHECK(tsize == 4);
     bool res = CLI::detail::lexical_conversion<decltype(x), decltype(x)>(input, x);
     CHECK(res);
     CHECK(19 == Approx(std::get<1>(x)));
diff --git a/packages/CLI11/tests/NewParseTest.cpp b/packages/CLI11/tests/NewParseTest.cpp
index a4ca09987..a72af823b 100644
--- a/packages/CLI11/tests/NewParseTest.cpp
+++ b/packages/CLI11/tests/NewParseTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -10,8 +10,6 @@
 #include <cstdint>
 #include <utility>
 
-using Catch::Matchers::Contains;
-
 using cx = std::complex<double>;
 
 TEST_CASE_METHOD(TApp, "ComplexOption", "[newparse]") {
@@ -163,14 +161,10 @@ class spair {
     std::string first{};
     std::string second{};
 };
-// an example of custom converter that can be used to add new parsing options
-// On MSVC and possibly some other new compilers this can be a free standing function without the template
-// specialization but this is compiler dependent
-namespace CLI {
-namespace detail {
-
-template <> bool lexical_cast<spair>(const std::string &input, spair &output) {
 
+// Example of a custom converter that can be used to add new parsing options.
+// It will be found via argument-dependent lookup, so should be in the same namespace as the `spair` type.
+bool lexical_cast(const std::string &input, spair &output) {
     auto sep = input.find_first_of(':');
     if((sep == std::string::npos) && (sep > 0)) {
         return false;
@@ -178,8 +172,6 @@ template <> bool lexical_cast<spair>(const std::string &input, spair &output) {
     output = {input.substr(0, sep), input.substr(sep + 1)};
     return true;
 }
-}  // namespace detail
-}  // namespace CLI
 
 TEST_CASE_METHOD(TApp, "custom_string_converter", "[newparse]") {
     spair val;
@@ -201,6 +193,96 @@ TEST_CASE_METHOD(TApp, "custom_string_converterFail", "[newparse]") {
     CHECK_THROWS_AS(run(), CLI::ConversionError);
 }
 
+/// Wrapper with an unconvenient interface
+template <class T> class badlywrapped {
+  public:
+    badlywrapped() : value() {}
+
+    CLI11_NODISCARD T get() const { return value; }
+
+    void set(T val) { value = val; }
+
+  private:
+    T value;
+};
+
+// Example of a custom converter for a template type.
+// It will be found via argument-dependent lookup, so should be in the same namespace as the `badlywrapped` type.
+template <class T> bool lexical_cast(const std::string &input, badlywrapped<T> &output) {
+    // This using declaration lets us use an unqualified call to lexical_cast below. This is important because
+    // unqualified call finds the proper overload via argument-dependent lookup, and thus it will be able to find
+    // an overload for `spair` type, which is not in `CLI::detail`.
+    using CLI::detail::lexical_cast;
+
+    T value;
+    if(!lexical_cast(input, value))
+        return false;
+    output.set(value);
+    return true;
+}
+
+TEST_CASE_METHOD(TApp, "custom_string_converter_flag", "[newparse]") {
+    badlywrapped<bool> val;
+    std::vector<badlywrapped<bool>> vals;
+    app.add_flag("-1", val);
+    app.add_flag("-2", vals);
+
+    val.set(false);
+    args = {"-1"};
+    run();
+    CHECK(true == val.get());
+
+    args = {"-2", "-2"};
+    run();
+    CHECK(2 == vals.size());
+    CHECK(true == vals[0].get());
+    CHECK(true == vals[1].get());
+}
+
+TEST_CASE_METHOD(TApp, "custom_string_converter_adl", "[newparse]") {
+    // This test checks that the lexical_cast calls route as expected.
+    badlywrapped<spair> val;
+
+    app.add_option("-d,--dual_string", val);
+
+    args = {"-d", "string1:string2"};
+
+    run();
+    CHECK("string1" == val.get().first);
+    CHECK("string2" == val.get().second);
+}
+
+/// Another wrapper to test that specializing CLI::detail::lexical_cast works
+struct anotherstring {
+    anotherstring() = default;
+    std::string s{};
+};
+
+// This is a custom converter done via specializing the CLI::detail::lexical_cast template. This was the recommended
+// mechanism for extending the library before, so we need to test it. Don't do this in your code, use
+// argument-dependent lookup as outlined in the examples for spair and template badlywrapped.
+namespace CLI {
+namespace detail {
+template <> bool lexical_cast<anotherstring>(const std::string &input, anotherstring &output) {
+    bool result = lexical_cast(input, output.s);
+    if(result)
+        output.s += "!";
+    return result;
+}
+}  // namespace detail
+}  // namespace CLI
+
+TEST_CASE_METHOD(TApp, "custom_string_converter_specialize", "[newparse]") {
+    anotherstring s;
+
+    app.add_option("-s", s);
+
+    args = {"-s", "something"};
+
+    run();
+    CHECK("something!" == s.s);
+}
+
 /// simple class to wrap another  with a very specific type constructor and assignment operators to test out some of the
 /// option assignments
 template <class X> class objWrapper {
@@ -221,6 +303,27 @@ template <class X> class objWrapper {
     X val_{};
 };
 
+/// simple class to wrap another  with a very specific type constructor and assignment operators to test out some of the
+/// option assignments
+template <class X> class objWrapperRestricted {
+  public:
+    objWrapperRestricted() = default;
+    explicit objWrapperRestricted(int val) : val_{val} {};
+    objWrapperRestricted(const objWrapperRestricted &) = delete;
+    objWrapperRestricted(objWrapperRestricted &&) = delete;
+    objWrapperRestricted &operator=(const objWrapperRestricted &) = delete;
+    objWrapperRestricted &operator=(objWrapperRestricted &&) = delete;
+
+    objWrapperRestricted &operator=(int val) {
+        val_ = val;
+        return *this;
+    }
+    CLI11_NODISCARD const X &value() const { return val_; }
+
+  private:
+    X val_{};
+};
+
 // I think there is a bug with the is_assignable in visual studio 2015 it is fixed in later versions
 // so this test will not compile in that compiler
 #if !defined(_MSC_VER) || _MSC_VER >= 1910
@@ -263,6 +366,26 @@ TEST_CASE_METHOD(TApp, "doubleWrapper", "[newparse]") {
     CHECK_THROWS_AS(run(), CLI::ConversionError);
 }
 
+TEST_CASE_METHOD(TApp, "intWrapperRestricted", "[newparse]") {
+    objWrapperRestricted<double> dWrapper;
+    app.add_option("-v", dWrapper);
+    args = {"-v", "4"};
+
+    run();
+
+    CHECK(4.0 == dWrapper.value());
+
+    args = {"-v", "thing"};
+
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+
+    args = {"-v", ""};
+
+    run();
+
+    CHECK(0.0 == dWrapper.value());
+}
+
 static_assert(CLI::detail::is_direct_constructible<objWrapper<int>, int>::value,
               "int wrapper is not constructible from int64");
 
diff --git a/packages/CLI11/tests/OptionGroupTest.cpp b/packages/CLI11/tests/OptionGroupTest.cpp
index bc3a9455f..ab4d3c638 100644
--- a/packages/CLI11/tests/OptionGroupTest.cpp
+++ b/packages/CLI11/tests/OptionGroupTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -6,8 +6,6 @@
 
 #include "app_helper.hpp"
 
-using Catch::Matchers::Contains;
-
 using vs_t = std::vector<std::string>;
 
 TEST_CASE_METHOD(TApp, "BasicOptionGroup", "[optiongroup]") {
@@ -448,6 +446,12 @@ TEST_CASE_METHOD(ManyGroups, "SingleGroup", "[optiongroup]") {
     CHECK_THROWS_AS(run(), CLI::RequiredError);
 }
 
+TEST_CASE_METHOD(ManyGroups, "getGroup", "[optiongroup]") {
+    auto *mn = app.get_option_group("main");
+    CHECK(mn == main);
+    CHECK_THROWS_AS(app.get_option_group("notfound"), CLI::OptionNotFound);
+}
+
 TEST_CASE_METHOD(ManyGroups, "ExcludesGroup", "[optiongroup]") {
     // only 1 group can be used
     g1->excludes(g2);
diff --git a/packages/CLI11/tests/OptionTypeTest.cpp b/packages/CLI11/tests/OptionTypeTest.cpp
index b48ba6d5b..6d06a5af3 100644
--- a/packages/CLI11/tests/OptionTypeTest.cpp
+++ b/packages/CLI11/tests/OptionTypeTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -336,6 +336,36 @@ TEST_CASE_METHOD(TApp, "pair_check", "[optiontype]") {
     CHECK_THROWS_AS(run(), CLI::ValidationError);
 }
 
+TEST_CASE_METHOD(TApp, "pair_check_string", "[optiontype]") {
+    std::string myfile{"pair_check_file.txt"};
+    bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a'));  // create file
+    CHECK(ok);
+
+    CHECK(CLI::ExistingFile(myfile).empty());
+    std::pair<std::string, std::string> findex;
+
+    auto v0 = CLI::ExistingFile;
+    v0.application_index(0);
+    auto v1 = CLI::PositiveNumber;
+    v1.application_index(1);
+    app.add_option("--file", findex)->check(v0)->check(v1);
+
+    args = {"--file", myfile, "2"};
+
+    CHECK_NOTHROW(run());
+
+    CHECK(myfile == findex.first);
+    CHECK("2" == findex.second);
+
+    args = {"--file", myfile, "-3"};
+
+    CHECK_THROWS_AS(run(), CLI::ValidationError);
+
+    args = {"--file", myfile, "2"};
+    std::remove(myfile.c_str());
+    CHECK_THROWS_AS(run(), CLI::ValidationError);
+}
+
 TEST_CASE_METHOD(TApp, "pair_check_take_first", "[optiontype]") {
     std::string myfile{"pair_check_file2.txt"};
     bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a'));  // create file
@@ -405,6 +435,86 @@ TEST_CASE_METHOD(TApp, "VectorIndexedValidator", "[optiontype]") {
     CHECK_THROWS_AS(run(), CLI::ValidationError);
 }
 
+TEST_CASE_METHOD(TApp, "IntegerOverFlowShort", "[optiontype]") {
+    std::int16_t A{0};
+    std::uint16_t B{0};
+
+    app.add_option("-a", A);
+    app.add_option("-b", B);
+
+    args = {"-a", "2626254242"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+
+    args = {"-b", "2626254242"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+
+    args = {"-b", "-26262"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+
+    args = {"-b", "-262624262525"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+}
+
+TEST_CASE_METHOD(TApp, "IntegerOverFlowInt", "[optiontype]") {
+    int A{0};
+    unsigned int B{0};
+
+    app.add_option("-a", A);
+    app.add_option("-b", B);
+
+    args = {"-a", "262625424225252"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+
+    args = {"-b", "262625424225252"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+
+    args = {"-b", "-2626225252"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+
+    args = {"-b", "-26262426252525252"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+}
+
+TEST_CASE_METHOD(TApp, "IntegerOverFlowLong", "[optiontype]") {
+    std::int32_t A{0};
+    std::uint32_t B{0};
+
+    app.add_option("-a", A);
+    app.add_option("-b", B);
+
+    args = {"-a", "1111111111111111111111111111"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+
+    args = {"-b", "1111111111111111111111111111"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+
+    args = {"-b", "-2626225252"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+
+    args = {"-b", "-111111111111111111111111"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+}
+
+TEST_CASE_METHOD(TApp, "IntegerOverFlowLongLong", "[optiontype]") {
+    std::int64_t A{0};
+    std::uint64_t B{0};
+
+    app.add_option("-a", A);
+    app.add_option("-b", B);
+
+    args = {"-a", "1111111111111111111111111111111111111111111111111111111111"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+
+    args = {"-b", "1111111111111111111111111111111111111111111111111111111111"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+
+    args = {"-b", "-2626225252"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+
+    args = {"-b", "-111111111111111111111111111111111111111111111111111111111"};
+    CHECK_THROWS_AS(run(), CLI::ConversionError);
+}
+
 TEST_CASE_METHOD(TApp, "VectorUnlimString", "[optiontype]") {
     std::vector<std::string> strvec;
     std::vector<std::string> answer{"mystring", "mystring2", "mystring3"};
diff --git a/packages/CLI11/tests/OptionalTest.cpp b/packages/CLI11/tests/OptionalTest.cpp
index 4094c44b6..3d78e3498 100644
--- a/packages/CLI11/tests/OptionalTest.cpp
+++ b/packages/CLI11/tests/OptionalTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/tests/SetTest.cpp b/packages/CLI11/tests/SetTest.cpp
index 8184350dc..b32698999 100644
--- a/packages/CLI11/tests/SetTest.cpp
+++ b/packages/CLI11/tests/SetTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -492,6 +492,23 @@ TEST_CASE_METHOD(TApp, "FailSet", "[set]") {
     CHECK_THROWS_AS(run(), CLI::ValidationError);
 }
 
+TEST_CASE_METHOD(TApp, "shortStringCheck", "[set]") {
+
+    std::string choice;
+    app.add_option("-q,--quick", choice)->check([](const std::string &v) {
+        if(v.size() > 5) {
+            return std::string{"string too long"};
+        }
+        return std::string{};
+    });
+
+    args = {"--quick", "3"};
+    CHECK_NOTHROW(run());
+
+    args = {"--quick=hello_goodbye"};
+    CHECK_THROWS_AS(run(), CLI::ValidationError);
+}
+
 TEST_CASE_METHOD(TApp, "FailMutableSet", "[set]") {
 
     int choice{0};
diff --git a/packages/CLI11/tests/SimpleTest.cpp b/packages/CLI11/tests/SimpleTest.cpp
index 84ec6f0c4..14d6558b4 100644
--- a/packages/CLI11/tests/SimpleTest.cpp
+++ b/packages/CLI11/tests/SimpleTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/tests/StringParseTest.cpp b/packages/CLI11/tests/StringParseTest.cpp
index 6a889e45c..cc1205fe3 100644
--- a/packages/CLI11/tests/StringParseTest.cpp
+++ b/packages/CLI11/tests/StringParseTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/tests/SubcommandTest.cpp b/packages/CLI11/tests/SubcommandTest.cpp
index a01b8863d..25415eaa7 100644
--- a/packages/CLI11/tests/SubcommandTest.cpp
+++ b/packages/CLI11/tests/SubcommandTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -6,8 +6,6 @@
 
 #include "app_helper.hpp"
 
-using Catch::Matchers::Contains;
-
 using vs_t = std::vector<std::string>;
 
 TEST_CASE_METHOD(TApp, "BasicSubcommands", "[subcom]") {
@@ -916,6 +914,10 @@ TEST_CASE_METHOD(TApp, "SubcomInheritCaseCheck", "[subcom]") {
     CHECK(app.get_subcommands({}).size() == 2u);
     CHECK(app.get_subcommands([](const CLI::App *s) { return s->get_name() == "sub1"; }).size() == 1u);
 
+    // check the const version of get_subcommands
+    const auto &app_const = app;
+    CHECK(app_const.get_subcommands([](const CLI::App *s) { return s->get_name() == "sub1"; }).size() == 1u);
+
     args = {"SuB1"};
     run();
     CHECK(app.get_subcommands().at(0) == sub1);
@@ -1192,6 +1194,18 @@ TEST_CASE_METHOD(ManySubcommands, "manyIndexQueryPtr", "[subcom]") {
     CHECK_THROWS_AS(app.get_subcommand_ptr(4), CLI::OptionNotFound);
 }
 
+TEST_CASE_METHOD(ManySubcommands, "manyIndexQueryPtrByName", "[subcom]") {
+    auto s1 = app.get_subcommand_ptr("sub1");
+    auto s2 = app.get_subcommand_ptr("sub2");
+    auto s3 = app.get_subcommand_ptr("sub3");
+    auto s4 = app.get_subcommand_ptr("sub4");
+    CHECK(sub1 == s1.get());
+    CHECK(sub2 == s2.get());
+    CHECK(sub3 == s3.get());
+    CHECK(sub4 == s4.get());
+    CHECK_THROWS_AS(app.get_subcommand_ptr("sub5"), CLI::OptionNotFound);
+}
+
 TEST_CASE_METHOD(ManySubcommands, "Required1Fuzzy", "[subcom]") {
 
     app.require_subcommand(0, 1);
@@ -1394,6 +1408,15 @@ TEST_CASE_METHOD(ManySubcommands, "SubcommandNeedsOptionsCallbackOrdering", "[su
     CHECK_NOTHROW(run());
 }
 
+TEST_CASE_METHOD(ManySubcommands, "SubcommandParseCompleteDotNotation", "[subcom]") {
+    int count{0};
+    sub1->add_flag("--flag1");
+    sub1->parse_complete_callback([&count]() { ++count; });
+    args = {"--sub1.flag1", "--sub1.flag1"};
+    run();
+    CHECK(count == 2);
+}
+
 TEST_CASE_METHOD(ManySubcommands, "SubcommandNeedsFail", "[subcom]") {
 
     auto *opt = app.add_flag("--subactive");
@@ -1968,3 +1991,126 @@ TEST_CASE_METHOD(TApp, "SubcommandInOptionGroupCallbackCount", "[subcom]") {
     run();
     CHECK(subcount == 1);
 }
+
+TEST_CASE_METHOD(TApp, "DotNotationSubcommand", "[subcom]") {
+    std::string v1, v2, vbase;
+
+    auto *sub1 = app.add_subcommand("sub1");
+    auto *sub2 = app.add_subcommand("sub2");
+    sub1->add_option("--value", v1);
+    sub2->add_option("--value", v2);
+    app.add_option("--value", vbase);
+    args = {"--sub1.value", "val1"};
+    run();
+    CHECK(v1 == "val1");
+
+    args = {"--sub2.value", "val2", "--value", "base"};
+    run();
+    CHECK(v2 == "val2");
+    CHECK(vbase == "base");
+    v1.clear();
+    v2.clear();
+    vbase.clear();
+
+    args = {"--sub2.value=val2", "--value=base"};
+    run();
+    CHECK(v2 == "val2");
+    CHECK(vbase == "base");
+
+    auto subs = app.get_subcommands();
+    REQUIRE(!subs.empty());
+    CHECK(subs.front()->get_name() == "sub2");
+}
+
+TEST_CASE_METHOD(TApp, "DotNotationSubcommandSingleChar", "[subcom]") {
+    std::string v1, v2, vbase;
+
+    auto *sub1 = app.add_subcommand("sub1");
+    auto *sub2 = app.add_subcommand("sub2");
+    sub1->add_option("-v", v1);
+    sub2->add_option("-v", v2);
+    app.add_option("-v", vbase);
+    args = {"--sub1.v", "val1"};
+    run();
+    CHECK(v1 == "val1");
+
+    args = {"--sub2.v", "val2", "-v", "base"};
+    run();
+    CHECK(v2 == "val2");
+    CHECK(vbase == "base");
+    v1.clear();
+    v2.clear();
+    vbase.clear();
+
+    args = {"--sub2.v=val2", "-vbase"};
+    run();
+    CHECK(v2 == "val2");
+    CHECK(vbase == "base");
+
+    auto subs = app.get_subcommands();
+    REQUIRE(!subs.empty());
+    CHECK(subs.front()->get_name() == "sub2");
+}
+
+TEST_CASE_METHOD(TApp, "DotNotationSubcommandRecusive", "[subcom]") {
+    std::string v1, v2, v3, vbase;
+
+    auto *sub1 = app.add_subcommand("sub1");
+    auto *sub2 = sub1->add_subcommand("sub2");
+    auto *sub3 = sub2->add_subcommand("sub3");
+
+    sub1->add_option("--value", v1);
+    sub2->add_option("--value", v2);
+    sub3->add_option("--value", v3);
+    app.add_option("--value", vbase);
+    args = {"--sub1.sub2.sub3.value", "val1"};
+    run();
+    CHECK(v3 == "val1");
+
+    args = {"--sub1.sub2.value", "val2"};
+    run();
+    CHECK(v2 == "val2");
+
+    args = {"--sub1.sub2.bob", "val2"};
+    CHECK_THROWS_AS(run(), CLI::ExtrasError);
+    app.allow_extras();
+    CHECK_NOTHROW(run());
+    auto extras = app.remaining();
+    CHECK(extras.size() == 2);
+    CHECK(extras.front() == "--sub1.sub2.bob");
+}
+
+TEST_CASE_METHOD(TApp, "DotNotationSubcommandRecusive2", "[subcom]") {
+    std::string v1, v2, v3, vbase;
+
+    auto *sub1 = app.add_subcommand("sub1");
+    auto *sub2 = sub1->add_subcommand("sub2");
+    auto *sub3 = sub2->add_subcommand("sub3");
+
+    sub1->add_option("--value", v1);
+    sub2->add_option("--value", v2);
+    sub3->add_option("--value", v3);
+    app.add_option("--value", vbase);
+    args = {"sub1.sub2.sub3", "--value", "val1"};
+    run();
+    CHECK(v3 == "val1");
+
+    args = {"sub1.sub2", "--value", "val2"};
+    run();
+    CHECK(v2 == "val2");
+
+    args = {"sub1.bob", "--value", "val2"};
+    CHECK_THROWS_AS(run(), CLI::ExtrasError);
+
+    args = {"sub1.sub2.bob", "--value", "val2"};
+    CHECK_THROWS_AS(run(), CLI::ExtrasError);
+
+    args = {"sub1.sub2.sub3.bob", "--value", "val2"};
+    CHECK_THROWS_AS(run(), CLI::ExtrasError);
+
+    app.allow_extras();
+    CHECK_NOTHROW(run());
+    auto extras = app.remaining();
+    CHECK(extras.size() == 1);
+    CHECK(extras.front() == "sub1.sub2.sub3.bob");
+}
diff --git a/packages/CLI11/tests/TimerTest.cpp b/packages/CLI11/tests/TimerTest.cpp
index a3d8c1d9e..e15d928cf 100644
--- a/packages/CLI11/tests/TimerTest.cpp
+++ b/packages/CLI11/tests/TimerTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -12,8 +12,6 @@
 #include <string>
 #include <thread>
 
-using Catch::Matchers::Contains;
-
 TEST_CASE("Timer: MSTimes", "[timer]") {
     CLI::Timer timer{"My Timer"};
     std::this_thread::sleep_for(std::chrono::milliseconds(123));
diff --git a/packages/CLI11/tests/TransformTest.cpp b/packages/CLI11/tests/TransformTest.cpp
index 5ace484ec..9406e0254 100644
--- a/packages/CLI11/tests/TransformTest.cpp
+++ b/packages/CLI11/tests/TransformTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/tests/TrueFalseTest.cpp b/packages/CLI11/tests/TrueFalseTest.cpp
index d7d2f2cd0..93f2f3fb8 100644
--- a/packages/CLI11/tests/TrueFalseTest.cpp
+++ b/packages/CLI11/tests/TrueFalseTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/tests/WindowsTest.cpp b/packages/CLI11/tests/WindowsTest.cpp
index 0527cfb08..a17d58735 100644
--- a/packages/CLI11/tests/WindowsTest.cpp
+++ b/packages/CLI11/tests/WindowsTest.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/tests/app_helper.hpp b/packages/CLI11/tests/app_helper.hpp
index f8d7e7221..5479e4863 100644
--- a/packages/CLI11/tests/app_helper.hpp
+++ b/packages/CLI11/tests/app_helper.hpp
@@ -13,6 +13,9 @@
 #endif
 
 #include "catch.hpp"
+#include <array>
+#include <fstream>
+#include <iomanip>
 #include <iostream>
 #include <string>
 #include <utility>
@@ -33,6 +36,8 @@ class TApp {
     }
 };
 
+CLI11_INLINE int fileClear(const std::string &name) { return std::remove(name.c_str()); }
+
 class TempFile {
     std::string _name{};
 
@@ -65,3 +70,54 @@ inline void unset_env(std::string name) {
     unsetenv(name.c_str());
 #endif
 }
+
+CLI11_INLINE void check_identical_files(const char *path1, const char *path2) {
+    std::string err1 = CLI::ExistingFile(path1);
+    if(!err1.empty()) {
+        FAIL("Could not open " << path1 << ": " << err1);
+    }
+
+    std::string err2 = CLI::ExistingFile(path2);
+    if(!err2.empty()) {
+        FAIL("Could not open " << path2 << ": " << err2);
+    }
+
+    // open files at the end to compare size first
+    std::ifstream file1(path1, std::ifstream::ate | std::ifstream::binary);
+    std::ifstream file2(path2, std::ifstream::ate | std::ifstream::binary);
+
+    if(!file1.good()) {
+        FAIL("File " << path1 << " is corrupted");
+    }
+
+    if(!file2.good()) {
+        FAIL("File " << path2 << " is corrupted");
+    }
+
+    if(file1.tellg() != file2.tellg()) {
+        FAIL("Different file sizes:\n  " << file1.tellg() << " bytes in " << path1 << "\n  " << file2.tellg()
+                                         << " bytes in " << path2);
+    }
+
+    // rewind files
+    file1.seekg(0);
+    file2.seekg(0);
+
+    std::array<uint8_t, 10240> buffer1;
+    std::array<uint8_t, 10240> buffer2;
+
+    for(size_t ibuffer = 0; file1.good(); ++ibuffer) {
+        // Flawfinder: ignore
+        file1.read(reinterpret_cast<char *>(buffer1.data()), static_cast<std::streamsize>(buffer1.size()));
+        // Flawfinder: ignore
+        file2.read(reinterpret_cast<char *>(buffer2.data()), static_cast<std::streamsize>(buffer2.size()));
+
+        for(size_t i = 0; i < static_cast<size_t>(file1.gcount()); ++i) {
+            if(buffer1[i] != buffer2[i]) {
+                FAIL(std::hex << std::setfill('0') << "Different bytes at position " << (ibuffer * 10240 + i) << ":\n  "
+                              << "0x" << std::setw(2) << static_cast<int>(buffer1[i]) << " in " << path1 << "\n  "
+                              << "0x" << std::setw(2) << static_cast<int>(buffer2[i]) << " in " << path2);
+            }
+        }
+    }
+}
diff --git a/packages/CLI11/tests/applications/system_args.cpp b/packages/CLI11/tests/applications/system_args.cpp
new file mode 100644
index 000000000..e1e77ba67
--- /dev/null
+++ b/packages/CLI11/tests/applications/system_args.cpp
@@ -0,0 +1,22 @@
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
+// under NSF AWARD 1414736 and by the respective contributors.
+// All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include <CLI/CLI.hpp>
+#include <cstring>
+
+int main(int argc, char **argv) {
+    if(argc != CLI::argc()) {
+        return -1;
+    }
+
+    for(int i = 0; i < argc; i++) {
+        if(std::strcmp(argv[i], CLI::argv()[i]) != 0) {
+            return i + 1;
+        }
+    }
+
+    return 0;
+}
diff --git a/packages/CLI11/tests/catch.hpp b/packages/CLI11/tests/catch.hpp
index da41d685d..e6de66732 100644
--- a/packages/CLI11/tests/catch.hpp
+++ b/packages/CLI11/tests/catch.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
@@ -6,4 +6,26 @@
 
 #pragma once
 
+#include <string>
+
+#ifdef CLI11_CATCH3
+
+#include <catch2/catch_approx.hpp>
+#include <catch2/catch_template_test_macros.hpp>
+#include <catch2/catch_test_macros.hpp>
+#include <catch2/generators/catch_generators.hpp>
+#include <catch2/matchers/catch_matchers_string.hpp>
+
+using Catch::Approx;            // NOLINT(google-global-names-in-headers)
+using Catch::Matchers::Equals;  // NOLINT(google-global-names-in-headers)
+
+inline auto Contains(const std::string &x) { return Catch::Matchers::ContainsSubstring(x); }
+
+#else
+
 #include <catch2/catch.hpp>
+
+using Catch::Equals;              // NOLINT(google-global-names-in-headers)
+using Catch::Matchers::Contains;  // NOLINT(google-global-names-in-headers)
+
+#endif
diff --git a/packages/CLI11/tests/data/unicode.txt b/packages/CLI11/tests/data/unicode.txt
new file mode 100644
index 000000000..f430f5423
--- /dev/null
+++ b/packages/CLI11/tests/data/unicode.txt
@@ -0,0 +1 @@
+Hello Halló Привет 你好 👩‍🚀❤️
diff --git a/packages/CLI11/tests/fuzzFail/fuzz_app_fail1 b/packages/CLI11/tests/fuzzFail/fuzz_app_fail1
new file mode 100644
index 0000000000000000000000000000000000000000..d133524b2731b74ba6845719bae4200eda67c09a
GIT binary patch
literal 41
mcmdPZEh#N9;nFqaGUC!TVh1rw=aoVMNXUqbfrX19?<xS&tqM^9

literal 0
HcmV?d00001

diff --git a/packages/CLI11/tests/fuzzFail/fuzz_app_fail2 b/packages/CLI11/tests/fuzzFail/fuzz_app_fail2
new file mode 100644
index 000000000..ac301930c
--- /dev/null
+++ b/packages/CLI11/tests/fuzzFail/fuzz_app_fail2
@@ -0,0 +1 @@
+1	c	e g0  g0 ��    --tup4 N3CLI10ParseErrorE% 0            %% 0   i��������������wrap    $             
\ No newline at end of file
diff --git a/packages/CLI11/tests/informational.cpp b/packages/CLI11/tests/informational.cpp
index 9df227fab..4f7f27b52 100644
--- a/packages/CLI11/tests/informational.cpp
+++ b/packages/CLI11/tests/informational.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/tests/link_test_1.cpp b/packages/CLI11/tests/link_test_1.cpp
index 1cbec7b77..ba1b2d837 100644
--- a/packages/CLI11/tests/link_test_1.cpp
+++ b/packages/CLI11/tests/link_test_1.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/tests/link_test_2.cpp b/packages/CLI11/tests/link_test_2.cpp
index 9dcc3db23..46d77be26 100644
--- a/packages/CLI11/tests/link_test_2.cpp
+++ b/packages/CLI11/tests/link_test_2.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/tests/main.cpp b/packages/CLI11/tests/main.cpp
index 20bb46d61..451f65038 100644
--- a/packages/CLI11/tests/main.cpp
+++ b/packages/CLI11/tests/main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
diff --git a/packages/CLI11/tests/meson.build b/packages/CLI11/tests/meson.build
index 27e221619..484798555 100644
--- a/packages/CLI11/tests/meson.build
+++ b/packages/CLI11/tests/meson.build
@@ -1,14 +1,21 @@
 catch2 = dependency('catch2')
 
-testmain = static_library(
-    'catch_main',
-    'main.cpp', 'catch.hpp',
-    dependencies: catch2,
-)
-testdep = declare_dependency(
-    link_with: testmain,
-    dependencies: [catch2, CLI11_dep]
-)
+if catch2.version().version_compare('<3')
+    testmain = static_library(
+        'catch_main',
+        'main.cpp', 'catch.hpp',
+        dependencies: catch2,
+    )
+    testdep = declare_dependency(
+        link_with: testmain,
+        dependencies: [catch2, CLI11_dep]
+    )
+else
+    testdep = declare_dependency(
+        dependencies: [CLI11_dep, dependency('catch2-with-main')],
+        compile_args: '-DCLI11_CATCH3'
+    )
+endif
 
 link_test_lib = library(
     'link_test_1',
@@ -57,6 +64,20 @@ testnames = [
     ['link_test_2', {'link_with': link_test_lib}],
 ]
 
+dependent_applications = [
+    'system_args'
+]
+dependent_applications_definitions = []
+#dependent_applications_targets = []
+foreach app: dependent_applications
+    app_target = executable(app, 'applications'/app + '.cpp',
+        build_by_default: false
+    )
+
+    #dependent_applications_targets += dependency(app_target)
+    dependent_applications_definitions += '-DCLI11_@0@_EXE="@1@"'.format(app.to_upper(), app_target)
+endforeach
+
 if host_machine.system() == 'windows'
     testnames += [['WindowsTest', {}]]
 endif
@@ -69,7 +90,7 @@ foreach n: testnames
     name = n[0]
     kwargs = n[1]
     t = executable(name, name + '.cpp',
-        cpp_args: kwargs.get('cpp_args', []),
+        cpp_args: kwargs.get('cpp_args', []) + dependent_applications_definitions,
         build_by_default: false,
         dependencies: [testdep] + kwargs.get('dependencies', []),
         link_with: kwargs.get('link_with', [])
diff --git a/packages/CLI11/tests/mesonTest/main.cpp b/packages/CLI11/tests/mesonTest/main.cpp
index 64d45eb6f..39bb7845c 100644
--- a/packages/CLI11/tests/mesonTest/main.cpp
+++ b/packages/CLI11/tests/mesonTest/main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2021, University of Cincinnati, developed by Henry Schreiner
+// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
 // under NSF AWARD 1414736 and by the respective contributors.
 // All rights reserved.
 //
-- 
GitLab