From ca09cf9ef34721702f64f7bc453ab131a32b7153 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 9 Jun 2026 13:05:37 -0400 Subject: [PATCH 1/8] 0.0.4 cleanup Signed-off-by: Leonard Carcaramo --- CMakeLists.txt | 31 ++++++- Jenkinsfile | 39 +++----- README.md | 6 +- cbxp/cbxp.cpp | 4 +- cbxp/cbxp.h | 2 +- cbxp/control_blocks/control_block.cpp | 6 +- cbxp/control_blocks/cvt.cpp | 2 +- cbxp/control_blocks/psa.cpp | 2 +- cbxp/python/_cbxp.c | 24 +---- python/cbxp/_C.pyi | 1 - python/cbxp/cbxp.py | 30 +----- ...{ascboffset40.bin => ascb_offset_0x40.bin} | Bin ...cboffset3A8.bin => oucb_offset_0x03a8.bin} | Bin tests/test.py | 86 ------------------ tests/test.sh | 8 +- 15 files changed, 70 insertions(+), 171 deletions(-) rename tests/samples/{ascboffset40.bin => ascb_offset_0x40.bin} (100%) rename tests/samples/{oucboffset3A8.bin => oucb_offset_0x03a8.bin} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a5751e..9bed14e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,7 +95,7 @@ target_compile_options(cbxp PUBLIC ${COMPILE_OPTIONS}) target_link_options(cbxp PUBLIC ${LINK_OPTIONS}) # ============================================================================ -# Packaging +# Package # ============================================================================ add_custom_target( package @@ -127,6 +127,35 @@ add_custom_target( DEPENDS libcbxp cbxp ) +# ============================================================================ +# Install +# ============================================================================ +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + SET(CMAKE_INSTALL_PREFIX "~/cbxp-${CMAKE_PROJECT_VERSION}" CACHE PATH "install path" FORCE) +endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + +include(GNUInstallDirs) + +install( + FILES "LICENSE" "NOTICES" + DESTINATION ${CMAKE_INSTALL_PREFIX} +) + +install( + TARGETS cbxp + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + +install( + TARGETS libcbxp + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +install( + FILES "./cbxp/cbxp.h" + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) + # ============================================================================ # Cppcheck # ============================================================================ diff --git a/Jenkinsfile b/Jenkinsfile index 281a168..d456720 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -89,13 +89,13 @@ pipeline { stage('Lint') { steps { echo "Linting with clang-format ..." - sh "gmake lint" + sh "cmake --build . --target lint --paralell" } } stage('Cppcheck') { steps { echo "Running cppcheck ..." - sh "gmake check" + sh "cmake --build . --target check --paralell" } } stage('Create Python Distribution Metadata') { @@ -118,7 +118,7 @@ pipeline { echo "Building '${wheel}' and '${tar}' ..." sh """ - ${python} -m pip install build>=1.3.0 + ${python} -m pip install build>=1.5.0 ${python} -m build """ @@ -139,25 +139,17 @@ pipeline { clean_python_environment() clean_git_repo() } - // Shell/C/C++ pax distribution + // Shell/C/C++ distribution def cbxp_version = get_cbxp_version() - def pax = "cbxp-${cbxp_version}.pax.Z" - echo "Building '${pax}' ..." + echo "Installing testing CBXP '${cbxp_version}' ..." sh """ - cmake . - gmake package - """ - - echo "Install testing '${pax}' ..." - sh """ - mkdir install-test - cd install-test - pax -rf ../dist/${pax} - ls -alT cbxp-${cbxp_version}/* + cmake . --install-prefix ${env.WORKSPACE}/install-test + cmake --build . --paralell + cmake --install . """ echo "'Function testing './dist/cbxp' ..." - sh "gmake test" + sh "cmake --build . --target test --paralell" clean_git_repo() } @@ -213,7 +205,9 @@ def create_python_executables_and_wheels_map(python_versions) { "cbxp-${cbxp_version}-cp3${python_version}-cp3${python_version}-zos.whl" ), "wheelPublish": ( - "cbxp-${cbxp_version}-cp3${python_version}-cp3${python_version}-zos.whl" + // New wheel naming convention does not work with PyPi so we + // do still need to rename the wheel file. + "cbxp-${cbxp_version}-cp3${python_version}-none-any.whl" ), "tarPublish": "cbxp-${cbxp_version}.tar.gz" ] @@ -334,14 +328,11 @@ def publish( echo "Building '${wheel_default}' ..." sh """ - ${python} -m pip install build>=1.2.2 + ${python} -m pip install build>=1.5.0 ${python} -m build -w """ - // Rename wheel file if the old naming convention is being used - if (wheel_default != wheel_publish) { - sh "mv ./dist/${wheel_default} ./dist/${wheel_publish}" - } + sh "mv ./dist/${wheel_default} ./dist/${wheel_publish}" if (tar_built == false) { tar_publish = python_executables_and_wheels_map[python]["tarPublish"] @@ -369,7 +360,7 @@ def publish( echo "Building '${pax}' ..." sh """ cmake . - gmake package + cmake --build . --target package --paralell """ echo "Uploading '${pax}' to '${release_title}' GitHub release ..." diff --git a/README.md b/README.md index 8233267..b9ac010 100644 --- a/README.md +++ b/README.md @@ -13,14 +13,14 @@ A unified and standardized interface for extracting and formatting z/OS control ## Description -z/OS Control Blocks are in-memory data structures that describe and control countless process, operating system components, and subsystems. Control blocks are ubiquitous on z/OS, but not very straight forward to access and extract information from. The mission of CBXP *(Control Block EXPlorer)* is to make it easy to extract z/OS control block data using industry standard tools and methodologies. CBXP accomplishes this by implementing a **C/C++ XPLINK ASCII** interface for extracting control blocks and post processing them into **JSON**. This makes it straight forward to integrate with industry standard programming languages and tools, which generally have well documented and understood foreign language interfaces for C/C++, and native and or third party JSON support that makes working with JSON data easy. +z/OS Control Blocks are in-memory data structures that describe and control countless process, operating system components, and subsystems. Control blocks are ubiquitous on z/OS, but not very straight forward to access and extract information from. The mission of CBXP *(Control Block EXPlorer)* is to make it easy to extract and format z/OS control block data using industry standard tools and methodologies. CBXP accomplishes this by implementing a **C/C++ XPLINK ASCII** interface for extracting control block data and post processing it into **JSON**. This makes it straight forward to integrate with industry standard programming languages and tools, which generally have well documented and understood foreign language interfaces for C/C++, and native and or third party JSON support that makes working with JSON data easy. CBXP is the successor to the existing [cbxplorer](https://github.com/ambitus/cbexplorer) project. CBXP mainly improves upon this existing work by being implemented in C/C++ so that it is not limited to a specific programming language or tool. CBXP also focuses heavily on providing an interface that is simple and straight forward to use. ## Getting Started ### Minimum z/OS & Language Versions -Currently, CBXP is being developed on **z/OS 3.1**. We hope to eventually support all z/OS versions that are fully supported by IBM. +Currently, CBXP is being developed on **z/OS 3.2**. We hope to eventually support all z/OS versions that are fully supported by IBM. * [z/OS Product Lifecycle](https://www.ibm.com/support/pages/lifecycle/search/?q=5655-ZOS,%205650-ZOS) All versions of the **IBM Open Enterprise SDK for Python** that are fully supported by IBM are supported by CBXP. @@ -33,7 +33,7 @@ All versions of the **IBM Open Enterprise SDK for Python** that are fully suppor ### Interfaces Currently, the following interfaces are provided for CBXP. Additional interfaces can be added in the future if there are use cases for them. * [Python Interface](https://ambitus.github.io/cbxp/interfaces/python) -* [CLI Interface](https://ambitus.github.io/cbxp/interfaces/shell) +* [CLI Interface](https://ambitus.github.io/cbxp/interfaces/cli) * [C/C++ Interface](https://ambitus.github.io/cbxp/interfaces/c_cpp) ### Supported Control Blocks diff --git a/cbxp/cbxp.cpp b/cbxp/cbxp.cpp index 94d6aa0..2ae70e0 100644 --- a/cbxp/cbxp.cpp +++ b/cbxp/cbxp.cpp @@ -42,7 +42,7 @@ cbxp_result_t* cbxp_extract(const char* control_block_name, cbxp_result_t* cbxp_format(const char* control_block_name, const size_t control_block_name_length, - const void* p_data, const size_t data_length, + const void* data, const size_t data_length, bool debug) { std::string control_block_name_string; @@ -60,7 +60,7 @@ cbxp_result_t* cbxp_format(const char* control_block_name, CBXP::ControlBlockExplorer explorer = CBXP::ControlBlockExplorer(p_cbxp_result); - explorer.formatControlBlock(control_block_name_string, p_data, data_length); + explorer.formatControlBlock(control_block_name_string, data, data_length); return p_cbxp_result; } diff --git a/cbxp/cbxp.h b/cbxp/cbxp.h index c55690b..359c16b 100644 --- a/cbxp/cbxp.h +++ b/cbxp/cbxp.h @@ -23,7 +23,7 @@ cbxp_result_t* cbxp_extract(const char* control_block_name, cbxp_result_t* cbxp_format(const char* control_block_name, const size_t control_block_name_length, - const void* p_data, const size_t data_length, + const void* data, const size_t data_length, bool debug); void cbxp_free(cbxp_result_t* cbxp_result, bool debug); diff --git a/cbxp/control_blocks/control_block.cpp b/cbxp/control_blocks/control_block.cpp index b3ffe1b..f386a12 100644 --- a/cbxp/control_blocks/control_block.cpp +++ b/cbxp/control_blocks/control_block.cpp @@ -165,14 +165,14 @@ void ControlBlock::createFilterLists(const std::vector& filters) { } void ControlBlock::addCurrentFilter(const std::string& filter) { - std::string filter_key, filter_value; std::vector operations = {"<=", ">=", "<", ">", "="}; for (std::string operation : operations) { size_t operation_pos = filter.find(operation); if (operation_pos != std::string::npos) { // If there's a delimeter then separate include into the key and its value - filter_value = filter.substr(operation_pos + operation.length()); - filter_key = filter.substr(0, operation_pos); + std::string filter_value = + filter.substr(operation_pos + operation.length()); + std::string filter_key = filter.substr(0, operation_pos); cbxp_filter_t filter_data = {operation, filter_value}; Logger::getInstance().debug("Adding '" + filter_key + operation + filter_value + diff --git a/cbxp/control_blocks/cvt.cpp b/cbxp/control_blocks/cvt.cpp index 92daa9e..29b5e5d 100644 --- a/cbxp/control_blocks/cvt.cpp +++ b/cbxp/control_blocks/cvt.cpp @@ -124,7 +124,7 @@ nlohmann::json CVT::get(const void* p_control_block, cvt_json["cvtpcnvt"] = formatter_.getHex(&(p_cvtmap->cvtpcnvt)); cvt_json["cvtprltv"] = formatter_.getHex(&(p_cvtmap->cvtprltv)); cvt_json["cvtprod"] = formatter_.getHex(p_cvtfix->cvtprod) + - formatter_.getHex(p_cvtfix->cvtprod + 8); + formatter_.getHex(p_cvtfix->cvtprod + 8); cvt_json["cvtpsxm"] = formatter_.getHex(&(p_cvtmap->cvtpsxm)); cvt_json["cvtpvtp"] = formatter_.getHex(&(p_cvtmap->cvtpvtp)); cvt_json["cvtqtd00"] = formatter_.getHex(&(p_cvtmap->cvtqtd00)); diff --git a/cbxp/control_blocks/psa.cpp b/cbxp/control_blocks/psa.cpp index 9824383..13e7ca6 100644 --- a/cbxp/control_blocks/psa.cpp +++ b/cbxp/control_blocks/psa.cpp @@ -48,7 +48,7 @@ nlohmann::json PSA::get(const void* p_control_block, reinterpret_cast(&p_psa->flcarch)); psa_json["flccvt64"] = formatter_.getHex(p_psa->flccvt64); psa_json["flcfacl"] = formatter_.getBitmap(p_psa->flcfacl) + - formatter_.getBitmap(p_psa->flcfacl + 8); + formatter_.getBitmap(p_psa->flcfacl + 8); psa_json["flcfacle"] = formatter_.getBitmap(p_psa->flcfacle) + formatter_.getBitmap(p_psa->flcfacle + 8); psa_json["psaaold"] = formatter_.getHex(p_psa->psaaold); diff --git a/cbxp/python/_cbxp.c b/cbxp/python/_cbxp.c index 9e26d00..f781084 100644 --- a/cbxp/python/_cbxp.c +++ b/cbxp/python/_cbxp.c @@ -50,33 +50,19 @@ static PyObject* call_cbxp_format(PyObject* self, PyObject* args, PyObject* debug_pyobj; const char* p_control_block_name; const char* p_data; - Py_ssize_t data_length, control_block_name_length, offset = 0; + Py_ssize_t data_length, control_block_name_length; bool debug = false; - static char* kwlist[] = {"control_block", "data", "offset", "debug", NULL}; + static char* kwlist[] = {"control_block", "data", "debug", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#y#|nO", kwlist, - &p_control_block_name, - &control_block_name_length, &p_data, - &data_length, &offset, &debug_pyobj)) { + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "s#y#|O", kwlist, &p_control_block_name, + &control_block_name_length, &p_data, &data_length, &debug_pyobj)) { return NULL; } debug = PyObject_IsTrue(debug_pyobj); - if (offset < 0) { - PyErr_SetString(PyExc_ValueError, "Offset cannot be negative"); - return NULL; - } - - if (offset > data_length) { - PyErr_SetString(PyExc_ArithmeticError, "Offset exceeds buffer length"); - return NULL; - } - - p_data += offset; - data_length -= offset; - cbxp_result_t* p_cbxp_result = cbxp_format(p_control_block_name, control_block_name_length, p_data, data_length, debug); diff --git a/python/cbxp/_C.pyi b/python/cbxp/_C.pyi index 356182e..195d8f9 100644 --- a/python/cbxp/_C.pyi +++ b/python/cbxp/_C.pyi @@ -7,6 +7,5 @@ def call_cbxp_extract( # noqa: N999 def call_cbxp_format( # noqa: N999 control_block: str, data: bytes, - offset: int = 0, debug: bool = False, ) -> dict: ... diff --git a/python/cbxp/cbxp.py b/python/cbxp/cbxp.py index d3189b0..d01e768 100644 --- a/python/cbxp/cbxp.py +++ b/python/cbxp/cbxp.py @@ -37,8 +37,6 @@ class CBXPErrorCode(Enum): # Negative Error Codes are from the Python interface COMMA_IN_INCLUDE = -1 COMMA_IN_FILTER = -2 - OFFSET_TOO_LARGE = -3 - OFFSET_NOT_POSITIVE_INT = -4 # Positive Error Codes are return codes from CBXP UNKNOWN_CONTROL_BLOCK = 1 BAD_INCLUDE = 2 @@ -56,10 +54,6 @@ def __init__(self, return_code: int, control_block_name: str): message = "Include patterns cannot contain commas" case CBXPErrorCode.COMMA_IN_FILTER.value: message = "Filters cannot contain commas" - case CBXPErrorCode.OFFSET_TOO_LARGE.value: - message = "Offset is too large for data provided" - case CBXPErrorCode.OFFSET_NOT_POSITIVE_INT.value: - message = "Offset must be a positive integer" case CBXPErrorCode.UNKNOWN_CONTROL_BLOCK.value: message = f"Unknown control block: {control_block_name}" case CBXPErrorCode.BAD_INCLUDE.value: @@ -116,27 +110,13 @@ def extract( def format( # noqa: A001 control_block: str, data: bytes, - offset: int = None, debug: bool = False, ) -> dict: - if offset is None: - offset = 0 - if not isinstance(offset, int): - raise CBXPError(CBXPErrorCode.OFFSET_NOT_POSITIVE_INT.value, control_block) - try: - response = call_cbxp_format( - control_block.lower(), - data, - offset=offset, - debug=debug, - ) - except ValueError as error: - raise CBXPError( - CBXPErrorCode.OFFSET_NOT_POSITIVE_INT.value, - control_block, - ) from error - except ArithmeticError as error: - raise CBXPError(CBXPErrorCode.OFFSET_TOO_LARGE.value, control_block) from error + response = call_cbxp_format( + control_block.lower(), + data, + debug=debug, + ) if response["return_code"]: raise CBXPError(response["return_code"], control_block) diff --git a/tests/samples/ascboffset40.bin b/tests/samples/ascb_offset_0x40.bin similarity index 100% rename from tests/samples/ascboffset40.bin rename to tests/samples/ascb_offset_0x40.bin diff --git a/tests/samples/oucboffset3A8.bin b/tests/samples/oucb_offset_0x03a8.bin similarity index 100% rename from tests/samples/oucboffset3A8.bin rename to tests/samples/oucb_offset_0x03a8.bin diff --git a/tests/test.py b/tests/test.py index 84ed572..d39469a 100644 --- a/tests/test.py +++ b/tests/test.py @@ -688,41 +688,6 @@ def test_cbxp_format_runs_in_debug_mode(self): cbdata = cbxp.format("ascb", data=self.read_sample("ascb.bin"), debug=True) self.assertIs(type(cbdata), dict) - # ============================================================================ - # Format -- Offset - # ============================================================================ - def test_cbxp_format_ascb_with_hex_offset(self): - cbdata = cbxp.format( - "ascb", - data=self.read_sample("ascboffset40.bin"), - offset=0x40, - ) - self.assertIs(type(cbdata), dict) - - def test_cbxp_format_ascb_with_decimal_offset(self): - cbdata = cbxp.format( - "ascb", - data=self.read_sample("ascboffset40.bin"), - offset=64, - ) - self.assertIs(type(cbdata), dict) - - def test_cbxp_format_oucb_with_hex_offset(self): - cbdata = cbxp.format( - "oucb", - data=self.read_sample("oucboffset3A8.bin"), - offset=0x3A8, - ) - self.assertIs(type(cbdata), dict) - - def test_cbxp_format_oucb_with_decimal_offset(self): - cbdata = cbxp.format( - "oucb", - data=self.read_sample("oucboffset3A8.bin"), - offset=936, - ) - self.assertIs(type(cbdata), dict) - # ============================================================================ # Format -- Testing Errors: Unknown Control Block # ============================================================================ @@ -734,57 +699,6 @@ def test_cbxp_format_raises_cbxp_error_if_unknown_control_block_is_provided(self str(e.exception), ) - # ============================================================================ - # Format -- Testing Errors: Bad Offset - # ============================================================================ - def test_cbxp_format_raises_cbxp_error_if_offset_is_too_large(self): - with self.assertRaises(CBXPError) as e: - cbxp.format( - "ascb", - data=self.read_sample("ascb.bin"), - offset=999999, - ) - self.assertEqual( - "Offset is too large for data provided", - str(e.exception), - ) - - def test_cbxp_format_raises_cbxp_error_if_offset_is_negative(self): - with self.assertRaises(CBXPError) as e: - cbxp.format( - "ascb", - data=self.read_sample("ascb.bin"), - offset=-1, - ) - self.assertEqual( - "Offset must be a positive integer", - str(e.exception), - ) - - def test_cbxp_format_raises_cbxp_error_if_offset_is_alpha(self): - with self.assertRaises(CBXPError) as e: - cbxp.format( - "ascb", - data=self.read_sample("ascb.bin"), - offset="JUNK", - ) - self.assertEqual( - "Offset must be a positive integer", - str(e.exception), - ) - - def test_cbxp_format_raises_cbxp_error_if_offset_is_float(self): - with self.assertRaises(CBXPError) as e: - cbxp.format( - "ascb", - data=self.read_sample("ascb.bin"), - offset=5.5, - ) - self.assertEqual( - "Offset must be a positive integer", - str(e.exception), - ) - # ============================================================================ # Format -- Testing Errors: Bad Data # ============================================================================ diff --git a/tests/test.sh b/tests/test.sh index 43d8593..2960ea5 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -143,10 +143,10 @@ run_with_expected_exit_code 0 ./dist/cbxp format -F tests/samples/oucb.bin oucb run_with_expected_exit_code 0 ./dist/cbxp format -F tests/samples/ascb.bin -d ascb run_with_expected_exit_code 0 ./dist/cbxp format -F tests/samples/ascb.bin --debug ascb # Format - Offset -run_with_expected_exit_code 0 ./dist/cbxp format -F tests/samples/ascboffset40.bin -o 0x40 ascb -run_with_expected_exit_code 0 ./dist/cbxp format -F tests/samples/ascboffset40.bin -o 64 ascb -run_with_expected_exit_code 0 cat tests/samples/oucboffset3A8.bin | ./dist/cbxp format -o 0x3A8 oucb -run_with_expected_exit_code 0 cat tests/samples/oucboffset3A8.bin | ./dist/cbxp format -o 936 oucb +run_with_expected_exit_code 0 ./dist/cbxp format -F tests/samples/ascb_offset_0x40.bin -o 0x40 ascb +run_with_expected_exit_code 0 ./dist/cbxp format -F tests/samples/ascb_offset_0x40.bin -o 64 ascb +run_with_expected_exit_code 0 cat tests/samples/oucb_offset_0x03a8.bin | ./dist/cbxp format -o 0x03a8 oucb +run_with_expected_exit_code 0 cat tests/samples/oucb_offset_0x03a8.bin | ./dist/cbxp format -o 936 oucb # Format - Errors: Bad Usage run_with_expected_exit_code 255 ./dist/cbxp format run_with_expected_exit_code 255 ./dist/cbxp format --junk From e035883bf581def7e8d0fa91e5d9beb4d9835e39 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 10 Jun 2026 11:24:39 -0400 Subject: [PATCH 2/8] Add ASCII art, remove package target, and debug clang-format action. Signed-off-by: Leonard Carcaramo --- .github/workflows/clang-format.yml | 8 +++---- CMakeLists.txt | 33 --------------------------- Jenkinsfile | 7 ++++-- cbxp/cli/command_processor.cpp | 36 ++++++++++++++++++++++++++++++ cbxp/cli/command_processor.hpp | 1 + 5 files changed, 46 insertions(+), 39 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index dab77c7..7e73ff9 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -8,13 +8,13 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install clang-format - run: sudo apt install -y cmake clang-format-19 + run: sudo apt install -y cmake clang-format-22 - name: clang-format - # Create symbolic link to clang-format-19 and + # Create symbolic link to clang-format-22 and # add it to PATH so that 'clang-format' can - # be used to run 'clang-format-19'. + # be used to run 'clang-format-22'. run: | - ln -s $(which clang-format-19) clang-format + ln -s $(which clang-format-22) clang-format export PATH=$PWD:$PATH cmake . make lint diff --git a/CMakeLists.txt b/CMakeLists.txt index 9bed14e..6bd2eba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,39 +94,6 @@ target_compile_definitions( target_compile_options(cbxp PUBLIC ${COMPILE_OPTIONS}) target_link_options(cbxp PUBLIC ${LINK_OPTIONS}) -# ============================================================================ -# Package -# ============================================================================ -add_custom_target( - package - COMMAND "mkdir" - "-p" - "cbxp-${CMAKE_PROJECT_VERSION}/bin" - "cbxp-${CMAKE_PROJECT_VERSION}/lib" - "cbxp-${CMAKE_PROJECT_VERSION}/include" - COMMAND "cp" - "LICENSE" - "cbxp-${CMAKE_PROJECT_VERSION}/" - COMMAND "cp" - "NOTICES" - "cbxp-${CMAKE_PROJECT_VERSION}/" - COMMAND "cp" - "./dist/cbxp" - "cbxp-${CMAKE_PROJECT_VERSION}/bin/" - COMMAND "cp" - "./dist/libcbxp.a" - "cbxp-${CMAKE_PROJECT_VERSION}/lib/" - COMMAND "cp" - "./cbxp/cbxp.h" - "cbxp-${CMAKE_PROJECT_VERSION}/include/" - COMMAND "pax" - "-x" "pax" - "-wzvf" - "./dist/cbxp-${CMAKE_PROJECT_VERSION}.pax.Z" - "cbxp-${CMAKE_PROJECT_VERSION}/*" - DEPENDS libcbxp cbxp -) - # ============================================================================ # Install # ============================================================================ diff --git a/Jenkinsfile b/Jenkinsfile index d456720..5ec3137 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -356,11 +356,14 @@ def publish( // Build and publish Shell/C/C++ interface pax def cbxp_version = get_cbxp_version() + def package_source_dir = "${env.WORKSPACE}/cbxp-${cbxp_version}" def pax = "cbxp-${cbxp_version}.pax.Z" echo "Building '${pax}' ..." sh """ - cmake . - cmake --build . --target package --paralell + cmake . --install-prefix ${package_source_dir} + cmake --build . --paralell + cmake --install . + pax -x pax -wzvf ./dist/${pax} ${package_source_dir}/* """ echo "Uploading '${pax}' to '${release_title}' GitHub release ..." diff --git a/cbxp/cli/command_processor.cpp b/cbxp/cli/command_processor.cpp index 7e35f9f..48cc34d 100644 --- a/cbxp/cli/command_processor.cpp +++ b/cbxp/cli/command_processor.cpp @@ -12,7 +12,43 @@ namespace CBXP { +void CommandProcessor::showASCIIArt() { + std::string ansi_blue = "\033[34m"; + std::string ansi_reset = "\033[0m"; + + // clang-format off + const std::vector logo_ascii_art = { + " ____________ ", + "| |", + "| 1010 |", + "| |", + "| {} |", + "|____________|" + }; + + const std::vector cbxp_ascii_art = { + " _____ ______ _______", + " / ____| _ \\ \\ / / __ \\", + " | | | |_) \\ V /| |__) |", + " | | | _ < > < | ___/", + " | |____| |_) / . \\| |", + " \\_____|____/_/ \\_\\_|" + }; + // clang-format on + + for (auto i = 0; i < logo_ascii_art.size(); i++) { + if (isatty(fileno(stdout))) { + std::cout << logo_ascii_art[i] << ansi_blue << cbxp_ascii_art[i] + << ansi_reset << std::endl; + } else { + std::cout << logo_ascii_art[i] << cbxp_ascii_art[i] << std::endl; + } + } + std::cout << std::endl; +} + void CommandProcessor::showGeneralUsage() const { + CommandProcessor::showASCIIArt(); std::cout << "Full CLI documentation is available at: " "https://ambitus.github.io/cbxp/interfaces/shell/" << std::endl diff --git a/cbxp/cli/command_processor.hpp b/cbxp/cli/command_processor.hpp index 4142030..32ba26e 100644 --- a/cbxp/cli/command_processor.hpp +++ b/cbxp/cli/command_processor.hpp @@ -67,6 +67,7 @@ class CommandProcessor { cbxp_global_options_t global_options_; cbxp_extract_options_t extract_options_; cbxp_format_options_t format_options_; + static void showASCIIArt(); void showGeneralUsage() const; void showExtractUsage() const; void showFormatUsage() const; From 94e9ed44c9a9d3280373444df0a0b5c76b598491 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 10 Jun 2026 13:09:54 -0400 Subject: [PATCH 3/8] Debug Jenkinsfile, fix ascii art, and debug clang-format check Signed-off-by: Leonard Carcaramo --- .github/workflows/clang-format.yml | 8 ++++---- Jenkinsfile | 10 +++++----- cbxp/cli/command_processor.cpp | 14 +++++++------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 7e73ff9..754892e 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -8,13 +8,13 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install clang-format - run: sudo apt install -y cmake clang-format-22 + run: sudo apt install -y cmake clang-format-21 - name: clang-format - # Create symbolic link to clang-format-22 and + # Create symbolic link to clang-format-21 and # add it to PATH so that 'clang-format' can - # be used to run 'clang-format-22'. + # be used to run 'clang-format-21'. run: | - ln -s $(which clang-format-22) clang-format + ln -s $(which clang-format-21) clang-format export PATH=$PWD:$PATH cmake . make lint diff --git a/Jenkinsfile b/Jenkinsfile index 5ec3137..d2e47c0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -89,13 +89,13 @@ pipeline { stage('Lint') { steps { echo "Linting with clang-format ..." - sh "cmake --build . --target lint --paralell" + sh "cmake --build . --target lint --parallel" } } stage('Cppcheck') { steps { echo "Running cppcheck ..." - sh "cmake --build . --target check --paralell" + sh "cmake --build . --target check --parallel" } } stage('Create Python Distribution Metadata') { @@ -144,12 +144,12 @@ pipeline { echo "Installing testing CBXP '${cbxp_version}' ..." sh """ cmake . --install-prefix ${env.WORKSPACE}/install-test - cmake --build . --paralell + cmake --build . --parallel cmake --install . """ echo "'Function testing './dist/cbxp' ..." - sh "cmake --build . --target test --paralell" + sh "cmake --build . --target test --parallel" clean_git_repo() } @@ -361,7 +361,7 @@ def publish( echo "Building '${pax}' ..." sh """ cmake . --install-prefix ${package_source_dir} - cmake --build . --paralell + cmake --build . --parallel cmake --install . pax -x pax -wzvf ./dist/${pax} ${package_source_dir}/* """ diff --git a/cbxp/cli/command_processor.cpp b/cbxp/cli/command_processor.cpp index 48cc34d..3592e83 100644 --- a/cbxp/cli/command_processor.cpp +++ b/cbxp/cli/command_processor.cpp @@ -18,12 +18,12 @@ void CommandProcessor::showASCIIArt() { // clang-format off const std::vector logo_ascii_art = { - " ____________ ", - "| |", - "| 1010 |", - "| |", - "| {} |", - "|____________|" + " ____________ ", + " | |", + " | 1010 |", + " | |", + " | {} |", + " |____________|" }; const std::vector cbxp_ascii_art = { @@ -32,7 +32,7 @@ void CommandProcessor::showASCIIArt() { " | | | |_) \\ V /| |__) |", " | | | _ < > < | ___/", " | |____| |_) / . \\| |", - " \\_____|____/_/ \\_\\_|" + " \\_____|____/_/ \\_\\_|" }; // clang-format on From 14a3cca025c9676c427132eb5e47d6f17efd54e2 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 10 Jun 2026 13:48:01 -0400 Subject: [PATCH 4/8] Cleanup clang-format and debug. Signed-off-by: Leonard Carcaramo --- .github/workflows/clang-format.yml | 8 ++++---- cbxp/cli/command_processor.cpp | 5 ++++- cbxp/control_blocks/cvt.cpp | 2 +- cbxp/control_blocks/psa.cpp | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 754892e..8d3e58d 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -8,13 +8,13 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install clang-format - run: sudo apt install -y cmake clang-format-21 + run: sudo apt install -y cmake clang-format-20 - name: clang-format - # Create symbolic link to clang-format-21 and + # Create symbolic link to clang-format-20 and # add it to PATH so that 'clang-format' can - # be used to run 'clang-format-21'. + # be used to run 'clang-format-20'. run: | - ln -s $(which clang-format-21) clang-format + ln -s $(which clang-format-20) clang-format export PATH=$PWD:$PATH cmake . make lint diff --git a/cbxp/cli/command_processor.cpp b/cbxp/cli/command_processor.cpp index 3592e83..e7f9bd8 100644 --- a/cbxp/cli/command_processor.cpp +++ b/cbxp/cli/command_processor.cpp @@ -36,6 +36,8 @@ void CommandProcessor::showASCIIArt() { }; // clang-format on + std::cout << std::endl; + for (auto i = 0; i < logo_ascii_art.size(); i++) { if (isatty(fileno(stdout))) { std::cout << logo_ascii_art[i] << ansi_blue << cbxp_ascii_art[i] @@ -44,13 +46,14 @@ void CommandProcessor::showASCIIArt() { std::cout << logo_ascii_art[i] << cbxp_ascii_art[i] << std::endl; } } + std::cout << std::endl; } void CommandProcessor::showGeneralUsage() const { CommandProcessor::showASCIIArt(); std::cout << "Full CLI documentation is available at: " - "https://ambitus.github.io/cbxp/interfaces/shell/" + "https://ambitus.github.io/cbxp/interfaces/cli/" << std::endl << std::endl; diff --git a/cbxp/control_blocks/cvt.cpp b/cbxp/control_blocks/cvt.cpp index 29b5e5d..92daa9e 100644 --- a/cbxp/control_blocks/cvt.cpp +++ b/cbxp/control_blocks/cvt.cpp @@ -124,7 +124,7 @@ nlohmann::json CVT::get(const void* p_control_block, cvt_json["cvtpcnvt"] = formatter_.getHex(&(p_cvtmap->cvtpcnvt)); cvt_json["cvtprltv"] = formatter_.getHex(&(p_cvtmap->cvtprltv)); cvt_json["cvtprod"] = formatter_.getHex(p_cvtfix->cvtprod) + - formatter_.getHex(p_cvtfix->cvtprod + 8); + formatter_.getHex(p_cvtfix->cvtprod + 8); cvt_json["cvtpsxm"] = formatter_.getHex(&(p_cvtmap->cvtpsxm)); cvt_json["cvtpvtp"] = formatter_.getHex(&(p_cvtmap->cvtpvtp)); cvt_json["cvtqtd00"] = formatter_.getHex(&(p_cvtmap->cvtqtd00)); diff --git a/cbxp/control_blocks/psa.cpp b/cbxp/control_blocks/psa.cpp index 13e7ca6..9824383 100644 --- a/cbxp/control_blocks/psa.cpp +++ b/cbxp/control_blocks/psa.cpp @@ -48,7 +48,7 @@ nlohmann::json PSA::get(const void* p_control_block, reinterpret_cast(&p_psa->flcarch)); psa_json["flccvt64"] = formatter_.getHex(p_psa->flccvt64); psa_json["flcfacl"] = formatter_.getBitmap(p_psa->flcfacl) + - formatter_.getBitmap(p_psa->flcfacl + 8); + formatter_.getBitmap(p_psa->flcfacl + 8); psa_json["flcfacle"] = formatter_.getBitmap(p_psa->flcfacle) + formatter_.getBitmap(p_psa->flcfacle + 8); psa_json["psaaold"] = formatter_.getHex(p_psa->psaaold); From 25370b1554b4a4d7f22f89d653d3adfc2ac97d7d Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 10 Jun 2026 15:36:18 -0400 Subject: [PATCH 5/8] Cleanup and fix pipe check. Signed-off-by: Leonard Carcaramo --- cbxp/cli/command_processor.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/cbxp/cli/command_processor.cpp b/cbxp/cli/command_processor.cpp index e7f9bd8..d71fd35 100644 --- a/cbxp/cli/command_processor.cpp +++ b/cbxp/cli/command_processor.cpp @@ -1,5 +1,8 @@ +#define _XOPEN_SOURCE_EXTENDED 1 + #include "command_processor.hpp" +#include #include #include @@ -13,8 +16,9 @@ namespace CBXP { void CommandProcessor::showASCIIArt() { - std::string ansi_blue = "\033[34m"; - std::string ansi_reset = "\033[0m"; + std::string ansi_bold = "\e[1m"; + std::string ansi_blue_bold = "\e[1;34m"; + std::string ansi_reset = "\e[0m"; // clang-format off const std::vector logo_ascii_art = { @@ -36,12 +40,10 @@ void CommandProcessor::showASCIIArt() { }; // clang-format on - std::cout << std::endl; - for (auto i = 0; i < logo_ascii_art.size(); i++) { if (isatty(fileno(stdout))) { - std::cout << logo_ascii_art[i] << ansi_blue << cbxp_ascii_art[i] - << ansi_reset << std::endl; + std::cout << ansi_bold << logo_ascii_art[i] << ansi_blue_bold + << cbxp_ascii_art[i] << ansi_reset << std::endl; } else { std::cout << logo_ascii_art[i] << cbxp_ascii_art[i] << std::endl; } @@ -340,7 +342,8 @@ void CommandProcessor::processFormatFlags() { throw CLIExitFailure(); } } - if (isatty(STDIN_FILENO) == 0) { + struct pollfd pfd = {STDIN_FILENO, POLLIN, 0}; + if (poll(&pfd, 1, 0) > 0 && (pfd.revents & POLLIN)) { CommandProcessor::readFormatDataFromPipe(); } if (format_options_.data_buffer.empty()) { From 5436f333fea3dbf2905d14881880379c58ecc083 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 10 Jun 2026 16:01:46 -0400 Subject: [PATCH 6/8] Debug Jenkinsfile Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index d2e47c0..b7787f6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -139,7 +139,7 @@ pipeline { clean_python_environment() clean_git_repo() } - // Shell/C/C++ distribution + // CLI/C/C++ distribution def cbxp_version = get_cbxp_version() echo "Installing testing CBXP '${cbxp_version}' ..." sh """ @@ -354,16 +354,15 @@ def publish( echo "Adding sha256 checksum for '${tar_publish}' to ${checksums_file}..." sh "cd dist && sha256sum -t ${tar_publish} >> ${checksums_file}" - // Build and publish Shell/C/C++ interface pax + // Build and publish CLI/C/C++ interface pax def cbxp_version = get_cbxp_version() - def package_source_dir = "${env.WORKSPACE}/cbxp-${cbxp_version}" def pax = "cbxp-${cbxp_version}.pax.Z" echo "Building '${pax}' ..." sh """ - cmake . --install-prefix ${package_source_dir} + cmake . --install-prefix ${env.WORKSPACE}/cbxp-${cbxp_version} cmake --build . --parallel cmake --install . - pax -x pax -wzvf ./dist/${pax} ${package_source_dir}/* + pax -x pax -wzvf ./dist/${pax} cbxp-${cbxp_version}/* """ echo "Uploading '${pax}' to '${release_title}' GitHub release ..." @@ -416,7 +415,7 @@ def build_description(python_executables_and_wheels_map, release_tag, release_no + "> :warning: _Requires z/OS Open XL C/C++ 2.2 compiler._\\n" + "```\\ncurl -O -L https://github.com/ambitus/cbxp/releases/download/${release_tag}/${tar} " + "&& python3 -m pip install ${tar}\\n```\\n" - + "## Shell/C/C++ Interface Installation\\n" + + "## CLI/C/C++ Interface Installation\\n" + "```\\ncurl -O -L https://github.com/ambitus/cbxp/releases/download/${release_tag}/${pax} " + "&& pax -rf ${pax}\\n```\\n" ) From fe8053d72ff4c20e7c5316ea5626b7959ffc99de Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Thu, 11 Jun 2026 10:32:18 -0400 Subject: [PATCH 7/8] Update ASCII art and add _POSIX_SOURCE feature test macro for isatty()/fileno() Signed-off-by: Leonard Carcaramo --- cbxp/cli/command_processor.cpp | 13 +++++++------ cbxp/logger.cpp | 2 ++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/cbxp/cli/command_processor.cpp b/cbxp/cli/command_processor.cpp index d71fd35..718bb7f 100644 --- a/cbxp/cli/command_processor.cpp +++ b/cbxp/cli/command_processor.cpp @@ -1,3 +1,4 @@ +#define _POSIX_SOURCE #define _XOPEN_SOURCE_EXTENDED 1 #include "command_processor.hpp" @@ -31,12 +32,12 @@ void CommandProcessor::showASCIIArt() { }; const std::vector cbxp_ascii_art = { - " _____ ______ _______", - " / ____| _ \\ \\ / / __ \\", - " | | | |_) \\ V /| |__) |", - " | | | _ < > < | ___/", - " | |____| |_) / . \\| |", - " \\_____|____/_/ \\_\\_|" + " _____ ____ __ __ _____ ", + " / ____|| _ \\\\ \\ / /| __ \\", + " | | | |_) |\\ V / | |__) |", + " | | | _ < > < | ___/", + " | |____ | |_) |/ . \\ | |", + " \\_____||____//_/ \\_\\|_|" }; // clang-format on diff --git a/cbxp/logger.cpp b/cbxp/logger.cpp index b10112e..6fe7c9f 100644 --- a/cbxp/logger.cpp +++ b/cbxp/logger.cpp @@ -1,3 +1,5 @@ +#define _POSIX_SOURCE + #include "logger.hpp" #include From f948b3a068b6efde1d21fe7f9deb10fce12e957c Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Thu, 11 Jun 2026 13:44:05 -0400 Subject: [PATCH 8/8] Fix sha256 checksum issue. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index b7787f6..be7bbe3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -345,14 +345,14 @@ def publish( upload_asset(release_id, wheel_publish) echo "Adding sha256 checksum for '${wheel_publish}' to ${checksums_file}..." - sh "cd dist && sha256sum -t ${wheel_publish} >> ${checksums_file}" + sh "cd dist && sha256sum ${wheel_publish} >> ${checksums_file}" } echo "Uploading '${tar_publish}' to '${release_title}' GitHub release ..." upload_asset(release_id, tar_publish) echo "Adding sha256 checksum for '${tar_publish}' to ${checksums_file}..." - sh "cd dist && sha256sum -t ${tar_publish} >> ${checksums_file}" + sh "cd dist && sha256sum ${tar_publish} >> ${checksums_file}" // Build and publish CLI/C/C++ interface pax def cbxp_version = get_cbxp_version() @@ -369,7 +369,7 @@ def publish( upload_asset(release_id, pax) echo "Adding sha256 checksum for '${pax}' to ${checksums_file}..." - sh "cd dist && sha256sum -t ${pax} >> ${checksums_file}" + sh "cd dist && sha256sum ${pax} >> ${checksums_file}" echo "Uploading '${checksums_file}' to '${release_title}' GitHub release ..." upload_asset(release_id, checksums_file)