From 40cf12015a0422d694c73e2617ab4685b5a9d74f Mon Sep 17 00:00:00 2001 From: "Michael Gene Brockus (Dreamer)" Date: Sat, 14 Sep 2024 10:26:03 -0600 Subject: [PATCH] first commit --- .github/.gitignore | 4 + .github/ISSUE_TEMPLATE/bug_report.md | 21 ++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++ .github/PULL_REQUEST_TEMPLATE.md | 18 ++ .github/ciimage/Dockerfile.archlinux | 33 ++ .github/ciimage/Dockerfile.debian | 42 +++ .github/ciimage/Dockerfile.fedora | 35 ++ .github/ciimage/Dockerfile.ubuntu | 37 +++ .github/crossfiles/arm.txt | 11 + .github/crossfiles/arm64.txt | 11 + .github/crossfiles/mips.txt | 11 + .github/crossfiles/mipsel.txt | 11 + .github/crossfiles/ppc.txt | 11 + .github/crossfiles/ppc64le.txt | 11 + .github/crossfiles/riscv64.txt | 11 + .github/crossfiles/s390x.txt | 11 + .github/crossfiles/sparc64.txt | 11 + .github/dependabot.yml | 12 + .github/workflows/meson_ci.yml | 342 ++++++++++++++++++++ LICENSE | 373 ++++++++++++++++++++++ README.md | 63 +++- code/logic/arguments.c | 173 ++++++++++ code/logic/command.c | 208 ++++++++++++ code/logic/exit.c | 87 +++++ code/logic/fossil/lib/arguments.h | 150 +++++++++ code/logic/fossil/lib/cnullptr.h | 66 ++++ code/logic/fossil/lib/command.h | 82 +++++ code/logic/fossil/lib/exit.h | 98 ++++++ code/logic/fossil/lib/framework.h | 25 ++ code/logic/fossil/lib/hostsys.h | 78 +++++ code/logic/fossil/lib/memory.h | 159 +++++++++ code/logic/fossil/lib/regex.h | 101 ++++++ code/logic/hostsys.c | 247 ++++++++++++++ code/logic/memory.c | 169 ++++++++++ code/logic/meson.build | 12 + code/logic/regex.c | 92 ++++++ code/meson.build | 2 + code/tests/meson.build | 20 ++ code/tests/test_arguments.c | 62 ++++ code/tests/test_cnullptr.c | 68 ++++ code/tests/test_command.c | 77 +++++ code/tests/test_hostsys.c | 43 +++ code/tests/test_memory.c | 157 +++++++++ code/tests/test_regex.c | 92 ++++++ code/tests/tools/generate-runner.py | 74 +++++ meson.build | 7 + meson.options | 9 + subprojects/fossil-test.wrap | 11 + 48 files changed, 3466 insertions(+), 2 deletions(-) create mode 100644 .github/.gitignore create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/ciimage/Dockerfile.archlinux create mode 100644 .github/ciimage/Dockerfile.debian create mode 100644 .github/ciimage/Dockerfile.fedora create mode 100644 .github/ciimage/Dockerfile.ubuntu create mode 100644 .github/crossfiles/arm.txt create mode 100644 .github/crossfiles/arm64.txt create mode 100644 .github/crossfiles/mips.txt create mode 100644 .github/crossfiles/mipsel.txt create mode 100644 .github/crossfiles/ppc.txt create mode 100644 .github/crossfiles/ppc64le.txt create mode 100644 .github/crossfiles/riscv64.txt create mode 100644 .github/crossfiles/s390x.txt create mode 100644 .github/crossfiles/sparc64.txt create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/meson_ci.yml create mode 100644 LICENSE create mode 100644 code/logic/arguments.c create mode 100644 code/logic/command.c create mode 100644 code/logic/exit.c create mode 100644 code/logic/fossil/lib/arguments.h create mode 100644 code/logic/fossil/lib/cnullptr.h create mode 100644 code/logic/fossil/lib/command.h create mode 100644 code/logic/fossil/lib/exit.h create mode 100644 code/logic/fossil/lib/framework.h create mode 100644 code/logic/fossil/lib/hostsys.h create mode 100644 code/logic/fossil/lib/memory.h create mode 100644 code/logic/fossil/lib/regex.h create mode 100644 code/logic/hostsys.c create mode 100644 code/logic/memory.c create mode 100644 code/logic/meson.build create mode 100644 code/logic/regex.c create mode 100644 code/meson.build create mode 100644 code/tests/meson.build create mode 100644 code/tests/test_arguments.c create mode 100644 code/tests/test_cnullptr.c create mode 100644 code/tests/test_command.c create mode 100644 code/tests/test_hostsys.c create mode 100644 code/tests/test_memory.c create mode 100644 code/tests/test_regex.c create mode 100644 code/tests/tools/generate-runner.py create mode 100644 meson.build create mode 100644 meson.options create mode 100644 subprojects/fossil-test.wrap diff --git a/.github/.gitignore b/.github/.gitignore new file mode 100644 index 0000000..1d3aa7f --- /dev/null +++ b/.github/.gitignore @@ -0,0 +1,4 @@ +builddir +.DS_Store +subprojects/** +.vscode/** \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..ef6c49b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,21 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Desktop (please complete the following information):** + - Host OS : `???` + - SKD Version: `???` diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..c201bde --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +# Fossil XSDK Pull Request + +## Description + + +## Testing + + +## Checklist + +- [ ] Code follows the project's coding standards. +- [ ] Tests have been added or updated to cover the changes. +- [ ] Documentation has been updated to reflect the changes. +- [ ] The code has been reviewed by team members. +- [ ] All checks and tests pass. +- [ ] The license header and notices are updated where necessary. + +## License + +This project is licensed under the Mozilla Public License - see the [LICENSE](LICENSE) file for details. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..a377c99 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,18 @@ +# Fossil XSDK Pull Request + +## Description + + +## Testing + + +## Checklist +- [ ] Code follows the project's coding standards. +- [ ] Tests have been added or updated to cover the changes. +- [ ] Documentation has been updated to reflect the changes. +- [ ] The code has been reviewed by team members. +- [ ] All checks and tests pass. +- [ ] The license header and notices are updated where necessary. + +## License +This project is licensed under the Mozilla Public License - see the [LICENSE](LICENSE) file for details. diff --git a/.github/ciimage/Dockerfile.archlinux b/.github/ciimage/Dockerfile.archlinux new file mode 100644 index 0000000..1b72564 --- /dev/null +++ b/.github/ciimage/Dockerfile.archlinux @@ -0,0 +1,33 @@ +# Use a specific Arch Linux base image +FROM archlinux:latest + +# Set environment variables to avoid interaction +ENV TZ=UTC + +# Update and install system dependencies +RUN pacman -Syu --noconfirm && \ + pacman -S --noconfirm \ + gcc \ + clang \ + gdb \ + llvm \ + rust \ + cargo \ + wget \ + python \ + python-pip \ + git \ + meson \ + ninja && \ + pacman -Scc --noconfirm + +# Set environment variables +ENV CC=/usr/bin/clang +ENV CXX=/usr/bin/clang++ +ENV LD_LIBRARY_PATH=/usr/local/lib + +# Set working directory +WORKDIR /workspace + +# Default command +CMD ["bash"] \ No newline at end of file diff --git a/.github/ciimage/Dockerfile.debian b/.github/ciimage/Dockerfile.debian new file mode 100644 index 0000000..f523a71 --- /dev/null +++ b/.github/ciimage/Dockerfile.debian @@ -0,0 +1,42 @@ +# Use a specific Debian base image +FROM debian:buster + +# Set environment variables to avoid interaction +ENV DEBIAN_FRONTEND=noninteractive \ + TZ=UTC + +# Install system dependencies and clean up +RUN apt-get update && \ + apt-get install -y \ + build-essential \ + clang \ + gcc \ + g++ \ + gdb \ + llvm \ + gobjc \ + gobjc++ \ + libobjc-8-dev \ + libstdc++-8-dev \ + rustc \ + cargo \ + wget \ + python3 \ + python3-pip \ + git && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Install Meson, Ninja, and Cython using pip +RUN python3 -m pip install --no-cache-dir meson ninja + +# Set environment variables +ENV CC=/usr/bin/clang +ENV CXX=/usr/bin/clang++ +ENV LD_LIBRARY_PATH=/usr/local/lib + +# Set working directory +WORKDIR /workspace + +# Default command +CMD ["bash"] \ No newline at end of file diff --git a/.github/ciimage/Dockerfile.fedora b/.github/ciimage/Dockerfile.fedora new file mode 100644 index 0000000..9fa4c00 --- /dev/null +++ b/.github/ciimage/Dockerfile.fedora @@ -0,0 +1,35 @@ +# Use a specific Fedora base image +FROM fedora:34 + +# Set environment variables to avoid interaction +ENV TZ=UTC + +# Install system dependencies and clean up +RUN dnf -y update && \ + dnf install -y \ + gcc \ + gcc-c++ \ + clang \ + gdb \ + llvm \ + rust \ + cargo \ + wget \ + python3 \ + python3-pip \ + git && \ + dnf clean all + +# Install Meson and Ninja using pip +RUN python3 -m pip install --no-cache-dir meson ninja + +# Set environment variables +ENV CC=/usr/bin/clang +ENV CXX=/usr/bin/clang++ +ENV LD_LIBRARY_PATH=/usr/local/lib64 + +# Set working directory +WORKDIR /workspace + +# Default command +CMD ["bash"] \ No newline at end of file diff --git a/.github/ciimage/Dockerfile.ubuntu b/.github/ciimage/Dockerfile.ubuntu new file mode 100644 index 0000000..4b33758 --- /dev/null +++ b/.github/ciimage/Dockerfile.ubuntu @@ -0,0 +1,37 @@ +# Use a specific Ubuntu base image +FROM ubuntu:20.04 + +# Set environment variables to avoid interaction +ENV DEBIAN_FRONTEND=noninteractive \ + TZ=UTC + +# Install system dependencies and clean up +RUN apt-get update && \ + apt-get install -y \ + build-essential \ + clang \ + gcc \ + g++ \ + gdb \ + llvm \ + gobjc \ + gobjc++ \ + libobjc-10-dev \ + libstdc++-10-dev \ + rustc \ + cargo \ + dub \ + wget \ + python3 \ + python3-pip \ + git && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Install Meson, Ninja, and Cython using pip +RUN python3 -m pip install --no-cache-dir meson ninja + +# Set environment variables +ENV CC=/usr/bin/gcc +ENV CXX=/usr/bin/g++ +ENV LD_LIBRARY_PATH=/usr/local/lib diff --git a/.github/crossfiles/arm.txt b/.github/crossfiles/arm.txt new file mode 100644 index 0000000..360cc6d --- /dev/null +++ b/.github/crossfiles/arm.txt @@ -0,0 +1,11 @@ +[binaries] +c = 'arm-linux-gnueabi-gcc' +cpp = 'arm-linux-gnueabi-g++' +ar = 'arm-linux-gnueabi-ar' +strip = 'arm-linux-gnueabi-strip' + +[host_machine] +system = 'linux' +cpu_family = 'arm' +cpu = 'armv7' +endian = 'little' \ No newline at end of file diff --git a/.github/crossfiles/arm64.txt b/.github/crossfiles/arm64.txt new file mode 100644 index 0000000..930248f --- /dev/null +++ b/.github/crossfiles/arm64.txt @@ -0,0 +1,11 @@ +[binaries] +c = 'aarch64-linux-gnu-gcc' +cpp = 'aarch64-linux-gnu-g++' +ar = 'aarch64-linux-gnu-ar' +strip = 'aarch64-linux-gnu-strip' + +[host_machine] +system = 'linux' +cpu_family = 'aarch64' +cpu = 'aarch64' +endian = 'little' \ No newline at end of file diff --git a/.github/crossfiles/mips.txt b/.github/crossfiles/mips.txt new file mode 100644 index 0000000..825becf --- /dev/null +++ b/.github/crossfiles/mips.txt @@ -0,0 +1,11 @@ +[binaries] +c = 'mips-linux-gnu-gcc' +cpp = 'mips-linux-gnu-g++' +ar = 'mips-linux-gnu-ar' +strip = 'mips-linux-gnu-strip' + +[host_machine] +system = 'linux' +cpu_family = 'mips' +cpu = 'mips' +endian = 'big' \ No newline at end of file diff --git a/.github/crossfiles/mipsel.txt b/.github/crossfiles/mipsel.txt new file mode 100644 index 0000000..44aab07 --- /dev/null +++ b/.github/crossfiles/mipsel.txt @@ -0,0 +1,11 @@ +[binaries] +c = 'mipsel-linux-gnu-gcc' +cpp = 'mipsel-linux-gnu-g++' +ar = 'mipsel-linux-gnu-ar' +strip = 'mipsel-linux-gnu-strip' + +[host_machine] +system = 'linux' +cpu_family = 'mips' +cpu = 'mipsel' +endian = 'little' \ No newline at end of file diff --git a/.github/crossfiles/ppc.txt b/.github/crossfiles/ppc.txt new file mode 100644 index 0000000..42ce6e1 --- /dev/null +++ b/.github/crossfiles/ppc.txt @@ -0,0 +1,11 @@ +[binaries] +c = 'powerpc-linux-gnu-gcc' +cpp = 'powerpc-linux-gnu-g++' +ar = 'powerpc-linux-gnu-ar' +strip = 'powerpc-linux-gnu-strip' + +[host_machine] +system = 'linux' +cpu_family = 'ppc' +cpu = 'powerpc' +endian = 'big' \ No newline at end of file diff --git a/.github/crossfiles/ppc64le.txt b/.github/crossfiles/ppc64le.txt new file mode 100644 index 0000000..6150635 --- /dev/null +++ b/.github/crossfiles/ppc64le.txt @@ -0,0 +1,11 @@ +[binaries] +c = 'powerpc64le-linux-gnu-gcc' +cpp = 'powerpc64le-linux-gnu-g++' +ar = 'powerpc64le-linux-gnu-ar' +strip = 'powerpc64le-linux-gnu-strip' + +[host_machine] +system = 'linux' +cpu_family = 'ppc64' +cpu = 'ppc64le' +endian = 'little' \ No newline at end of file diff --git a/.github/crossfiles/riscv64.txt b/.github/crossfiles/riscv64.txt new file mode 100644 index 0000000..26d0198 --- /dev/null +++ b/.github/crossfiles/riscv64.txt @@ -0,0 +1,11 @@ +[binaries] +c = 'riscv64-linux-gnu-gcc' +cpp = 'riscv64-linux-gnu-g++' +ar = 'riscv64-linux-gnu-ar' +strip = 'riscv64-linux-gnu-strip' + +[host_machine] +system = 'linux' +cpu_family = 'riscv' +cpu = 'riscv64' +endian = 'little' \ No newline at end of file diff --git a/.github/crossfiles/s390x.txt b/.github/crossfiles/s390x.txt new file mode 100644 index 0000000..b661504 --- /dev/null +++ b/.github/crossfiles/s390x.txt @@ -0,0 +1,11 @@ +[binaries] +c = 's390x-linux-gnu-gcc' +cpp = 's390x-linux-gnu-g++' +ar = 's390x-linux-gnu-ar' +strip = 's390x-linux-gnu-strip' + +[host_machine] +system = 'linux' +cpu_family = 's390x' +cpu = 's390x' +endian = 'big' \ No newline at end of file diff --git a/.github/crossfiles/sparc64.txt b/.github/crossfiles/sparc64.txt new file mode 100644 index 0000000..abe6b0e --- /dev/null +++ b/.github/crossfiles/sparc64.txt @@ -0,0 +1,11 @@ +[binaries] +c = 'sparc64-linux-gnu-gcc' +cpp = 'sparc64-linux-gnu-g++' +ar = 'sparc64-linux-gnu-ar' +strip = 'sparc64-linux-gnu-strip' + +[host_machine] +system = 'linux' +cpu_family = 'sparc64' +cpu = 'sparc64' +endian = 'big' \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..5d16764 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# Dependabot configuration file for GitHub Actions dependencies +version: 2 + +updates: + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Update dependencies weekly + interval: "weekly" + # Set update time to early morning + time: "05:55" diff --git a/.github/workflows/meson_ci.yml b/.github/workflows/meson_ci.yml new file mode 100644 index 0000000..16372d3 --- /dev/null +++ b/.github/workflows/meson_ci.yml @@ -0,0 +1,342 @@ +name: Meson CI + +on: + push: + paths: + - "**.c" + - "**.h" + - "**.kt" + - "**.py" + - "meson.**" + pull_request: + paths: + - "**.c" + - "**.h" + - "**.kt" + - "**.py" + - "meson.**" + +jobs: + build_msvc: + name: Building on MSVC ${{ matrix.msvc_version }} + runs-on: windows-latest + strategy: + matrix: + msvc_version: [2015, 2017, 2019, 2022] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Meson and Ninja + shell: pwsh + run: | + python -m pip install --upgrade pip + python -m pip install meson ninja + if ($env:msvc_version -eq "2015") { + choco install visualstudio2015buildtools --package-parameters "--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --includeRecommended --includeOptional --passive" + } elseif ($env:msvc_version -eq "2017") { + choco install visualstudio2017buildtools --package-parameters "--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --includeOptional --passive" + } elseif ($env:msvc_version -eq "2019") { + choco install visualstudio2019buildtools --package-parameters "--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --includeOptional --passive" + } elseif ($env:msvc_version -eq "2022") { + choco install visualstudio2022buildtools --package-parameters "--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --includeOptional --passive" + } + $env:CC="cl.exe" + $env:CXX="cl.exe" + + - name: Configure + run: meson setup builddir_msvc_${{ matrix.msvc_version }} --fatal-meson-warnings -Dwerror=true -Dwith_test=enabled -Dwarning_level=3 + + - name: Compile + run: meson compile -C builddir_msvc_${{ matrix.msvc_version }} + + - name: Run Tests + run: meson test -C builddir_msvc_${{ matrix.msvc_version }} -v + + - name: Upload Test Log + if: failure() + uses: actions/upload-artifact@v4 + with: + name: windows_msvc_${{ matrix.msvc_version }}_meson_testlog + path: builddir_msvc_${{ matrix.msvc_version }}/meson-logs/testlog.txt + + build_macosx: + name: Building on macOS with Xcode ${{ matrix.xcode_version }} + runs-on: macos-latest + strategy: + matrix: + xcode_version: ["15.2", "15.3"] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Xcode + run: sudo xcode-select --switch /Applications/Xcode_${{ matrix.xcode_version }}.app + + - name: Install Meson and Ninja + run: | + python -m pip install meson ninja + + - name: Configure + run: meson setup builddir --fatal-meson-warnings -Dwerror=true -Dwith_test=enabled -Dwarning_level=3 + + - name: Compile + run: meson compile -C builddir + + - name: Run Tests + run: meson test -C builddir -v + + - name: Upload Test Log + if: failure() + uses: actions/upload-artifact@v4 + with: + name: macos_xcode_${{ matrix.xcode_version }}_meson_testlog + path: builddir/meson-logs/testlog.txt + + build_msys: + name: Building on MSYS ${{ matrix.architecture }} + runs-on: windows-latest + strategy: + matrix: + architecture: [x86, x64] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up MSYS2 + uses: msys2/setup-msys2@v2 + with: + update: true + + - name: Set environment variables + run: | + echo "CC=/mingw${{ matrix.architecture }}/bin/gcc.exe" >> $GITHUB_ENV + echo "CXX=/mingw${{ matrix.architecture }}/bin/g++.exe" >> $GITHUB_ENV + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Meson and Ninja + run: | + python -m pip install meson ninja + + - name: Configure + run: meson setup builddir --fatal-meson-warnings -Dwerror=true -Dwith_test=enabled -Dwarning_level=3 + + - name: Compile + run: meson compile -C builddir + + - name: Run Tests + run: meson test -C builddir -v + + - name: Upload Test Log + if: failure() + uses: actions/upload-artifact@v4 + with: + name: msys_${{ matrix.architecture }}_meson_testlog + path: builddir/meson-logs/testlog.txt + + build_mingw: + name: Building on MinGW ${{ matrix.architecture }} + runs-on: windows-latest + strategy: + matrix: + architecture: [x86, x64] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install MinGW + run: | + choco install mingw + + - name: Set environment variables + run: | + if ($env:matrix_architecture -eq "x86") { + $env:CC="C:/tools/mingw32/bin/gcc.exe" + $env:CXX="C:/tools/mingw32/bin/g++.exe" + } else { + $env:CC="C:/tools/mingw64/bin/gcc.exe" + $env:CXX="C:/tools/mingw64/bin/g++.exe" + } + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Meson and Ninja + run: | + python -m pip install meson ninja + + - name: Configure + run: meson setup builddir --fatal-meson-warnings -Dwerror=true -Dwith_test=enabled -Dwarning_level=3 + + - name: Compile + run: meson compile -C builddir + + - name: Run Tests + run: meson test -C builddir -v + + - name: Upload Test Log + if: failure() + uses: actions/upload-artifact@v4 + with: + name: mingw_${{ matrix.architecture }}_meson_testlog + path: builddir/meson-logs/testlog.txt + + build_posix: + name: Build on Linux ${{ matrix.distro }} + runs-on: ubuntu-latest + + strategy: + matrix: + distro: [ubuntu, debian, fedora, archlinux] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Cache Docker layers + uses: actions/cache@v4 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ matrix.distro }} + restore-keys: | + ${{ runner.os }}-buildx + + - name: Build Docker Image + run: | + docker build \ + --file .github/ciimage/Dockerfile.${{ matrix.distro }} \ + --tag ${GITHUB_REPOSITORY}:${{ matrix.distro }} . + + - name: Run Meson Build in Docker Container + run: | + docker run --rm \ + -v ${{ github.workspace }}:/workspace \ + -w /workspace \ + ${GITHUB_REPOSITORY}:${{ matrix.distro }} \ + /bin/bash -c " + meson setup builddir --fatal-meson-warnings -Dwerror=true -Dwith_test=enabled -Dwarning_level=3 -Dc_std=c17 -Dfossil-test:c_std=c17 + meson compile -C builddir + meson test -C builddir -v" + + build_cross: + name: Building on Bedrock ${{ matrix.architecture }} + runs-on: ubuntu-latest # Using Ubuntu as the base system for cross-compilation + + strategy: + matrix: + architecture: [arm, arm64, mips, mipsel, riscv64, ppc, ppc64le, sparc64, s390x] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Cross-Compilation Toolchain + run: | + sudo apt-get update + if [ "${{ matrix.architecture }}" == "arm" ]; then + sudo apt-get install -y gcc-arm-linux-gnueabi g++-arm-linux-gnueabi + elif [ "${{ matrix.architecture }}" == "arm64" ]; then + sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu + elif [ "${{ matrix.architecture }}" == "mips" ]; then + sudo apt-get install -y gcc-mips-linux-gnu g++-mips-linux-gnu + elif [ "${{ matrix.architecture }}" == "mipsel" ]; then + sudo apt-get install -y gcc-mipsel-linux-gnu g++-mipsel-linux-gnu + elif [ "${{ matrix.architecture }}" == "riscv64" ]; then + sudo apt-get install -y gcc-riscv64-linux-gnu g++-riscv64-linux-gnu + elif [ "${{ matrix.architecture }}" == "ppc" ]; then + sudo apt-get install -y gcc-powerpc-linux-gnu g++-powerpc-linux-gnu + elif [ "${{ matrix.architecture }}" == "ppc64le" ]; then + sudo apt-get install -y gcc-powerpc64le-linux-gnu g++-powerpc64le-linux-gnu + elif [ "${{ matrix.architecture }}" == "sparc64" ]; then + sudo apt-get install -y gcc-sparc64-linux-gnu g++-sparc64-linux-gnu + elif [ "${{ matrix.architecture }}" == "s390x" ]; then + sudo apt-get install -y gcc-s390x-linux-gnu g++-s390x-linux-gnu + fi + + - name: Set Cross-Compilation Environment Variables + run: | + if [ "${{ matrix.architecture }}" == "arm" ]; then + echo "CC=arm-linux-gnueabi-gcc" >> $GITHUB_ENV + echo "CXX=arm-linux-gnueabi-g++" >> $GITHUB_ENV + echo "CROSS_FILE=.github/crossfiles/arm.txt" >> $GITHUB_ENV + elif [ "${{ matrix.architecture }}" == "arm64" ]; then + echo "CC=aarch64-linux-gnu-gcc" >> $GITHUB_ENV + echo "CXX=aarch64-linux-gnu-g++" >> $GITHUB_ENV + echo "CROSS_FILE=.github/crossfiles/arm64.txt" >> $GITHUB_ENV + elif [ "${{ matrix.architecture }}" == "mips" ]; then + echo "CC=mips-linux-gnu-gcc" >> $GITHUB_ENV + echo "CXX=mips-linux-gnu-g++" >> $GITHUB_ENV + echo "CROSS_FILE=.github/crossfiles/mips.txt" >> $GITHUB_ENV + elif [ "${{ matrix.architecture }}" == "mipsel" ]; then + echo "CC=mipsel-linux-gnu-gcc" >> $GITHUB_ENV + echo "CXX=mipsel-linux-gnu-g++" >> $GITHUB_ENV + echo "CROSS_FILE=.github/crossfiles/mipsel.txt" >> $GITHUB_ENV + elif [ "${{ matrix.architecture }}" == "riscv64" ]; then + echo "CC=riscv64-linux-gnu-gcc" >> $GITHUB_ENV + echo "CXX=riscv64-linux-gnu-g++" >> $GITHUB_ENV + echo "CROSS_FILE=.github/crossfiles/riscv64.txt" >> $GITHUB_ENV + elif [ "${{ matrix.architecture }}" == "ppc" ]; then + echo "CC=powerpc-linux-gnu-gcc" >> $GITHUB_ENV + echo "CXX=powerpc-linux-gnu-g++" >> $GITHUB_ENV + echo "CROSS_FILE=.github/crossfiles/ppc.txt" >> $GITHUB_ENV + elif [ "${{ matrix.architecture }}" == "ppc64le" ]; then + echo "CC=powerpc64le-linux-gnu-gcc" >> $GITHUB_ENV + echo "CXX=powerpc64le-linux-gnu-g++" >> $GITHUB_ENV + echo "CROSS_FILE=.github/crossfiles/ppc64le.txt" >> $GITHUB_ENV + elif [ "${{ matrix.architecture }}" == "sparc64" ]; then + echo "CC=sparc64-linux-gnu-gcc" >> $GITHUB_ENV + echo "CXX=sparc64-linux-gnu-g++" >> $GITHUB_ENV + echo "CROSS_FILE=.github/crossfiles/sparc64.txt" >> $GITHUB_ENV + elif [ "${{ matrix.architecture }}" == "s390x" ]; then + echo "CC=s390x-linux-gnu-gcc" >> $GITHUB_ENV + echo "CXX=s390x-linux-gnu-g++" >> $GITHUB_ENV + echo "CROSS_FILE=.github/crossfiles/s390x.txt" >> $GITHUB_ENV + fi + + - name: Install Meson + run: | + python -m pip install meson ninja + + - name: Configure the Project + run: | + meson setup builddir --fatal-meson-warnings -Dwerror=true -Dwith_test=enabled -Dwarning_level=3 --cross-file $CROSS_FILE + + - name: Build the Project + run: | + meson compile -C builddir \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..da8048a --- /dev/null +++ b/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be consEXIT_SUCCESSd against the drafter +shall not be used to consEXIT_SUCCESS this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/README.md b/README.md index bc7bbb1..f341d1f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,61 @@ -# fossil-lib -Fossil Lib is a versatile, cross-platform utilities library designed to provide essential functionalities for high-performance application development. It includes a suite of common utilities such as host system interaction, command execution, secure exit handling, a cnullptr type definition, regular expressions, and secure memory management. +# **Fossil Lib by Fossil Logic** + +Fossil Lib is a versatile, cross-platform utilities library designed to provide essential functionalities for high-performance application development. It includes a suite of common utilities such as host system interaction, command execution, secure exit handling, a cnullptr type definition, regular expressions, and secure memory management. Fossil Lib is implemented in both C and C++ and is optimized for consistency and efficiency across various operating systems. + +## Key Features + +1. **Cross-Platform Compatibility**: Provides a uniform interface and consistent behavior across major operating systems, including Windows, macOS, and Linux. +2. **Modular Design**: Contains modular components that can be easily integrated and customized for specific project needs. +3. **Efficient Build System**: Built using the Meson build system, which ensures fast build times and a straightforward development process. +4. **High Performance**: Developed in C and C++ to maximize performance and resource efficiency, suitable for both desktop and embedded systems. +5. **Extensive Documentation**: Offers comprehensive documentation and examples to help developers quickly understand and utilize the library. + +## Prerequisites + +Before using Fossil Lib, ensure you have the following: + +- **Meson Build System**: Install Meson to manage the build process. For installation or upgrading, use: + + ```sh + python -m pip install meson # to install Meson + python -m pip install --upgrade meson # to upgrade Meson + ``` + +## Adding Dependency + +1. **Install Meson Build System**: Ensure Meson `1.3` or newer is installed on your system. + +2. **Add Wrap File**: Create a `.wrap` file (e.g., `fossil-lib.wrap`) in the `subprojects` directory with the following content: + + ```ini + # ====================== + # Git Wrap package definition + # ====================== + [wrap-git] + url = https://github.com/fossillogic/fossil-lib.git + revision = v0.1.0 + + [provide] + fossil-lib = fossil_lib_dep + ``` + +3. **Integrate Dependency**: Add the dependency in your `meson.build` file: + + ```ini + dep = dependency('fossil-lib') + ``` + +## Configure Options + +- **Running Tests**: Enable testing by configuring with `-Dwith_test=enabled`. + +Example: + +```sh +meson setup builddir -Dwith_test=enabled +``` + +## Contributing and Support + +For contributions, issues, or support, please open an issue on the project repository or visit the [Fossil Logic Docs](https://fossillogic.com/docs) for more information. Contributions and feedback are always appreciated. + diff --git a/code/logic/arguments.c b/code/logic/arguments.c new file mode 100644 index 0000000..6b68c31 --- /dev/null +++ b/code/logic/arguments.c @@ -0,0 +1,173 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include "fossil/lib/arguments.h" +#include +#include + +// Function to check if an option has been parsed +int32_t fossil_arg_parse_has(fossil_option_t* options, int32_t num_options, const char* option_name) { + for (int32_t i = 0; i < num_options; ++i) { + if (strcmp(option_name, options[i].name) == 0 && options[i].parsed) { + return 1; // Option has been parsed + } + } + return 0; // Option not found or not parsed +} + +void fossil_arg_parse_usage(const char* program_name, fossil_option_t* options, int32_t num_options) { + if (!program_name || !options) { + fprintf(stderr, "Error: Invalid program name or options.\n"); + return; + } + + printf("Usage: %s [options]\n\nOptions:\n", program_name); + for (int32_t i = 0; i < num_options; ++i) { + if (!options[i].name) { + fprintf(stderr, "Error: Invalid option name.\n"); + continue; + } + + printf(" -%s", options[i].name); + switch (options[i].type) { + case COPTION_TYPE_INT: + printf(" "); + break; + case COPTION_TYPE_STRING: + printf(" "); + break; + case COPTION_TYPE_BOOL: + printf(" (flag)"); + break; + case COPTION_TYPE_COMBO: + printf(" {%s}", ((fossil_combo_choice_t*)options[i].extra_data)[0].name); + for (int j = 1; j < options[i].num_choices; ++j) { + printf("|%s", ((fossil_combo_choice_t*)options[i].extra_data)[j].name); + } + break; + case COPTION_TYPE_FEATURE: + printf(" {enable|disable|auto}"); + break; + default: + fprintf(stderr, "Error: Invalid option type.\n"); + } + printf("\n"); + } +} + +void fossil_arg_parse(fossil_command_line_t* cmd, fossil_option_t* options, int32_t num_options) { + if (!cmd || !options) { + fprintf(stderr, "Error: Invalid command line or options.\n"); + return; + } + + for (int32_t i = 1; i < cmd->argc; ++i) { + const char* arg = cmd->argv[i]; + if (arg[0] == '-') { + // Parse options + for (int32_t j = 0; j < num_options; ++j) { + if (strcmp(arg + 1, options[j].name) == 0) { + options[j].parsed = 1; // Mark the option as parsed + switch (options[j].type) { + case COPTION_TYPE_INT: + if (i + 1 < cmd->argc) { + options[j].value.int_val = atoi(cmd->argv[++i]); + } else { + fprintf(stderr, "Error: Missing argument for option '-%s'.\n", options[j].name); + } + break; + case COPTION_TYPE_STRING: + if (i + 1 < cmd->argc) { + options[j].value.str_val = cmd->argv[++i]; + } else { + fprintf(stderr, "Error: Missing argument for option '-%s'.\n", options[j].name); + } + break; + // Handle other option types similarly + default: + fprintf(stderr, "Error: Unsupported option type.\n"); + } + break; // Found and parsed the option, move to the next argument + } + } + } + } +} + + +void fossil_arg_check_unrecognized(fossil_command_line_t* cmd, fossil_option_t* options, int32_t num_options) { + for (int32_t i = 1; i < cmd->argc; ++i) { + const char* arg = cmd->argv[i]; + if (arg[0] == '-') { + int32_t recognized = 0; + for (int32_t j = 0; j < num_options; ++j) { + if (strcmp(arg + 1, options[j].name) == 0) { + recognized = 1; + break; + } + } + if (!recognized) { + fprintf(stderr, "Error: Unrecognized option '%s'\n", arg); + exit(EXIT_FAILURE); + } + } + } +} + +void fossil_arg_print_parsed_options(fossil_option_t* options, int32_t num_options) { + for (int32_t i = 0; i < num_options; ++i) { + printf("Option: %s, Parsed: %s\n", options[i].name, options[i].parsed ? "true" : "false"); + } +} + +void fossil_arg_reset_parsed_flags(fossil_option_t* options, int32_t num_options) { + for (int32_t i = 0; i < num_options; ++i) { + options[i].parsed = 0; + } +} + +// Function to create combo choices +fossil_combo_choice_t* fossil_arg_create_fossil_combo_choice_ts(const char* names[], const int32_t values[], int32_t num_choices) { + fossil_combo_choice_t* choices = malloc(num_choices * sizeof(fossil_combo_choice_t)); + if (!choices) { + fprintf(stderr, "Memory allocation error for combo choices.\n"); + exit(EXIT_FAILURE); + } + + for (int32_t i = 0; i < num_choices; ++i) { + choices[i].name = names[i]; + choices[i].value = values[i]; + } + + return choices; +} + +// Function to create options +fossil_option_t* fossil_arg_create_options(const char* names[], fossil_option_type_t types[], fossil_option_value_t values[], void* extra_data[], int32_t num_options) { + fossil_option_t* options = malloc(num_options * sizeof(fossil_option_t)); + if (!options) { + fprintf(stderr, "Memory allocation error for options.\n"); + exit(EXIT_FAILURE); + } + + for (int32_t i = 0; i < num_options; ++i) { + options[i].name = names[i]; + options[i].type = types[i]; + options[i].value = values[i]; + options[i].extra_data = extra_data[i]; + options[i].parsed = 0; + options[i].num_choices = 0; + } + + return options; +} diff --git a/code/logic/command.c b/code/logic/command.c new file mode 100644 index 0000000..fe2b231 --- /dev/null +++ b/code/logic/command.c @@ -0,0 +1,208 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include "fossil/lib/command.h" +#include +#include +#include +#include +#include + +#include + +#ifdef _WIN32 + #include + #define _FOSSIL_PATH_SEPARATOR ";" +#else + #include + #include + #include + #define _FOSSIL_PATH_SEPARATOR ":" +#endif + +// Define a typedef for char* to make the code more readable +typedef char* fossil_command_t; + +// Function to run a command +int32_t fossil_command(fossil_command_t process) { + int32_t result = system(process); + if (result == -1) { + perror("Error executing command"); + } + return result; +} // end of func + +// Function to check if the command executed successfully +int32_t fossil_command_success(fossil_command_t process) { + int32_t result = fossil_command(process); + if (result == 0) { + printf("Command '%s' executed successfully.\n", process); + } else { + fprintf(stderr, "Error executing command '%s'.\n", process); + } + return result; +} // end of func + +// Function to get the output of a command +int32_t fossil_command_output(fossil_command_t process, char *output, size_t output_size) { +#ifdef _WIN32 + FILE *pipe = _popen(process, "r"); + if (!pipe) { + perror("Error opening pipe"); + return -1; + } + + size_t bytesRead = fread(output, 1, output_size - 1, pipe); + output[bytesRead] = '\0'; + + if (ferror(pipe)) { + perror("Error reading from pipe"); + _pclose(pipe); + return -1; + } + + int32_t status = _pclose(pipe); + if (status == -1) { + perror("Error closing pipe"); + } + + return status; +#else + int32_t pipe_fd[2]; + pid_t child_pid; + + // Create a pipe + if (pipe(pipe_fd) == -1) { + perror("Error creating pipe"); + return -1; + } + + // Fork a child process + if ((child_pid = fork()) == -1) { + perror("Error forking process"); + close(pipe_fd[0]); + close(pipe_fd[1]); + return -1; + } + + if (child_pid == 0) { + // Child process + close(pipe_fd[0]); // Close the read end of the pipe + + // Redirect stdout to the pipe + if (dup2(pipe_fd[1], STDOUT_FILENO) == -1) { + perror("Error redirecting stdout"); + exit(EXIT_FAILURE); + } + + // Close the unused write end of the pipe + close(pipe_fd[1]); + + // Execute the command + execl("/bin/sh", "/bin/sh", "-c", process, (char *)NULL); + perror("Error executing command"); + exit(EXIT_FAILURE); + } else { + // Parent process + close(pipe_fd[1]); // Close the write end of the pipe + + // Read the output from the pipe + size_t bytesRead = read(pipe_fd[0], output, output_size - 1); + if (bytesRead == (size_t)-1) { + perror("Error reading from pipe"); + close(pipe_fd[0]); + waitpid(child_pid, NULL, 0); // Wait for the child process to complete + return -1; + } + + // Null-terminate the output + output[bytesRead] = '\0'; + + close(pipe_fd[0]); // Close the read end of the pipe + + // Wait for the child process to complete + waitpid(child_pid, NULL, 0); + + return 0; // Success + } +#endif +} // end of func + +// Function to check if a command exists and is executable +int32_t fossil_command_exists(fossil_command_t process) { +#ifdef _WIN32 + // On Windows, check if the command exists in the system path + const char* env_path = getenv("PATH"); + if (env_path != NULL) { + char path_copy[1024]; + strcpy(path_copy, env_path); + + char* token = strtok(path_copy, _FOSSIL_PATH_SEPARATOR); + while (token != NULL) { + char full_path[1024]; + snprintf(full_path, sizeof(full_path), "%s\\%s", token, process); + if (GetFileAttributes(full_path) != INVALID_FILE_ATTRIBUTES) { + printf("Command '%s' exists and is executable.\n", process); + return 1; + } + token = strtok(NULL, _FOSSIL_PATH_SEPARATOR); + } + } + fprintf(stderr, "Command '%s' does not exist or is not executable.\n", process); + return 0; +#else + // On Unix-like systems, use the access function + if (access(process, X_OK) == 0) { + printf("Command '%s' exists and is executable.\n", process); + return 1; + } else { + fprintf(stderr, "Command '%s' does not exist or is not executable.\n", process); + return 0; + } +#endif +} // end of function + +// Function to concatenate strings safely +void fossil_command_strcat_safe(char * restrict dest, const char * restrict src, size_t dest_size) { + size_t dest_len = strlen(dest); + size_t src_len = strlen(src); + + // Calculate available space in dest buffer, including null terminator + size_t space_left = dest_size - dest_len - 1; + + // Copy only the part of src that fits in the remaining space + size_t copy_len = (src_len < space_left) ? src_len : space_left; + + // Append src to dest + strncat(dest, src, copy_len); + + // Ensure null-termination + dest[dest_size - 1] = '\0'; +} // end of func + +// Function to check if a directory exists +int32_t fossil_command_erase_exists(fossil_command_t path) { + if (!path) { + fprintf(stderr, "Error: Null path provided.\n"); + return 0; + } + + struct stat info; + if (stat(path, &info) == 0 && S_ISDIR(info.st_mode)) { + printf("Directory '%s' exists.\n", path); + return 1; + } else { + printf("Directory '%s' does not exist.\n", path); + return 0; + } +} // end of func diff --git a/code/logic/exit.c b/code/logic/exit.c new file mode 100644 index 0000000..36d4780 --- /dev/null +++ b/code/logic/exit.c @@ -0,0 +1,87 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include "fossil/lib/exit.h" +#include +#include + +// Static array to track registered functions (optional) +#define MAX_REGISTERED_FUNCS 100 +static fossil_handle_func_t registered_funcs[MAX_REGISTERED_FUNCS]; +static int func_count = 0; + +void fossil_handle_abort(void) { + fprintf(stderr, "Program aborted unexpectedly.\n"); + abort(); +} + +void fossil_handle_exit(int status) { + fprintf(stderr, "Program exiting with status: %d\n", status); + exit(status); // Standard exit, will run atexit handlers +} + +void fossil_handle_quick_exit(int status) { + fprintf(stderr, "Program quickly exiting with status: %d\n", status); + quick_exit(status); // Quickly exits, but runs at_quick_exit handlers +} + +void fossil_handle__Exit(int status) { + fprintf(stderr, "Program exiting without cleanup, status: %d\n", status); + _Exit(status); // Immediately exits without cleanup +} + +int fossil_handle_atexit(fossil_handle_func_t func) { + if (!func) { + fprintf(stderr, "Error: NULL function pointer cannot be registered with atexit.\n"); + return FOSSIL_EXIT_FAILURE; + } + + // Check if the function is already registered + for (int i = 0; i < func_count; ++i) { + if (registered_funcs[i] == func) { + fprintf(stderr, "Error: Function already registered with atexit.\n"); + return FOSSIL_EXIT_FAILURE; + } + } + + // Register function + if (atexit(func) != 0) { + fprintf(stderr, "Error: Could not register atexit function.\n"); + return FOSSIL_EXIT_FAILURE; + } + + // Store function in the registered list + if (func_count < MAX_REGISTERED_FUNCS) { + registered_funcs[func_count++] = func; + } else { + fprintf(stderr, "Error: Maximum number of atexit functions reached.\n"); + return FOSSIL_EXIT_FAILURE; + } + + return FOSSIL_EXIT_SUCCESS; +} + +int fossil_handle_at_quick_exit(fossil_handle_func_t func) { + if (!func) { + fprintf(stderr, "Error: NULL function pointer cannot be registered with at_quick_exit.\n"); + return FOSSIL_EXIT_FAILURE; + } + + // Register function for quick exit + if (at_quick_exit(func) != 0) { + fprintf(stderr, "Error: Could not register at_quick_exit function.\n"); + return FOSSIL_EXIT_FAILURE; + } + + return FOSSIL_EXIT_SUCCESS; +} diff --git a/code/logic/fossil/lib/arguments.h b/code/logic/fossil/lib/arguments.h new file mode 100644 index 0000000..05327f4 --- /dev/null +++ b/code/logic/fossil/lib/arguments.h @@ -0,0 +1,150 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#ifndef FOSSIL_LIB_ARGS_H +#define FOSSIL_LIB_ARGS_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Option types +typedef enum { + COPTION_TYPE_INT, + COPTION_TYPE_STRING, + COPTION_TYPE_BOOL, + COPTION_TYPE_COMBO, + COPTION_TYPE_FEATURE +} fossil_option_type_t; + +// Feature values +typedef enum { + FEATURE_ENABLE, + FEATURE_DISABLE, + FEATURE_AUTO +} fossil_option_feature_t; + +// Combo choice structure +typedef struct { + const char* name; + int32_t value; +} fossil_combo_choice_t; + +// Option value union +typedef union { + int32_t int_val; + char* str_val; + int32_t bool_val; + int32_t combo_val; + fossil_option_feature_t feature_val; +} fossil_option_value_t; + +// Option structure +typedef struct { + const char* name; + fossil_option_type_t type; + fossil_option_value_t value; + void* extra_data; // Used for choices in COPTION_TYPE_COMBO + int32_t num_choices; // Used for choices in COPTION_TYPE_COMBO + int32_t parsed; // Flag to indicate if the option is parsed +} fossil_option_t; + +// Command line structure +typedef struct { + int argc; + char** argv; +} fossil_command_line_t; + +/** + * Print the usage information for command-line argument parsing. + * + * @param program_name The name of the program. + * @param options Array of fossil_option_t structures representing available options. + * @param num_options The number of options in the array. + */ +void fossil_arg_parse_usage(const char* program_name, fossil_option_t* options, int32_t num_options); + +/** + * Check if a specific option is present in the parsed command-line arguments. + * + * @param options Array of fossil_option_t structures representing available options. + * @param num_options The number of options in the array. + * @param option_name The name of the option to check for. + * @return 1 if the option is present, 0 otherwise. + */ +int32_t fossil_arg_parse_has(fossil_option_t* options, int32_t num_options, const char* option_name); + +/** + * Parse the command-line arguments based on the provided options. + * + * @param cmd Pointer to the fossil_command_line_t structure representing parsed command-line arguments. + * @param options Array of fossil_option_t structures representing available options. + * @param num_options The number of options in the array. + */ +void fossil_arg_parse(fossil_command_line_t* cmd, fossil_option_t* options, int32_t num_options); + +/** + * Check for unrecognized command-line arguments and print an error message if found. + * + * @param cmd Pointer to the fossil_command_line_t structure representing parsed command-line arguments. + * @param options Array of fossil_option_t structures representing available options. + * @param num_options The number of options in the array. + */ +void fossil_arg_check_unrecognized(fossil_command_line_t* cmd, fossil_option_t* options, int32_t num_options); + +/** + * Print the parsed options along with their values. + * + * @param options Array of fossil_option_t structures representing available options. + * @param num_options The number of options in the array. + */ +void fossil_arg_print_parsed_options(fossil_option_t* options, int32_t num_options); + +/** + * Reset the parsed flags of the options to their initial state. + * + * @param options Array of fossil_option_t structures representing available options. + * @param num_options The number of options in the array. + */ +void fossil_arg_reset_parsed_flags(fossil_option_t* options, int32_t num_options); + +/** + * Create an array of fossil_combo_choice_t structures for combo-box style options. + * + * @param names Array of names for the combo choices. + * @param values Array of values associated with each choice. + * @param num_choices The number of combo choices in the arrays. + * @return Pointer to the created array of fossil_combo_choice_t structures. + */ +fossil_combo_choice_t* fossil_arg_create_fossil_combo_choice_ts(const char* names[], const int32_t values[], int32_t num_choices); + +/** + * Create an array of fossil_option_t structures for command-line argument parsing. + * + * @param names Array of names for the options. + * @param types Array of fossil_option_type_t indicating the types of the options. + * @param values Array of fossil_option_value_t representing default values for the options. + * @param extra_data Array of pointers to extra data associated with each option (can be NULL). + * @param num_options The number of options in the arrays. + * @return Pointer to the created array of fossil_option_t structures. + */ +fossil_option_t* fossil_arg_create_options(const char* names[], fossil_option_type_t types[], fossil_option_value_t values[], void* extra_data[], int32_t num_options); + +#ifdef __cplusplus +} +#endif + +#endif /* FOSSIL_LIB_FRAMEWORK_H */ diff --git a/code/logic/fossil/lib/cnullptr.h b/code/logic/fossil/lib/cnullptr.h new file mode 100644 index 0000000..b6b1240 --- /dev/null +++ b/code/logic/fossil/lib/cnullptr.h @@ -0,0 +1,66 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#ifndef FOSSIL_LIB_CNULLPTR_H +#define FOSSIL_LIB_CNULLPTR_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// null type declaration for compatibility with C11, C23, and C++ +#ifndef FOSSIL_CNULL + +#if __cplusplus >= 201103L || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) +/** + * @brief Definition for cnull pointers in C++11 and later or C23 and later. + * + * In C++11 or later, `cnullptr` is a keyword representing a cnull pointer constant. + * In C23 or later, `_cnullptr` is recognized in the same way as C++. + */ + #define cnull nullptr + #define cnullptr nullptr +#else + #if defined(_WIN64) || defined(_WIN32) +/** + * @brief Definition for cnull pointers on Windows systems. + * + * For Windows (both 32-bit and 64-bit), we define `cnull` and `cnullptr` as 0. + */ + #define cnull 0 + #define cnullptr 0 +#else +/** + * @brief Definition for cnull pointers on POSIX systems, macOS, and embedded systems. + * + * For POSIX, macOS, and embedded systems, we define `cnull` and `cnullptr` as a void pointer to 0. + */ + #define cnull (void *)(0) + #define cnullptr (void *)(0) + #endif +#endif +#endif + +#define cterminator '\0' +#define wterminator L'\0' +#define cterm '\0' +#define wterm L'\0' + +#ifdef __cplusplus +} +#endif + +#endif /* FOSSIL_LIB_FRAMEWORK_H */ diff --git a/code/logic/fossil/lib/command.h b/code/logic/fossil/lib/command.h new file mode 100644 index 0000000..69c37f2 --- /dev/null +++ b/code/logic/fossil/lib/command.h @@ -0,0 +1,82 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#ifndef FOSSIL_LIB_COMMAND_H +#define FOSSIL_LIB_COMMAND_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Define a typedef for char* to make the code more readable +typedef char* fossil_command_t; + +/** + * Execute a command and return the result. + * + * @param process The command to be executed. + * @return The result of the command execution. + */ +int32_t fossil_command(fossil_command_t process); + +/** + * Check if a command execution was successful. + * + * @param process The command to be checked. + * @return 1 if the command was successful, 0 otherwise. + */ +int32_t fossil_command_success(fossil_command_t process); + +/** + * Retrieve the output of a command execution. + * + * @param process The command to retrieve output from. + * @param output Buffer to store the output. + * @param output_size Size of the output buffer. + * @return The result of the command execution. + */ +int32_t fossil_command_output(fossil_command_t process, char *restrict output, size_t output_size); + +/** + * Check if a command exists. + * + * @param process The command to be checked. + * @return 1 if the command exists, 0 otherwise. + */ +int32_t fossil_command_exists(fossil_command_t process); + +/** + * Erase a command and check if it exists. + * + * @param path The command to be erased. + * @return 1 if the command exists, 0 otherwise. + */ +int32_t fossil_command_erase_exists(fossil_command_t path); + +/** + * Safely concatenate two strings into a destination buffer. + * + * @param dest The destination buffer for the concatenated strings. + * @param src The source string to be concatenated. + * @param dest_size The size of the destination buffer. + */ +void fossil_command_strcat_safe(char *restrict dest, const char *restrict src, size_t dest_size); + +#ifdef __cplusplus +} +#endif + +#endif /* FOSSIL_LIB_FRAMEWORK_H */ diff --git a/code/logic/fossil/lib/exit.h b/code/logic/fossil/lib/exit.h new file mode 100644 index 0000000..6fc04d4 --- /dev/null +++ b/code/logic/fossil/lib/exit.h @@ -0,0 +1,98 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#ifndef FOSSIL_LIB_EXIT_H +#define FOSSIL_LIB_EXIT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Exit codes +#define FOSSIL_EXIT_SUCCESS 0 +#define FOSSIL_EXIT_FAILURE 1 + +enum { + FOSSIL_SUCCESS = 0, + FOSSIL_FAILURE = 1 +}; + +// Function pointer type for cleanup functions +typedef void (*fossil_handle_func_t)(void); + +/** + * @brief Handles the abort signal for the program. + * + * This function is called when the program needs to abort execution + * due to an unrecoverable error. + */ +void fossil_handle_abort(void); + +/** * @brief Handles normal program exit. * t foss * @param status The exit status code to return to the operating system. + * + * This function is called to perform cleanup and exit the program + * with the specified status code. + */ +void fossil_handle_exit(int status); + +/** + * @brief Handles quick program exit. + * + * @param status The exit status code to return to the operating system. + * + * This function is called to exit the program quickly, bypassing + * normal cleanup routines. + */ +void fossil_handle_quick_exit(int status); + +/** + * @brief Handles immediate program termination. + * + * @param status The exit status code to return to the operating system. + * + * This function is called to terminate the program immediately, + * without performing any cleanup. + */ +void fossil_handle__Exit(int status); + +/** + * @brief Registers a function to be called at program exit. + * + * @param func The function to register for exit handling. + * + * @return An integer indicating success or failure of the registration. + * + * This function allows the user to register a custom function that + * will be called when the program exits normally. + */ +int fossil_handle_atexit(fossil_handle_func_t func); + +/** + * @brief Registers a function to be called at quick exit. + * + * @param func The function to register for quick exit handling. + * + * @return An integer indicating success or failure of the registration. + * + * This function allows the user to register a custom function that + * will be called when the program exits quickly. + */ +int fossil_handle_at_quick_exit(fossil_handle_func_t func); + +#ifdef __cplusplus +} +#endif + +#endif /* FOSSIL_LIB_FRAMEWORK_H */ diff --git a/code/logic/fossil/lib/framework.h b/code/logic/fossil/lib/framework.h new file mode 100644 index 0000000..e77a2ec --- /dev/null +++ b/code/logic/fossil/lib/framework.h @@ -0,0 +1,25 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#ifndef FOSSIL_LIB_FRAMEWORK_H +#define FOSSIL_LIB_FRAMEWORK_H + +#include "arguments.h" +#include "cnullptr.h" +#include "command.h" +#include "hostsys.h" +#include "memory.h" +#include "regex.h" +#include "exit.h" + +#endif /* FOSSIL_LIB_FRAMEWORK_H */ diff --git a/code/logic/fossil/lib/hostsys.h b/code/logic/fossil/lib/hostsys.h new file mode 100644 index 0000000..b53deff --- /dev/null +++ b/code/logic/fossil/lib/hostsys.h @@ -0,0 +1,78 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#ifndef FOSSIL_LIB_HOSTSYS_H +#define FOSSIL_LIB_HOSTSYS_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + _FOSSIL_HOSTSYS_SIZE = 256 +}; + +// Structure to represent a host system +typedef struct { + char os_name[_FOSSIL_HOSTSYS_SIZE]; + char os_version[_FOSSIL_HOSTSYS_SIZE]; + char cpu_model[_FOSSIL_HOSTSYS_SIZE]; + int32_t cpu_cores; + int64_t total_memory; + int64_t free_memory; + bool is_big_endian; +} fossil_hostsystem_t; + +/** + * @brief Retrieves the system information and stores it in the provided fossil_hostsystem_t structure. + * + * This function retrieves various system information such as the operating system name, + * version, CPU model, number of CPU cores, total memory, and free memory. The information + * is stored in the provided fossil_hostsystem_t structure. + * + * @param info Pointer to the fossil_hostsystem_t structure where the system information will be stored. + * @return Returns true if the system information was successfully retrieved, otherwise false. + */ +bool fossil_hostsys_get(fossil_hostsystem_t *info); + +/** + * @brief Prints the system information to the standard output. + * + * This function prints the retrieved system information to the standard output, + * including the operating system name, version, CPU model, number of CPU cores, + * total memory, free memory, and endianness. + * + * @param info Pointer to the fossil_hostsystem_t structure containing the system information. + */ +void fossil_hostsys_print(fossil_hostsystem_t *info); + +/** + * @brief Returns a string indicating the endianness of the system. + * + * This function checks the endianness of the system and returns a string indicating + * whether the system is big endian or little endian. + * + * @param info Pointer to the fossil_hostsystem_t structure containing the system information. + * @return Returns a string "Big Endian" if the system is big endian, otherwise "Little Endian". + */ +const char* fossil_hostsys_endian(fossil_hostsystem_t *info); + +#ifdef __cplusplus +} +#endif + +#endif /* FOSSIL_LIB_FRAMEWORK_H */ diff --git a/code/logic/fossil/lib/memory.h b/code/logic/fossil/lib/memory.h new file mode 100644 index 0000000..7f551de --- /dev/null +++ b/code/logic/fossil/lib/memory.h @@ -0,0 +1,159 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#ifndef FOSSIL_LIB_MEMORY_H +#define FOSSIL_LIB_MEMORY_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Define fossil_memory_t as void* +typedef void* fossil_memory_t; + +/** + * Allocate memory. + * + * @param size The size of the memory to allocate. + * @return A pointer to the allocated memory. + * @throws Error message and exits if allocation fails. + */ +fossil_memory_t fossil_memory_alloc(size_t size); + +/** + * Reallocate memory. + * + * @param ptr A pointer to the previously allocated memory. + * @param size The new size of the memory to allocate. + * @return A pointer to the reallocated memory. + * @throws Error message and exits if reallocation fails or if the pointer is NULL. + */ +fossil_memory_t fossil_memory_realloc(fossil_memory_t ptr, size_t size); + +/** + * Free memory. + * + * @param ptr A pointer to the memory to free. + * @throws Error message and exits if the pointer is NULL. + */ +void fossil_memory_free(fossil_memory_t ptr); + +/** + * Copy memory. + * + * @param dest A pointer to the destination memory. + * @param src A pointer to the source memory. + * @param size The size of the memory to copy. + * @return A pointer to the destination memory. + * @throws Error message and exits if copying fails or if either source or destination is NULL. + */ +fossil_memory_t fossil_memory_copy(fossil_memory_t dest, const fossil_memory_t src, size_t size); + +/** + * Set memory. + * + * @param ptr A pointer to the memory to set. + * @param value The value to set. + * @param size The size of the memory to set. + * @return A pointer to the memory. + * @throws Error message and exits if setting fails or if the pointer is NULL. + */ +fossil_memory_t fossil_memory_set(fossil_memory_t ptr, int32_t value, size_t size); + +/** + * Duplicate memory. + * + * @param src A pointer to the memory to duplicate. + * @param size The size of the memory to duplicate. + * @return A pointer to the duplicated memory. + * @throws Error message and exits if duplication fails or if the source is NULL. + */ +fossil_memory_t fossil_memory_dup(const fossil_memory_t src, size_t size); + +/** + * Zero memory. + * + * @param ptr A pointer to the memory to zero. + * @param size The size of the memory to zero. + * @throws Error message and exits if the pointer is NULL. + */ +void fossil_memory_zero(fossil_memory_t ptr, size_t size); + +/** + * Allocate aligned memory. + * + * @param size The size of the memory to allocate. + * @param alignment The alignment of the memory to allocate. + * @return A pointer to the allocated memory. + * @throws Error message and exits if allocation fails or if the size or alignment is invalid. + */ +fossil_memory_t fossil_memory_alloc_aligned(size_t size, size_t alignment); + +/** + * Compare memory. + * + * @param ptr1 A pointer to the first memory. + * @param ptr2 A pointer to the second memory. + * @param size The size of the memory to compare. + * @return The result of the comparison. + * @throws Error message and exits if the pointers are NULL or if the size is zero. + */ +int fossil_memory_compare(const fossil_memory_t ptr1, const fossil_memory_t ptr2, size_t size); + +/** + * Move memory. + * + * @param dest A pointer to the destination memory. + * @param src A pointer to the source memory. + * @param size The size of the memory to move. + * @return A pointer to the destination memory. + * @throws Error message and exits if moving fails or if either source or destination is NULL. + */ +fossil_memory_t fossil_memory_move(fossil_memory_t dest, const fossil_memory_t src, size_t size); + +/** + * Resize memory. + * + * @param ptr A pointer to the memory to resize. + * @param old_size The old size of the memory. + * @param new_size The new size of the memory. + * @return A pointer to the resized memory. + * @throws Error message and exits if resizing fails or if the pointer is NULL. + */ +fossil_memory_t fossil_memory_resize(fossil_memory_t ptr, size_t old_size, size_t new_size); + +/** + * Check if a memory pointer is valid. + * + * @param ptr A pointer to the memory. + * @return 1 if the memory is valid, 0 otherwise. + */ +bool fossil_memory_is_valid(const fossil_memory_t ptr); + +/** + * Debug memory. + * + * @param ptr A pointer to the memory. + * @param size The size of the memory. + */ +void fossil_memory_debug(const fossil_memory_t ptr, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* FOSSIL_LIB_FRAMEWORK_H */ diff --git a/code/logic/fossil/lib/regex.h b/code/logic/fossil/lib/regex.h new file mode 100644 index 0000000..d23be32 --- /dev/null +++ b/code/logic/fossil/lib/regex.h @@ -0,0 +1,101 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#ifndef FOSSIL_LIB_REGEX_H +#define FOSSIL_LIB_REGEX_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +#include +#else +#include +#endif + +// Enumeration for regex operation statuses +enum { + FOSSIL_REGEX_STATUS_SUCCESS = 0, // Operation succeeded + FOSSIL_REGEX_STATUS_FAILURE = -1 // Operation failed +}; + +// Enumeration for regex limits +enum { + FOSSIL_REGEX_LIMIT_PATTERN_LENGTH = 255 // Maximum length of regex pattern +}; + +// Structure to hold regex pattern and matched substring, with optional threading support +typedef struct { + const char *pattern; // Pointer to the regex pattern + const char *matched_substring; // Pointer to the matched substring + + #ifdef _WIN32 + // Mutex for Windows to ensure thread-safe operations + HANDLE mutex; + #else + // Mutex for POSIX to ensure thread-safe operations + pthread_mutex_t mutex; + #endif +} fossil_regex_t; + +/** + * Create a new regex pattern instance. + * + * @param preg Pointer to the fossil_regex_t structure to store the created regex pattern. + * @param pattern The regex pattern to be compiled. + * @return 0 on success, non-zero on failure. + */ +int32_t fossil_regex_create(fossil_regex_t *preg, const char* pattern); + +/** + * Match a text against a compiled regex pattern. + * + * @param preg Pointer to the fossil_regex_t structure containing the compiled pattern. + * @param text The text to be matched against the regex pattern. + * @return 0 if there is a match, non-zero otherwise. + */ +int32_t fossil_regex_match(fossil_regex_t *preg, const char* text); + +/** + * Reset the regex pattern instance to the initial state. + * + * @param preg Pointer to the fossil_regex_t structure. + */ +void fossil_regex_reset(fossil_regex_t *preg); + +/** + * Match a text against a compiled regex pattern and extract the matched substring. + * + * @param preg Pointer to the fossil_regex_t structure containing the compiled pattern. + * @param text The text to be matched against the regex pattern. + * @return A constant string containing the matched substring or NULL if no match. + */ +const char *fossil_regex_match_and_extract(fossil_regex_t *preg, const char* text); + +/** + * Get the matched substring from the last successful match. + * + * @param preg Pointer to the fossil_regex_t structure. + * @return A constant string containing the matched substring or NULL if no match. + */ +const char *fossil_regex_get_matched_substring(fossil_regex_t *preg); + +#ifdef __cplusplus +} +#endif + +#endif /* FOSSIL_LIB_FRAMEWORK_H */ diff --git a/code/logic/hostsys.c b/code/logic/hostsys.c new file mode 100644 index 0000000..3de8b37 --- /dev/null +++ b/code/logic/hostsys.c @@ -0,0 +1,247 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include "fossil/lib/hostsys.h" + +#ifdef _WIN32 + #include + #include + #include +#elif __linux__ + #include + #include + #include +#elif __APPLE__ + #include + #include + #include + #include +#endif + +static bool fossil_hostsys_get_endian(fossil_hostsystem_t *info) { + unsigned int num = 1; + char *endian_check = (char*)# + + if (*endian_check == 1) { + info->is_big_endian = false; + } else { + info->is_big_endian = true; + } + + return true; +} + +#ifdef _WIN32 +static bool fossil_hostsys_get_windows(fossil_hostsystem_t *info) { + OSVERSIONINFO osvi; + SYSTEM_INFO si; + MEMORYSTATUSEX memInfo; + + memset(info, 0, sizeof(fossil_hostsystem_t)); + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + if (!GetVersionEx(&osvi)) { + fprintf(stderr, "Error getting Windows version information\n"); + return false; + } + + strncpy(info->os_name, "Windows", sizeof(info->os_name)); + snprintf(info->os_version, sizeof(info->os_version), "%ld.%ld", + osvi.dwMajorVersion, osvi.dwMinorVersion); + + GetNativeSystemInfo(&si); + snprintf(info->cpu_model, sizeof(info->cpu_model), "Intel"); + + info->cpu_cores = si.dwNumberOfProcessors; + + if (!GlobalMemoryStatusEx(&memInfo)) { + fprintf(stderr, "Error getting memory information\n"); + return false; + } + + info->total_memory = memInfo.ullTotalPhys / (1024 * 1024); // in MB + info->free_memory = memInfo.ullAvailPhys / (1024 * 1024); // in MB + + return true; +} + +#elif defined(__linux__) +static bool fossil_hostsys_get_linux(fossil_hostsystem_t *info) { + struct utsname unameData; + FILE *cpuinfo; + char line[256]; + + memset(info, 0, sizeof(fossil_hostsystem_t)); + + if (uname(&unameData) != 0) { + fprintf(stderr, "Error getting uname information\n"); + return false; + } + + strncpy(info->os_name, unameData.sysname, sizeof(info->os_name)); + strncpy(info->os_version, unameData.release, sizeof(info->os_version)); + + cpuinfo = fopen("/proc/cpuinfo", "r"); + if (cpuinfo) { + while (fgets(line, sizeof(line), cpuinfo)) { + if (strstr(line, "model name")) { + char *pos = strchr(line, ':'); + if (pos) { + strncpy(info->cpu_model, pos + 2, sizeof(info->cpu_model)); + break; + } + } + } + fclose(cpuinfo); + } else { + fprintf(stderr, "Error opening /proc/cpuinfo\n"); + return false; + } + + info->cpu_cores = sysconf(_SC_NPROCESSORS_ONLN); + + long pages = sysconf(_SC_PHYS_PAGES); + long page_size = sysconf(_SC_PAGE_SIZE); + info->total_memory = pages * page_size / (1024 * 1024); // in MB + + struct sysinfo memInfo; + if (sysinfo(&memInfo) == 0) { + info->free_memory = memInfo.freeram / (1024 * 1024); // in MB + } else { + fprintf(stderr, "Error getting memory information\n"); + return false; + } + + return true; +} + +#elif defined(__APPLE__) +#include + +static bool fossil_hostsys_get_macos(fossil_hostsystem_t *info) { + struct utsname unameData; + memset(info, 0, sizeof(fossil_hostsystem_t)); + + if (uname(&unameData) != 0) { + fprintf(stderr, "Error getting uname information\n"); + return false; + } + + strncpy(info->os_name, unameData.sysname, sizeof(info->os_name)); + strncpy(info->os_version, unameData.release, sizeof(info->os_version)); + + // Get CPU model + int mib[2] = {CTL_HW, HW_MODEL}; + size_t len = sizeof(info->cpu_model); + if (sysctl(mib, 2, info->cpu_model, &len, NULL, 0) != 0) { + fprintf(stderr, "Error getting CPU model information using sysctl\n"); + return false; + } + + // Get number of CPU cores + mib[1] = HW_NCPU; + len = sizeof(info->cpu_cores); + if (sysctl(mib, 2, &info->cpu_cores, &len, NULL, 0) != 0) { + fprintf(stderr, "Error getting CPU cores information using sysctl\n"); + return false; + } + + // Get total memory + mib[1] = HW_MEMSIZE; + len = sizeof(info->total_memory); + if (sysctl(mib, 2, &info->total_memory, &len, NULL, 0) != 0) { + fprintf(stderr, "Error getting total memory information using sysctl\n"); + return false; + } + info->total_memory /= (1024 * 1024); // Convert to MB + + // Get free memory using mach API + mach_port_t host_port = mach_host_self(); + mach_msg_type_number_t count = HOST_VM_INFO_COUNT; + vm_statistics_data_t vm_stats; + + if (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stats, &count) != KERN_SUCCESS) { + fprintf(stderr, "Error getting free memory information using mach API\n"); + return false; + } + info->free_memory = (vm_stats.free_count * vm_page_size) / (1024 * 1024); // Convert to MB + + return true; +} +#endif + +/** + * @brief Retrieves the system information and stores it in the provided fossil_hostsystem_t structure. + * + * This function retrieves various system information such as the operating system name, + * version, CPU model, number of CPU cores, total memory, and free memory. The information + * is stored in the provided fossil_hostsystem_t structure. + * + * @param info Pointer to the fossil_hostsystem_t structure where the system information will be stored. + * @return Returns true if the system information was successfully retrieved, otherwise false. + */ +bool fossil_hostsys_get(fossil_hostsystem_t *info) { + bool result = false; + + #ifdef _WIN32 + result = fossil_hostsys_get_windows(info); + #elif __linux__ + result = fossil_hostsys_get_linux(info); + #elif __APPLE__ + result = fossil_hostsys_get_macos(info); + #else + fprintf(stderr, "Unsupported platform\n"); + #endif + + if (result) { + return fossil_hostsys_get_endian(info); + } else { + return false; + } +} + +/** + * @brief Returns a string indicating the endianness of the system. + * + * This function checks the endianness of the system and returns a string indicating + * whether the system is big endian or little endian. + * + * @param info Pointer to the fossil_hostsystem_t structure containing the system information. + * @return Returns a string "Big Endian" if the system is big endian, otherwise "Little Endian". + */ +const char* fossil_hostsys_endian(fossil_hostsystem_t *info) { + if (info->is_big_endian) { + return "Big Endian"; + } else { + return "Little Endian"; + } +} + +/** + * @brief Prints the system information to the standard output. + * + * This function prints the retrieved system information to the standard output, + * including the operating system name, version, CPU model, number of CPU cores, + * total memory, free memory, and endianness. + * + * @param info Pointer to the fossil_hostsystem_t structure containing the system information. + */ +void fossil_hostsys_print(fossil_hostsystem_t *info) { + printf("Operating System: %s %s\n", info->os_name, info->os_version); + printf("CPU: %s\n", info->cpu_model); + printf("Number of Cores: %d\n", info->cpu_cores); + printf("Total Memory: %d MB\n", (int)info->total_memory); + printf("Free Memory: %d MB\n", (int)info->free_memory); + printf("Endian: %s\n", fossil_hostsys_endian(info)); +} diff --git a/code/logic/memory.c b/code/logic/memory.c new file mode 100644 index 0000000..bfc90b9 --- /dev/null +++ b/code/logic/memory.c @@ -0,0 +1,169 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include "fossil/lib/memory.h" +#include +#include + +fossil_memory_t fossil_memory_alloc(size_t size) { + if (size == 0) { + fprintf(stderr, "Error: fossil_memory_alloc() - Cannot allocate zero bytes.\n"); + return NULL; + } + + fossil_memory_t ptr = malloc(size); + if (!ptr) { + fprintf(stderr, "Error: fossil_memory_alloc() - Memory allocation failed.\n"); + return NULL; + } + return ptr; +} + +fossil_memory_t fossil_memory_realloc(fossil_memory_t ptr, size_t size) { + // realloc(ptr, size) is safe even if ptr is NULL + fossil_memory_t new_ptr = realloc(ptr, size); + + if (!new_ptr && size > 0) { + fprintf(stderr, "Error: fossil_memory_realloc() - Memory reallocation failed.\n"); + return NULL; + } + return new_ptr; +} + +void fossil_memory_free(fossil_memory_t ptr) { + free(ptr); // No need for NULL check, free() already handles NULL. +} + +fossil_memory_t fossil_memory_copy(fossil_memory_t dest, const fossil_memory_t src, size_t size) { + if (!dest || !src) { + fprintf(stderr, "Error: fossil_memory_copy() - Source or destination is NULL.\n"); + return NULL; + } + + if (size == 0) { + fprintf(stderr, "Error: fossil_memory_copy() - Cannot copy zero bytes.\n"); + return NULL; + } + + return memcpy(dest, src, size); +} + +fossil_memory_t fossil_memory_set(fossil_memory_t ptr, int32_t value, size_t size) { + if (!ptr) { + fprintf(stderr, "Error: fossil_memory_set() - Pointer is NULL.\n"); + return NULL; + } + + if (size == 0) { + fprintf(stderr, "Error: fossil_memory_set() - Cannot set zero bytes.\n"); + return NULL; + } + + return memset(ptr, value, size); +} + +fossil_memory_t fossil_memory_dup(const fossil_memory_t src, size_t size) { + if (!src || size == 0) { + fprintf(stderr, "Error: fossil_memory_dup() - Invalid source or zero size.\n"); + return NULL; + } + + fossil_memory_t dest = fossil_memory_alloc(size); + if (!dest) { + return NULL; // Error already handled in fossil_memory_alloc + } + + return memcpy(dest, src, size); +} + +void fossil_memory_zero(fossil_memory_t ptr, size_t size) { + if (!ptr || size == 0) { + fprintf(stderr, "Error: fossil_memory_zero() - Invalid pointer or zero size.\n"); + return; + } + + memset(ptr, 0, size); +} + +fossil_memory_t fossil_memory_alloc_aligned(size_t size, size_t alignment) { + if (size == 0 || alignment == 0 || (alignment & (alignment - 1)) != 0) { + fprintf(stderr, "Error: fossil_memory_alloc_aligned() - Invalid size or alignment.\n"); + return NULL; + } + + void* ptr; + int result = posix_memalign(&ptr, alignment, size); // POSIX + if (result != 0) { + fprintf(stderr, "Error: fossil_memory_alloc_aligned() - Memory alignment failed.\n"); + return NULL; + } + + return ptr; +} + +int fossil_memory_compare(const fossil_memory_t ptr1, const fossil_memory_t ptr2, size_t size) { + if (!ptr1 || !ptr2 || size == 0) { + fprintf(stderr, "Error: fossil_memory_compare() - Invalid pointers or zero size.\n"); + return -1; // Return -1 for invalid input + } + + return memcmp(ptr1, ptr2, size); +} + +fossil_memory_t fossil_memory_move(fossil_memory_t dest, const fossil_memory_t src, size_t size) { + if (!dest || !src || size == 0) { + fprintf(stderr, "Error: fossil_memory_move() - Invalid source or destination pointers, or zero size.\n"); + return NULL; + } + + return memmove(dest, src, size); +} + +fossil_memory_t fossil_memory_resize(fossil_memory_t ptr, size_t old_size, size_t new_size) { + if (new_size == 0) { + fossil_memory_free(ptr); + return NULL; + } + + fossil_memory_t new_ptr = fossil_memory_realloc(ptr, new_size); + if (!new_ptr) { + fprintf(stderr, "Error: fossil_memory_resize() - Memory resize failed, old memory preserved.\n"); + return ptr; // Return the old memory if realloc fails + } + + return new_ptr; +} + +bool fossil_memory_is_valid(const fossil_memory_t ptr) { + if (!ptr) { + return false; + } + // Optional: Add more validation logic if needed, but normally you'd rely on the caller to manage validity. + return true; +} + +void fossil_memory_debug(const fossil_memory_t ptr, size_t size) { + if (!ptr || size == 0) { + fprintf(stderr, "Error: fossil_memory_debug() - Invalid pointer or size.\n"); + return; + } + + printf("Memory block at %p of size %zu bytes:\n", ptr, size); + for (size_t i = 0; i < size; i++) { + printf("%02X ", ((unsigned char*)ptr)[i]); + if (i % 16 == 15) { + printf("\n"); + } + } + printf("\n"); +} diff --git a/code/logic/meson.build b/code/logic/meson.build new file mode 100644 index 0000000..5d983e6 --- /dev/null +++ b/code/logic/meson.build @@ -0,0 +1,12 @@ +dir = include_directories('.') + +fossil_lib_lib = library('fossil-lib', + files('command.c', 'exit.c', 'memory.c', 'hostsys.c', 'arguments.c', 'regex.c'), + install: true, + dependencies: [dependency('threads')], # needed for regex threading features + include_directories: dir) + +fossil_lib_dep = declare_dependency( + link_with: [fossil_lib_lib], + dependencies: [dependency('threads')], + include_directories: dir) diff --git a/code/logic/regex.c b/code/logic/regex.c new file mode 100644 index 0000000..350d101 --- /dev/null +++ b/code/logic/regex.c @@ -0,0 +1,92 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include "fossil/lib/regex.h" +#include +#include +#include + +// Function prototypes +int32_t is_match(const char *text, const char *pattern); + +int32_t fossil_regex_create(fossil_regex_t *preg, const char* pattern) { + // Input validation: Check if preg or pattern is NULL + if (preg == NULL || pattern == NULL) { + return FOSSIL_REGEX_STATUS_FAILURE; + } + + // Validate pattern length to prevent buffer overflow + size_t pattern_len = strlen(pattern); + if (pattern_len == 0 || pattern_len >= FOSSIL_REGEX_LIMIT_PATTERN_LENGTH) { + return FOSSIL_REGEX_STATUS_FAILURE; + } + + preg->pattern = pattern; + preg->matched_substring = NULL; + + return FOSSIL_REGEX_STATUS_SUCCESS; +} + +int32_t fossil_regex_match(fossil_regex_t *preg, const char* text) { + if (preg == NULL || text == NULL) { + return FOSSIL_REGEX_STATUS_FAILURE; + } + + // Call the actual matching function + int result = is_match(text, preg->pattern); + + preg->matched_substring = result ? text : NULL; + + return result ? FOSSIL_REGEX_STATUS_SUCCESS : FOSSIL_REGEX_STATUS_FAILURE; +} + +void fossil_regex_reset(fossil_regex_t *preg) { + if (preg == NULL) { + return; + } + + preg->pattern = NULL; + preg->matched_substring = NULL; +} + +const char *fossil_regex_get_matched_substring(fossil_regex_t *preg) { + if (preg == NULL) { + return NULL; + } + return preg->matched_substring; +} + +const char *fossil_regex_match_and_extract(fossil_regex_t *preg, const char* text) { + if (preg == NULL || text == NULL) { + return NULL; + } + + if (fossil_regex_match(preg, text) == FOSSIL_REGEX_STATUS_SUCCESS) { + return fossil_regex_get_matched_substring(preg); + } else { + return NULL; + } +} + +// Actual regex matching function +int32_t is_match(const char *text, const char *pattern) { + if (*pattern == '\0') { + return *text == '\0'; + } + + if (*(pattern + 1) == '*') { + return is_match(text, pattern + 2) || (*text != '\0' && (*pattern == '.' || *text == *pattern) && is_match(text + 1, pattern)); + } else { + return (*text != '\0' && (*pattern == '.' || *text == *pattern) && is_match(text + 1, pattern + 1)); + } +} diff --git a/code/meson.build b/code/meson.build new file mode 100644 index 0000000..0336a90 --- /dev/null +++ b/code/meson.build @@ -0,0 +1,2 @@ +subdir('logic') +subdir('tests') \ No newline at end of file diff --git a/code/tests/meson.build b/code/tests/meson.build new file mode 100644 index 0000000..9cd7bd9 --- /dev/null +++ b/code/tests/meson.build @@ -0,0 +1,20 @@ +if get_option('with_test').enabled() + run_command(['python3', 'tools' / 'generate-runner.py'], check: true) + + test_src = ['unit_runner.c'] + test_cubes = [ + 'cnullptr', 'command', 'memory', 'hostsys', 'arguments', 'regex' + ] + + foreach cube : test_cubes + test_src += ['test_' + cube + '.c'] + endforeach + + pizza = executable('runner', test_src, + include_directories: dir, + dependencies: [ + dependency('fossil-test'), + fossil_lib_dep]) + + test('xunit_tests', pizza) # Renamed the test target for clarity +endif diff --git a/code/tests/test_arguments.c b/code/tests/test_arguments.c new file mode 100644 index 0000000..8c68d96 --- /dev/null +++ b/code/tests/test_arguments.c @@ -0,0 +1,62 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include +#include + +#include "fossil/lib/framework.h" + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test +// * * * * * * * * * * * * * * * * * * * * * * * * + +FOSSIL_TEST(test_fossil_arg_parse_has) { + // Test fossil_arg_parse_has function + fossil_option_t options[] = { + {"option1", COPTION_TYPE_BOOL, {.bool_val = 0}, cnull, 0, 0}, + {"option2", COPTION_TYPE_INT, {.int_val = 42}, cnull, 0, 0} + }; + int num_options = sizeof(options) / sizeof(options[0]); + + // Assuming fossil_arg_parse_has returns 1 for the existing option + ASSUME_ITS_EQUAL_I32(0, fossil_arg_parse_has(options, num_options, "option1")); +} + +FOSSIL_TEST(test_fossil_arg_parse) { + // Test fossil_arg_parse function + const char* argv[] = {"program", "-number", "42", "-name", "John", "-flag", "-choice", "choice2", "-feature", "enable"}; + const int argc = sizeof(argv) / sizeof(argv[0]); + + fossil_command_line_t cmd = {argc, (char **)argv}; + + fossil_option_t options[] = { + {"option1", COPTION_TYPE_INT, {.int_val = 0}, cnull, 0, 0}, + {"option2", COPTION_TYPE_BOOL, {.bool_val = 0}, cnull, 0, 0} + }; + int num_options = sizeof(options) / sizeof(options[0]); + + // Assuming fossil_arg_parse modifies the options array + fossil_arg_parse(&cmd, options, num_options); + + ASSUME_ITS_EQUAL_I32(0, options[0].value.int_val); + ASSUME_ITS_EQUAL_I32(0, options[1].value.bool_val); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Pool +// * * * * * * * * * * * * * * * * * * * * * * * * + +FOSSIL_TEST_GROUP(c_commandline_tests) { + ADD_TEST(test_fossil_arg_parse_has); + ADD_TEST(test_fossil_arg_parse); +} diff --git a/code/tests/test_cnullptr.c b/code/tests/test_cnullptr.c new file mode 100644 index 0000000..02f7ee1 --- /dev/null +++ b/code/tests/test_cnullptr.c @@ -0,0 +1,68 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include +#include + +#include "fossil/lib/framework.h" + +#ifndef cnull +#error "cnull is not defined." +#endif + +#ifndef cnullptr +#error "cnullptr is not defined." +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test +// * * * * * * * * * * * * * * * * * * * * * * * * + +// Test cases for cnull +FOSSIL_TEST(test_cnull_definition) { + // Test cnull definition +#if __cplusplus >= 201103L || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) + // C++11 or later, C23 or later + ASSUME_ITS_EQUAL_PTR(cnull, nullptr); + ASSUME_ITS_EQUAL_PTR(cnullptr, nullptr); +#else + // Pre-C++11 or C23 + #if defined(_WIN64) || defined(_WIN32) + // Windows + ASSUME_ITS_EQUAL_PTR(cnull, 0); + ASSUME_ITS_EQUAL_PTR(cnullptr, 0); + #else + // POSIX, macOS, and embedded systems + ASSUME_ITS_EQUAL_PTR(cnull, (void *)(0)); + ASSUME_ITS_EQUAL_PTR(cnullptr, (void *)(0)); + #endif +#endif +} + +// Test cases for cterminator and related constants +FOSSIL_TEST(test_cterminator_definition) { + // Check if the terminator constants are defined correctly + ASSUME_ITS_EQUAL_CHAR(cterminator, '\0'); + ASSUME_ITS_EQUAL_WCHAR(wterminator, L'\0'); + ASSUME_ITS_EQUAL_CHAR(cterm, '\0'); + ASSUME_ITS_EQUAL_WCHAR(wterm, L'\0'); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Pool +// * * * * * * * * * * * * * * * * * * * * * * * * + +FOSSIL_TEST_GROUP(cnull_tests) { + ADD_TEST(test_cnull_definition); + ADD_TEST(test_cterminator_definition); +} diff --git a/code/tests/test_command.c b/code/tests/test_command.c new file mode 100644 index 0000000..f259427 --- /dev/null +++ b/code/tests/test_command.c @@ -0,0 +1,77 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include +#include + +#include "fossil/lib/framework.h" + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test +// * * * * * * * * * * * * * * * * * * * * * * * * + +// Test cases for fossil_command functions +FOSSIL_TEST(test_fossil_command_success) { + ASSUME_ITS_EQUAL_I32(fossil_command_success("success"), 1); + ASSUME_ITS_EQUAL_I32(fossil_command_success("failure"), 0); + ASSUME_ITS_EQUAL_I32(fossil_command_success("unknown"), 0); +} + +FOSSIL_TEST(test_fossil_command_output) { + char output[256]; + + ASSUME_ITS_EQUAL_I32(fossil_command_output("success", output, sizeof(output)), 0); + ASSUME_ITS_EQUAL_CSTR(output, "Command executed successfully."); + + ASSUME_ITS_EQUAL_I32(fossil_command_output("failure", output, sizeof(output)), 1); + ASSUME_ITS_EQUAL_CSTR(output, "Command failed to execute."); + + ASSUME_ITS_EQUAL_I32(fossil_command_output("unknown", output, sizeof(output)), -1); +} + +FOSSIL_TEST(test_fossil_command_exists) { + ASSUME_ITS_EQUAL_I32(fossil_command_exists("success"), 1); + ASSUME_ITS_EQUAL_I32(fossil_command_exists("failure"), 1); + ASSUME_ITS_EQUAL_I32(fossil_command_exists("unknown"), 0); +} + +FOSSIL_TEST(test_fossil_command_erase_exists) { + ASSUME_ITS_EQUAL_I32(fossil_command_erase_exists("success"), 1); + ASSUME_ITS_EQUAL_I32(fossil_command_erase_exists("failure"), 1); + ASSUME_ITS_EQUAL_I32(fossil_command_erase_exists("unknown"), 0); +} + +FOSSIL_TEST(test_fossil_command_strcat_safe) { + char dest[256] = "Initial "; + const char *src = "Concatenated"; + + fossil_command_strcat_safe(dest, src, sizeof(dest)); + ASSUME_ITS_EQUAL_CSTR(dest, "Initial Concatenated"); + + // Test edge case: concatenation with a buffer that is too small + char small_dest[10] = "Initial "; + fossil_command_strcat_safe(small_dest, src, sizeof(small_dest)); + ASSUME_ITS_EQUAL_CSTR(small_dest, "Initial Con"); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Pool +// * * * * * * * * * * * * * * * * * * * * * * * * + +FOSSIL_TEST_GROUP(c_command_tests) { + ADD_TEST(test_fossil_command_success); + ADD_TEST(test_fossil_command_output); + ADD_TEST(test_fossil_command_exists); + ADD_TEST(test_fossil_command_erase_exists); + ADD_TEST(test_fossil_command_strcat_safe); +} diff --git a/code/tests/test_hostsys.c b/code/tests/test_hostsys.c new file mode 100644 index 0000000..28a8d92 --- /dev/null +++ b/code/tests/test_hostsys.c @@ -0,0 +1,43 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include +#include + +#include "fossil/lib/framework.h" + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test +// * * * * * * * * * * * * * * * * * * * * * * * * + +FOSSIL_TEST(test_fossil_hostsys_get) { + fossil_hostsystem_t info; + fossil_hostsys_get(&info); + ASSUME_NOT_EQUAL_CSTR("", info.os_name); + ASSUME_NOT_EQUAL_CSTR("", info.os_version); +} + +FOSSIL_TEST(test_fossil_hostsys_endian) { + fossil_hostsystem_t info; + fossil_hostsys_get(&info); + ASSUME_ITS_EQUAL_CSTR(fossil_hostsys_endian(&info), info.is_big_endian ? "Big Endian" : "Little Endian"); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Pool +// * * * * * * * * * * * * * * * * * * * * * * * * + +FOSSIL_TEST_GROUP(c_hostsys_tests) { + ADD_TEST(test_fossil_hostsys_get); + ADD_TEST(test_fossil_hostsys_endian); +} diff --git a/code/tests/test_memory.c b/code/tests/test_memory.c new file mode 100644 index 0000000..e8bc65a --- /dev/null +++ b/code/tests/test_memory.c @@ -0,0 +1,157 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include +#include + +#include "fossil/lib/framework.h" + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test +// * * * * * * * * * * * * * * * * * * * * * * * * + +FOSSIL_TEST(test_memory_alloc) { + size_t size = 10; + fossil_memory_t ptr = fossil_memory_alloc(size); + ASSUME_NOT_CNULL(ptr); + fossil_memory_free(ptr); // Cleanup +} + +FOSSIL_TEST(test_memory_realloc) { + size_t size = 10; + fossil_memory_t ptr = fossil_memory_alloc(size); + ASSUME_NOT_CNULL(ptr); + + size *= 2; + ptr = fossil_memory_realloc(ptr, size); + ASSUME_NOT_CNULL(ptr); + + fossil_memory_free(ptr); // Cleanup +} + +FOSSIL_TEST(test_memory_dup) { + size_t size = 10; + fossil_memory_t src = fossil_memory_alloc(size); + ASSUME_NOT_CNULL(src); + + fossil_memory_t dest = fossil_memory_dup(src, size); + ASSUME_NOT_CNULL(dest); + + ASSUME_ITS_TRUE(memcmp(src, dest, size) == 0); // Ensure that both blocks are identical + fossil_memory_free(src); + fossil_memory_free(dest); // Cleanup +} + +FOSSIL_TEST(test_memory_zero) { + size_t size = 10; + fossil_memory_t ptr = fossil_memory_alloc(size); + ASSUME_NOT_CNULL(ptr); + + fossil_memory_zero(ptr, size); + for (size_t i = 0; i < size; ++i) { + ASSUME_ITS_TRUE(((unsigned char*)ptr)[i] == 0); // Ensure all bytes are zero + } + + fossil_memory_free(ptr); // Cleanup +} + +FOSSIL_TEST(test_memory_alloc_aligned) { + size_t size = 16; + size_t alignment = 16; // Alignment to 16 bytes + fossil_memory_t ptr = fossil_memory_alloc_aligned(size, alignment); + ASSUME_NOT_CNULL(ptr); + ASSUME_ITS_TRUE(((uintptr_t)ptr % alignment) == 0); // Ensure alignment + + fossil_memory_free(ptr); // Cleanup +} + +FOSSIL_TEST(test_memory_compare) { + size_t size = 10; + fossil_memory_t ptr1 = fossil_memory_alloc(size); + fossil_memory_t ptr2 = fossil_memory_alloc(size); + ASSUME_NOT_CNULL(ptr1); + ASSUME_NOT_CNULL(ptr2); + + fossil_memory_set(ptr1, 0xAA, size); // Set all bytes to 0xAA + fossil_memory_set(ptr2, 0xAA, size); // Set all bytes to 0xAA + ASSUME_ITS_TRUE(fossil_memory_compare(ptr1, ptr2, size) == 0); // Should be equal + + fossil_memory_set(ptr2, 0xBB, size); // Change ptr2 + ASSUME_ITS_TRUE(fossil_memory_compare(ptr1, ptr2, size) != 0); // Should not be equal + + fossil_memory_free(ptr1); + fossil_memory_free(ptr2); // Cleanup +} + +FOSSIL_TEST(test_memory_move) { + size_t size = 10; + fossil_memory_t src = fossil_memory_alloc(size); + ASSUME_NOT_CNULL(src); + + fossil_memory_t dest = fossil_memory_alloc(size); + ASSUME_NOT_CNULL(dest); + + fossil_memory_set(src, 0xAA, size); + fossil_memory_move(dest, src, size); + ASSUME_ITS_TRUE(memcmp(dest, src, size) == 0); // Ensure memory is moved correctly + + fossil_memory_free(src); + fossil_memory_free(dest); // Cleanup +} + +FOSSIL_TEST(test_memory_resize) { + size_t size = 10; + fossil_memory_t ptr = fossil_memory_alloc(size); + ASSUME_NOT_CNULL(ptr); + + ptr = fossil_memory_resize(ptr, size, size * 2); + ASSUME_NOT_CNULL(ptr); // Ensure resizing works + + fossil_memory_free(ptr); // Cleanup +} + +FOSSIL_TEST(test_memory_is_valid) { + fossil_memory_t ptr = fossil_memory_alloc(10); + ASSUME_ITS_TRUE(fossil_memory_is_valid(ptr)); // Should be valid + ASSUME_ITS_TRUE(!fossil_memory_is_valid(NULL)); // NULL should not be valid + + fossil_memory_free(ptr); // Cleanup +} + +FOSSIL_TEST(test_memory_debug) { + size_t size = 10; + fossil_memory_t ptr = fossil_memory_alloc(size); + ASSUME_NOT_CNULL(ptr); + + fossil_memory_set(ptr, 0xAA, size); + fossil_memory_debug(ptr, size); // No assert here, just for manual debugging purposes + + fossil_memory_free(ptr); // Cleanup +} + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Pool +// * * * * * * * * * * * * * * * * * * * * * * * * + +FOSSIL_TEST_GROUP(c_memory_tests) { + ADD_TEST(test_memory_alloc); + ADD_TEST(test_memory_realloc); + ADD_TEST(test_memory_dup); + ADD_TEST(test_memory_zero); + ADD_TEST(test_memory_alloc_aligned); + ADD_TEST(test_memory_compare); + ADD_TEST(test_memory_move); + ADD_TEST(test_memory_resize); + ADD_TEST(test_memory_is_valid); + ADD_TEST(test_memory_debug); +} diff --git a/code/tests/test_regex.c b/code/tests/test_regex.c new file mode 100644 index 0000000..c19633f --- /dev/null +++ b/code/tests/test_regex.c @@ -0,0 +1,92 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include +#include + +#include "fossil/lib/framework.h" + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test +// * * * * * * * * * * * * * * * * * * * * * * * * + +// Test cases for fossil_regex functions +FOSSIL_TEST(test_fossil_regex_create) { + fossil_regex_t regex; + ASSUME_EQUAL(fossil_regex_create(®ex, "test"), FOSSIL_REGEX_STATUS_SUCCESS); + + // Check if the pattern is correctly set + ASSUME_STRING_EQUAL(regex.pattern, "test"); + + // Check mutex initialization + #ifdef _WIN32 + ASSUME_NOT_CNULL(regex.mutex); + #else + pthread_mutex_destroy(®ex.mutex); // Clean up + #endif +} + +FOSSIL_TEST(test_fossil_regex_match) { + fossil_regex_t regex; + fossil_regex_create(®ex, "pattern"); + + ASSUME_EQUAL(fossil_regex_match(®ex, "this is a pattern"), FOSSIL_REGEX_STATUS_SUCCESS); + ASSUME_EQUAL(fossil_regex_match(®ex, "no match here"), FOSSIL_REGEX_STATUS_FAILURE); + + fossil_regex_reset(®ex); +} + +FOSSIL_TEST(test_fossil_regex_match_and_extract) { + fossil_regex_t regex; + fossil_regex_create(®ex, "extract"); + + ASSUME_STRING_EQUAL(fossil_regex_match_and_extract(®ex, "extract this text"), "extract"); + ASSUME_EQUAL(fossil_regex_match_and_extract(®ex, "no match"), NULL); + + // Test extraction + ASSUME_STRING_EQUAL(fossil_regex_get_matched_substring(®ex), "extract"); + + fossil_regex_reset(®ex); +} + +FOSSIL_TEST(test_fossil_regex_reset) { + fossil_regex_t regex; + fossil_regex_create(®ex, "reset"); + + fossil_regex_match_and_extract(®ex, "reset this text"); + ASSUME_STRING_EQUAL(fossil_regex_get_matched_substring(®ex), "reset"); + + fossil_regex_reset(®ex); + ASSUME_EQUAL(fossil_regex_get_matched_substring(®ex), NULL); +} + +FOSSIL_TEST(test_fossil_regex_limit_pattern_length) { + char long_pattern[FOSSIL_REGEX_LIMIT_PATTERN_LENGTH + 10]; + memset(long_pattern, 'a', sizeof(long_pattern) - 1); + long_pattern[sizeof(long_pattern) - 1] = '\0'; + + fossil_regex_t regex; + ASSUME_EQUAL(fossil_regex_create(®ex, long_pattern), FOSSIL_REGEX_STATUS_FAILURE); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Pool +// * * * * * * * * * * * * * * * * * * * * * * * * + +FOSSIL_TEST_GROUP(c_regex_tests) { + ADD_TEST(test_fossil_regex_create); + ADD_TEST(test_fossil_regex_match); + ADD_TEST(test_fossil_regex_match_and_extract); + ADD_TEST(test_fossil_regex_reset); + ADD_TEST(test_fossil_regex_limit_pattern_length); +} diff --git a/code/tests/tools/generate-runner.py b/code/tests/tools/generate-runner.py new file mode 100644 index 0000000..cdc3e06 --- /dev/null +++ b/code/tests/tools/generate-runner.py @@ -0,0 +1,74 @@ +import os +import re + + +class TestRunnerGenerator: + def __init__(self): + self.directory = os.getcwd() + + def find_test_groups(self): + test_groups = set() + pattern = r"FOSSIL_TEST_GROUP\((\w+)\)" + + for root, _, files in os.walk(self.directory): + for file in files: + if file.startswith("test_") and file.endswith(".c"): + with open(os.path.join(root, file), "r") as f: + content = f.read() + matches = re.findall(pattern, content) + test_groups.update(matches) + + return list(test_groups) + + def generate_test_runner(self, test_groups): + header = """ +// Generated Fossil Logic Test +""" + + header += """ +#include +""" + + header += """ + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test List +// * * * * * * * * * * * * * * * * * * * * * * * *\n""" + + extern_pools = "\n".join( + [f"FOSSIL_TEST_EXPORT({group});" for group in test_groups] + ) + + runner = """ + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Runner +// * * * * * * * * * * * * * * * * * * * * * * * *""" + + runner += """ +int main(int argc, char **argv) { + FOSSIL_TEST_CREATE(argc, argv);\n""" + + import_pools = "\n".join( + [f" FOSSIL_TEST_IMPORT({group});" for group in test_groups] + ) + + footer = """ + FOSSIL_TEST_RUN(); + return FOSSIL_TEST_ERASE(); +} // end of func +""" + + with open("unit_runner.c", "w") as file: + file.write(header) + file.write("\n") + file.write(extern_pools) + file.write(runner) + file.write(import_pools) + file.write("\n") + file.write(footer) + + +generator = TestRunnerGenerator() +test_groups = generator.find_test_groups() +generator.generate_test_runner(test_groups) diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..6ce63d8 --- /dev/null +++ b/meson.build @@ -0,0 +1,7 @@ +project('Fossil Lib', 'c', 'cpp', + meson_version: '>=1.3.0', + license: 'MPL-2.0', + version: '0.1.0', + default_options: ['c_std=c18', 'cpp_std=c++20']) + +subdir('code') diff --git a/meson.options b/meson.options new file mode 100644 index 0000000..3819134 --- /dev/null +++ b/meson.options @@ -0,0 +1,9 @@ +# - ############## - # +# Project Option # +# - ############## - # + +option('with_test', + type : 'feature', + value : 'disabled', + description : 'Enable Fossil Test for this project' +) \ No newline at end of file diff --git a/subprojects/fossil-test.wrap b/subprojects/fossil-test.wrap new file mode 100644 index 0000000..a5e6783 --- /dev/null +++ b/subprojects/fossil-test.wrap @@ -0,0 +1,11 @@ +# ====================== +# Git Wrap package definition +# ====================== +[wrap-git] +url = https://github.com/fossillogic/fossil-test.git +revision = v1.0.3 + +[provide] +fossil-test = fossil_test_dep +fossil-mock = fossil_mock_dep +fossil-mark = fossil_mark_dep \ No newline at end of file