From d2f56a3df3be74ceb05eec62135891fd49135b79 Mon Sep 17 00:00:00 2001 From: Matt Wilson <152443343+mwsis@users.noreply.github.com> Date: Mon, 17 Aug 2026 22:29:02 +1000 Subject: [PATCH 1/8] Boilerplate (#1) * .vscode/settings.json * .gitattributes * .vimrc * minimal version * ci * README.md "related projects" * README.md operating-system badge * README.md initial contents * chore: standardise helper project identity handling * chore: standardize shell-script color output * chore: canonicalised helper scripts * LICENSE --- .gitattributes | 99 +++++++++++++++ .github/workflows/ci-cell.yml | 89 +++++++++++++ .github/workflows/ci.yml | 40 ++++++ .sis/project_name.txt | 1 + .sis/script_info_lines.txt | 2 + .vimrc | 70 +++++++++++ .vscode/settings.json | 197 +++++++++++++++++++++++++++++ CMakeLists.txt | 36 ++++++ LICENSE | 27 ++-- README.md | 94 +++++++++++++- build_cmake.sh | 150 ++++++++++++++++++++++ clean_cmake.sh | 112 +++++++++++++++++ main.c | 8 ++ prepare_cmake.sh | 228 ++++++++++++++++++++++++++++++++++ remove_cmake_artefacts.sh | 171 +++++++++++++++++++++++++ run_all_unit_tests.cmd | 141 +++++++++++++++++++++ run_all_unit_tests.sh | 175 ++++++++++++++++++++++++++ 17 files changed, 1626 insertions(+), 14 deletions(-) create mode 100644 .gitattributes create mode 100644 .github/workflows/ci-cell.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .sis/project_name.txt create mode 100644 .sis/script_info_lines.txt create mode 100644 .vimrc create mode 100644 .vscode/settings.json create mode 100644 CMakeLists.txt create mode 100755 build_cmake.sh create mode 100755 clean_cmake.sh create mode 100644 main.c create mode 100755 prepare_cmake.sh create mode 100755 remove_cmake_artefacts.sh create mode 100644 run_all_unit_tests.cmd create mode 100755 run_all_unit_tests.sh diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..66f0c82 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,99 @@ +# .gitattributes — C++ (GitHub-hosted) +# +# Sources: GitHub Docs (line endings), git-scm gitattributes (diff=cpp), +# gitattributes/gitattributes C++.gitattributes + Common.gitattributes, +# github-linguist overrides. + +# Default: detect text, normalize to LF in the repository +* text=auto + +# --- Source --- +*.c text diff=cpp +*.c++ text diff=cpp +*.cc text diff=cpp +*.cpp text diff=cpp +*.cxx text diff=cpp +*.h text diff=cpp +*.h++ text diff=cpp +*.hh text diff=cpp +*.hpp text diff=cpp +*.hxx text diff=cpp +*.inc text +*.inl text +*.ipp text +*.tcc text +*.tpp text + +# --- Build / config --- +*.am text +*.cmake text +*.m4 text +*.mak text +*.mk text +*akefile text +CMakeLists.txt text +configure text eol=lf +configure.ac text + +# --- Scripts --- +*.bash text eol=lf +*.bat text eol=crlf +*.cmd text eol=crlf +*.ps1 text eol=crlf +*.sh text eol=lf +*.zsh text eol=lf + +# --- Docs / meta --- +*.adoc text +*.markdown text diff=markdown +*.md text diff=markdown +*.txt text +AUTHORS text +CHANGELOG text +CHANGES text +CONTRIBUTING text +COPYING text +LICENSE text +NEWS text +README text +TODO text +.gitattributes text +.gitignore text + +# --- Serialisation --- +*.json text +*.toml text +*.xml text +*.yaml text +*.yml text + +# --- Compiled / binary artefacts --- +*.a binary +*.dll binary +*.dylib binary +*.exe binary +*.gch binary +*.la binary +*.lai binary +*.lib binary +*.lo binary +*.o binary +*.obj binary +*.out binary +*.pch binary +*.slo binary +*.so binary + +# --- Archives / images (common) --- +*.gif binary +*.gz binary +*.ico binary +*.jpeg binary +*.jpg binary +*.png binary +*.tar binary +*.zip binary + +# --- GitHub Linguist --- +**/build/** linguist-generated +**/cmake-build-*/** linguist-generated diff --git a/.github/workflows/ci-cell.yml b/.github/workflows/ci-cell.yml new file mode 100644 index 0000000..2cf3270 --- /dev/null +++ b/.github/workflows/ci-cell.yml @@ -0,0 +1,89 @@ +name: CI cell + +on: + workflow_call: + inputs: + cell-id: + required: true + type: string + os: + required: true + type: string + c-compiler: + required: true + type: string + cpp-compiler: + required: true + type: string + build-type: + required: false + type: string + default: Release + +jobs: + cell: + name: ${{ inputs.cell-id }} + runs-on: ${{ inputs.os }} + + steps: + - uses: actions/checkout@v4 + + - name: Setup MSYS2 MinGW + if: inputs.c-compiler == 'mingw' + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + update: true + install: >- + mingw-w64-x86_64-toolchain + mingw-w64-x86_64-cmake + mingw-w64-x86_64-make + + - name: Configure + shell: bash + run: | + set -euo pipefail + if [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + cmake -B build -G "MinGW Makefiles" \ + -DCMAKE_BUILD_TYPE="${{ inputs.build-type }}" \ + -DCMAKE_C_COMPILER=gcc \ + -DCMAKE_CXX_COMPILER=g++ \ + -DBUILD_TESTING=OFF + else + cmake -B build -S . \ + -DBUILD_TESTING=OFF + fi + + - name: Build + shell: bash + run: | + set -euo pipefail + if [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + cmake --build build --parallel 2 + else + cmake --build build --config "${{ inputs.build-type }}" --parallel + fi + + - name: Install and verify + shell: bash + run: | + set -euo pipefail + PREFIX="${RUNNER_TEMP}/install-prefix" + PROJECT="$(tr -d '[:space:]' < .sis/project_name.txt)" + if [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + cmake --install build --prefix "$PREFIX" + else + cmake --install build --config "${{ inputs.build-type }}" --prefix "$PREFIX" + fi + test -f "$PREFIX/bin/${PROJECT}.exe" + + - name: Smoke run + shell: bash + run: | + set -euo pipefail + PREFIX="${RUNNER_TEMP}/install-prefix" + PROJECT="$(tr -d '[:space:]' < .sis/project_name.txt)" + "$PREFIX/bin/${PROJECT}.exe" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..5d553a0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,40 @@ +name: CI + +on: + push: + branches: + - master + - dev + - boilerplate + - idiomatic + - rc1 + - rc2 + - rc3 + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + cell: + name: CI (${{ matrix.id }}) + strategy: + fail-fast: false + matrix: + include: + - id: windows-cl + os: windows-latest + c_compiler: cl + cpp_compiler: cl + - id: windows-mingw + os: windows-latest + c_compiler: mingw + cpp_compiler: g++ + uses: ./.github/workflows/ci-cell.yml + with: + cell-id: ${{ matrix.id }} + os: ${{ matrix.os }} + c-compiler: ${{ matrix.c_compiler }} + cpp-compiler: ${{ matrix.cpp_compiler }} + build-type: Release diff --git a/.sis/project_name.txt b/.sis/project_name.txt new file mode 100644 index 0000000..2e3ac91 --- /dev/null +++ b/.sis/project_name.txt @@ -0,0 +1 @@ +ReadDebugString diff --git a/.sis/script_info_lines.txt b/.sis/script_info_lines.txt new file mode 100644 index 0000000..8129a6d --- /dev/null +++ b/.sis/script_info_lines.txt @@ -0,0 +1,2 @@ +ReadDebugString is a Windows CLI that reads messages from the Windows debugger +Copyright (c) 2026, Matthew Wilson and Synesis Information Systems diff --git a/.vimrc b/.vimrc new file mode 100644 index 0000000..1bf33a0 --- /dev/null +++ b/.vimrc @@ -0,0 +1,70 @@ +" Synesis C/C++ project .vimrc — aligned with .sis/.vscode/c_cxx/settings.json + +set nocompatible +filetype indent plugin on +syntax enable +set autoindent +set backspace=indent,eol,start +set hlsearch +set incsearch +set number + +" files.insertFinalNewline +set eol +set fixeol + +" editor.renderWhitespace: all +set list +set listchars=tab:->,trail:-,extends:>,precedes:<,nbsp:+ + +" editor.detectIndentation: false — global defaults (editor.tabSize: 4, insertSpaces: true) +set colorcolumn=76 +set expandtab +set shiftwidth=4 +set softtabstop=4 +set tabstop=4 + +" colorcolumn draws a full-column tint in Vim (not a VS Code-style 1px line). +" Keep it subtle via the ColorColumn highlight group; reapply after colorscheme changes. +if has('termguicolors') + " set termguicolors +endif + +function! s:ConfigureColorColumn() abort + highlight ColorColumn ctermbg=236 guibg=#2a2a2a cterm=NONE gui=NONE +endfunction + +call s:ConfigureColorColumn() +autocmd ColorScheme * call s:ConfigureColorColumn() + +" files.trimTrailingWhitespace +autocmd BufWritePre * %s/\s\+$//e + +augroup sis_c_cxx + autocmd! + + " [c] / [cpp] + autocmd FileType c,cpp setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,64,68,72,76 + + " [rust] + autocmd FileType rs setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=76 + + " [cmake] + autocmd FileType cmake setlocal noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 + + " [shellscript] + autocmd FileType sh,bash,zsh setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 colorcolumn=60,76 + + " [bat] + autocmd FileType bat,dosbatch setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,76 + + " [json] / [markdown] / [yaml] / [ruby] + autocmd FileType json,markdown,yaml,ruby setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 + + " [python] + autocmd FileType python setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,76 + + " [toml] + autocmd FileType toml setlocal noexpandtab tabstop=2 shiftwidth=2 softtabstop=2 +augroup END + diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a20fc3c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,197 @@ +{ + "[bat]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 76 ], + "editor.tabSize": 4, + }, + "[c]": { + "editor.defaultFormatter": "ms-vscode.cpptools", + "editor.formatOnSave": true, + "editor.insertSpaces": true, + "editor.rulers": [ 60, 64, 68, 72, 76 ], + "editor.tabSize": 4, + }, + "[cmake]": { + "editor.insertSpaces": false, + "editor.tabSize": 4, + }, + "[cpp]": { + "editor.defaultFormatter": "ms-vscode.cpptools", + "editor.formatOnSave": true, + "editor.insertSpaces": true, + "editor.rulers": [ 60, 64, 68, 72, 76 ], + "editor.tabSize": 4, + }, + "[json]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "[markdown]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "[python]": { + "diffEditor.ignoreTrimWhitespace": false, + "editor.insertSpaces": true, + "editor.rulers": [ 51, 60, 61, 76 ], + "editor.tabSize": 4, + }, + "[ruby]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "[shellscript]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 76 ], + "editor.tabSize": 2, + }, + "[toml]": { + "editor.insertSpaces": false, + "editor.tabSize": 2, + }, + "[yaml]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "C_Cpp.autocompleteAddParentheses": true, + "C_Cpp.clang_format_fallbackStyle": "none", + "C_Cpp.clang_format_style": "file", + "C_Cpp.default.cStandard": "c17", + "C_Cpp.default.cppStandard": "c++17", + "C_Cpp.enhancedColorization": "enabled", + "C_Cpp.errorSquiggles": "enabled", + "C_Cpp.formatting": "clangFormat", + "C_Cpp.intelliSenseEngine": "default", + "cmake.configureOnOpen": false, + "debug.allowBreakpointsEverywhere": true, + "editor.detectIndentation": false, + "editor.insertSpaces": false, + "editor.renderWhitespace": "all", + "editor.rulers": [ 76 ], + "editor.tabSize": 2, + "files.associations": { + "__bit_reference": "cpp", + "__bits": "cpp", + "__config": "cpp", + "__debug": "cpp", + "__errc": "cpp", + "__functional_03": "cpp", + "__functional_base": "cpp", + "__hash_table": "cpp", + "__locale": "cpp", + "__memory": "cpp", + "__mutex_base": "cpp", + "__node_handle": "cpp", + "__nullptr": "cpp", + "__split_buffer": "cpp", + "__string": "cpp", + "__threading_support": "cpp", + "__tree": "cpp", + "__tuple": "cpp", + "__verbose_abort": "cpp", + "algorithm": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "complex": "cpp", + "concepts": "cpp", + "console_functions.h": "c", + "corecrt.h": "c", + "crtdefs.h": "c", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "exception": "cpp", + "execution": "cpp", + "fcntl.h": "c", + "format": "cpp", + "forward_list": "cpp", + "functional": "cpp", + "implicit_link.h": "c", + "initializer_list": "cpp", + "io.h": "c", + "iomanip": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "list": "cpp", + "locale": "cpp", + "map": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "numeric": "cpp", + "optional": "cpp", + "ostream": "cpp", + "print": "cpp", + "queue": "cpp", + "random": "cpp", + "ranges": "cpp", + "ratio": "cpp", + "semaphore": "cpp", + "set": "cpp", + "setenv.h": "c", + "shwild.h": "c", + "span": "cpp", + "sstream": "cpp", + "stack": "cpp", + "stdexcept": "cpp", + "stdio.h": "c", + "stop_token": "cpp", + "streambuf": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "terse-api.h": "c", + "text_encoding": "cpp", + "thread": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "uio.h": "c", + "unixem.h": "c", + "unordered_map": "cpp", + "util.h": "c", + "utility": "cpp", + "variant": "cpp", + "vector": "cpp", + "xfacet": "cpp", + "xhash": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xlocbuf": "cpp", + "xlocinfo": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "xmemory": "cpp", + "xstring": "cpp", + "xtests.internal.string.c": "cpp", + "xtr1common": "cpp", + "xtree": "cpp", + "xutility": "cpp", + }, + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + "git.mergeEditor": false, +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..796fb29 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.20 FATAL_ERROR) + +project(ReadDebugString + VERSION 0.0.1 + DESCRIPTION "ReadDebugString is a Windows CLI that reads messages from the Windows debugger." + HOMEPAGE_URL "https://github.com/sistools/ReadDebugString" + LANGUAGES C +) + +if(NOT WIN32) + message(FATAL_ERROR "${PROJECT_NAME} targets Windows only") +endif() + +set(CMAKE_C_STANDARD 17) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS ON) + +include(GNUInstallDirs) + +add_executable(${PROJECT_NAME} + main.c +) + +target_compile_options(${PROJECT_NAME} + PRIVATE + $<$: + -Werror -Wall -Wextra -pedantic + > + $<$: + /WX /W4 + > +) + +install(TARGETS ${PROJECT_NAME} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/LICENSE b/LICENSE index 6926798..9f8757e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,12 +1,13 @@ -BSD 3-Clause License +ReadDebugString - BSD 3-Clause License -Copyright (c) 2025, sistools +Copyright (c) 2025-2026, Synesis Information Systems +All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation @@ -18,11 +19,13 @@ modification, are permitted provided that the following conditions are met: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + diff --git a/README.md b/README.md index e69f828..ad74804 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,92 @@ -# ReadDebugString -Windows CLI C program that permits reading from the Windows debugger +# ReadDebugString + +Reads messages from the Windows debugger. + + +![C](https://img.shields.io/badge/C-00599C?style=flat&logo=c&logoColor=white) +![Windows](https://img.shields.io/badge/OS-Windows-0078D6?style=flat&logo=windows&logoColor=white) +[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) +[![GitHub release](https://img.shields.io/github/v/release/sistools/ReadDebugString.svg)](https://github.com/sistools/ReadDebugString/releases/latest) +[![Last Commit](https://img.shields.io/github/last-commit/sistools/ReadDebugString)](https://github.com/sistools/ReadDebugString/commits/master) +[![CI](https://github.com/sistools/ReadDebugString/actions/workflows/ci.yml/badge.svg)](https://github.com/sistools/ReadDebugString/actions/workflows/ci.yml) + + +## Table of Contents + +- [Introduction](#introduction) +- [Installation](#installation) +- [Components](#components) +- [Examples](#examples) +- [Project Information](#project-information) + - [Where to get help](#where-to-get-help) + - [Contribution guidelines](#contribution-guidelines) + - [Related projects](#related-projects) + - [License](#license) + + +## Introduction + +**ReadDebugString** is a small Windows-only utility that reads messages from +the Windows debugger. + +The current implementation is a minimal buildable scaffold. Its debugger +message-reading behaviour is still being developed. + + +## Installation + +The project uses CMake. From the project directory: + +```powershell +cmake -S . -B _build +cmake --build _build --config Release +``` + + +## Components + +The project creates a single executable program, **ReadDebugString**. + + +## Examples + +The current scaffold does not yet expose command-line options or produce +debugger output. + + +## Project Information + + +### Where to get help + +[GitHub Page](https://github.com/sistools/ReadDebugString "GitHub Page") + + +### Contribution guidelines + +Defect reports, feature requests, and pull requests are welcome on [the +**ReadDebugString** GitHub page](https://github.com/sistools/ReadDebugString). + + +### Related projects + +Other **sistools** projects include: + +* [**chomp**](https://github.com/sistools/chomp); +* [**errni**](https://github.com/sistools/errni) (errno on all platforms, and also GetLastError codes on Windows); +* [**lnunique**](https://github.com/sistools/lnunique); +* [**lslocales**](https://github.com/sistools/lslocales); +* [**lstrip**](https://github.com/sistools/lstrip); +* [**mksock**](https://github.com/sistools/mksock) (Unix-only); +* [**realpath**](https://github.com/sistools/realpath) (Windows-only); +* [**rstrip**](https://github.com/sistools/rstrip); +* [**WriteDebugString**](https://github.com/sistools/WriteDebugString) (Windows-only); + + +### License + +**ReadDebugString** is released under the 3-clause BSD license. See [LICENSE](./LICENSE) +for details. + + + diff --git a/build_cmake.sh b/build_cmake.sh new file mode 100755 index 0000000..3f261e7 --- /dev/null +++ b/build_cmake.sh @@ -0,0 +1,150 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd "$(dirname "$ScriptPath")" && pwd) +Basename=$(basename "$ScriptPath") + +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +if [[ -n "$MSYSTEM" ]]; then + + DefaultMakeCmd=mingw32-make.exe + MinGW=1 +else + + DefaultMakeCmd=make +fi +MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") + +IgnoreRemainingFlagsAndOptions=0 +Targets=() + + +# ########################################################## +# colours + +if command -v tput > /dev/null; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_None=${FD_NONE:-$(tput sgr0)} +else + + SisClr_Blue= + SisClr_Red= + SisClr_Bold= + SisClr_None= +fi + + +# ########################################################## +# functions + +function join_by { local IFS="$1"; shift; echo "$*"; } + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + if [ $IgnoreRemainingFlagsAndOptions -ne 0 ]; then + + Targets+=($1) + + shift + + continue + else + + if [ ! ${1:0:1} = '-' ]; then + + Targets+=($1) + + shift + + continue + fi + fi + + case $1 in + --) + + IgnoreRemainingFlagsAndOptions=1 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Executes CMake-generated artefacts to (re)build project + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: ${SisClr_Red}${SisClr_Bold}unrecognised argument '$1'${SisClr_None}; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +if [ ! -d "$CMakeDir" ]; then + + >&2 echo "$ScriptPath: ${SisClr_Red}${SisClr_Bold}CMake build directory '$CMakeDir' not found${SisClr_None} so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" + + exit 1 +else + + cd $CMakeDir + + if [ ! -f "$CMakeDir/Makefile" ]; then + + >&2 echo "$ScriptPath: ${SisClr_Red}${SisClr_Bold}CMake build directory '$CMakeDir' does not contain expected file 'Makefile'${SisClr_None}, so a clean cannot be performed. It is recommended that you remove all CMake artefacts using script 'remove_cmake_artefacts.sh' followed by regeneration via 'prepare_cmake.sh'" + + cd ->/dev/null + + exit 1 + else + + if [ -z "$Targets" ]; then + + echo "Executing build of ${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None} (via command \`${SisClr_Blue}${SisClr_Bold}$MakeCmd${SisClr_None}\`)" + else + + echo "Executing build of ${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None} (via command \`${SisClr_Blue}${SisClr_Bold}$MakeCmd${SisClr_None}\`) with specific target(s) $(join_by , "${Targets[@]}")" + fi + + $MakeCmd ${Targets[*]} + status=$? + + cd ->/dev/null + + exit $status + fi +fi + + +# ############################## end of file ############################# # diff --git a/clean_cmake.sh b/clean_cmake.sh new file mode 100755 index 0000000..96b6c07 --- /dev/null +++ b/clean_cmake.sh @@ -0,0 +1,112 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd "$(dirname "$ScriptPath")" && pwd) +Basename=$(basename "$ScriptPath") + +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +if [[ -n "$MSYSTEM" ]]; then + + DefaultMakeCmd=mingw32-make.exe + MinGW=1 +else + + DefaultMakeCmd=make +fi +MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") + + +# ########################################################## +# colours + +if command -v tput > /dev/null; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_None=${FD_NONE:-$(tput sgr0)} +else + + SisClr_Blue= + SisClr_Red= + SisClr_Bold= + SisClr_None= +fi + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Executes CMake-generated artefacts to clean project + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: ${SisClr_Red}${SisClr_Bold}unrecognised argument '$1'${SisClr_None}; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +if [ ! -d "$CMakeDir" ]; then + + >&2 echo "$ScriptPath: ${SisClr_Red}${SisClr_Bold}CMake build directory '$CMakeDir' not found${SisClr_None} so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" + + exit 1 +else + + cd $CMakeDir + + if [ ! -f "$CMakeDir/Makefile" ]; then + + >&2 echo "$ScriptPath: ${SisClr_Red}${SisClr_Bold}CMake build directory '$CMakeDir' does not contain expected file 'Makefile'${SisClr_None}, so a clean cannot be performed. It is recommended that you remove all CMake artefacts using script 'remove_cmake_artefacts.sh' followed by regeneration via 'prepare_cmake.sh'" + + cd ->/dev/null + + exit 1 + else + + echo "Cleaning ${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None} (via command \`${SisClr_Blue}${SisClr_Bold}$MakeCmd clean${SisClr_None}\`)" + + $MakeCmd clean + status=$? + + cd ->/dev/null + + exit $status + fi +fi + + +# ############################## end of file ############################# # diff --git a/main.c b/main.c new file mode 100644 index 0000000..4b782de --- /dev/null +++ b/main.c @@ -0,0 +1,8 @@ +#define READDEBUGSTRING_VER_MAJOR 0 +#define READDEBUGSTRING_VER_MINOR 0 +#define READDEBUGSTRING_VER_PATCH 1 + +int main(void) +{ + return 0; +} diff --git a/prepare_cmake.sh b/prepare_cmake.sh new file mode 100755 index 0000000..417cb1b --- /dev/null +++ b/prepare_cmake.sh @@ -0,0 +1,228 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd "$(dirname "$ScriptPath")" && pwd) +Basename=$(basename "$ScriptPath") + +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +if [[ -n "$MSYSTEM" ]]; then + + DefaultMakeCmd=mingw32-make.exe + MinGW=1 +else + + DefaultMakeCmd=make +fi +MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") + +Configuration=Release +CStandard= +MSVC_MT=0 +MinGW="${MinGW:=0}" +RunMake=0 +STLSoftDirGiven= +TestingDisabled=0 +VerboseMakefile=0 + + +# ########################################################## +# colours + +if command -v tput > /dev/null; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_None=${FD_NONE:-$(tput sgr0)} +else + + SisClr_Blue= + SisClr_Red= + SisClr_Bold= + SisClr_None= +fi + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --c-standard) + + shift + CStandard=$1 + case $CStandard in + 99|11|17|23) + ;; + *) + + >&2 echo "$ScriptPath: ${SisClr_Red}${SisClr_Bold}invalid C standard '$CStandard'${SisClr_None}; expected 99, 11, 17, or 23" + + exit 1 + ;; + esac + ;; + --cmake-verbose-makefile|-v) + + VerboseMakefile=1 + ;; + --debug-configuration|-d) + + Configuration=Debug + ;; + --disable-testing|-T) + + TestingDisabled=1 + ;; + --mingw) + + MinGW=1 + ;; + --msvc-mt) + + MSVC_MT=1 + ;; + --run-make|-m) + + RunMake=1 + ;; + --stlsoft-root-dir|-s) + + shift + STLSoftDirGiven=$1 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Creates/reinitialises the CMake build script(s) + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + --c-standard {99|11|17|23} + sets CMAKE_C_STANDARD (default is 11) + + -v + --cmake-verbose-makefile + configures CMake to run verbosely (by setting CMAKE_VERBOSE_MAKEFILE + to be ON) + + -d + --debug-configuration + use Debug configuration (by setting CMAKE_BUILD_TYPE=Debug). Default + is to use Release + + -T + --disable-testing + disables building of tests (by setting BUILD_TESTING=OFF) + + --mingw + uses explicitly the "MinGW Makefiles" generator, and defaults the + make-command to "mingw32-make.exe" + + --msvc-mt + when using Visual C++ (MSVC), the static runtime library will be + selected; the default is the dynamic runtime library + + -m + --run-make + executes make after a successful running of CMake + + -s + --stlsoft-root-dir + specifies the STLSoft root-directory, which will be passed to CMake + as the variable STLSOFT, and which will override the environment + variable STLSOFT (if present) + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: ${SisClr_Red}${SisClr_Bold}unrecognised argument '$1'${SisClr_None}; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +mkdir -p $CMakeDir || exit 1 + +cd $CMakeDir + +echo "Executing CMake for ${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None} (in ${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None})" + +if [ -z "$CStandard" ]; then CMakeCStandardVariable="" ; else CMakeCStandardVariable="-DCMAKE_C_STANDARD=$CStandard" ; fi +if [ $MSVC_MT -eq 0 ]; then CMakeMsvcMtFlag="OFF" ; else CMakeMsvcMtFlag="ON" ; fi +if [ -z "$STLSoftDirGiven" ]; then CMakeSTLSoftVariable="" ; else CMakeSTLSoftVariable="-DSTLSOFT=$STLSoftDirGiven/" ; fi +if [ $TestingDisabled -eq 0 ]; then CMakeBuildTestingFlag="ON" ; else CMakeBuildTestingFlag="OFF" ; fi +if [ $VerboseMakefile -eq 0 ]; then CMakeVerboseMakefileFlag="OFF" ; else CMakeVerboseMakefileFlag="ON" ; fi + +if [ $MinGW -ne 0 ]; then + + cmake \ + $CMakeCStandardVariable \ + $CMakeSTLSoftVariable \ + -DBUILD_TESTING:BOOL=$CMakeBuildTestingFlag \ + -DCMAKE_BUILD_TYPE=$Configuration \ + -G "MinGW Makefiles" \ + -S $Dir \ + -B $CMakeDir \ + || (cd ->/dev/null ; exit 1) +else + + cmake \ + $CMakeCStandardVariable \ + $CMakeSTLSoftVariable \ + -DBUILD_TESTING:BOOL=$CMakeBuildTestingFlag \ + -DCMAKE_BUILD_TYPE=$Configuration \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=$CMakeVerboseMakefileFlag \ + -DMSVC_USE_MT:BOOL=$CMakeMsvcMtFlag \ + -S $Dir \ + -B $CMakeDir \ + || (cd ->/dev/null ; exit 1) +fi + +status=0 + +if [ $RunMake -ne 0 ]; then + + echo "Executing build (via command \`${SisClr_Blue}${SisClr_Bold}$MakeCmd${SisClr_None}\`)" + + $MakeCmd + status=$? +fi + +cd ->/dev/null + +if [ $VerboseMakefile -ne 0 ]; then + + echo -e "contents of $CMakeDir:" + ls -al $CMakeDir +fi + +exit $status + + +# ############################## end of file ############################# # diff --git a/remove_cmake_artefacts.sh b/remove_cmake_artefacts.sh new file mode 100755 index 0000000..992153f --- /dev/null +++ b/remove_cmake_artefacts.sh @@ -0,0 +1,171 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd "$(dirname "$ScriptPath")" && pwd) +Basename=$(basename "$ScriptPath") + +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") + +Directories=( + CMakeFiles + Testing + cmake + examples + projects + src + test +) +Files=( + CMakeCache.txt + CTestTestfile.cmake + DartConfiguration.tcl + Makefile + cmake_install.cmake + install_manifest.txt +) + + +# ########################################################## +# colours + +if command -v tput > /dev/null; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_None=${FD_NONE:-$(tput sgr0)} +else + + SisClr_Blue= + SisClr_Red= + SisClr_Bold= + SisClr_None= +fi + + +# ########################################################## +# operating environment detection + +OsName="$(uname -s)" +case "${OsName}" in + CYGWIN*|MINGW*|MSYS_NT*) + + Directories+=( + ARM64 + Win32 + x64 + ) + Files+=( + "*.filters" + "*.sln" + "*.vcxproj" + ) + ;; + *) + + ;; +esac + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Removes all known CMake artefacts + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: ${SisClr_Red}${SisClr_Bold}unrecognised argument '$1'${SisClr_None}; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +if [ ! -d "$CMakeDir" ]; then + + echo "$ScriptPath: CMake build directory '$CMakeDir' ${SisClr_Red}${SisClr_Bold}not found${SisClr_None} so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" + + exit 0 +else + + echo "Removing all ${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None} cmake artefacts in '${SisClr_Blue}${SisClr_Bold}$CMakeDir${SisClr_None}'" + + num_dirs_removed=0 + num_files_removed=0 + + for d in ${Directories[@]} + do + + fq_dir_path="$CMakeDir/$d" + + [ -d "$fq_dir_path" ] || continue + + echo "removing directory '$d'" + + rm -dfr "$fq_dir_path" + + num_dirs_removed=$((num_dirs_removed+1)) + done + + cd "$CMakeDir" + + for f in ${Files[@]} + do + + for fq_file_path in $f + do + + [ -f "$fq_file_path" ] || continue + + echo "removing file '$fq_file_path'" + + rm -f "$fq_file_path" + + num_files_removed=$((num_files_removed+1)) + done + done + + cd ->/dev/null + + if [ 0 -eq $num_dirs_removed ] && [ 0 -eq $num_files_removed ]; then + + echo "nothing to do" + else + + echo "removed $num_dirs_removed directories and $num_files_removed files" + fi +fi + + +# ############################## end of file ############################# # diff --git a/run_all_unit_tests.cmd b/run_all_unit_tests.cmd new file mode 100644 index 0000000..8c11cf4 --- /dev/null +++ b/run_all_unit_tests.cmd @@ -0,0 +1,141 @@ +@echo off + +SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION + +SET SCRIPT_DIRECTORY=%~dp0 +SET SCRIPT_PATH_DOC=%~n0[%~x0] +IF DEFINED SIS_CMAKE_BUILD_DIR ( + + SET "CMAKE_DIR=%SIS_CMAKE_BUILD_DIR%" +) ELSE ( + + SET "CMAKE_DIR=%SCRIPT_DIRECTORY%_build" +) + +SET ListOnly=0 +SET Verbose=0 +SET status=0 + +FOR %%a IN (%*) DO ( + IF /I {--help}=={%%a} ( + IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( + + type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" + ) + ECHO ^ + +Runs all ^(matching^) component and unit test programs ^ + +^ + +%SCRIPT_PATH_DOC% [ ... flags/options ... ] ^ + +^ + +Flags/options: ^ + + behaviour: ^ + +^ + + -l ^ + + --list-only ^ + + lists the target programs but does not execute them ^ + +^ + + -M ^ + + --no-make ^ + + accepted for parity with the .sh script ^(build is not invoked^) ^ + +^ + + -v ^ + + --verbose ^ + + lists each test program before executing it ^ + +^ + + standard flags: ^ + +^ + + --help ^ + + displays this help and terminates ^ + + + EXIT /B 0 + ) ELSE IF /I {-l}=={%%a} ( + SET ListOnly=1 + ) ELSE IF /I {--list-only}=={%%a} ( + SET ListOnly=1 + ) ELSE IF /I {-M}=={%%a} ( + REM no-op: this .cmd never invokes the build + ) ELSE IF /I {--no-make}=={%%a} ( + REM no-op: this .cmd never invokes the build + ) ELSE IF /I {-v}=={%%a} ( + SET Verbose=1 + ) ELSE IF /I {--verbose}=={%%a} ( + SET Verbose=1 + ) ELSE ( + ECHO %SCRIPT_PATH_DOC%: unrecognised argument '%%a'; use --help for usage 1>&2 + + EXIT /B 1 + ) +) + +IF NOT EXIST "%CMAKE_DIR%" ( + + ECHO %SCRIPT_PATH_DOC%: CMake build directory '%CMAKE_DIR%' does not exist 1>&2 + + EXIT /B 1 +) + +SET "ProjectName=" +FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO SET "ProjectName=%%p" + +IF NOT DEFINED ProjectName ( + + ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 + + EXIT /B 1 +) + +IF !ListOnly! EQU 1 ( + + ECHO Listing all component and unit test programs +) ELSE ( + + ECHO Running all component and unit test programs +) + +FOR /F "usebackq delims=" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%\*.exe" 2^>NUL ^| FINDSTR /I /R "!ProjectName!.*test.*\.exe$"`) DO ( + IF !ListOnly! EQU 1 ( + + ECHO would execute %%f: + ) ELSE ( + + IF !Verbose! EQU 1 ( + + ECHO executing %%f: + ) + + "%%f" + IF ERRORLEVEL 1 ( + + SET status=1 + + GOTO :done + ) + ) +) + +:done +EXIT /B !status! diff --git a/run_all_unit_tests.sh b/run_all_unit_tests.sh new file mode 100755 index 0000000..b05b671 --- /dev/null +++ b/run_all_unit_tests.sh @@ -0,0 +1,175 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd "$(dirname "$ScriptPath")" && pwd) +Basename=$(basename "$ScriptPath") + +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +if [[ -n "$MSYSTEM" ]]; then + + DefaultMakeCmd=mingw32-make.exe + MinGW=1 +else + + DefaultMakeCmd=make +fi +MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") + +ListOnly=0 +RunMake=1 +Verbose=0 + + +# ########################################################## +# colours + +if command -v tput > /dev/null; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_None=${FD_NONE:-$(tput sgr0)} +else + + SisClr_Blue= + SisClr_Red= + SisClr_Bold= + SisClr_None= +fi + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --list-only|-l) + + ListOnly=1 + ;; + --no-make|-M) + + RunMake=0 + ;; + --verbose|-v) + + Verbose=1 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Runs all (matching) component and unit test programs + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + -l + --list-only + lists the target programs but does not execute them + + -M + --no-make + does not execute CMake and make before running tests + + -v + --verbose + lists each test program before executing it + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: ${SisClr_Red}${SisClr_Bold}unrecognised argument '$1'${SisClr_None}; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +status=0 + +if [ $RunMake -ne 0 ]; then + + if [ $ListOnly -eq 0 ]; then + + echo "Executing build (via command \`${SisClr_Blue}${SisClr_Bold}$MakeCmd${SisClr_None}\`) and then running all component and unit test programs" + + mkdir -p $CMakeDir || exit 1 + + cd $CMakeDir + + $MakeCmd + status=$? + + cd ->/dev/null + fi +else + + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ] || [ ! -d "$CMakeDir/CMakeFiles" ]; then + + >&2 echo "$ScriptPath: ${SisClr_Red}${SisClr_Bold}cannot run in '--no-make' mode without a previous successful build step${SisClr_None}" + fi +fi + +if [ $status -eq 0 ]; then + + if [ $ListOnly -ne 0 ]; then + + echo "Listing all component and unit test programs" + else + + echo "Running all component and unit test programs" + fi + + for f in $(find $CMakeDir -type f '(' -name "*${ProjectName}*test*" ')' -exec test -x {} \; -print) + do + + if [ $ListOnly -ne 0 ]; then + + echo "would execute ${SisClr_Blue}${SisClr_Bold}$f${SisClr_None}:" + + continue + fi + + if [ $Verbose -ne 0 ]; then + + echo "executing ${SisClr_Blue}${SisClr_Bold}$f${SisClr_None}:" + fi + + if $f; then + + : + else + + status=$? + + break 1 + fi + done +fi + +exit $status + + +# ############################## end of file ############################# # From bc6bc4129c7b9e32cc0f43122e6707c6b72f9fbc Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Sun, 23 Aug 2026 11:13:21 +1000 Subject: [PATCH 2/8] boilerplate --- .sis/script_info_lines.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.sis/script_info_lines.txt b/.sis/script_info_lines.txt index 8129a6d..79719eb 100644 --- a/.sis/script_info_lines.txt +++ b/.sis/script_info_lines.txt @@ -1,2 +1,2 @@ ReadDebugString is a Windows CLI that reads messages from the Windows debugger -Copyright (c) 2026, Matthew Wilson and Synesis Information Systems +Copyright (c) 2025-2026, Matthew Wilson and Synesis Information Systems From 19fd63533f01f45732ecbe70dea6f570f9bb2526 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Sun, 23 Aug 2026 11:16:01 +1000 Subject: [PATCH 3/8] .gitignore --- .gitignore | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..35a19d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,152 @@ + +# directories (by name) + +/.svn/ +/.vs/ + +/_build/ +/_internal/ + +/bin/ +/doc/ +/include/ +/lib/ +/node_modules/ + +/include/b64/ +/include/shwild/ +/include/xcontract/ +/include/xcover/ +/include/xtests/ + +/src/b64/ +/src/shwild/ +/src/xcontract/ +/src/xcover/ +/src/xtests/ + +Debug Multithreaded DLL/ +Debug Multithreaded Dll/ +Debug Multithreaded pseudoUNIX/ +Debug Multithreaded pseudoUnix/ +Debug Multithreaded/ +Debug/ +DebugDLLUNIX/ +DebugDll/ +DebugMTDLL/ +DebugMt/ +DebugNox/ +DebugUNIX/ +DebugUnix/ +Release Multithreaded DLL/ +Release Multithreaded Dll/ +Release Multithreaded pseudoUNIX/ +Release Multithreaded pseudoUnix/ +Release Multithreaded/ +Release/ +ReleaseDLLUNIX/ +ReleaseDll/ +ReleaseMTDLL/ +ReleaseMt/ +ReleaseNox/ +ReleaseUnix/ +UDebug/ +UDebugMt/ +URelease/ +UReleaseMt/ +Unicode Debug Multithreaded DLL/ +Unicode Debug Multithreaded Dll/ +Unicode Debug Multithreaded/ +Unicode Debug/ +Unicode Release Multithreaded DLL/ +Unicode Release Multithreaded Dll/ +Unicode Release Multithreaded/ +Unicode Release/ + +Win32/ +ipch/ +x64/ + + +# directories (by pattern) + + +# files (by name) + +.DS_Store +.ruby-version +.svnignore +.svnignore-at-root +.update_deps + +list_changes.cmd +logging-bailout.txt +prepare.cmd +sh.exe.stackdump +update_deps.cmd + +build/makefile.tmpl +build/makefile.tools.xml + +ReadDebugString +ReadDebugString_test + + +# files (by pattern) + +RCa0* +RCb0* + +*~ +*.???_obj +*.a +*.app +*.aps +*.b64 +*.bak +*.chm +*.class +*.csproj*user +*.d +*.dll +*.dylib +*.exe +*.gch +*.gem +*.idb +*.ilk +*.iobj +*.ipch +*.ipdb +*.la +*.lai +*.lib +*.lo +*.log +*.ncb +*.o +*.obj +*.opensdf +*.opt +*.org +*.out +*.pch +*.pdb +*.pyc +*.rar +*.res +*.sbr +*.scc +*.sdf +*.slo +*.so +*.suo +*.swp +*.tlog +*.tmp +*.unsuccessfulbuild +*.vcproj*user +*.vcxproj*user +*.xcuserstate +*.zip + From f5a92efcede4b8729debb9375b05982bcc181718 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Mon, 24 Aug 2026 06:48:28 +1000 Subject: [PATCH 4/8] chore: fixed colour terminal check --- build_cmake.sh | 2 +- clean_cmake.sh | 2 +- prepare_cmake.sh | 2 +- remove_cmake_artefacts.sh | 2 +- run_all_unit_tests.sh | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build_cmake.sh b/build_cmake.sh index 3f261e7..08eccf0 100755 --- a/build_cmake.sh +++ b/build_cmake.sh @@ -24,7 +24,7 @@ Targets=() # ########################################################## # colours -if command -v tput > /dev/null; then +if [ -n "${TERM:-}" ] && [ -t 1 ] && command -v tput >/dev/null 2>&1; then SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} SisClr_Red=${FG_RED:-$(tput setaf 1)} diff --git a/clean_cmake.sh b/clean_cmake.sh index 96b6c07..b90f682 100755 --- a/clean_cmake.sh +++ b/clean_cmake.sh @@ -21,7 +21,7 @@ ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") # ########################################################## # colours -if command -v tput > /dev/null; then +if [ -n "${TERM:-}" ] && [ -t 1 ] && command -v tput >/dev/null 2>&1; then SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} SisClr_Red=${FG_RED:-$(tput setaf 1)} diff --git a/prepare_cmake.sh b/prepare_cmake.sh index 417cb1b..91ae7e0 100755 --- a/prepare_cmake.sh +++ b/prepare_cmake.sh @@ -30,7 +30,7 @@ VerboseMakefile=0 # ########################################################## # colours -if command -v tput > /dev/null; then +if [ -n "${TERM:-}" ] && [ -t 1 ] && command -v tput >/dev/null 2>&1; then SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} SisClr_Red=${FG_RED:-$(tput setaf 1)} diff --git a/remove_cmake_artefacts.sh b/remove_cmake_artefacts.sh index 992153f..5b4478e 100755 --- a/remove_cmake_artefacts.sh +++ b/remove_cmake_artefacts.sh @@ -30,7 +30,7 @@ Files=( # ########################################################## # colours -if command -v tput > /dev/null; then +if [ -n "${TERM:-}" ] && [ -t 1 ] && command -v tput >/dev/null 2>&1; then SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} SisClr_Red=${FG_RED:-$(tput setaf 1)} diff --git a/run_all_unit_tests.sh b/run_all_unit_tests.sh index b05b671..936d980 100755 --- a/run_all_unit_tests.sh +++ b/run_all_unit_tests.sh @@ -25,7 +25,7 @@ Verbose=0 # ########################################################## # colours -if command -v tput > /dev/null; then +if [ -n "${TERM:-}" ] && [ -t 1 ] && command -v tput >/dev/null 2>&1; then SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} SisClr_Red=${FG_RED:-$(tput setaf 1)} From 86b3f4a5a8af91c2850bcf419ab7a1ea09f7755c Mon Sep 17 00:00:00 2001 From: synesissoftware Date: Mon, 24 Aug 2026 16:12:42 +1000 Subject: [PATCH 5/8] Helper scripts fixes (#4) * initial version * v0 * squash-commit * CMake * fix * squash-commit * CMake fixes (#5) * typos * Support uninstalled STLSoft source directories Resolve STLSoft before dependent packages and provide the STLSoft::STLSoft target when using a local source directory. * fix * fix * fix * fix * ci * 0.0.1 * fix * fix --- .github/workflows/ci-cell.yml | 10 +- AUTHORS.md | 17 +++ CHANGES.md | 19 +++ CMakeLists.txt | 257 ++++++++++++++++++++++++++++++--- INSTALL.md | 41 ++++++ Makefile | 29 ++++ NEWS.md | 10 ++ README.md | 6 +- REQUISITES.md | 26 ++++ TODO.md | 0 build_cmake.sh | 1 - clean_cmake.sh | 1 - cmake/BuildType.cmake | 59 ++++++++ main.c | 8 - main.cpp | 265 ++++++++++++++++++++++++++++++++++ prepare_cmake.sh | 15 +- run_all_unit_tests.sh | 1 - 17 files changed, 726 insertions(+), 39 deletions(-) create mode 100644 AUTHORS.md create mode 100644 CHANGES.md create mode 100644 INSTALL.md create mode 100644 Makefile create mode 100644 NEWS.md create mode 100644 REQUISITES.md create mode 100644 TODO.md create mode 100644 cmake/BuildType.cmake delete mode 100644 main.c create mode 100644 main.cpp diff --git a/.github/workflows/ci-cell.yml b/.github/workflows/ci-cell.yml index 2cf3270..e8c9e48 100644 --- a/.github/workflows/ci-cell.yml +++ b/.github/workflows/ci-cell.yml @@ -39,6 +39,12 @@ jobs: mingw-w64-x86_64-cmake mingw-w64-x86_64-make + - name: Checkout STLSoft + shell: bash + run: | + set -euo pipefail + git clone --depth 1 https://github.com/synesissoftware/STLSoft "$RUNNER_TEMP/stlsoft" + - name: Configure shell: bash run: | @@ -49,9 +55,11 @@ jobs: -DCMAKE_BUILD_TYPE="${{ inputs.build-type }}" \ -DCMAKE_C_COMPILER=gcc \ -DCMAKE_CXX_COMPILER=g++ \ + -DSTLSOFT="$RUNNER_TEMP/stlsoft" \ -DBUILD_TESTING=OFF else cmake -B build -S . \ + -DSTLSOFT="$RUNNER_TEMP/stlsoft" \ -DBUILD_TESTING=OFF fi @@ -86,4 +94,4 @@ jobs: set -euo pipefail PREFIX="${RUNNER_TEMP}/install-prefix" PROJECT="$(tr -d '[:space:]' < .sis/project_name.txt)" - "$PREFIX/bin/${PROJECT}.exe" + "$PREFIX/bin/${PROJECT}.exe" --version diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 0000000..b5b0893 --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,17 @@ +# ReadDebugString - Authors + + +## Major Contributors + +* Matthew Wilson ([mwsis](https://github.com/mwsis)); + + +## Defect reports, fixes and suggestions (for which we are very grateful) + +* \ (yet); + + +Contributions are welcomed. + + + diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..adf5fe4 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,19 @@ +# ReadDebugString - Changes + + +## 0.0.1 - 23rd August 2026 + +* Improved CMake flexibility for uninstalled **STLSoft** source trees supplied via **STLSOFT**; +* Added validation and an imported **STLSoft::STLSoft** target for local STLSoft source trees; +* Added Windows **cl** and MinGW CI configuration with STLSoft source checkout; +* Added an installation smoke test using **--version** so the long-running reader is not started; + + +## 0.0.0 - 16th August 2026 + +* Added the initial Windows-only **ReadDebugString** executable scaffold; +* Added **--help** and **--version** command-line handling; +* Added CMake configuration, helper scripts, and editor settings; + + + diff --git a/CMakeLists.txt b/CMakeLists.txt index 796fb29..e35b7ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,36 +1,259 @@ +# ######################################################################## # +# File: /CMakeLists.txt +# +# Purpose: Top-level CMake lists file for ReadDebugString +# +# Created: 15th August 2025 +# Updated: 18th August 2026 +# +# ######################################################################## # + + +# ########################################################## +# CMake + cmake_minimum_required(VERSION 3.20 FATAL_ERROR) +# require out-of-source builds +file(TO_CMAKE_PATH "${CMAKE_CURRENT_BINARY_DIR}/CMakeLists.txt" LOC_PATH) +if(EXISTS "${LOC_PATH}") + + message(FATAL_ERROR "You cannot build in a source directory (or any directory with a CMakeLists.txt file). Please make a build subdirectory. Feel free to remove CMakeCache.txt and CMakeFiles.") +endif() + +# directory for CMake specific extensions and source files. +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) + + +# ########################################################## +# project + project(ReadDebugString - VERSION 0.0.1 - DESCRIPTION "ReadDebugString is a Windows CLI that reads messages from the Windows debugger." - HOMEPAGE_URL "https://github.com/sistools/ReadDebugString" - LANGUAGES C + DESCRIPTION "ReadDebugString is a Windows CLI that reads messages from the Windows debugger." + HOMEPAGE_URL "https://github.com/sistools/ReadDebugString" + LANGUAGES C CXX ) -if(NOT WIN32) - message(FATAL_ERROR "${PROJECT_NAME} targets Windows only") -endif() +string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER) +string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPER) +# handle version number +set(RX_PROJ_TAG "${PROJECT_NAME_UPPER}") +set(RX_WS "[ \t]") +file(READ "${CMAKE_SOURCE_DIR}/main.cpp" _impl_file) +string(REGEX MATCH "#${RX_WS}*define${RX_WS}+_?${RX_PROJ_TAG}_VER_MAJOR${RX_WS}+([0-9]+)" MAJOR_DUMMY ${_impl_file}) +set(_VERSION_MAJOR ${CMAKE_MATCH_1}) +string(REGEX MATCH "#${RX_WS}*define${RX_WS}+_?${RX_PROJ_TAG}_VER_MINOR${RX_WS}+([0-9]+)" MINOR_DUMMY ${_impl_file}) +set(_VERSION_MINOR ${CMAKE_MATCH_1}) +string(REGEX MATCH "#${RX_WS}*define${RX_WS}+_?${RX_PROJ_TAG}_VER_PATCH${RX_WS}+([0-9]+)" PATCH_DUMMY ${_impl_file}) +set(_VERSION_PATCH ${CMAKE_MATCH_1}) + +# set project version number here +set(PROJECT_VERSION_MAJOR ${_VERSION_MAJOR}) +set(PROJECT_VERSION_MINOR ${_VERSION_MINOR}) +set(PROJECT_VERSION_PATCH ${_VERSION_PATCH}) +set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") + +# adhere strictly to C and C++ standards plus extensions. These are actually +# useless since we do not compile anything; they merely state our intention. set(CMAKE_C_STANDARD 17) set(CMAKE_C_STANDARD_REQUIRED ON) -set(CMAKE_C_EXTENSIONS ON) +set(CMAKE_C_EXTENSIONS ON) # GNU extensions and POSIX standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS ON) + +if(MSVC) + + if(MSVC_VERSION GREATER_EQUAL 1914) + + add_compile_options("/Zc:__cplusplus") + + add_definitions(-D_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING) + endif() + + if(MSVC_VERSION LESS 1930) + + set(CMAKE_C_STANDARD 90) + set(CMAKE_CXX_STANDARD 98) + endif() + + if(MSVC_USE_MT) + + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + endif(MSVC_USE_MT) +else(MSVC) + + if(MSVC_USE_MT) + + # this here just to absorb warning about not using `MSVC_USE_MT` (to + # enable **prepare_cmake.sh** to be simple) + endif(MSVC_USE_MT) +endif(MSVC) + + +# ########################################################## +# dependencies, includes, options + +# ################################################ +# includes - 1 + +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/BuildType.cmake") + + include(BuildType) +endif() +#[====[ +include(LanguageFullVersion) +include(TargetMacros) +#]====] + + +# ################################################ +# dependencies, features, and options + + +# ###################################### +# options + +option(BUILD_EXAMPLES "Build examples" ON) + +option(BUILD_TESTING "Build tests" ON) + + +# ###################################### +# features + +# This tool targets Windows only (WinSTL). +if(NOT WIN32) + + message(FATAL_ERROR "${PROJECT_NAME} targets Windows only") +endif() + +# ###################################### +# dependencies +# +# required: +# - STLSoft; +# +# required if testing enabled: +# - (none); +# +# optional: + + +# ############################ +# STLSoft +# +# NOTE: This is resolved before other dependencies because imported targets +# may reference STLSoft::STLSoft in their link interfaces. + +if(DEFINED STLSOFT) + + message("-- STLSOFT provided as CMake variable with value '${STLSOFT}'") + set(STLSOFT_INCLUDE_DIR "${STLSOFT}/include") +elseif(DEFINED ENV{STLSOFT}) + + message("-- STLSOFT provided as environment variable with value '$ENV{STLSOFT}'") + set(STLSOFT_INCLUDE_DIR "$ENV{STLSOFT}/include") +endif() + +if(DEFINED STLSOFT_INCLUDE_DIR) + + if(NOT IS_DIRECTORY "${STLSOFT_INCLUDE_DIR}") + + message(FATAL_ERROR "STLSoft include directory not found: ${STLSOFT_INCLUDE_DIR}") + endif() + + if(NOT TARGET STLSoft::STLSoft) + + add_library(STLSoft::STLSoft INTERFACE IMPORTED GLOBAL) + set_target_properties(STLSoft::STLSoft PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${STLSOFT_INCLUDE_DIR}" + ) + endif() +else() + + set(STLSoft_REQUIRED_VERSION_ 1.11.1) + + find_package(STLSoft ${STLSoft_REQUIRED_VERSION_} REQUIRED) + + message("-- CMake package STLSoft found (version ${STLSoft_VERSION}; ${STLSoft_REQUIRED_VERSION_} requested)") +endif() + +if(DEFINED STLSOFT_INCLUDE_DIR) + + include_directories("${STLSOFT_INCLUDE_DIR}") +endif() + + +# ################################################ +# includes - 2 + +include(CMakePackageConfigHelpers) +if(BUILD_TESTING) + + include(CTest) +endif(BUILD_TESTING) include(GNUInstallDirs) + +# ########################################################## +# tool + add_executable(${PROJECT_NAME} - main.c + main.cpp ) target_compile_options(${PROJECT_NAME} - PRIVATE - $<$: - -Werror -Wall -Wextra -pedantic - > - $<$: - /WX /W4 - > + PRIVATE + $<$,$,$>: + -Werror -Wall -Wextra -pedantic + > + $<$,$>: + -Wno-anonymous-structs + > + $<$: + /WX /W4 + + /wd4201 + > +) + +target_link_options(${PROJECT_NAME} + PRIVATE + $<$:-municode> +) + +target_link_libraries(${PROJECT_NAME} + $<$:STLSoft::STLSoft> ) install(TARGETS ${PROJECT_NAME} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) + + +# ################################################ +# examples + + +# ################################################ +# tests + +if(BUILD_TESTING) + + message("-- enabled building of tests ...") +else(BUILD_TESTING) + + message("-- disabled building of tests - define BUILD_TESTING to enable") +endif(BUILD_TESTING) + + +# ########################################################## +# completion + +message(NOTICE "Generating CMake build scripts for ${PROJECT_NAME} ${PROJECT_VERSION}, for C${CMAKE_C_STANDARD} C++${CMAKE_CXX_STANDARD}") + + +# ############################## end of file ############################# # diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..539479d --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,41 @@ +# ReadDebugString - Installation and Use + + +## Building + +The primary build method is **CMake**. From a Visual Studio developer +environment: + +```powershell +cmake -S . -B _build +cmake --build _build --config Release +``` + +If **STLSoft** is not installed as a CMake package, provide its source-tree +root: + +```powershell +cmake -S . -B _build -DSTLSOFT=C:\path\to\STLSoft +cmake --build _build --config Release +``` + +The resulting executable is installed with: + +```powershell +cmake --install _build --config Release +``` + + +## Command-line use + +The program is intended to remain running while it reads messages from the +Windows debugger. Use `--help` or `--version` for commands that terminate +immediately: + +```powershell +ReadDebugString.exe --help +ReadDebugString.exe --version +``` + + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..95c9118 --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ + +!ifndef STLSOFT +!error Environment variable STLSOFT is not defined +!endif # STLSOFT + +CC=cl.exe +LINK=link.exe + +CFLAGS=/EHsc /Zi /nologo /std:c++17 /Zc:__cplusplus /I "$(STLSOFT)/include" + +LDFLAGS=/NOLOGO + +SRCS=main.cpp + +OBJS=$(SRCS:.cpp=.obj) + +all: build + +build: ReadDebugString.exe + +ReadDebugString.exe: main.obj + $(LINK) $(LDFLAGS) /OUT:$@ $(OBJS) + +.cpp.obj: + $(CC) $(CFLAGS) /c $< + +clean: + @del /Q *.obj *.exe + diff --git a/NEWS.md b/NEWS.md new file mode 100644 index 0000000..23ab42d --- /dev/null +++ b/NEWS.md @@ -0,0 +1,10 @@ +# ReadDebugString - News + + +| Date | News Item | +| ------------------- | --------- | +| 23rd August 2026 | [0.0.1 released](https://github.com/sistools/ReadDebugString/releases/tag/0.0.1) | +| 16th August 2026 | [0.0.0 released](https://github.com/sistools/ReadDebugString/releases/tag/0.0.0) | + + + diff --git a/README.md b/README.md index ad74804..045c7e6 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,8 @@ cmake -S . -B _build cmake --build _build --config Release ``` +Detailed installation and usage instructions are in [INSTALL.md](./INSTALL.md). + ## Components @@ -50,8 +52,8 @@ The project creates a single executable program, **ReadDebugString**. ## Examples -The current scaffold does not yet expose command-line options or produce -debugger output. +The program supports `--help` and `--version`. Its debugger message-reading +behaviour is still being developed. ## Project Information diff --git a/REQUISITES.md b/REQUISITES.md new file mode 100644 index 0000000..bbabb58 --- /dev/null +++ b/REQUISITES.md @@ -0,0 +1,26 @@ +# ReadDebugString - Requisites + + +## Introduction + +Building **ReadDebugString** requires **CMake** 3.20 or later and a Windows +C++ toolchain supporting C++17. + + +## Required dependencies + +**ReadDebugString** depends on: + +* [**STLSoft**](https://github.com/synesissoftware/STLSoft) 1.11.1 or later; + +An installed **STLSoft** CMake package is used by default. An uninstalled +source tree may be supplied through the **STLSOFT** CMake variable, the +**STLSOFT** environment variable, or **prepare_cmake.sh --stlsoft-root-dir**. + + +## Operating system + +The program targets Microsoft Windows and uses the Windows debugger APIs. + + + diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..e69de29 diff --git a/build_cmake.sh b/build_cmake.sh index 08eccf0..6b96a40 100755 --- a/build_cmake.sh +++ b/build_cmake.sh @@ -8,7 +8,6 @@ CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} if [[ -n "$MSYSTEM" ]]; then DefaultMakeCmd=mingw32-make.exe - MinGW=1 else DefaultMakeCmd=make diff --git a/clean_cmake.sh b/clean_cmake.sh index b90f682..17d36a3 100755 --- a/clean_cmake.sh +++ b/clean_cmake.sh @@ -8,7 +8,6 @@ CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} if [[ -n "$MSYSTEM" ]]; then DefaultMakeCmd=mingw32-make.exe - MinGW=1 else DefaultMakeCmd=make diff --git a/cmake/BuildType.cmake b/cmake/BuildType.cmake new file mode 100644 index 0000000..a315b8d --- /dev/null +++ b/cmake/BuildType.cmake @@ -0,0 +1,59 @@ + +# ######################################################################## # +# File: /cmake/BuildType.cmake +# +# Purpose: CMake module file (for BuildType) +# +# Created: 16th October 2019 +# Updated: 25th October 2024 +# +# ######################################################################## # + + +# Including this module sets the `CMAKE_BUILD_TYPE` value as follows: +# +# 1. If user specifies on the command line, then `CMAKE_BUILD_TYPE` already +# has a valid, so this is accepted; +# 2. If the top-level .git directory is specified, then "Debug" is used; +# otherwise +# 3. "Release" is used. +# +# Note: +# - `CMAKE_BUILD_TYPE` is the build (configuration) type; +# - `CMAKE_CONFIGURATION_TYPES` is, if specified, a list of valid +# configurations (see +# https://cmake.org/cmake/help/latest/variable/CMAKE_CONFIGURATION_TYPES.html); +# +# Example usage: +# +#[========[ + +# CMakeLists.txt + +include(BuildType) + +]========] + + +if(EXISTS "${CMAKE_SOURCE_DIR}/.git") + set(DEFAULT_BUILD_TYPE "Debug") +else() + set(DEFAULT_BUILD_TYPE "Release") +endif() + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + + message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.") + + set(CACHE CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" + STRING "Choose the type of build." FORCE + ) + + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo" + ) +endif() + +# ############################## end of file ############################# # + diff --git a/main.c b/main.c deleted file mode 100644 index 4b782de..0000000 --- a/main.c +++ /dev/null @@ -1,8 +0,0 @@ -#define READDEBUGSTRING_VER_MAJOR 0 -#define READDEBUGSTRING_VER_MINOR 0 -#define READDEBUGSTRING_VER_PATCH 1 - -int main(void) -{ - return 0; -} diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..17e2567 --- /dev/null +++ b/main.cpp @@ -0,0 +1,265 @@ + +#define _UNICODE +#define UNICODE + +#include + +#if _STLSOFT_VER < 0x010b01c3 +# error requires STLSoft v1.11.1-rc3 or later +#endif +#if __cplusplus < 201702L +# error requires C++17 or later +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + +#define PROGRAM_VER_MAJOR 0 +#define PROGRAM_VER_MINOR 0 +#define PROGRAM_VER_PATCH 1 + + +union Payload +{ +#if defined(__GNUC__) && !defined(__clang__) + __extension__ +#endif + struct + { + DWORD pid; + CHAR content[1]; + }; + UCHAR bytes[4096]; +}; + +// [[noreturn]] +__declspec(noreturn) +void throw_( + DWORD le +, char const* msg +) +{ + using namespace winstl; + + if (ERROR_ACCESS_DENIED == le) + { + STLSOFT_THROW_X(access_exception(msg, le)); + } + else + { + STLSOFT_THROW_X(winstl_exception(msg, le)); + } +} + + +std::string GetProcessNameFromPid(DWORD pid) { + HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); + if (hProcess == NULL) { + return "Error: Could not open process"; + } + + char buffer[MAX_PATH]; + if (GetProcessImageFileNameA(hProcess, buffer, MAX_PATH) == 0) { + CloseHandle(hProcess); + return "Error: Could not get image file name"; + } + + CloseHandle(hProcess); + + std::string fullPath(buffer); + size_t lastSlash = fullPath.find_last_of("\\"); + std::string processName = (lastSlash == std::string::npos) ? fullPath : fullPath.substr(lastSlash + 1); + + return processName; +} + +// [[noreturn]] +__declspec(noreturn) +void run() +{ + winstl::event ev_buffer_ready(L"DBWIN_BUFFER_READY", false, false); + winstl::event ev_data_ready(L"DBWIN_DATA_READY", false, false); + + HANDLE const hFileMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Payload), "DBWIN_BUFFER"); + + if (NULL == hFileMap) + { + DWORD const le = ::GetLastError(); + + throw_(le, "failed to create file-mapping"); + } + + stlsoft::scoped_handle scoper_fm(hFileMap, ::CloseHandle); + + Payload* const payload = (Payload*)::MapViewOfFile(hFileMap, SECTION_MAP_READ, 0, 0, 0); + + if (NULL == payload) + { + DWORD const le = ::GetLastError(); + + throw_(le, "failed to map view"); + } + + HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE); + + for (;;) + { + ev_buffer_ready.set(); + + DWORD const wait = ::WaitForSingleObject(ev_data_ready.handle(), INFINITE); + + if (WAIT_OBJECT_0 != wait) + { + DWORD const le = ::GetLastError(); + + throw_(le, "failed to wait for buffer-ready"); + } + size_t len = strlen(payload->content); + + for ( ; 0 != len; --len) + { + if ('\r' != payload->content[len - 1] && + '\n' != payload->content[len - 1]) + { + break; + } + } + + if (len != 0) + { + using stlsoft::stlsoft_C_snprintf; + + char msg[4096]; + int r = stlsoft_C_snprintf(msg, "%lu - %s: %.*s", payload->pid, GetProcessNameFromPid(payload->pid).c_str(), (int)len, payload->content); + DWORD numWritten; + + if (r < 5) + { + ::WriteFile(hStderr, "could not prepare output line\r\n", 31, &numWritten, NULL); + } + else + { + if (r > int(STLSOFT_NUM_ELEMENTS(msg) - 3)) + { + msg[STLSOFT_NUM_ELEMENTS(msg) - 3] = '\r'; + msg[STLSOFT_NUM_ELEMENTS(msg) - 2] = '\n'; + msg[STLSOFT_NUM_ELEMENTS(msg) - 1] = '\0'; + } + else + { + msg[r++] = '\r'; + msg[r++] = '\n'; + msg[r] = '\0'; + } + + ::WriteFile(hStderr, msg, (DWORD)r, &numWritten, NULL); + } + } + } +} + + +int wmain(int argc, wchar_t* argv[]) +{ + stlsoft::string_slice_w_t const program_name = platformstl::get_executable_name_from_path(argv[0]); + + try + { + switch (argc) + { + case 2: + + if (0 == std::wcscmp(L"--help", argv[1])) + { + std::wcout + << L"USAGE: " + << program_name + << L" [ { --help | --version } ]" + << std::endl; + + return EXIT_SUCCESS; + } + else + if (0 == std::wcscmp(L"--version", argv[1])) + { + std::wcout + << program_name + << L" v" + << PROGRAM_VER_MAJOR + << L'.' + << PROGRAM_VER_MINOR + << L'.' + << PROGRAM_VER_PATCH + << std::endl; + + return EXIT_SUCCESS; + } + else + { + std::wcerr + << program_name + << L": unrecognised argument '" + << argv[1] + << L"'; use --help for usage" + << std::endl; + + return EXIT_FAILURE; + } + break; + case 1: + + run(); + +#ifndef NDEBUG + + fwprintf( + stderr + , L"%.*s: %s:%d: UNEXPECTED\n" + , int(program_name.len), program_name.ptr + , STLSOFT_STRINGIZE_w(__FILE__), __LINE__ + ); + + ::DebugBreak(); + + return EXIT_FAILURE; +#endif + default: + + std::wcerr + << program_name + << L": too many arguments; use --help for usage" + << std::endl; + + return EXIT_FAILURE; + } + } + catch (std::bad_alloc&) + { + fputws(L"out of memory\n", stderr); + } + catch (std::exception& x) + { + fwprintf( + stderr + , L"%.*s: process failed: %S\n" + , int(program_name.len), program_name.ptr + , x.what() + ); + } + + return EXIT_SUCCESS; +} + diff --git a/prepare_cmake.sh b/prepare_cmake.sh index 91ae7e0..b98a74d 100755 --- a/prepare_cmake.sh +++ b/prepare_cmake.sh @@ -8,7 +8,6 @@ CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} if [[ -n "$MSYSTEM" ]]; then DefaultMakeCmd=mingw32-make.exe - MinGW=1 else DefaultMakeCmd=make @@ -18,7 +17,7 @@ ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") Configuration=Release -CStandard= +CxxStandard= MSVC_MT=0 MinGW="${MinGW:=0}" RunMake=0 @@ -51,16 +50,16 @@ fi while [[ $# -gt 0 ]]; do case $1 in - --c-standard) + --cxx-standard) shift - CStandard=$1 - case $CStandard in - 99|11|17|23) + CxxStandard=$1 + case $CxxStandard in + 98|11|14|17|20|23) ;; *) - >&2 echo "$ScriptPath: ${SisClr_Red}${SisClr_Bold}invalid C standard '$CStandard'${SisClr_None}; expected 99, 11, 17, or 23" + >&2 echo "$ScriptPath: ${SisClr_Red}${SisClr_Bold}invalid C++ standard '$CxxStandard'${SisClr_None}; expected 98, 11, 14, 17, 20, or 23" exit 1 ;; @@ -173,7 +172,7 @@ cd $CMakeDir echo "Executing CMake for ${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None} (in ${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None})" -if [ -z "$CStandard" ]; then CMakeCStandardVariable="" ; else CMakeCStandardVariable="-DCMAKE_C_STANDARD=$CStandard" ; fi +if [ -z "$CxxStandard" ]; then CMakeCStandardVariable="" ; else CMakeCStandardVariable="-DCMAKE_C_STANDARD=$CxxStandard" ; fi if [ $MSVC_MT -eq 0 ]; then CMakeMsvcMtFlag="OFF" ; else CMakeMsvcMtFlag="ON" ; fi if [ -z "$STLSoftDirGiven" ]; then CMakeSTLSoftVariable="" ; else CMakeSTLSoftVariable="-DSTLSOFT=$STLSoftDirGiven/" ; fi if [ $TestingDisabled -eq 0 ]; then CMakeBuildTestingFlag="ON" ; else CMakeBuildTestingFlag="OFF" ; fi diff --git a/run_all_unit_tests.sh b/run_all_unit_tests.sh index 936d980..55b53fc 100755 --- a/run_all_unit_tests.sh +++ b/run_all_unit_tests.sh @@ -8,7 +8,6 @@ CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} if [[ -n "$MSYSTEM" ]]; then DefaultMakeCmd=mingw32-make.exe - MinGW=1 else DefaultMakeCmd=make From 7ee76002ff6d2ad64a43b5eeba9e116cdfeedf41 Mon Sep 17 00:00:00 2001 From: synesissoftware Date: Mon, 24 Aug 2026 16:19:13 +1000 Subject: [PATCH 6/8] V0 (#3) * initial version * v0 * squash-commit * CMake * fix * squash-commit * squash-commit From 79e7022ea6a637735de39b99a9299264a80d8dfd Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Mon, 24 Aug 2026 16:26:08 +1000 Subject: [PATCH 7/8] squash-commit --- .gitignore | 1 - CHANGES.md | 6 +++++- CMakeLists.txt | 7 ++++++- NEWS.md | 3 ++- README.md | 12 +++++------- doc/readdebugstring.1 | 37 +++++++++++++++++++++++++++++++++++++ 6 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 doc/readdebugstring.1 diff --git a/.gitignore b/.gitignore index 35a19d3..c83ed53 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ /_internal/ /bin/ -/doc/ /include/ /lib/ /node_modules/ diff --git a/CHANGES.md b/CHANGES.md index adf5fe4..89d581a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,12 +1,16 @@ # ReadDebugString - Changes -## 0.0.1 - 23rd August 2026 +## 0.0.1 - 24th August 2026 +* Replaced the initial executable scaffold with a Windows debugger message reader; +* Added process identification to reader output; +* Improved error handling for Windows file-mapping and debugger access failures; * Improved CMake flexibility for uninstalled **STLSoft** source trees supplied via **STLSOFT**; * Added validation and an imported **STLSoft::STLSoft** target for local STLSoft source trees; * Added Windows **cl** and MinGW CI configuration with STLSoft source checkout; * Added an installation smoke test using **--version** so the long-running reader is not started; +* Added a section-1 reference page and installed it with CMake; ## 0.0.0 - 16th August 2026 diff --git a/CMakeLists.txt b/CMakeLists.txt index e35b7ab..da52cce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ # Purpose: Top-level CMake lists file for ReadDebugString # # Created: 15th August 2025 -# Updated: 18th August 2026 +# Updated: 24th August 2026 # # ######################################################################## # @@ -233,6 +233,11 @@ install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) +install(FILES + doc/${PROJECT_NAME_LOWER}.1 + DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 +) + # ################################################ # examples diff --git a/NEWS.md b/NEWS.md index 23ab42d..62441bb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,7 +3,8 @@ | Date | News Item | | ------------------- | --------- | -| 23rd August 2026 | [0.0.1 released](https://github.com/sistools/ReadDebugString/releases/tag/0.0.1) | +| 24th August 2026 | [0.0.1 released](https://github.com/sistools/ReadDebugString/releases/tag/0.0.1) | +| 16th August 2026 | [0.0.0 released](https://github.com/sistools/ReadDebugString/releases/tag/0.0.0) | | 16th August 2026 | [0.0.0 released](https://github.com/sistools/ReadDebugString/releases/tag/0.0.0) | diff --git a/README.md b/README.md index 045c7e6..1d2600d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Reads messages from the Windows debugger. -![C](https://img.shields.io/badge/C-00599C?style=flat&logo=c&logoColor=white) +![C++](https://img.shields.io/badge/C%2B%2B-00599C?style=flat&logo=cplusplus&logoColor=white) ![Windows](https://img.shields.io/badge/OS-Windows-0078D6?style=flat&logo=windows&logoColor=white) [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) [![GitHub release](https://img.shields.io/github/v/release/sistools/ReadDebugString.svg)](https://github.com/sistools/ReadDebugString/releases/latest) @@ -27,10 +27,8 @@ Reads messages from the Windows debugger. ## Introduction **ReadDebugString** is a small Windows-only utility that reads messages from -the Windows debugger. - -The current implementation is a minimal buildable scaffold. Its debugger -message-reading behaviour is still being developed. +the Windows debugger, identifies the originating process, and writes formatted +messages to standard error. ## Installation @@ -52,8 +50,8 @@ The project creates a single executable program, **ReadDebugString**. ## Examples -The program supports `--help` and `--version`. Its debugger message-reading -behaviour is still being developed. +With no arguments, the program waits for and displays messages from the Windows +debugger. Use `--help` or `--version` for commands that terminate immediately. ## Project Information diff --git a/doc/readdebugstring.1 b/doc/readdebugstring.1 new file mode 100644 index 0000000..d261e4f --- /dev/null +++ b/doc/readdebugstring.1 @@ -0,0 +1,37 @@ +.\" Copyright (c) 2025-2026, Matthew Wilson and Synesis Information Systems +.\" +.TH READDEBUGSTRING 1 "August 2026" "readdebugstring 0.0.1" "User Commands" +.SH NAME +readdebugstring \- read messages from the Windows debug output stream +.SH SYNOPSIS +.B readdebugstring +.br +.B readdebugstring +.B \-\-help +.br +.B readdebugstring +.B \-\-version +.SH DESCRIPTION +.B readdebugstring +waits for messages sent to the Windows debug output stream and writes each +message to standard error. Output includes the originating process ID and +process name when available. +.PP +With no arguments, the program continues waiting for debugger messages until +it is terminated. This is a Windows-only command. +.SH OPTIONS +.TP +.B \-\-help +Display usage information and exit. +.TP +.B \-\-version +Display version information and exit. +.SH SEE ALSO +.BR WriteDebugString (1) +.SH REPORTING BUGS +Report defects and feature requests at +https://github.com/sistools/ReadDebugString. +.SH AUTHOR +Matthew Wilson and Synesis Information Systems +.br +Copyright (c) 2025\-2026, Matthew Wilson and Synesis Information Systems From 7c9fff1485b962172e10b54db09c6185f9ff91c5 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Mon, 24 Aug 2026 16:31:52 +1000 Subject: [PATCH 8/8] warning --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index da52cce..31e2ec7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,6 +217,7 @@ target_compile_options(${PROJECT_NAME} /WX /W4 /wd4201 + /wd4702 > )