From 1f4186691a651a7b6ca7a3441685345baf1ac760 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Fri, 15 Aug 2025 06:15:55 +1000 Subject: [PATCH 1/7] initial version --- .gitattributes | 0 .gitignore | 12 +++ .vimrc | 8 ++ .vscode/settings.json | 18 ++++ CHANGES.md | 0 Makefile | 29 ++++++ README.md | 0 TODO.md | 0 main.cpp | 236 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 303 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .vimrc create mode 100644 .vscode/settings.json create mode 100644 CHANGES.md create mode 100644 Makefile create mode 100644 README.md create mode 100644 TODO.md create mode 100644 main.cpp diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc5e712 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ + +*~ +*.*~ +*.exe +*.ilk +*.obj +*.map +*.pdb +*.swp +*.tmp +*.zip + diff --git a/.vimrc b/.vimrc new file mode 100644 index 0000000..b2ce772 --- /dev/null +++ b/.vimrc @@ -0,0 +1,8 @@ + +set expandtab +set hlsearch +set number +set shiftwidth=4 +set softtabstop=4 +set tabstop=4 + diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..2c808f7 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,18 @@ +{ + "editor.detectIndentation": false, + "editor.insertSpaces": true, + "editor.tabSize": 4, + "files.associations": { + "format": "cpp", + "istream": "cpp", + "memory": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "xutility": "cpp", + }, +} diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..e69de29 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/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..e69de29 diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..dacce3f --- /dev/null +++ b/main.cpp @@ -0,0 +1,236 @@ + +#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 + + +#define PROGRAM_VER_MAJOR 0 +#define PROGRAM_VER_MINOR 0 +#define PROGRAM_VER_PATCH 1 + + +union Payload +{ + 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)); + } +} + + +// [[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 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 > 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(); + + fwprintf( + stderr + , L"%.*s: %s:%d: UNEXPECTED\n" + , int(program_name.len), program_name.ptr + , STLSOFT_STRINGIZE_w(__FILE__), __LINE__ + ); + + ::DebugBreak(); + + return EXIT_FAILURE; + 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; +} + From 05e32d0c720bfb259adc937a7856a1accfea1c0f Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Tue, 18 Aug 2026 06:17:20 +1000 Subject: [PATCH 2/7] v0 --- README.md | 15 +++++++++++++++ main.cpp | 23 +++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/README.md b/README.md index e69de29..718fe8a 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,15 @@ +# ReadDebugString + +[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg) + +Windows CLI C++ program that permits reading from the Windows debugger + + +## Table of Contents + + +## Introduction + + + + diff --git a/main.cpp b/main.cpp index dacce3f..9760bca 100644 --- a/main.cpp +++ b/main.cpp @@ -19,10 +19,12 @@ #include #include +#include #include #include #include +#include #define PROGRAM_VER_MAJOR 0 @@ -60,6 +62,27 @@ void throw_( } +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() From c793877571fcb0904f3503daa1c3d2aaeb82ee66 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Tue, 18 Aug 2026 06:25:48 +1000 Subject: [PATCH 3/7] squash-commit --- .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 | 44 +++++++ .vscode/settings.json | 211 ++++++++++++++++++++++++++++--- CMakeLists.txt | 36 ++++++ LICENSE | 31 +++++ README.md | 83 ++++++++++++- 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, 1602 insertions(+), 19 deletions(-) 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 CMakeLists.txt create mode 100644 LICENSE 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 index e69de29..66f0c82 100644 --- a/.gitattributes +++ 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 index b2ce772..7d103b0 100644 --- a/.vimrc +++ b/.vimrc @@ -6,3 +6,47 @@ 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 index 2c808f7..a20fc3c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,18 +1,197 @@ { - "editor.detectIndentation": false, - "editor.insertSpaces": true, - "editor.tabSize": 4, - "files.associations": { - "format": "cpp", - "istream": "cpp", - "memory": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "xlocmes": "cpp", - "xlocmon": "cpp", - "xlocnum": "cpp", - "xloctime": "cpp", - "xutility": "cpp", - }, + "[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 new file mode 100644 index 0000000..9f8757e --- /dev/null +++ b/LICENSE @@ -0,0 +1,31 @@ +ReadDebugString - BSD 3-Clause License + +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. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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. + diff --git a/README.md b/README.md index 718fe8a..ad74804 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,92 @@ # ReadDebugString -[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg) +Reads messages from the Windows debugger. -Windows CLI C++ program that permits reading 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 fa3c0ff3c8c8989668cdd584ab1a086cca04c800 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Tue, 18 Aug 2026 06:41:09 +1000 Subject: [PATCH 4/7] CMake --- .gitignore | 144 +++++++++++++++++++++++++- CMakeLists.txt | 234 +++++++++++++++++++++++++++++++++++++++--- cmake/BuildType.cmake | 59 +++++++++++ main.c | 8 -- 4 files changed, 418 insertions(+), 27 deletions(-) create mode 100644 cmake/BuildType.cmake delete mode 100644 main.c diff --git a/.gitignore b/.gitignore index bc5e712..f369e23 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +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 + +realpath +realpath_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 -*.map +*.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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 796fb29..83d7b93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,36 +1,236 @@ +# ######################################################################## # +# 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 + +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) +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-ignored-qualifiers + -Wno-incompatible-pointer-types-discards-qualifiers + -Wno-unused-parameter + > + $<$: + /WX /W4 + > +) + +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/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; -} From 71489b0cc7501eb22f857e46ab82ad93d0463651 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Tue, 18 Aug 2026 07:00:21 +1000 Subject: [PATCH 5/7] fix --- build_cmake.sh | 1 - clean_cmake.sh | 1 - prepare_cmake.sh | 1 - run_all_unit_tests.sh | 1 - 4 files changed, 4 deletions(-) diff --git a/build_cmake.sh b/build_cmake.sh index 3f261e7..f081647 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 96b6c07..b2e61b3 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/prepare_cmake.sh b/prepare_cmake.sh index 417cb1b..6529aa9 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 diff --git a/run_all_unit_tests.sh b/run_all_unit_tests.sh index b05b671..e5bed55 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 24e94bc0aa777e9c1139689e78cd9ffd037513f6 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Sun, 23 Aug 2026 11:28:01 +1000 Subject: [PATCH 6/7] squash-commit --- .gitignore | 4 ++-- .sis/script_info_lines.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index f369e23..35a19d3 100644 --- a/.gitignore +++ b/.gitignore @@ -88,8 +88,8 @@ update_deps.cmd build/makefile.tmpl build/makefile.tools.xml -realpath -realpath_test +ReadDebugString +ReadDebugString_test # files (by pattern) 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 ab3009aa7144ac141db1f7324816beb0ad92a096 Mon Sep 17 00:00:00 2001 From: synesissoftware Date: Mon, 24 Aug 2026 16:08:50 +1000 Subject: [PATCH 7/7] 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 | 43 +++++++++++++++++++++++++++-------- INSTALL.md | 41 +++++++++++++++++++++++++++++++++ NEWS.md | 10 ++++++++ README.md | 6 +++-- REQUISITES.md | 26 +++++++++++++++++++++ main.cpp | 10 ++++++-- prepare_cmake.sh | 14 ++++++------ 10 files changed, 174 insertions(+), 22 deletions(-) create mode 100644 AUTHORS.md create mode 100644 INSTALL.md create mode 100644 NEWS.md create mode 100644 REQUISITES.md 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 index e69de29..adf5fe4 100644 --- a/CHANGES.md +++ 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 83d7b93..e35b7ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,17 +144,34 @@ endif() # ############################ # 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) + 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() - set(STLSOFT_INCLUDE_DIR $ENV{STLSOFT}/include) + 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) @@ -166,7 +183,7 @@ endif() if(DEFINED STLSOFT_INCLUDE_DIR) - include_directories(${STLSOFT_INCLUDE_DIR}) + include_directories("${STLSOFT_INCLUDE_DIR}") endif() @@ -190,18 +207,24 @@ add_executable(${PROJECT_NAME} target_compile_options(${PROJECT_NAME} PRIVATE - $<$,$,$>: + $<$,$,$>: -Werror -Wall -Wextra -pedantic - - -Wno-ignored-qualifiers - -Wno-incompatible-pointer-types-discards-qualifiers - -Wno-unused-parameter > - $<$: + $<$,$>: + -Wno-anonymous-structs + > + $<$: /WX /W4 + + /wd4201 > ) +target_link_options(${PROJECT_NAME} + PRIVATE + $<$:-municode> +) + target_link_libraries(${PROJECT_NAME} $<$:STLSoft::STLSoft> ) 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/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/main.cpp b/main.cpp index 9760bca..17e2567 100644 --- a/main.cpp +++ b/main.cpp @@ -34,6 +34,9 @@ union Payload { +#if defined(__GNUC__) && !defined(__clang__) + __extension__ +#endif struct { DWORD pid; @@ -90,7 +93,7 @@ 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 hFileMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Payload), "DBWIN_BUFFER"); + HANDLE const hFileMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Payload), "DBWIN_BUFFER"); if (NULL == hFileMap) { @@ -149,7 +152,7 @@ void run() } else { - if (r > STLSOFT_NUM_ELEMENTS(msg) - 3) + if (r > int(STLSOFT_NUM_ELEMENTS(msg) - 3)) { msg[STLSOFT_NUM_ELEMENTS(msg) - 3] = '\r'; msg[STLSOFT_NUM_ELEMENTS(msg) - 2] = '\n'; @@ -220,6 +223,8 @@ int wmain(int argc, wchar_t* argv[]) run(); +#ifndef NDEBUG + fwprintf( stderr , L"%.*s: %s:%d: UNEXPECTED\n" @@ -230,6 +235,7 @@ int wmain(int argc, wchar_t* argv[]) ::DebugBreak(); return EXIT_FAILURE; +#endif default: std::wcerr diff --git a/prepare_cmake.sh b/prepare_cmake.sh index 6529aa9..287b129 100755 --- a/prepare_cmake.sh +++ b/prepare_cmake.sh @@ -17,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 @@ -50,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 ;; @@ -172,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